aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h2
-rw-r--r--openbsc/include/openbsc/msc_ifaces.h1
-rw-r--r--openbsc/include/openbsc/transaction.h7
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c170
-rw-r--r--openbsc/src/libmsc/msc_ifaces.c51
5 files changed, 140 insertions, 91 deletions
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 05aa6c00e..1dd27aaa2 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -84,4 +84,6 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn);
int gsm48_multirate_config(uint8_t *lv, const struct amr_multirate_conf *mr, const struct amr_mode *modes);
+int gsm48_tch_rtp_create(struct gsm_trans *trans);
+
#endif
diff --git a/openbsc/include/openbsc/msc_ifaces.h b/openbsc/include/openbsc/msc_ifaces.h
index 620859b7c..a1071ae9b 100644
--- a/openbsc/include/openbsc/msc_ifaces.h
+++ b/openbsc/include/openbsc/msc_ifaces.h
@@ -39,3 +39,4 @@ int msc_tx_common_id(struct gsm_subscriber_connection *conn);
int msc_call_assignment(struct gsm_trans *trans);
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2);
void msc_call_release(struct gsm_trans *trans);
+int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip);
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 4ed1d3ad4..4930fbd32 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -49,6 +49,13 @@ struct gsm_trans {
/* bearer capabilities (rate and codec) */
struct gsm_mncc_bearer_cap bearer_cap;
+ /* status of the assignment, true when done */
+ bool assignment_done;
+
+ /* if true, TCH_RTP_CREATE is sent after the
+ * assignment is done */
+ bool tch_rtp_create;
+
union {
struct {
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)