Add initial CSD support with external MNCC
Implement and use CSD bearer service logic (with similar audio codec code):
* csd_filter (codec_filter)
* csd_bs (sdp_audio_codec)
* csd_bs_list (sdp_audio_codecs)
Related: OS#4394
Change-Id: Ide8b8321e0401dcbe35da2ec9cee0abca821d99a
diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c
index 4bc87af..1d99421 100644
--- a/src/libmsc/gsm_04_08_cc.c
+++ b/src/libmsc/gsm_04_08_cc.c
@@ -808,55 +808,86 @@
trans_cc_filter_set_bss(trans, trans->msc_a);
if (setup->fields & MNCC_F_BEARER_CAP)
trans->bearer_cap.transfer = setup->bearer_cap.transfer;
- /* sdp.remote: if SDP is included in the MNCC, take that as definitive list of remote audio codecs. */
- rx_mncc_sdp(trans, setup->msg_type, setup->sdp);
- /* sdp.remote: if there is no SDP information or we failed to parse it, try using the Bearer Capability from
- * MNCC, if any. */
- if (!trans->cc.remote.audio_codecs.count && (setup->fields & MNCC_F_BEARER_CAP)) {
- trans->cc.remote = (struct sdp_msg){};
- trans_cc_set_remote_from_bc(trans, &setup->bearer_cap);
- LOG_TRANS_CAT(trans, DMNCC, LOGL_DEBUG, "rx %s Bearer Cap: remote=%s\n",
- get_mncc_name(setup->msg_type), sdp_msg_to_str(&trans->cc.remote));
+
+ switch (trans->bearer_cap.transfer) {
+ case GSM48_BCAP_ITCAP_SPEECH:
+ /* sdp.remote: if SDP is included in the MNCC, take that as definitive list of remote audio codecs. */
+ rx_mncc_sdp(trans, setup->msg_type, setup->sdp);
+ /* sdp.remote: if there is no SDP information or we failed to parse it, try using the Bearer Capability from
+ * MNCC, if any. */
+ if (!trans->cc.remote.audio_codecs.count && (setup->fields & MNCC_F_BEARER_CAP)) {
+ trans->cc.remote = (struct sdp_msg){};
+ trans_cc_set_remote_from_bc(trans, &setup->bearer_cap);
+ LOG_TRANS_CAT(trans, DMNCC, LOGL_DEBUG, "rx %s Bearer Cap: remote=%s\n",
+ get_mncc_name(setup->msg_type), sdp_msg_to_str(&trans->cc.remote));
+ }
+ if (!trans->cc.remote.audio_codecs.count)
+ LOG_TRANS(trans, LOGL_INFO,
+ "Got no information of remote audio codecs: neither SDP nor Bearer Capability. Trying anyway.\n");
+ break;
+ case GSM48_BCAP_ITCAP_UNR_DIG_INF:
+ sdp_audio_codecs_set_csd(&trans->cc.codecs.ms);
+ break;
+ default:
+ LOG_TRANS(trans, LOGL_ERROR, "Handling of information transfer capability %d not implemented\n",
+ trans->bearer_cap.transfer);
}
- if (!trans->cc.remote.audio_codecs.count)
- LOG_TRANS(trans, LOGL_INFO,
- "Got no information of remote audio codecs: neither SDP nor Bearer Capability. Trying anyway.\n");
trans_cc_filter_run(trans);
- /* Compose Bearer Capability information that reflects only the codecs (Speech Versions) remaining after
- * intersecting MS, BSS and remote call leg restrictions. To store in trans for later use, and to include in
- * the outgoing CC Setup message. */
- bearer_cap = (struct gsm_mncc_bearer_cap){
- .speech_ver = { -1 },
- };
- sdp_audio_codecs_to_bearer_cap(&bearer_cap, &trans->cc.local.audio_codecs);
- rc = bearer_cap_set_radio(&bearer_cap);
- if (rc) {
- LOG_TRANS(trans, LOGL_ERROR, "Error composing Bearer Capability for CC Setup\n");
- trans_free(trans);
- msgb_free(msg);
- return rc;
+ /* Compose Bearer Capability information that reflects only the codecs (Speech Versions) / CSD bearer services
+ * remaining after intersecting MS, BSS and remote call leg restrictions. To store in trans for later use, and
+ * to include in the outgoing CC Setup message. */
+ switch (trans->bearer_cap.transfer) {
+ case GSM48_BCAP_ITCAP_SPEECH:
+ bearer_cap = (struct gsm_mncc_bearer_cap){
+ .speech_ver = { -1 },
+ };
+ sdp_audio_codecs_to_bearer_cap(&bearer_cap, &trans->cc.local.audio_codecs);
+ rc = bearer_cap_set_radio(&bearer_cap);
+ if (rc) {
+ LOG_TRANS(trans, LOGL_ERROR, "Error composing Bearer Capability for CC Setup\n");
+ trans_free(trans);
+ msgb_free(msg);
+ return rc;
+ }
+ /* If no resulting codecs remain, error out. We cannot find a codec that matches both call legs. If the MGW were
+ * able to transcode, we could use non-identical codecs on each conn of the MGW endpoint, but we are aiming for
+ * finding a matching codec. */
+ if (bearer_cap.speech_ver[0] == -1) {
+ LOG_TRANS(trans, LOGL_ERROR, "%s: no codec match possible: %s\n",
+ get_mncc_name(setup->msg_type),
+ codec_filter_to_str(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote));
+
+ /* incompatible codecs */
+ rc = mncc_release_ind(trans->net, trans, trans->callref,
+ GSM48_CAUSE_LOC_PRN_S_LU,
+ GSM48_CC_CAUSE_INCOMPAT_DEST /* TODO: correct cause code? */);
+ trans->callref = 0;
+ trans_free(trans);
+ msgb_free(msg);
+ return rc;
+ }
+ break;
+ case GSM48_BCAP_ITCAP_UNR_DIG_INF:
+ if (csd_bs_list_to_bearer_cap(&bearer_cap, &trans->cc.local.bearer_services) == 0) {
+ LOG_TRANS(trans, LOGL_ERROR, "Error composing Bearer Capability for CC Setup\n");
+
+ /* incompatible codecs */
+ rc = mncc_release_ind(trans->net, trans, trans->callref,
+ GSM48_CAUSE_LOC_PRN_S_LU,
+ GSM48_CC_CAUSE_INCOMPAT_DEST /* TODO: correct cause code? */);
+ trans->callref = 0;
+ trans_free(trans);
+ msgb_free(msg);
+ return rc;
+ }
+ break;
}
+
/* Create a copy of the bearer capability in the transaction struct, so we can use this information later */
trans->bearer_cap = bearer_cap;
- /* If no resulting codecs remain, error out. We cannot find a codec that matches both call legs. If the MGW were
- * able to transcode, we could use non-identical codecs on each conn of the MGW endpoint, but we are aiming for
- * finding a matching codec. */
- if (bearer_cap.speech_ver[0] == -1) {
- LOG_TRANS(trans, LOGL_ERROR, "%s: no codec match possible: %s\n",
- get_mncc_name(setup->msg_type),
- codec_filter_to_str(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote));
- /* incompatible codecs */
- rc = mncc_release_ind(trans->net, trans, trans->callref,
- GSM48_CAUSE_LOC_PRN_S_LU,
- GSM48_CC_CAUSE_INCOMPAT_DEST /* TODO: correct cause code? */);
- trans->callref = 0;
- trans_free(trans);
- msgb_free(msg);
- return rc;
- }
gsm48_encode_bearer_cap(msg, 0, &bearer_cap);
/* facility */