diff options
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/gsm_04_08.h | 2 | ||||
-rw-r--r-- | openbsc/include/openbsc/msc_ifaces.h | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/transaction.h | 7 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 170 | ||||
-rw-r--r-- | openbsc/src/libmsc/msc_ifaces.c | 51 |
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) |