mgcp: use osmo-mgw to switch RTP streams

osmo-bsc currently negotiates the RTP stream directly with the
BTS and reports back the RTP IP/Port on the BTS. This works fine
for a single BTS, but for Handover the port/ip pointing to the
MSC side must not change, so an entity in between the BTSs and
the MSC is required.

Integrate the mgcp-client and use osmo-mgw to switch the RTP
streams.

Depends: osmo-mgw Ib5fcc72775bf72b489ff79ade36fb345d8d20736
Depends: osmo-mgw I44b338b09de45e1675cedf9737fa72dde72e979a
Depends: osmo-mgw I29c5e2fb972896faeb771ba040f015592487fcbe

Change-Id: Ia2882b7ca31a3219c676986e85045fa08a425d7a
This commit is contained in:
Philipp Maier 2017-09-27 15:51:34 +02:00 committed by Harald Welte
parent 9eb208fcfb
commit 39c609b7c9
13 changed files with 1324 additions and 67 deletions

View File

@ -47,8 +47,9 @@ PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.3.2)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.1.0)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 0.8.0)
PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5)
PKG_CHECK_MODULES(LIBOSMOLEGACYMGCP, libosmo-legacy-mgcp >= 0.0.1)
PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.2)
PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOLEGACYMGCP, libosmo-legacy-mgcp >= 1.0.0)
dnl checks for header files
AC_HEADER_STDC
@ -135,7 +136,6 @@ AC_OUTPUT(
src/libfilter/Makefile
src/libcommon-cs/Makefile
src/osmo-bsc/Makefile
src/osmo-bsc_nat/Makefile
src/ipaccess/Makefile
src/utils/Makefile
tests/Makefile

View File

@ -41,6 +41,7 @@ noinst_HEADERS = \
openbscdefines.h \
osmo_bsc.h \
osmo_bsc_grace.h \
osmo_bsc_mgcp.h \
osmo_bsc_rf.h \
osmo_bsc_sigtran.h \
bsc_msc_data.h \

View File

@ -478,6 +478,11 @@ struct gsm_network {
/* Periodic location update default value */
uint8_t t3212;
struct {
struct mgcp_client_conf *conf;
struct mgcp_client *client;
} mgw;
struct {
/* CS7 instance id number (set via VTY) */
uint32_t cs7_instance;

View File

@ -29,6 +29,20 @@ struct osmo_bsc_sccp_con {
uint32_t rtp_ip;
int rtp_port;
/* RTP address of the remote end (assigned by MSC through assignment
* request) */
struct sockaddr_storage aoip_rtp_addr_remote;
/* Local RTP address (reported back to the MSC by us with the
* assignment complete message) */
struct sockaddr_storage aoip_rtp_addr_local;
/* storage to keep states of the MGCP connection handler, the
* handler is created when an assignment request is received
* and is terminated when the assignment complete message is
* sent */
struct mgcp_ctx *mgcp_ctx;
/* for advanced ping/pong */
int send_ping;
@ -72,4 +86,6 @@ void bsc_gen_location_state_trap(struct gsm_bts *bts);
struct llist_head *bsc_access_lists(void);
int bssmap_send_aoip_ass_compl(struct gsm_lchan *lchan);
#endif

View File

@ -0,0 +1,48 @@
/* (C) 2017 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/* MGCP state handler context (fsm etc..) */
struct mgcp_ctx {
/* FSM instance, which handles the connection switching procedure */
struct osmo_fsm_inst *fsm;
/* RTP endpoint number */
uint16_t rtp_endpoint;
/* Copy of the pointer and the data with context information
* needed to process the AoIP and MGCP requests (system data) */
struct mgcp_client *mgcp;
struct osmo_bsc_sccp_con *conn;
enum gsm48_chan_mode chan_mode;
bool full_rate;
struct gsm_lchan *lchan;
struct gsm_lchan *ho_lchan;
struct msgb *resp;
};
struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp, struct osmo_bsc_sccp_con *conn,
enum gsm48_chan_mode chan_mode, bool full_rate);
void mgcp_clear_complete(struct mgcp_ctx *mgcp_ctx, struct msgb *resp);
void mgcp_ass_complete(struct mgcp_ctx *mgcp_ctx, struct gsm_lchan *lchan);
void mgcp_handover(struct mgcp_ctx *mgcp_ctx, struct gsm_lchan *ho_lchan);
void mgcp_free_ctx(struct mgcp_ctx *mgcp_ctx);

View File

@ -33,5 +33,4 @@ SUBDIRS += \
utils \
ipaccess \
osmo-bsc \
osmo-bsc_nat \
$(NULL)

View File

@ -15,6 +15,7 @@ AM_CFLAGS = \
$(COVERAGE_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOSIGTRAN_CFLAGS) \
$(LIBOSMOMGCPCLIENT_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@ -30,6 +31,7 @@ osmo_bsc_SOURCES = \
osmo_bsc_vty.c \
osmo_bsc_api.c \
osmo_bsc_grace.c \
osmo_bsc_mgcp.c \
osmo_bsc_msc.c \
osmo_bsc_sigtran.c \
osmo_bsc_filter.c \
@ -53,4 +55,5 @@ osmo_bsc_LDADD = \
$(COVERAGE_LDFLAGS) \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
$(LIBOSMOMGCPCLIENT_LIBS) \
$(NULL)

View File

@ -29,47 +29,10 @@
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm0808_utils.h>
#include <osmocom/bsc/osmo_bsc_sigtran.h>
#include <osmocom/bsc/osmo_bsc_mgcp.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;
struct gsm0808_speech_codec sc;
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));
/* Extrapolate speech codec from speech mode */
gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode);
/* 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,
&sc,
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)
{
@ -117,18 +80,19 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
/* NOTE: When an ho_lchan exists, the MDCX is part of an
* handover operation (intra-bsc). This means we will not
* inform the MSC about the event, which means that no
* assignment complete message is transmitted */
LOGP(DMSC, LOGL_INFO," RTP connection handover complete\n");
* assignment complete message is transmitted, we just
* inform the logic that controls the MGW about the new
* connection info */
LOGP(DMSC, LOGL_INFO,"RTP connection handover initiated...\n");
mgcp_handover(con->sccp_con->mgcp_ctx, con->ho_lchan);
} else 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;
mgcp_ass_complete(con->sccp_con->mgcp_ctx, lchan);
}
break;
break;
}
return 0;

