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:
parent
292f39900c
commit
40609ca94b
|
@ -192,6 +192,119 @@ static void mncc_set_bearer(struct gsm_mncc *mncc,
|
||||||
mncc->bearer_cap.mode = GSM48_BCAP_TMOD_CIRCUIT;
|
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
|
* 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_call *call = get_call_ref(data->callref);
|
||||||
struct gsm_mncc mncc;
|
struct gsm_mncc mncc;
|
||||||
uint8_t cause;
|
uint8_t cause;
|
||||||
int8_t speech_ver = -1, speech_ver_half = -1, temp;
|
|
||||||
int first_call = 0;
|
int first_call = 0;
|
||||||
|
|
||||||
/* call does not exist */
|
/* 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;
|
cause = GSM48_CC_CAUSE_USER_BUSY;
|
||||||
goto release;
|
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 */
|
/* presentation allowed if present == 0 */
|
||||||
if (data->calling.present || !data->calling.number[0])
|
if (data->calling.present || !data->calling.number[0])
|
||||||
l23_vty_ms_notify(ms, "Incoming call (anonymous)\n");
|
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);
|
data->calling.number, call->callref);
|
||||||
memset(&mncc, 0, sizeof(struct gsm_mncc));
|
memset(&mncc, 0, sizeof(struct gsm_mncc));
|
||||||
mncc.callref = call->callref;
|
mncc.callref = call->callref;
|
||||||
/* only include bearer cap, if not given in setup
|
/* Bearer capability (optional) */
|
||||||
* or if multiple codecs are given
|
if (mncc_handle_bcap(&mncc, data, &ms->settings) != 0) {
|
||||||
* or if not only full rate
|
cause = GSM48_CC_CAUSE_INCOMPAT_DEST;
|
||||||
* or if given codec is unimplemented
|
goto release;
|
||||||
*/
|
}
|
||||||
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);
|
|
||||||
/* CC capabilities (optional) */
|
/* CC capabilities (optional) */
|
||||||
if (ms->settings.cc_dtmf) {
|
if (ms->settings.cc_dtmf) {
|
||||||
mncc.fields |= MNCC_F_CCCAP;
|
mncc.fields |= MNCC_F_CCCAP;
|
||||||
|
|
Loading…
Reference in New Issue