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.

Change-Id: I693e428b6bfdd8534eb5b88fa4d47dac20db88ea
This commit is contained in:
Philipp Maier 2017-05-29 13:14:18 +02:00 committed by Neels Hofmeyr
parent 38b3f767e5
commit 4599007a41
5 changed files with 135 additions and 16 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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");
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;
resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel,
encr_alg_id, speech_model);
queue_msg_or_return(resp);
} 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,

View File

@ -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;

View File

@ -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);