View File

@ -25,6 +25,7 @@
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/bsc_subscriber.h>
#include <osmocom/legacy_mgcp/mgcp.h>
#include <osmocom/bsc/osmo_bsc_mgcp.h>
#include <osmocom/bsc/paging.h>
#include <osmocom/bsc/gsm_04_08_utils.h>
@ -351,14 +352,28 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
conn->conn = NULL;
}
/* send the clear complete message */
/* generate the clear complete message */
resp = gsm0808_create_clear_complete();
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
return -1;
}
osmo_bsc_sigtran_send(conn, resp);
if (conn->mgcp_ctx) {
/* NOTE: This is the AoIP case, osmo-bsc has to negotiate with
* the MGCP-GW. For this an mgcp_ctx should be created that
* contains the FSM and some system data. When the connection
* is removed from the MGCP-GW, then osmo_bsc_sigtran_send()
* calls osmo_bsc_sigtran_send(). */
mgcp_clear_complete(conn->mgcp_ctx, resp);
} else {
/* NOTE: This is the SCCP-Lite case, since we do not handle
* the MGCP-GW switching ourselves, we may skip everything
* that is MGCP-GW related and sent the clear complete message
* directly */
osmo_bsc_sigtran_send(conn, resp);
}
return 0;
}
@ -456,7 +471,6 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
int port, full_rate = -1;
bool aoip = false;
struct sockaddr_storage rtp_addr;
struct sockaddr_in *rtp_addr_in;
struct gsm0808_channel_type ct;
struct gsm0808_speech_codec_list scl;
struct gsm0808_speech_codec_list *scl_ptr = NULL;
@ -561,29 +575,40 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
get_value_string(gsm48_chan_mode_names, chan_mode),
ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));
if (aoip == false) {
/* map it to a MGCP Endpoint and a RTP port */
/* Forward the assingment request to lower layers */
if (aoip) {
/* Store network side RTP connection information, we will
* process this address later after we have established an RTP
* connection to the BTS. This is just for organizational
* reasons, functional wise it would not matter when exactly
* the network side RTP connection is made, as long it is made
* before we return with the assignment complete message. */
memcpy(&conn->aoip_rtp_addr_remote, &rtp_addr, sizeof(rtp_addr));
/* Create an assignment request using the MGCP fsm. This FSM
* is directly started when its created (now) and will also
* take care about the further processing (creating RTP
* endpoints, calling gsm0808_assign_req(), rsponding to
* the assignment request etc... */
conn->mgcp_ctx = mgcp_assignm_req(msc->network, msc->network->mgw.client, conn, chan_mode, full_rate);
if (!conn->mgcp_ctx) {
LOGP(DMSC, LOGL_ERROR, "MGCP GW failure, rejecting assignment... (id=%i)\n", conn->conn_id);
goto reject;
}
/* We now may return here, the FSM will do all further work */
return 0;
} else {
/* Note: In the sccp-lite case we to not perform any mgcp operation,
* (the MSC does that for us). We set conn->rtp_ip to 0 and check
* on this later. By this we know that we have to behave accordingly
* to sccp-lite. */
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);
}
return gsm0808_assign_req(conn->conn, chan_mode, full_rate);
reject:
resp =
gsm0808_create_assignment_failure
@ -759,3 +784,39 @@ int bsc_handle_dt(struct osmo_bsc_sccp_con *conn,
return -1;
}
/* Generate and send assignment complete message */
int bssmap_send_aoip_ass_compl(struct gsm_lchan *lchan)
{
struct msgb *resp;
struct gsm0808_speech_codec sc;
struct gsm_subscriber_connection *conn;
conn = lchan->conn;
OSMO_ASSERT(lchan->abis_ip.ass_compl.valid);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->sccp_con);
LOGP(DMSC, LOGL_DEBUG, "Sending assignment complete message... (id=%i)\n", conn->sccp_con->conn_id);
/* Extrapolate speech codec from speech mode */
gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode);
/* 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,
&conn->sccp_con->aoip_rtp_addr_local,
&sc,
NULL);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message! (id=%i)\n",
conn->sccp_con->conn_id);
return -EINVAL;
}
return osmo_bsc_sigtran_send(conn->sccp_con, resp);
}

View File

@ -44,6 +44,7 @@
#include <osmocom/abis/abis.h>
#include <osmocom/sccp/sccp.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#define _GNU_SOURCE
#include <getopt.h>
@ -206,6 +207,9 @@ int main(int argc, char **argv)
exit(1);
}
bsc_gsmnet->mgw.conf = talloc_zero(bsc_gsmnet, struct mgcp_client_conf);
mgcp_client_conf_init(bsc_gsmnet->mgw.conf);
bts_init();
libosmo_abis_init(tall_bsc_ctx);
@ -274,6 +278,15 @@ int main(int argc, char **argv)
}
}
bsc_gsmnet->mgw.client = mgcp_client_init(bsc_gsmnet, bsc_gsmnet->mgw.conf);
if (mgcp_client_connect(bsc_gsmnet->mgw.client)) {
LOGP(DNM, LOGL_ERROR, "MGW connect failed at (%s:%u)\n",
bsc_gsmnet->mgw.conf->remote_addr,
bsc_gsmnet->mgw.conf->remote_port);
exit(1);
}
if (osmo_bsc_sigtran_init(&bsc_gsmnet->bsc_data->mscs) != 0) {
LOGP(DNM, LOGL_ERROR, "Failed to initalize sigtran backhaul.\n");
exit(1);

1136
src/osmo-bsc/osmo_bsc_mgcp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
#include <osmocom/bsc/osmo_bsc_sigtran.h>
#include <osmocom/bsc/a_reset.h>
#include <osmocom/bsc/gsm_04_80.h>
#include <osmocom/bsc/osmo_bsc_mgcp.h>
/* A pointer to a list with all involved MSCs
* (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
@ -384,6 +385,10 @@ int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn)
a_reset_conn_fail(conn->msc->a.reset);
}
/* Remove mgcp context if existant */
if (conn->mgcp_ctx)
mgcp_free_ctx(conn->mgcp_ctx);
llist_del(&conn->entry);
talloc_free(conn);

View File

@ -29,6 +29,8 @@
#include <osmocom/core/talloc.h>
#include <osmocom/vty/logging.h>
#include <osmocom/sccp/sccp_types.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <time.h>
@ -972,6 +974,8 @@ DEFUN(logging_fltr_imsi,
int bsc_vty_init_extra(void)
{
struct gsm_network *net = bsc_gsmnet;
install_element(CONFIG_NODE, &cfg_net_msc_cmd);
install_element(CONFIG_NODE, &cfg_net_bsc_cmd);
@ -1034,5 +1038,7 @@ int bsc_vty_init_extra(void)
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
mgcp_client_vty_init(net, MSC_NODE, net->mgw.conf);
return 0;
}