diff options
Diffstat (limited to 'src/libmsc/msc_ifaces.c')
-rw-r--r-- | src/libmsc/msc_ifaces.c | 214 |
1 files changed, 160 insertions, 54 deletions
diff --git a/src/libmsc/msc_ifaces.c b/src/libmsc/msc_ifaces.c index 56cbd49d4..7d2e8981b 100644 --- a/src/libmsc/msc_ifaces.c +++ b/src/libmsc/msc_ifaces.c @@ -29,6 +29,7 @@ #include <openbsc/mgcp.h> #include <openbsc/mgcpgw_client.h> #include <openbsc/vlr.h> +#include <openbsc/a_iface.h> #include "../../bscconfig.h" @@ -41,13 +42,18 @@ extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg) { + if (!conn) + return -EINVAL; + if (!msg) + return -EINVAL; + DEBUGP(DMSC, "msc_tx %u bytes to %s via %s\n", msg->len, vlr_subscr_name(conn->vsub), ran_type_name(conn->via_ran)); switch (conn->via_ran) { case RAN_GERAN_A: msg->dst = conn; - return a_tx(msg); + return a_iface_tx_dtap(msg); case RAN_UTRAN_IU: msg->dst = conn->iu.ue_ctx; @@ -72,9 +78,15 @@ int msc_tx_dtap(struct gsm_subscriber_connection *conn, /* 9.2.5 CM service accept */ int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn) { - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC"); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + struct msgb *msg; + struct gsm48_hdr *gh; + + if (!conn) + return -EINVAL; + msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC"); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_CM_SERV_ACC; @@ -89,6 +101,10 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, enum gsm48_reject_value value) { struct msgb *msg; + + if (!conn) + return -EINVAL; + conn->received_cm_service_request = false; msg = gsm48_create_mm_serv_rej(value); @@ -104,6 +120,9 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, int msc_tx_common_id(struct gsm_subscriber_connection *conn) { + if (!conn) + return -EINVAL; + /* Common ID is only sent over IuCS */ if (conn->via_ran != RAN_UTRAN_IU) { LOGP(DMM, LOGL_INFO, @@ -118,10 +137,10 @@ int msc_tx_common_id(struct gsm_subscriber_connection *conn) return iu_tx_common_id(conn->iu.ue_ctx, conn->vsub->imsi); } -#ifdef BUILD_IU -static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id, - uint32_t rtp_ip, uint16_t rtp_port) +static int iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id, + uint32_t rtp_ip, uint16_t rtp_port) { +#ifdef BUILD_IU struct msgb *msg; bool use_x213_nsap; uint32_t conn_id = uectx->conn_id; @@ -140,6 +159,11 @@ static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id, LOGP(DIUCS, LOGL_ERROR, "Failed to send RAB Assignment:" " conn_id=%d rab_id=%d rtp=%x:%u\n", conn_id, rab_id, rtp_ip, rtp_port); + return 0; +#else + LOGP(DMSC, LOGL_ERROR, "Cannot send Iu RAB Assignment: built without Iu support\n"); + return -ENOTSUP; +#endif } static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv) @@ -165,71 +189,75 @@ static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv) goto rab_act_cs_error; } - conn->iu.mgcp_rtp_port_cn = r->audio_port; + conn->rtp.port_cn = r->audio_port; rtp_ip = mgcpgw_client_remote_addr_n(conn->network->mgcpgw.client); - iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip, - conn->iu.mgcp_rtp_port_ue); - /* use_x213_nsap == 0 for ip.access nano3G */ + + if (trans->conn->via_ran == RAN_UTRAN_IU) { + /* Assign a voice channel via RANAP on 3G */ + if (iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip, conn->rtp.port_subscr)) + goto rab_act_cs_error; + } else if (trans->conn->via_ran == RAN_GERAN_A) { + /* Assign a voice channel via A on 2G */ + if (a_iface_tx_assignment(trans)) + goto rab_act_cs_error; + } 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; + } + return; rab_act_cs_error: /* FIXME abort call, invalidate conn, ... */ + LOGP(DMSC, LOGL_ERROR, "%s: failure during assignment\n", + vlr_subscr_name(trans->vsub)); return; } -static int conn_iu_rab_act_cs(struct gsm_trans *trans) +int msc_call_assignment(struct gsm_trans *trans) { - struct gsm_subscriber_connection *conn = trans->conn; - struct mgcpgw_client *mgcp = conn->network->mgcpgw.client; + struct gsm_subscriber_connection *conn; + struct mgcpgw_client *mgcp; struct msgb *msg; + uint16_t bts_base; + + if (!trans) + return -EINVAL; + if (!trans->conn) + return -EINVAL; - /* HACK. where to scope the RAB Id? At the conn / subscriber / - * ue_conn_ctx? */ - static uint8_t next_rab_id = 1; - conn->iu.rab_id = next_rab_id ++; + conn = trans->conn; + mgcp = conn->network->mgcpgw.client; - conn->iu.mgcp_rtp_endpoint = +#ifdef BUILD_IU + /* FIXME: HACK. where to scope the RAB Id? At the conn / subscriber / ue_conn_ctx? */ + static uint8_t next_iu_rab_id = 1; + if (conn->via_ran == RAN_UTRAN_IU) + conn->iu.rab_id = next_iu_rab_id ++; +#endif + + conn->rtp.mgcp_rtp_endpoint = mgcpgw_client_next_endpoint(conn->network->mgcpgw.client); - /* HACK: the addresses should be known from CRCX response - * and config. */ - conn->iu.mgcp_rtp_port_ue = 4000 + 2 * conn->iu.mgcp_rtp_endpoint; + + /* This will calculate the port we assign to the BTS via AoIP + * assignment command (or rab-assignment on 3G) The BTS will send + * its RTP traffic to that port on the MGCPGW side. The MGCPGW only + * gets the endpoint ID via the CRCX. It will do the same calculation + * on his side too to get knowledge of the rtp port. */ + bts_base = mgcp->actual.bts_base; + conn->rtp.port_subscr = bts_base + 2 * conn->rtp.mgcp_rtp_endpoint; /* Establish the RTP stream first as looping back to the originator. * The MDCX will patch through to the counterpart. TODO: play a ring * tone instead. */ - msg = mgcp_msg_crcx(mgcp, conn->iu.mgcp_rtp_endpoint, trans->callref, - MGCP_CONN_LOOPBACK); + msg = mgcp_msg_crcx(mgcp, conn->rtp.mgcp_rtp_endpoint, + conn->rtp.mgcp_rtp_endpoint, MGCP_CONN_LOOPBACK); return mgcpgw_client_tx(mgcp, msg, mgcp_response_rab_act_cs_crcx, trans); } -#endif - -int msc_call_assignment(struct gsm_trans *trans) -{ - struct gsm_subscriber_connection *conn = trans->conn; - - switch (conn->via_ran) { - case RAN_GERAN_A: - LOGP(DMSC, LOGL_ERROR, - "msc_call_assignment(): A-interface BSSMAP Assignment" - " Request not yet implemented\n"); - return -ENOTSUP; - - case RAN_UTRAN_IU: -#ifdef BUILD_IU - return conn_iu_rab_act_cs(trans); -#else - LOGP(DMSC, LOGL_ERROR, - "msc_call_assignment(): cannot send RAB Activation, built without Iu support\n"); - return -ENOTSUP; -#endif - - default: - LOGP(DMSC, LOGL_ERROR, - "msc_tx(): conn->via_ran invalid (%d)\n", - conn->via_ran); - return -EINVAL; - } -} static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv); @@ -252,8 +280,8 @@ static void mgcp_bridge(struct gsm_trans *from, struct gsm_trans *to, ip = mgcpgw_client_remote_addr_str(mgcp); msg = mgcp_msg_mdcx(mgcp, - conn1->iu.mgcp_rtp_endpoint, - ip, conn2->iu.mgcp_rtp_port_cn, + conn1->rtp.mgcp_rtp_endpoint, + ip, conn2->rtp.port_cn, mode); if (mgcpgw_client_tx(mgcp, msg, mgcp_response_bridge_mdcx, from)) LOGP(DMGCP, LOGL_ERROR, @@ -302,8 +330,58 @@ 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->rtp.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) + return -EINVAL; + if (!trans2) + return -EINVAL; + /* First setup as loopback and configure the counterparts' endpoints, * so that when transmission starts the originating addresses are * already known to be valid. The mgcp callback will continue. */ @@ -314,3 +392,31 @@ int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2) return 0; } + +void msc_call_release(struct gsm_trans *trans) +{ + struct msgb *msg; + struct gsm_subscriber_connection *conn; + struct mgcpgw_client *mgcp; + + if (!trans) + return; + if (!trans->conn) + return; + if (!trans->conn->network) + return; + + conn = trans->conn; + mgcp = conn->network->mgcpgw.client; + + /* Send DLCX */ + msg = mgcp_msg_dlcx(mgcp, conn->rtp.mgcp_rtp_endpoint, + conn->rtp.mgcp_rtp_endpoint); + if (mgcpgw_client_tx(mgcp, msg, NULL, NULL)) + LOGP(DMGCP, LOGL_ERROR, + "Failed to send DLCX message for %s\n", + vlr_subscr_name(trans->vsub)); + + /* Release endpoint id */ + mgcpgw_client_release_endpoint(conn->rtp.mgcp_rtp_endpoint, mgcp); +} |