send + receive SDP via MNCC
CC MNCC
| ---ALERTING--> | add SDP to MNCC msg
| <--ALERTING--- | store remote side SDP
| <--SETUP-RESP- | store remote side SDP
| --SETUP-CNF--> | add SDP to MNCC msg
| -RTP-CREATE--> | use codec_filter, add SDP
| <-RTP-CONNECT- | store remote SDP
Related: SYS#5066
Change-Id: Ie0668c0e079ec69da1532b52d00621efe114fc2c
diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c
index 63b83d0..328f1cf 100644
--- a/src/libmsc/gsm_04_08_cc.c
+++ b/src/libmsc/gsm_04_08_cc.c
@@ -515,6 +515,10 @@
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
struct tlv_parsed tp;
struct gsm_mncc setup;
+ struct osmo_sockaddr_str *rtp_cn_local;
+ struct sdp_msg *sdp;
+ struct msc_a *msc_a = trans->msc_a;
+ int rc;
gsm48_start_guard_timer(trans);
@@ -624,6 +628,27 @@
rate_ctr_inc(rate_ctr_group_get_ctr(trans->net->msc_ctrs, MSC_CTR_CALL_MO_SETUP));
+ /* Insert the CN side RTP port now available into SDP and compose SDP string */
+ rtp_cn_local = call_leg_local_ip(msc_a->cc.call_leg, RTP_TO_CN);
+ if (!osmo_sockaddr_str_is_nonzero(rtp_cn_local)) {
+ LOG_TRANS(trans, LOGL_ERROR, "Cannot compose SDP for MNCC_SETUP_IND: no RTP set up for the CN side\n");
+ /* FIXME: re-add below two lines as soon as CN CRCX is done first
+ * (see Change-Id Ie433db1ba0c46d4b97538a969233c155cefac21c).
+ * keeping it non-fatal for the moment, for tests to continue succeeding. */
+ //trans_free(trans);
+ //return -EINVAL;
+ }
+
+ codec_filter_set_local_rtp(&trans->cc.codecs, rtp_cn_local);
+ codec_filter_run(&trans->cc.codecs);
+ sdp = trans->cc.codecs.result.audio_codecs.count ? &trans->cc.codecs.result : NULL;
+ rc = sdp_msg_to_sdp_str_buf(setup.sdp, sizeof(setup.sdp), sdp);
+ if (rc >= sizeof(setup.sdp)) {
+ LOG_TRANS(trans, LOGL_ERROR, "MNCC_SETUP_IND: SDP too long (%d > %zu bytes)\n", rc, sizeof(setup.sdp));
+ trans_free(trans);
+ return -EINVAL;
+ }
+
/* indicate setup to MNCC */
mncc_recvmsg(trans->net, trans, MNCC_SETUP_IND, &setup);
@@ -843,6 +868,7 @@
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
struct tlv_parsed tp;
struct gsm_mncc alerting;
+ int rc;
gsm48_stop_cc_timer(trans);
gsm48_start_cc_timer(trans, 0x301, GSM48_T301);
@@ -872,6 +898,16 @@
new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
+ codec_filter_run(&trans->cc.codecs);
+ LOG_TRANS(trans, LOGL_DEBUG, "codecs: %s\n", codec_filter_to_str(&trans->cc.codecs));
+ rc = sdp_msg_to_sdp_str_buf(alerting.sdp, sizeof(alerting.sdp), &trans->cc.codecs.result);
+ if (rc >= sizeof(alerting.sdp)) {
+ LOG_TRANS(trans, LOGL_ERROR, "MNCC_ALERT_IND: SDP too long (%d > %zu bytes)\n",
+ rc, sizeof(alerting.sdp));
+ trans_free(trans);
+ return -EINVAL;
+ }
+
return mncc_recvmsg(trans->net, trans, MNCC_ALERT_IND,
&alerting);
}
@@ -896,6 +932,19 @@
new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
+ if (alerting->sdp[0]) {
+ struct call_leg *cl = trans->msc_a->cc.call_leg;
+ struct rtp_stream *rtp_cn = cl ? cl->rtp[RTP_TO_CN] : NULL;
+ codec_filter_set_remote(&trans->cc.codecs, alerting->sdp);
+ codec_filter_run(&trans->cc.codecs);
+ LOG_TRANS(trans, LOGL_DEBUG, "%s codecs: %s\n",
+ get_mncc_name(alerting->msg_type), codec_filter_to_str(&trans->cc.codecs));
+ if (rtp_cn) {
+ rtp_stream_set_remote_addr_and_codecs(rtp_cn, &trans->cc.codecs.remote);
+ rtp_stream_commit(rtp_cn);
+ }
+ }
+
return trans_tx_gsm48(trans, msg);
}
@@ -942,6 +991,20 @@
new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
+ /* Received an MNCC_SETUP_RSP with the remote leg's SDP information. Apply codec choice. */
+ if (connect->sdp[0]) {
+ struct call_leg *cl = trans->msc_a->cc.call_leg;
+ struct rtp_stream *rtp_cn = cl ? cl->rtp[RTP_TO_CN] : NULL;
+ sdp_msg_from_sdp_str(&trans->cc.codecs.remote, connect->sdp);
+ LOG_TRANS(trans, LOGL_DEBUG, "%s codecs: %s\n",
+ get_mncc_name(connect->msg_type),
+ codec_filter_to_str(&trans->cc.codecs));
+ if (rtp_cn) {
+ rtp_stream_set_remote_addr_and_codecs(rtp_cn, &trans->cc.codecs.remote);
+ rtp_stream_commit(rtp_cn);
+ }
+ }
+
return trans_tx_gsm48(trans, msg);
}
@@ -984,6 +1047,8 @@
new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
rate_ctr_inc(rate_ctr_group_get_ctr(trans->net->msc_ctrs, MSC_CTR_CALL_MT_CONNECT));
+ codec_filter_run(&trans->cc.codecs);
+ sdp_msg_to_sdp_str_buf(connect.sdp, sizeof(connect.sdp), &trans->cc.codecs.result);
return mncc_recvmsg(trans->net, trans, MNCC_SETUP_CNF, &connect);
}
@@ -1790,7 +1855,7 @@
}
return mncc_recv_rtp(net, trans, trans->callref, MNCC_RTP_CREATE, rtp_cn_local,
- codec->payload_type, mncc_payload_msg_type, NULL);
+ codec->payload_type, mncc_payload_msg_type, &trans->cc.codecs.result);
}
static int tch_rtp_connect(struct gsm_network *net, const struct gsm_mncc_rtp *rtp)
@@ -1798,7 +1863,6 @@
struct gsm_trans *trans;
struct call_leg *cl;
struct rtp_stream *rtps;
- struct osmo_sockaddr_str rtp_addr;
char ipbuf[INET6_ADDRSTRLEN];
/* FIXME: in *rtp we should get the codec information of the remote
@@ -1838,12 +1902,26 @@
return -EINVAL;
}
- if (osmo_sockaddr_str_from_sockaddr(&rtp_addr, &rtp->addr) < 0) {
- LOG_TRANS_CAT(trans, DMNCC, LOGL_ERROR, "RTP connect with invalid IP addr\n");
- mncc_recv_rtp_err(net, trans, rtp->callref, MNCC_RTP_CONNECT);
- return -EINVAL;
+ if (rtp->sdp[0]) {
+ sdp_msg_from_sdp_str(&trans->cc.codecs.remote, rtp->sdp);
+ LOG_TRANS(trans, LOGL_DEBUG, "%s contained SDP %s\n",
+ get_mncc_name(rtp->msg_type),
+ sdp_msg_to_str(&trans->cc.codecs.remote));
}
- rtp_stream_set_remote_addr(rtps, &rtp_addr);
+
+ rtp_stream_set_remote_addr_and_codecs(rtps, &trans->cc.codecs.remote);
+
+ if (!osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
+ /* Didn't get an IP address from SDP. Try legacy MNCC IP address */
+ struct osmo_sockaddr_str rtp_addr;
+ if (osmo_sockaddr_str_from_sockaddr(&rtp_addr, &rtp->addr) < 0) {
+ LOG_TRANS_CAT(trans, DMNCC, LOGL_ERROR, "RTP connect with invalid IP addr\n");
+ mncc_recv_rtp_err(net, trans, rtp->callref, MNCC_RTP_CONNECT);
+ return -EINVAL;
+ }
+ rtp_stream_set_remote_addr(rtps, &rtp_addr);
+ }
+
rtp_stream_commit(rtps);
return 0;
}
@@ -2025,6 +2103,19 @@
return -ENOMEM;
}
+ /* Remember remote SDP, if any */
+ if (data->sdp[0]) {
+ if (sdp_msg_from_sdp_str(&trans->cc.codecs.remote, data->sdp)) {
+ LOG_TRANS(trans, LOGL_ERROR, "Failed to parse incoming SDP: %s\n",
+ osmo_quote_str(data->sdp, -1));
+ vlr_subscr_put(vsub, __func__);
+ mncc_release_ind(net, NULL, data->callref,
+ GSM48_CAUSE_LOC_PRN_S_LU,
+ GSM48_CC_CAUSE_NORMAL_UNSPEC);
+ return -EINVAL;
+ }
+ }
+
/* If subscriber has no conn */
if (!msc_a) {
/* This condition will return before the common logging of the received MNCC message below, so