aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-07-14 15:18:11 +0200
committerPhilipp Maier <pmaier@sysmocom.de>2017-07-14 15:18:11 +0200
commit7941a94244d2f3e7ffed811fca41d7849c7d398e (patch)
treefaf55fe35f3beb20b3e3ddb7ce35cf99b8fcb991 /openbsc/src/libmsc
parentbd85cdf71acc0d043ad978afaba830d603888c7b (diff)
mncc: make external mncc work
The external mncc currently does not work properly since the MNCC_RTP_CREATE commands are removed due to the MSC-Split. It is possible to operate without these commands, but then it is not possible to route the RTP streams to an outside leg. Only internal bridging is currenlty possible. This method is used when the internal MNCC is enabled. Add the missing MNCC_RTP_CREATE implementation. Add logic to keep the old bridging mode working.
Diffstat (limited to 'openbsc/src/libmsc')
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c170
-rw-r--r--openbsc/src/libmsc/msc_ifaces.c51
2 files changed, 130 insertions, 91 deletions
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 64c5a673d..c310453e4 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1281,6 +1281,8 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
struct msgb *msg;
unsigned char *data;
+ DEBUGP(DMNCC, "transmit message %s\n", get_mncc_name(msg_type));
+
#if BEFORE_MSCSPLIT
if (trans)
if (trans->conn && trans->conn->lchan)
@@ -1952,6 +1954,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
struct tlv_parsed tp;
struct gsm_mncc call_conf;
+ int rc;
gsm48_stop_cc_timer(trans);
gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
@@ -2001,7 +2004,18 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
- msc_call_assignment(trans);
+ /* Assign call (if not done yet) */
+ if (trans->assignment_done == false) {
+ rc = msc_call_assignment(trans);
+ trans->assignment_done = true;
+ }
+ else
+ rc = 0;
+
+ /* don't continue, if there were problems with
+ * the call assignment. */
+ if (rc)
+ return rc;
return mncc_recvmsg(trans->net, trans, MNCC_CALL_CONF_IND,
&call_conf);
@@ -2032,7 +2046,15 @@ static int gsm48_cc_tx_call_proc_and_assign(struct gsm_trans *trans, void *arg)
if (rc)
return rc;
- return msc_call_assignment(trans);
+ /* Assign call (if not done yet) */
+ if (trans->assignment_done == false) {
+ rc = msc_call_assignment(trans);
+ trans->assignment_done = true;
+ }
+ else
+ rc = 0;
+
+ return rc;
}
static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
@@ -2905,7 +2927,6 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
}
-#if BEFORE_MSCSPLIT
static void mncc_recv_rtp(struct gsm_network *net, uint32_t callref,
int cmd, uint32_t addr, uint16_t port, uint32_t payload_type,
uint32_t payload_msg_type)
@@ -2927,34 +2948,27 @@ static void mncc_recv_rtp(struct gsm_network *net, uint32_t callref,
static void mncc_recv_rtp_sock(struct gsm_network *net, struct gsm_trans *trans, int cmd)
{
- struct gsm_lchan *lchan;
int msg_type;
- lchan = trans->conn->lchan;
- switch (lchan->abis_ip.rtp_payload) {
- case RTP_PT_GSM_FULL:
- msg_type = GSM_TCHF_FRAME;
- break;
- case RTP_PT_GSM_EFR:
- msg_type = GSM_TCHF_FRAME_EFR;
- break;
- case RTP_PT_GSM_HALF:
- msg_type = GSM_TCHH_FRAME;
- break;
- case RTP_PT_AMR:
- msg_type = GSM_TCH_FRAME_AMR;
- break;
- default:
- LOGP(DMNCC, LOGL_ERROR, "%s unknown payload type %d\n",
- gsm_lchan_name(lchan), lchan->abis_ip.rtp_payload);
- msg_type = 0;
- break;
- }
+ /* FIXME This has to be set to some meaningful value.
+ * Possible options are:
+ * GSM_TCHF_FRAME, GSM_TCHF_FRAME_EFR,
+ * GSM_TCHH_FRAME, GSM_TCH_FRAME_AMR
+ * (0 if unknown) */
+ msg_type = GSM_TCHF_FRAME;
+
+ uint32_t addr = mgcpgw_client_remote_addr_n(net->mgcpgw.client);
+ uint16_t port = trans->conn->rtp.port_cn;
+
+ /* FIXME: This has to be set to some meaningful value,
+ * before the MSC-Split, this value was pulled from
+ * lchan->abis_ip.rtp_payload */
+ uint32_t payload_type = 0;
return mncc_recv_rtp(net, trans->callref, cmd,
- lchan->abis_ip.bound_ip,
- lchan->abis_ip.bound_port,
- lchan->abis_ip.rtp_payload,
+ addr,
+ port,
+ payload_type,
msg_type);
}
@@ -2962,15 +2976,11 @@ static void mncc_recv_rtp_err(struct gsm_network *net, uint32_t callref, int cmd
{
return mncc_recv_rtp(net, callref, cmd, 0, 0, 0, 0);
}
-#endif
static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
{
-#if BEFORE_MSCSPLIT
- struct gsm_bts *bts;
- struct gsm_lchan *lchan;
struct gsm_trans *trans;
- enum gsm48_chan_mode m;
+ int rc;
/* Find callref */
trans = trans_find_by_callref(net, callref);
@@ -2986,50 +2996,49 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
return 0;
}
- lchan = trans->conn->lchan;
- bts = lchan->ts->trx->bts;
- if (!is_ipaccess_bts(bts)) {
- /*
- * I want this to be straight forward and have no audio flow
- * through the nitb/osmo-mss system. This currently means that
- * this will not work with BS11/Nokia type BTS. We would need
- * to have a trau<->rtp bridge for these but still preferable
- * in another process.
- */
- LOGP(DMNCC, LOGL_ERROR, "RTP create only works with IP systems\n");
- mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE);
- return -EINVAL;
- }
-
trans->conn->mncc_rtp_bridge = 1;
- /*
- * *sigh* we need to pick a codec now. Pick the most generic one
- * right now and hope we could fix that later on. This is very
- * similiar to the routine above.
- * Fallback to the internal MNCC mode to select a route.
- */
- if (lchan->tch_mode == GSM48_CMODE_SIGN) {
- trans->conn->mncc_rtp_create_pending = 1;
- m = mncc_codec_for_mode(lchan->type);
- LOGP(DMNCC, LOGL_DEBUG, "RTP create: codec=%s, chan_type=%s\n",
- get_value_string(gsm48_chan_mode_names, m),
- get_value_string(gsm_chan_t_names, lchan->type));
- return gsm0808_assign_req(trans->conn, m,
- lchan->type != GSM_LCHAN_TCH_H);
+
+ /* When we call msc_call_assignment() we will trigger, depending
+ * on the RAN type the call assignment on the A or Iu interface.
+ * msc_call_assignment() also takes care about sending the CRCX
+ * command to the MGCP-GW. The CRCX will return the port number,
+ * where the PBX (e.g. Asterisk) will send its RTP stream to. We
+ * have to return this port number back to the MNCC by sending
+ * it back with the TCH_RTP_CREATE message. To make sure that
+ * this message is sent AFTER the response to CRCX from the
+ * MGCP-GW has arrived, we need will instruct msc_call_assignment()
+ * to take care of this by setting trans->tch_rtp_create to true.
+ * This will make sure that gsm48_tch_rtp_create() (below) is
+ * called as soon as the local port number has become known. */
+ trans->tch_rtp_create = true;
+
+ /* Assign call (if not done yet) */
+ if (trans->assignment_done == false) {
+ rc = msc_call_assignment(trans);
+ trans->assignment_done = true;
}
+ else
+ rc = 0;
- mncc_recv_rtp_sock(trans->net, trans, MNCC_RTP_CREATE);
+ return rc;
+}
+
+/* Trigger TCH_RTP_CREATE acknowledgement */
+int gsm48_tch_rtp_create(struct gsm_trans *trans)
+{
+ /* This function is called as soon as the port, on which the
+ * mgcp-gw expects the incoming RTP stream from the remote
+ * end (e.g. Asterisk) is known. */
+
+ struct gsm_subscriber_connection *conn = trans->conn;
+ struct gsm_network *network = conn->network;
+
+ mncc_recv_rtp_sock(network, trans, MNCC_RTP_CREATE);
return 0;
-#else
- /* not implemented yet! */
- return -1;
-#endif
}
static int tch_rtp_connect(struct gsm_network *net, void *arg)
{
-#if BEFORE_MSCSPLIT
- struct gsm_lchan *lchan;
struct gsm_trans *trans;
struct gsm_mncc_rtp *rtp = arg;
@@ -3047,29 +3056,8 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg)
return 0;
}
- lchan = trans->conn->lchan;
- LOGP(DMNCC, LOGL_DEBUG, "RTP connect: codec=%s, chan_type=%s\n",
- get_value_string(gsm48_chan_mode_names,
- mncc_codec_for_mode(lchan->type)),
- get_value_string(gsm_chan_t_names, lchan->type));
-
- /* TODO: Check if payload_msg_type is compatible with what we have */
- if (rtp->payload_type != lchan->abis_ip.rtp_payload) {
- LOGP(DMNCC, LOGL_ERROR, "RTP connect with different RTP payload\n");
- mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT);
- }
-
- /*
- * FIXME: payload2 can't be sent with MDCX as the osmo-bts code
- * complains about both rtp and rtp payload2 being present in the
- * same package!
- */
- trans->conn->mncc_rtp_connect_pending = 1;
- return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0);
-#else
- /* not implemented yet! */
- return -1;
-#endif
+ msc_call_connect(trans,rtp->port,rtp->ip);
+ return 0;
}
#if BEFORE_MSCSPLIT
diff --git a/openbsc/src/libmsc/msc_ifaces.c b/openbsc/src/libmsc/msc_ifaces.c
index 021885ec4..27f644e5f 100644
--- a/openbsc/src/libmsc/msc_ifaces.c
+++ b/openbsc/src/libmsc/msc_ifaces.c
@@ -204,6 +204,12 @@ static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
} else
goto rab_act_cs_error;
+ /* Respond back to MNCC (if requested) */
+ if (trans->tch_rtp_create) {
+ if (gsm48_tch_rtp_create(trans))
+ goto rab_act_cs_error;
+ }
+
rab_act_cs_error:
/* FIXME abort call, invalidate conn, ... */
return;
@@ -361,6 +367,51 @@ static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv)
}
}
+int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip)
+{
+ /* With this function we inform the MGCP-GW where (ip/port) it
+ * has to send its outgoing voic traffic. The receiving end will
+ * usually be a PBX (e.g. Asterisk). The IP-Address we tell, will
+ * not only be used to direct the traffic, it will also be used
+ * as a filter to make sure only RTP packets from the right
+ * remote end will reach the BSS. This is also the reason why
+ * inbound audio will not work until this step is performed */
+
+ /* NOTE: This function is used when msc_call_bridge(), is not
+ * applicable. This is usually the case when an external MNCC
+ * is in use */
+
+ struct gsm_subscriber_connection *conn;
+ struct mgcpgw_client *mgcp;
+ struct msgb *msg;
+
+ if (!trans)
+ return -EINVAL;
+ if (!trans->conn)
+ return -EINVAL;
+ if (!trans->conn->network)
+ return -EINVAL;
+ if (!trans->conn->network->mgcpgw.client)
+ return -EINVAL;
+
+ mgcp = trans->conn->network->mgcpgw.client;
+
+ struct in_addr ip_addr;
+ ip_addr.s_addr = ntohl(ip);
+
+ conn = trans->conn;
+
+ msg = mgcp_msg_mdcx(mgcp,
+ conn->iu.mgcp_rtp_endpoint,
+ inet_ntoa(ip_addr), port, MGCP_CONN_RECV_SEND);
+ if (mgcpgw_client_tx(mgcp, msg, NULL, trans))
+ LOGP(DMGCP, LOGL_ERROR,
+ "Failed to send MDCX message for %s\n",
+ vlr_subscr_name(trans->vsub));
+
+ return 0;
+}
+
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2)
{
if (!trans1)