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:
parent
9eb208fcfb
commit
39c609b7c9
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -33,5 +33,4 @@ SUBDIRS += \
|
|||
utils \
|
||||
ipaccess \
|
||||
osmo-bsc \
|
||||
osmo-bsc_nat \
|
||||
$(NULL)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue