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/transaction_cc.c b/src/libmsc/transaction_cc.c
index cb1424b..35ec5dc 100644
--- a/src/libmsc/transaction_cc.c
+++ b/src/libmsc/transaction_cc.c
@@ -24,32 +24,52 @@
 
 #include <osmocom/msc/transaction_cc.h>
 #include <osmocom/msc/codec_filter.h>
+#include <osmocom/msc/csd_filter.h>
 
 void trans_cc_filter_init(struct gsm_trans *trans)
 {
 	trans->cc.codecs = (struct codec_filter){};
+	trans->cc.csd = (struct csd_filter){};
 }
 
 void trans_cc_filter_set_ran(struct gsm_trans *trans, enum osmo_rat_type ran_type)
 {
 	codec_filter_set_ran(&trans->cc.codecs, ran_type);
+	csd_filter_set_ran(&trans->cc.csd, ran_type);
 }
 
 void trans_cc_filter_set_bss(struct gsm_trans *trans, struct msc_a *msc_a)
 {
 	codec_filter_set_bss(&trans->cc.codecs, &msc_a->cc.compl_l3_codec_list_bss_supported);
+
+	/* For CSD, there is no list of supported bearer services passed in
+	 * Complete Layer 3. TODO: make it configurable? */
 }
 
 void trans_cc_filter_run(struct gsm_trans *trans)
 {
-	codec_filter_run(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote);
-	LOG_TRANS(trans, LOGL_DEBUG, "codecs: %s\n",
-		  codec_filter_to_str(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote));
+	switch (trans->bearer_cap.transfer) {
+	case GSM48_BCAP_ITCAP_SPEECH:
+		codec_filter_run(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote);
+		LOG_TRANS(trans, LOGL_DEBUG, "codecs: %s\n",
+			  codec_filter_to_str(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote));
+		break;
+	case GSM48_BCAP_ITCAP_UNR_DIG_INF:
+		csd_filter_run(&trans->cc.csd, &trans->cc.local, &trans->cc.remote);
+		LOG_TRANS(trans, LOGL_DEBUG, "codec/BS: %s\n",
+			  csd_filter_to_str(&trans->cc.csd, &trans->cc.local, &trans->cc.remote));
+		break;
+	default:
+		LOG_TRANS(trans, LOGL_ERROR, "Handling of information transfer capability %d not implemented\n",
+			  trans->bearer_cap.transfer);
+		break;
+	}
 }
 
 void trans_cc_filter_set_ms_from_bc(struct gsm_trans *trans, const struct gsm_mncc_bearer_cap *bcap)
 {
 	trans->cc.codecs.ms = (struct sdp_audio_codecs){0};
+	trans->cc.csd.ms = (struct csd_bs_list){0};
 
 	if (!bcap)
 		return;
@@ -58,6 +78,10 @@
 	case GSM48_BCAP_ITCAP_SPEECH:
 		sdp_audio_codecs_from_bearer_cap(&trans->cc.codecs.ms, bcap);
 		break;
+	case GSM48_BCAP_ITCAP_UNR_DIG_INF:
+		sdp_audio_codecs_set_csd(&trans->cc.codecs.ms);
+		csd_bs_list_from_bearer_cap(&trans->cc.csd.ms, bcap);
+		break;
 	default:
 		LOG_TRANS(trans, LOGL_ERROR, "Handling of information transfer capability %d not implemented\n",
 			  bcap->transfer);
@@ -68,6 +92,7 @@
 void trans_cc_set_remote_from_bc(struct gsm_trans *trans, const struct gsm_mncc_bearer_cap *bcap)
 {
 	trans->cc.remote.audio_codecs = (struct sdp_audio_codecs){0};
+	trans->cc.remote.bearer_services = (struct csd_bs_list){0};
 
 	if (!bcap)
 		return;
@@ -76,6 +101,10 @@
 	case GSM48_BCAP_ITCAP_SPEECH:
 		sdp_audio_codecs_from_bearer_cap(&trans->cc.remote.audio_codecs, bcap);
 		break;
+	case GSM48_BCAP_ITCAP_UNR_DIG_INF:
+		sdp_audio_codecs_set_csd(&trans->cc.remote.audio_codecs);
+		csd_bs_list_from_bearer_cap(&trans->cc.remote.bearer_services, bcap);
+		break;
 	default:
 		LOG_TRANS(trans, LOGL_ERROR, "Handling of information transfer capability %d not implemented\n",
 			  bcap->transfer);