mobile: improve handling of Bearer Capability IE for MT calls

This patch prepares for adding MT data call support:

* Move handling of the Bearer Capability IE into a function.
* Check transfer mode and coding standard in the received BCap.

Change-Id: I3a5cac8c35ba6b7bdc5fcb077690b32848747756
Related: OS#4396
This commit is contained in:
Vadim Yanitskiy 2023-10-17 17:24:27 +07:00
parent 292f39900c
commit 40609ca94b
1 changed files with 118 additions and 58 deletions

View File

@ -192,6 +192,119 @@ static void mncc_set_bearer(struct gsm_mncc *mncc,
mncc->bearer_cap.mode = GSM48_BCAP_TMOD_CIRCUIT;
}
/* Check the given Bearer Capability, select first supported speech codec version.
* The choice between half-rate and full-rate is made based on current settings.
* Return a selected codec or -1 if no speech codec was selected. */
static int mncc_handle_bcap_speech(const struct gsm_mncc_bearer_cap *bcap,
const struct gsm_settings *set)
{
int speech_ver_half = -1;
int speech_ver = -1;
for (unsigned int i = 0; bcap->speech_ver[i] >= 0; i++) {
int temp = mncc_get_bearer(set, bcap->speech_ver[i]);
switch (temp) {
case GSM48_BCAP_SV_AMR_H:
case GSM48_BCAP_SV_HR:
/* only the first half rate */
if (speech_ver_half < 0)
speech_ver_half = temp;
break;
default:
if (temp < 0)
continue;
/* only the first full rate */
if (speech_ver < 0)
speech_ver = temp;
break;
}
}
/* half and full given */
if (speech_ver_half >= 0 && speech_ver >= 0) {
if (set->half_prefer) {
LOGP(DMNCC, LOGL_INFO, " both supported"
" codec rates are given, using "
"preferred half rate\n");
speech_ver = speech_ver_half;
} else {
LOGP(DMNCC, LOGL_INFO, " both supported"
" codec rates are given, using "
"preferred full rate\n");
}
} else if (speech_ver_half < 0 && speech_ver < 0) {
LOGP(DMNCC, LOGL_INFO, " no supported codec "
"rate is given\n");
/* only half rate is given, use it */
} else if (speech_ver_half >= 0) {
LOGP(DMNCC, LOGL_INFO, " only supported half "
"rate codec is given, using it\n");
speech_ver = speech_ver_half;
/* only full rate is given, use it */
} else {
LOGP(DMNCC, LOGL_INFO, " only supported full "
"rate codec is given, using it\n");
}
return speech_ver;
}
static int mncc_handle_bcap(struct gsm_mncc *mncc_out, /* CC Call Confirmed */
const struct gsm_mncc *mncc_in, /* CC Setup */
const struct gsm_settings *set)
{
const struct gsm_mncc_bearer_cap *bcap = &mncc_in->bearer_cap;
/* 3GPP TS 24.008, section 9.3.2.2 defines several cases in which the
* Bearer Capability 1 IE is to be included, provided that at least
* one of these conditions is met. */
/* if the Bearer Capability 1 IE is not present */
if (~mncc_in->fields & MNCC_F_BEARER_CAP) {
/* ... include our own Bearer Capability, assuming a speech call */
mncc_set_bearer(mncc_out, set, -1);
return 0;
}
if (bcap->mode != GSM48_BCAP_TMOD_CIRCUIT) {
LOGP(DMNCC, LOGL_ERROR,
"%s(): Transfer mode 0x%02x is not supported\n",
__func__, bcap->mode);
return -ENOTSUP;
}
if (bcap->coding != GSM48_BCAP_CODING_GSM_STD) {
LOGP(DMNCC, LOGL_ERROR,
"%s(): Coding standard 0x%02x is not supported\n",
__func__, bcap->coding);
return -ENOTSUP;
}
switch (bcap->transfer) {
case GSM48_BCAP_ITCAP_SPEECH:
{
int speech_ver = mncc_handle_bcap_speech(bcap, set);
/* include bearer cap, if not given in setup (see above)
* or if multiple codecs are given
* or if not only full rate
* or if given codec is unimplemented
*/
if (speech_ver < 0)
mncc_set_bearer(mncc_out, set, -1);
else if (bcap->speech_ver[1] >= 0 || speech_ver != 0)
mncc_set_bearer(mncc_out, set, speech_ver);
break;
}
case GSM48_BCAP_ITCAP_UNR_DIG_INF:
default:
LOGP(DMNCC, LOGL_ERROR,
"%s(): Information transfer capability 0x%02x is not supported\n",
__func__, bcap->transfer);
return -ENOTSUP;
}
return 0;
}
/*
* MNCCms dummy application
*/
@ -264,7 +377,6 @@ int mncc_recv_internal(struct osmocom_ms *ms, int msg_type, void *arg)
struct gsm_call *call = get_call_ref(data->callref);
struct gsm_mncc mncc;
uint8_t cause;
int8_t speech_ver = -1, speech_ver_half = -1, temp;
int first_call = 0;
/* call does not exist */
@ -397,53 +509,6 @@ int mncc_recv_internal(struct osmocom_ms *ms, int msg_type, void *arg)
cause = GSM48_CC_CAUSE_USER_BUSY;
goto release;
}
/* select first supported speech_ver */
if ((data->fields & MNCC_F_BEARER_CAP)) {
int i;
for (i = 0; data->bearer_cap.speech_ver[i] >= 0; i++) {
temp = mncc_get_bearer(set, data->bearer_cap.speech_ver[i]);
switch (temp) {
case GSM48_BCAP_SV_AMR_H:
case GSM48_BCAP_SV_HR:
/* only the first half rate */
if (speech_ver_half < 0)
speech_ver_half = temp;
break;
default:
if (temp < 0)
continue;
/* only the first full rate */
if (speech_ver < 0)
speech_ver = temp;
break;
}
}
/* half and full given */
if (speech_ver_half >= 0 && speech_ver >= 0) {
if (set->half_prefer) {
LOGP(DMNCC, LOGL_INFO, " both supported"
" codec rates are given, using "
"preferred half rate\n");
speech_ver = speech_ver_half;
} else
LOGP(DMNCC, LOGL_INFO, " both supported"
" codec rates are given, using "
"preferred full rate\n");
} else if (speech_ver_half < 0 && speech_ver < 0) {
LOGP(DMNCC, LOGL_INFO, " no supported codec "
"rate is given\n");
/* only half rate is given, use it */
} else if (speech_ver_half >= 0) {
LOGP(DMNCC, LOGL_INFO, " only supported half "
"rate codec is given, using it\n");
speech_ver = speech_ver_half;
/* only full rate is given, use it */
} else {
LOGP(DMNCC, LOGL_INFO, " only supported full "
"rate codec is given, using it\n");
}
}
/* presentation allowed if present == 0 */
if (data->calling.present || !data->calling.number[0])
l23_vty_ms_notify(ms, "Incoming call (anonymous)\n");
@ -460,16 +525,11 @@ int mncc_recv_internal(struct osmocom_ms *ms, int msg_type, void *arg)
data->calling.number, call->callref);
memset(&mncc, 0, sizeof(struct gsm_mncc));
mncc.callref = call->callref;
/* only include bearer cap, if not given in setup
* or if multiple codecs are given
* or if not only full rate
* or if given codec is unimplemented
*/
if (!(data->fields & MNCC_F_BEARER_CAP) || speech_ver < 0)
mncc_set_bearer(&mncc, set, -1);
else if (data->bearer_cap.speech_ver[1] >= 0
|| speech_ver != 0)
mncc_set_bearer(&mncc, set, speech_ver);
/* Bearer capability (optional) */
if (mncc_handle_bcap(&mncc, data, &ms->settings) != 0) {
cause = GSM48_CC_CAUSE_INCOMPAT_DEST;
goto release;
}
/* CC capabilities (optional) */
if (ms->settings.cc_dtmf) {
mncc.fields |= MNCC_F_CCCAP;