From e818b91729de56db7643c0961f810c1652f65701 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Mon, 29 May 2017 13:14:18 +0200 Subject: osmo-bsc: Negotiate rtp ip address/port with BTS This patch adds the support for the RTP IP-Address/Port assignment. The post communicated via the assignment request is now transmitted via RSL/IPACC to the BTS. The Response containing the RX-Port at the BTS side is communicated back to the MSC. Since we plan to add a private MGCPGW to each BSC, this has to be extended. Currently it only creates a direct connection to the BTS. This will be introduced with a future patch. --- openbsc/include/openbsc/gsm_data_shared.h | 10 ++++++ openbsc/include/openbsc/osmo_bsc.h | 1 + openbsc/src/osmo-bsc/osmo_bsc_api.c | 27 +++++++++++--- openbsc/src/osmo-bsc/osmo_bsc_audio.c | 59 ++++++++++++++++++++++++++++++- openbsc/src/osmo-bsc/osmo_bsc_bssap.c | 56 +++++++++++++++++++++++------ 5 files changed, 136 insertions(+), 17 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 0790807b1..537da43de 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -252,6 +252,16 @@ struct gsm_lchan { uint8_t speech_mode; #ifdef ROLE_BSC struct rtp_socket *rtp_socket; + + /* info we need to postpone the AoIP + * assignment completed message */ + struct { + uint8_t rr_cause; + uint8_t chosen_channel; + uint8_t encr_alg_id; + uint8_t speech_mode; + bool valid; + } ass_compl; #else struct osmo_rtp_socket *rtp_socket; #endif diff --git a/openbsc/include/openbsc/osmo_bsc.h b/openbsc/include/openbsc/osmo_bsc.h index 5d3ff6a7f..41a6bb003 100644 --- a/openbsc/include/openbsc/osmo_bsc.h +++ b/openbsc/include/openbsc/osmo_bsc.h @@ -26,6 +26,7 @@ struct osmo_bsc_sccp_con { /* for audio handling */ uint16_t cic; + uint32_t rtp_ip; int rtp_port; /* for advanced ping/pong */ diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c index d15ec40cd..f7343f743 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_api.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c @@ -435,11 +435,28 @@ static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_ struct msgb *resp; return_when_not_connected(conn); - LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n"); - - resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel, - encr_alg_id, speech_model); - queue_msg_or_return(resp); + if (is_ipaccess_bts(conn->bts) && conn->sccp_con->rtp_ip) { + /* NOTE: In a network that makes use of an IPA base station + * and AoIP, we have to wait until the BTS reports its RTP + * IP/Port combination back to BSC via RSL. Unfortunately, the + * IPA protocol sends its Abis assignment complete message + * before it sends its RTP IP/Port via IPACC. So we will now + * postpone the AoIP assignment completed message until we + * know the RTP IP/Port combination. */ + LOGP(DMSC, LOGL_INFO, "POSTPONE MSC ASSIGN COMPL\n"); + conn->lchan->abis_ip.ass_compl.rr_cause = rr_cause; + conn->lchan->abis_ip.ass_compl.chosen_channel = chosen_channel; + conn->lchan->abis_ip.ass_compl.encr_alg_id = encr_alg_id; + conn->lchan->abis_ip.ass_compl.speech_mode = speech_model; + conn->lchan->abis_ip.ass_compl.valid = true; + + } else { + /* NOTE: Send the A assignment complete message immediately. */ + LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n"); + resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel, + encr_alg_id, speech_model); + queue_msg_or_return(resp); + } } static void bsc_assign_fail(struct gsm_subscriber_connection *conn, diff --git a/openbsc/src/osmo-bsc/osmo_bsc_audio.c b/openbsc/src/osmo-bsc/osmo_bsc_audio.c index 116020900..79b513aa3 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_audio.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_audio.c @@ -26,15 +26,52 @@ #include #include #include +#include +#include #include +/* Generate and send assignment complete message */ +static int send_aoip_ass_compl(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan) +{ + struct msgb *resp; + struct sockaddr_storage rtp_addr; + struct sockaddr_in rtp_addr_in; + + OSMO_ASSERT(lchan->abis_ip.ass_compl.valid == true); + + /* Package RTP-Address data */ + memset(&rtp_addr_in, 0, sizeof(rtp_addr_in)); + rtp_addr_in.sin_family = AF_INET; + rtp_addr_in.sin_port = htons(lchan->abis_ip.bound_port); + rtp_addr_in.sin_addr.s_addr = htonl(lchan->abis_ip.bound_ip); + memset(&rtp_addr, 0, sizeof(rtp_addr)); + memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in)); + + /* Generate message */ + resp = gsm0808_create_ass_compl(lchan->abis_ip.ass_compl.rr_cause, + lchan->abis_ip.ass_compl.chosen_channel, + lchan->abis_ip.ass_compl.encr_alg_id, + lchan->abis_ip.ass_compl.speech_mode, + &rtp_addr, + NULL, + NULL); + + if (!resp) { + LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message!\n"); \ + return -EINVAL; + } + + return osmo_bsc_sigtran_send(conn->sccp_con, resp); +} + static int handle_abisip_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct gsm_subscriber_connection *con; struct gsm_lchan *lchan = signal_data; int rc; + uint32_t rtp_ip; if (subsys != SS_ABISIP) return 0; @@ -49,11 +86,19 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, * TODO: handle handover here... then the audio should go to * the old mgcp port.. */ + /* we can ask it to connect now */ LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n", con->sccp_con->rtp_port, lchan->abis_ip.conn_id); - rc = rsl_ipacc_mdcx(lchan, ntohl(INADDR_ANY), + /* If AoIP is in use, the rtp_ip, which has been communicated + * via the A interface as connect_ip */ + if(con->sccp_con->rtp_ip) + rtp_ip = con->sccp_con->rtp_ip; + else + rtp_ip = ntohl(INADDR_ANY); + + rc = rsl_ipacc_mdcx(lchan, rtp_ip, con->sccp_con->rtp_port, lchan->abis_ip.rtp_payload2); if (rc < 0) { @@ -61,6 +106,18 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, return rc; } break; + + case S_ABISIP_MDCX_ACK: + if (is_ipaccess_bts(con->bts) && con->sccp_con->rtp_ip) { + /* NOTE: This is only relevant on AoIP networks with + * IPA based base stations. See also osmo_bsc_api.c, + * function bsc_assign_compl() */ + LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n"); + if (send_aoip_ass_compl(con, lchan) != 0) + return -EINVAL; + } + break; + break; } return 0; diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c index 57a62a5eb..e705e708d 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c @@ -29,7 +29,11 @@ #include #include +#include #include +#include + +#define IP_V4_ADDR_LEN 4 /* * helpers for the assignment command @@ -305,10 +309,14 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, struct bsc_msc_data *msc; struct tlv_parsed tp; uint8_t *data; - uint8_t timeslot; - uint8_t multiplex; + uint8_t timeslot = 0; + uint8_t multiplex = 0; enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN; int i, supported, port, full_rate = -1; + bool aoip = false; + struct sockaddr_storage rtp_addr; + struct sockaddr_in *rtp_addr_in; + int rc; if (!conn->conn) { LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n"); @@ -322,15 +330,25 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, goto reject; } - if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { - LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n"); + /* Detect if a CIC code is present, if so, we use the classic ip.access + * method to calculate the RTP port */ + if (TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { + conn->cic = osmo_load16be(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)); + timeslot = conn->cic & 0x1f; + multiplex = (conn->cic & ~0x1f) >> 5; + } else if(TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) { + /* Decode AoIP transport address element */ + rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr, TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR), TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR)); + if (rc < 0) { + LOGP(DMSC, LOGL_ERROR, "Unable to decode aoip transport address.\n"); + goto reject; + } + aoip = true; + } else { + LOGP(DMSC, LOGL_ERROR, "transport address missing. Audio routing will not work.\n"); goto reject; } - conn->cic = osmo_load16be(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)); - timeslot = conn->cic & 0x1f; - multiplex = (conn->cic & ~0x1f) >> 5; - /* * Currently we only support a limited subset of all * possible channel types. The limitation ends by not using @@ -383,9 +401,25 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, goto reject; } - /* map it to a MGCP Endpoint and a RTP port */ - port = mgcp_timeslot_to_endpoint(multiplex, timeslot); - conn->rtp_port = rtp_calculate_port(port, msc->rtp_base); + if (aoip == false) { + /* map it to a MGCP Endpoint and a RTP port */ + port = mgcp_timeslot_to_endpoint(multiplex, timeslot); + conn->rtp_port = rtp_calculate_port(port, msc->rtp_base); + conn->rtp_ip = 0; + } else { + /* use address / port supplied with the AoIP + * transport address element */ + if(rtp_addr.ss_family == AF_INET) + { + rtp_addr_in = (struct sockaddr_in *)&rtp_addr; + conn->rtp_port = osmo_ntohs(rtp_addr_in->sin_port); + memcpy(&conn->rtp_ip, &rtp_addr_in->sin_addr.s_addr, IP_V4_ADDR_LEN); + conn->rtp_ip = osmo_ntohl(conn->rtp_ip); + } else { + LOGP(DMSC, LOGL_ERROR, "Unsopported addressing scheme. (supports only IPV4)\n"); + goto reject; + } + } return gsm0808_assign_req(conn->conn, chan_mode, full_rate); -- cgit v1.2.3