summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2023-10-17 17:24:27 +0700
committerVadim Yanitskiy <vyanitskiy@sysmocom.de>2023-10-18 20:46:35 +0700
commit40609ca94b2fb055ea0a405850e5e4894819d74b (patch)
tree22bdf1f92a31f4bdc05cd78dd75fcd1d1d43025c
parent292f39900c6837c093b54b2b4353a79b7ce26427 (diff)
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
-rw-r--r--src/host/layer23/src/mobile/mnccms.c176
1 files changed, 118 insertions, 58 deletions
diff --git a/src/host/layer23/src/mobile/mnccms.c b/src/host/layer23/src/mobile/mnccms.c
index be43afa4..d23fbb70 100644
--- a/src/host/layer23/src/mobile/mnccms.c
+++ b/src/host/layer23/src/mobile/mnccms.c
@@ -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;