summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-05-29 13:14:18 +0200
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-06-18 17:50:08 +0200
commite818b91729de56db7643c0961f810c1652f65701 (patch)
tree8d4b447c1a6f1ea53470d53b83dff329f0aa265f
parent805b83a1ef41bbc1d0d6c944e949dbbd33fcfc75 (diff)
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.
-rw-r--r--openbsc/include/openbsc/gsm_data_shared.h10
-rw-r--r--openbsc/include/openbsc/osmo_bsc.h1
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_api.c27
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_audio.c59
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_bssap.c56
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 0790807..537da43 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 5d3ff6a..41a6bb0 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 d15ec40..f7343f7 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 1160209..79b513a 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_audio.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_audio.c
@@ -26,15 +26,52 @@
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/signal.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <openbsc/osmo_bsc_sigtran.h>
#include <arpa/inet.h>
+/* 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 57a62a5..e705e70 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
@@ -29,7 +29,11 @@
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/gsm0808_utils.h>
#include <openbsc/osmo_bsc_sigtran.h>
+#include <osmocom/core/byteswap.h>
+
+#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);