aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@gnumonks.org>2014-02-05 18:56:17 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-05-22 14:39:16 +0200
commitcab6e7528c475d6aee687001a6146e5f20d8f53d (patch)
tree5d172538444f1b503ff3d2a7a09da5c139ad815f
parent038f97a69fe58d2bcb6cabcb82b3485f7d622ed2 (diff)
mgcp: add voice muxer support
This patch adds the voice muxer. You can use this to batch RTP traffic to reduce bandwidth comsuption. Basically, osmux transforms RTP flows to a compact batch format, that is later on decompacted to its original form. Port UDP/1984 is used for the muxer traffic between osmo-bsc_nat and osmo-bsc_mgcp (in the BSC side). This feature depends on libosmo-netif, which contains the osmux core support. Osmux is requested on-demand via the MGCP CRCX/MDCX messages (using the vendor-specific extension X-Osmux: on) coming from the BSC-NAT, so you can selectively enable osmux per BSC from one the bsc-nat.cfg file, so we have a centralized point to enable/disable osmux. First thing you need to do is to accept requests to use Osmux, this can be done from VTY interface of osmo-bsc_nat and osmo-bsc_mgcp by adding the following line: mgcp ... osmux on osmux batch-factor 4 This just initializes the osmux engine. You still have to specify what BSC uses osmux from osmo-bsc_nat configuration file: ... bsc 1 osmux on bsc 2 ... bsc 3 osmux on In this case, bsc 1 and 3 should use osmux if possible, bsc 2 does not have osmux enabled. Thus, you can selectively enable osmux depending on the BSC, and we have a centralized point for configuration from the bsc-nat to enable osmux on demand, as suggested by Holger. At this moment, this patch contains heavy debug logging for each RTP packet that can be removed later to save cycles. The RTP ssrc/seqnum/timestamp is randomly allocated for each MDCX that is received to configure an endpoint.
-rw-r--r--openbsc/configure.ac1
-rw-r--r--openbsc/include/openbsc/Makefile.am3
-rw-r--r--openbsc/include/openbsc/bsc_nat.h5
-rw-r--r--openbsc/include/openbsc/mgcp.h13
-rw-r--r--openbsc/include/openbsc/mgcp_internal.h15
-rw-r--r--openbsc/include/openbsc/osmux.h19
-rw-r--r--openbsc/src/libmgcp/Makefile.am8
-rw-r--r--openbsc/src/libmgcp/mgcp_network.c62
-rw-r--r--openbsc/src/libmgcp/mgcp_protocol.c42
-rw-r--r--openbsc/src/libmgcp/mgcp_vty.c44
-rw-r--r--openbsc/src/libmgcp/osmux.c398
-rw-r--r--openbsc/src/osmo-bsc_mgcp/Makefile.am3
-rw-r--r--openbsc/src/osmo-bsc_nat/Makefile.am5
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c32
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_vty.c19
-rw-r--r--openbsc/tests/bsc-nat/Makefile.am4
-rw-r--r--openbsc/tests/bsc-nat/bsc_nat_test.c2
-rw-r--r--openbsc/tests/mgcp/Makefile.am2
18 files changed, 629 insertions, 48 deletions
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 5eb8bf9c2..26a7b6209 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -27,6 +27,7 @@ PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4)
+PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1)
# Enabke/disable the NAT?
AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])],
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 8f7c1c423..d902315b5 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -13,7 +13,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \
osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \
bss.h gsm_data_shared.h control_cmd.h ipaccess.h mncc_int.h \
- arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h
+ arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \
+ osmux.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 7bd582cf6..7a161ff27 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -176,6 +176,9 @@ struct bsc_config {
struct bsc_config_stats stats;
struct llist_head lac_list;
+
+ /* Osmux is enabled/disabled per BSC */
+ int osmux;
};
struct bsc_lac_entry {
@@ -418,7 +421,7 @@ int bsc_mgcp_nat_init(struct bsc_nat *nat);
struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(char *input, int length, int endp, const char *ip,
- int port, int *payload_type);
+ int port, int osmux, int *payload_type);
void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index 1d7407820..939e7eed1 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -181,6 +181,15 @@ struct mgcp_config {
int last_bts_port;
enum mgcp_role role;
+
+ /* osmux translator: 0 means disabled, 1 means enabled */
+ int osmux;
+ /* The BSC-NAT may ask for enabling osmux on demand. This tells us if
+ * the osmux socket is already initialized.
+ */
+ int osmux_init;
+ /* osmux batch factor: from 1 to 4 maximum */
+ int osmux_batch;
};
/* config management */
@@ -222,4 +231,8 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
int mgcp_send_reset_all(struct mgcp_config *cfg);
+int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
+int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, struct sockaddr_in *addr, char *buf, int rc);
+int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
+
#endif
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 9b9716539..8fe9f8182 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -126,8 +126,12 @@ struct mgcp_lco {
enum mgcp_type {
MGCP_RTP_DEFAULT = 0,
MGCP_RTP_TRANSCODED,
+ MGCP_OSMUX_BSC,
+ MGCP_OSMUX_BSC_NAT,
};
+#include <openbsc/osmux.h>
+
struct mgcp_endpoint {
int allocated;
uint32_t ci;
@@ -163,6 +167,11 @@ struct mgcp_endpoint {
/* tap for the endpoint */
struct mgcp_rtp_tap taps[MGCP_TAP_COUNT];
+
+ /* osmux is enabled/disabled */
+ int osmux;
+ /* osmux internal to unbatch messages for this endpoint */
+ struct osmux_out_handle osmux_out;
};
#define ENDPOINT_NUMBER(endp) abs(endp - endp->tcfg->endpoints)
@@ -197,5 +206,11 @@ void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *,
uint32_t *expected, int *loss);
uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *);
+enum {
+ MGCP_DEST_NET = 0,
+ MGCP_DEST_BTS,
+};
+
+#define MGCP_DUMMY_LOAD 0x23
#endif
diff --git a/openbsc/include/openbsc/osmux.h b/openbsc/include/openbsc/osmux.h
new file mode 100644
index 000000000..33456b76d
--- /dev/null
+++ b/openbsc/include/openbsc/osmux.h
@@ -0,0 +1,19 @@
+#ifndef _OPENBSC_OSMUX_H_
+#define _OPENBSC_OSMUX_H_
+
+#include <osmocom/netif/osmux.h>
+
+enum {
+ OSMUX_ROLE_BSC = 0,
+ OSMUX_ROLE_BSC_NAT,
+};
+
+int osmux_init(int role, struct mgcp_config *cfg);
+int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role);
+
+int osmux_xfrm_to_rtp(struct mgcp_endpoint *endp, int type, char *buf, int rc);
+int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp);
+
+int osmux_send_dummy(struct mgcp_endpoint *endp);
+
+#endif
diff --git a/openbsc/src/libmgcp/Makefile.am b/openbsc/src/libmgcp/Makefile.am
index 72f625dd4..262ad34a2 100644
--- a/openbsc/src/libmgcp/Makefile.am
+++ b/openbsc/src/libmgcp/Makefile.am
@@ -1,7 +1,9 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
-AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
-AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) $(COVERAGE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMONETIF_LIBS) $(COVERAGE_LDFLAGS)
noinst_LIBRARIES = libmgcp.a
-libmgcp_a_SOURCES = mgcp_protocol.c mgcp_network.c mgcp_vty.c
+libmgcp_a_SOURCES = mgcp_protocol.c mgcp_network.c mgcp_vty.c osmux.c
diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c
index 8a5656a83..7c6926d28 100644
--- a/openbsc/src/libmgcp/mgcp_network.c
+++ b/openbsc/src/libmgcp/mgcp_network.c
@@ -35,6 +35,8 @@
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
+#include <openbsc/osmux.h>
+
#warning "Make use of the rtp proxy code"
/* attempt to determine byte order */
@@ -78,20 +80,11 @@ struct rtp_hdr {
#define RTP_MAX_DROPOUT 3000
#define RTP_MAX_MISORDER 100
-
-enum {
- MGCP_DEST_NET = 0,
- MGCP_DEST_BTS,
-};
-
enum {
MGCP_PROTO_RTP,
MGCP_PROTO_RTCP,
};
-#define MGCP_DUMMY_LOAD 0x23
-
-
/**
* This does not need to be a precision timestamp and
* is allowed to wrap quite fast. The returned value is
@@ -118,8 +111,7 @@ static uint32_t get_current_ts(unsigned unit)
return ret;
}
-static int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf,
- int len)
+int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
{
struct sockaddr_in out;
out.sin_family = AF_INET;
@@ -567,8 +559,8 @@ static int mgcp_send_transcoder(struct mgcp_rtp_end *end,
return rc;
}
-static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
- struct sockaddr_in *addr, char *buf, int rc)
+int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
+ struct sockaddr_in *addr, char *buf, int rc)
{
struct mgcp_trunk_config *tcfg = endp->tcfg;
struct mgcp_rtp_end *rtp_end;
@@ -587,10 +579,22 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
rtp_end = &endp->net_end;
rtp_state = &endp->bts_state;
tap_idx = MGCP_TAP_NET_OUT;
+
+ LOGP(DMGCP, LOGL_DEBUG, "delivering RTP to Network"
+ "via addr=%s, port=%u\n",
+ inet_ntoa(endp->net_end.addr),
+ ntohs(endp->net_end.rtp_port));
+
} else {
rtp_end = &endp->bts_end;
rtp_state = &endp->net_state;
tap_idx = MGCP_TAP_BTS_OUT;
+
+ LOGP(DMGCP, LOGL_DEBUG, "delivering RTP to BTS"
+ "via addr=%s, port=%u\n",
+ inet_ntoa(endp->bts_end.addr),
+ ntohs(endp->bts_end.rtp_port));
+
}
if (!rtp_end->output_enabled)
@@ -655,12 +659,20 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
return -1;
}
- if (endp->net_end.rtp_port != addr.sin_port &&
- endp->net_end.rtcp_port != addr.sin_port) {
- LOGP(DMGCP, LOGL_ERROR,
- "Data from wrong source port %d on 0x%x\n",
- ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
- return -1;
+ switch(endp->type) {
+ case MGCP_RTP_DEFAULT:
+ case MGCP_RTP_TRANSCODED:
+ if (endp->net_end.rtp_port != addr.sin_port &&
+ endp->net_end.rtcp_port != addr.sin_port) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Data from wrong source port %d on 0x%x\n",
+ ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
+ return -1;
+ }
+ break;
+ case MGCP_OSMUX_BSC:
+ case MGCP_OSMUX_BSC_NAT:
+ break;
}
/* throw away the dummy message */
@@ -683,6 +695,10 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
case MGCP_RTP_TRANSCODED:
return mgcp_send_transcoder(&endp->trans_net, endp->cfg,
proto == MGCP_PROTO_RTP, buf, rc);
+ case MGCP_OSMUX_BSC_NAT:
+ return osmux_xfrm_to_osmux(MGCP_DEST_BTS, buf, rc, endp);
+ case MGCP_OSMUX_BSC: /* Should not happen */
+ break;
}
LOGP(DMGCP, LOGL_ERROR, "Bad MGCP type %u on endpoint %u\n",
@@ -771,6 +787,11 @@ static int rtp_data_bts(struct osmo_fd *fd, unsigned int what)
case MGCP_RTP_TRANSCODED:
return mgcp_send_transcoder(&endp->trans_bts, endp->cfg,
proto == MGCP_PROTO_RTP, buf, rc);
+ case MGCP_OSMUX_BSC:
+ /* OSMUX translation: BTS -> BSC */
+ return osmux_xfrm_to_osmux(MGCP_DEST_NET, buf, rc, endp);
+ case MGCP_OSMUX_BSC_NAT:
+ break; /* Should not happen */
}
LOGP(DMGCP, LOGL_ERROR, "Bad MGCP type %u on endpoint %u\n",
@@ -835,8 +856,7 @@ static int rtp_data_trans_bts(struct osmo_fd *fd, unsigned int what)
return rtp_data_transcoder(&endp->trans_bts, endp, MGCP_DEST_BTS, fd);
}
-static int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd,
- int port)
+int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
{
struct sockaddr_in addr;
int on = 1;
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index 5c88c9dd3..1480acca3 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -236,7 +236,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
addr = endp->cfg->source_addr;
len = snprintf(sdp_record, sizeof(sdp_record) - 1,
- "I: %u\n\n"
+ "I: %u%s\n\n"
"v=0\r\n"
"o=- %u 23 IN IP4 %s\r\n"
"c=IN IP4 %s\r\n"
@@ -244,7 +244,8 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
"m=audio %d RTP/AVP %d\r\n"
"a=rtpmap:%d %s\r\n"
"%s%s",
- endp->ci, endp->ci, addr, addr,
+ endp->ci, endp->cfg->osmux && endp->osmux ? "\nX-Osmux: On" : "",
+ endp->ci, addr, addr,
endp->net_end.local_port, endp->bts_end.payload_type,
endp->bts_end.payload_type, endp->tcfg->audio_name,
fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
@@ -759,6 +760,14 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
case 'M':
mode = (const char *) line + 3;
break;
+ case 'X':
+ if (strcmp("Osmux: on", line + 2) == 0 &&
+ osmux_enable_endpoint(endp, OSMUX_ROLE_BSC) < 0) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Could not activate osmux in endpoint %d\n",
+ ENDPOINT_NUMBER(endp));
+ }
+ break;
case '\0':
have_sdp = 1;
goto mgcp_header_done;
@@ -859,8 +868,12 @@ mgcp_header_done:
if (p->cfg->change_cb)
p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
- if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0)
- mgcp_send_dummy(endp);
+ if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
+ if (endp->osmux)
+ osmux_send_dummy(endp);
+ else
+ mgcp_send_dummy(endp);
+ }
create_transcoder(endp);
return create_response_with_sdp(endp, "CRCX", p->trans);
@@ -874,7 +887,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
{
struct mgcp_endpoint *endp = p->endp;
int error_code = 500;
- int silent = 0;
+ int silent = 0, osmux = 0;
char *line;
const char *local_options = NULL;
@@ -909,6 +922,10 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
}
endp->orig_mode = endp->conn_mode;
break;
+ case 'X':
+ if (strcmp("Osmux: on", line + 2) == 0)
+ osmux = 1;
+ break;
case 'Z':
silent = strcmp("noanswer", line + 3) == 0;
break;
@@ -926,6 +943,21 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
}
}
+ /* Re-enable Osmux if we receive a MDCX, we have to set up a new
+ * RTP flow: this generates a randomly allocated RTP SSRC and sequence
+ * number.
+ */
+ if (osmux) {
+ if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC) < 0) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Could not update osmux in endpoint %d\n",
+ ENDPOINT_NUMBER(endp));
+ }
+ LOGP(DMGCP, LOGL_NOTICE,
+ "Re-enabling osmux in endpoint %d, we got updated\n",
+ ENDPOINT_NUMBER(endp));
+ }
+
set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
local_options);
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index 953d34b67..e9b7d1227 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -129,6 +129,10 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " rtp transcoder-range %u %u%s",
g_cfg->transcoder_ports.range_start, g_cfg->transcoder_ports.range_end, VTY_NEWLINE);
vty_out(vty, " transcoder-remote-base %u%s", g_cfg->transcoder_remote_base, VTY_NEWLINE);
+ vty_out(vty, " osmux %s%s",
+ g_cfg->osmux == 1 ? "on" : "off", VTY_NEWLINE);
+ vty_out(vty, " osmux batch-factor %d%s",
+ g_cfg->osmux_batch, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -434,6 +438,10 @@ DEFUN(cfg_mgcp_loop,
"Loop audio for all endpoints on main trunk\n"
"Don't Loop\n" "Loop\n")
{
+ if (g_cfg->osmux) {
+ vty_out(vty, "Cannot use `loop' with `osmux'.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
g_cfg->trunk.audio_loop = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -726,6 +734,10 @@ DEFUN(cfg_trunk_loop,
{
struct mgcp_trunk_config *trunk = vty->index;
+ if (g_cfg->osmux) {
+ vty_out(vty, "Cannot use `loop' with `osmux'.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
trunk->audio_loop = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -1056,6 +1068,33 @@ DEFUN(reset_all_endp, reset_all_endp_cmd,
return CMD_SUCCESS;
}
+#define OSMUX_STR "RTP multiplexing"
+DEFUN(cfg_mgcp_osmux,
+ cfg_mgcp_osmux_cmd,
+ "osmux (on|off)",
+ OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n")
+{
+ if (strcmp(argv[0], "on") == 0) {
+ g_cfg->osmux = 1;
+ if (g_cfg->trunk.audio_loop) {
+ vty_out(vty, "Cannot use `loop' with `osmux'.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ } else if (strcmp(argv[0], "off") == 0)
+ g_cfg->osmux = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_osmux_batch_factor,
+ cfg_mgcp_osmux_batch_factor_cmd,
+ "osmux batch-factor <1-4>",
+ OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
+{
+ g_cfg->osmux_batch = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
int mgcp_vty_init(void)
{
@@ -1108,6 +1147,8 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_ptime_cmd);
install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_ptime_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
install_node(&trunk_node, config_write_trunk);
@@ -1203,6 +1244,9 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
int rc;
struct mgcp_trunk_config *trunk;
+ /* Default to 4 messages */
+ cfg->osmux_batch = 4;
+
g_cfg = cfg;
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
diff --git a/openbsc/src/libmgcp/osmux.c b/openbsc/src/libmgcp/osmux.c
new file mode 100644
index 000000000..3fdc652b0
--- /dev/null
+++ b/openbsc/src/libmgcp/osmux.c
@@ -0,0 +1,398 @@
+/*
+ * (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
+ * (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
+ * All rights not specifically granted under this license are reserved.
+ *
+ * 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.
+ */
+
+#include <stdio.h> /* for printf */
+#include <string.h> /* for memcpy */
+#include <stdlib.h> /* for abs */
+#include <netinet/in.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+
+#include <osmocom/netif/osmux.h>
+#include <osmocom/netif/rtp.h>
+
+#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
+#include <openbsc/osmux.h>
+
+#define OSMUX_PORT 1984
+
+static struct osmo_fd osmux_fd;
+
+static LLIST_HEAD(osmux_handle_list);
+
+struct osmux_handle {
+ struct llist_head head;
+ struct osmux_in_handle *in;
+};
+
+static void *osmux;
+
+static void osmux_deliver(struct msgb *batch_msg, void *data)
+{
+ struct in_addr *addr = data;
+ struct sockaddr_in out = {
+ .sin_family = AF_INET,
+ .sin_port = htons(OSMUX_PORT),
+ };
+ char buf[4096];
+
+ memcpy(&out.sin_addr, addr, sizeof(*addr));
+
+ osmux_snprintf(buf, sizeof(buf), batch_msg);
+ LOGP(DMGCP, LOGL_DEBUG, "OSMUX delivering batch to addr=%s: %s\n",
+ inet_ntoa(out.sin_addr), buf);
+
+ sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
+ (struct sockaddr *)&out, sizeof(out));
+}
+
+static struct osmux_in_handle *
+osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr)
+{
+ struct osmux_handle *h;
+
+ /* Lookup for existing OSMUX handle for this destination address. */
+ llist_for_each_entry(h, &osmux_handle_list, head) {
+ if (memcmp(h->in->data, addr, sizeof(struct in_addr)) == 0) {
+ LOGP(DMGCP, LOGL_DEBUG, "using existing OSMUX handle "
+ "for addr=%s\n",
+ inet_ntoa(*addr));
+ goto out;
+ }
+ }
+
+ /* Does not exist, allocate it. */
+ h = talloc_zero(osmux, struct osmux_handle);
+ if (!h)
+ return NULL;
+
+ h->in = talloc_zero(osmux, struct osmux_in_handle);
+ if (!h->in) {
+ talloc_free(h);
+ return NULL;
+ }
+
+ h->in->osmux_seq = 0; /* sequence number to start OSmux message from */
+ h->in->batch_factor = cfg->osmux_batch;
+ h->in->deliver = osmux_deliver;
+ osmux_xfrm_input_init(h->in);
+ h->in->data = addr;
+
+ llist_add(&h->head, &osmux_handle_list);
+
+ LOGP(DMGCP, LOGL_DEBUG, "creating new OSMUX handle for addr=%s\n",
+ inet_ntoa(*addr));
+out:
+ return h->in;
+}
+
+int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp)
+{
+ int ret;
+ struct msgb *msg;
+ struct in_addr *addr;
+ struct osmux_in_handle *in;
+
+ msg = msgb_alloc(4096, "RTP");
+ if (!msg)
+ return 0;
+
+ memcpy(msg->data, buf, rc);
+ msgb_put(msg, rc);
+
+ switch(type) {
+ case MGCP_DEST_NET:
+ addr = &endp->net_end.addr;
+ break;
+ case MGCP_DEST_BTS:
+ addr = &endp->bts_end.addr;
+ break;
+ default:
+ /* Should not ever happen */
+ LOGP(DMGCP, LOGL_ERROR, "Bad type %d. Fix your code.\n", type);
+ return 0;
+ }
+
+ /* Lookup for osmux input handle that munches this RTP frame */
+ in = osmux_handle_lookup(endp->cfg, addr);
+ if (!in) {
+ LOGP(DMGCP, LOGL_ERROR, "No osmux handle, aborting\n");
+ return 0;
+ }
+
+ LOGP(DMGCP, LOGL_DEBUG, "Osmux uses cid=%u from endpoint=%d (active=%d)\n",
+ endp->ci, ENDPOINT_NUMBER(endp), endp->allocated);
+
+ while ((ret = osmux_xfrm_input(in, msg, endp->ci)) > 0) {
+ /* batch full, build and deliver it */
+ osmux_xfrm_input_deliver(in);
+ }
+ return 0;
+}
+
+static struct mgcp_endpoint *
+endpoint_lookup(struct mgcp_config *cfg, int cid,
+ struct in_addr *from_addr, int type)
+{
+ struct mgcp_endpoint *tmp = NULL;
+ int i;
+
+ /* Lookup for the endpoint that corresponds to this port */
+ for (i=0; i<cfg->trunk.number_endpoints; i++) {
+ struct in_addr *this;
+
+ tmp = &cfg->trunk.endpoints[i];
+
+ if (!tmp->allocated)
+ continue;
+
+ switch(type) {
+ case MGCP_DEST_NET:
+ this = &tmp->net_end.addr;
+ break;
+ case MGCP_DEST_BTS:
+ this = &tmp->bts_end.addr;
+ break;
+ default:
+ /* Should not ever happen */
+ LOGP(DMGCP, LOGL_ERROR, "Bad type %d. Fix your code.\n", type);
+ return NULL;
+ }
+
+ if (tmp->ci == cid && this->s_addr == from_addr->s_addr)
+ return tmp;
+ }
+
+ LOGP(DMGCP, LOGL_ERROR, "Cannot find endpoint with cid=%d\n!\n", cid);
+
+ return NULL;
+}
+
+static void scheduled_tx_net_cb(struct msgb *msg, void *data)
+{
+ struct mgcp_endpoint *endp = data;
+ struct sockaddr_in addr;
+
+ mgcp_send(endp, MGCP_DEST_NET, 1, &addr, (char *)msg->data, msg->len);
+ msgb_free(msg);
+}
+
+static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
+{
+ struct mgcp_endpoint *endp = data;
+ struct sockaddr_in addr;
+
+ mgcp_send(endp, MGCP_DEST_BTS, 1, &addr, (char *)msg->data, msg->len);
+ msgb_free(msg);
+}
+
+static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
+{
+ struct msgb *msg;
+ socklen_t slen = sizeof(*addr);
+ int ret;
+
+ msg = msgb_alloc(4096, "OSMUX");
+ if (!msg) {
+ LOGP(DMGCP, LOGL_ERROR, "cannot allocate message\n");
+ return NULL;
+ }
+ ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0,
+ (struct sockaddr *)addr, &slen);
+ if (ret <= 0) {
+ msgb_free(msg);
+ LOGP(DMGCP, LOGL_ERROR, "cannot receive message\n");
+ return NULL;
+ }
+ msgb_put(msg, ret);
+
+ return msg;
+}
+
+int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ struct msgb *msg;
+ struct osmux_hdr *osmuxh;
+ struct llist_head list;
+ struct sockaddr_in addr;
+ struct mgcp_config *cfg = ofd->data;
+ char buf[4096];
+
+ msg = osmux_recv(ofd, &addr);
+ if (!msg)
+ return -1;
+
+ /* not any further processing dummy messages */
+ if (msg->data[0] == MGCP_DUMMY_LOAD)
+ goto out;
+
+ osmux_snprintf(buf, sizeof(buf), msg);
+ LOGP(DMGCP, LOGL_DEBUG, "received OSMUX message from "
+ "BSC NAT (len=%d) %s\n", msg->len, buf);
+
+ while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
+ struct mgcp_endpoint *endp;
+
+ /* Yes, we use MGCP_DEST_NET to locate the origin */
+ endp = endpoint_lookup(cfg, osmuxh->circuit_id,
+ &addr.sin_addr, MGCP_DEST_NET);
+ if (!endp) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Cannot find an endpoint for circuit_id=%d\n",
+ osmuxh->circuit_id);
+ goto out;
+ }
+
+ LOGP(DMGCP, LOGL_DEBUG,
+ "sending extracted RTP from OSMUX to BSC via endpoint=%u "
+ "(allocated=%d)\n", ENDPOINT_NUMBER(endp), endp->allocated);
+
+ osmux_xfrm_output(osmuxh, &endp->osmux_out, &list);
+ osmux_tx_sched(&list, scheduled_tx_bts_cb, endp);
+ }
+out:
+ msgb_free(msg);
+ return 0;
+}
+
+int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ struct msgb *msg;
+ struct osmux_hdr *osmuxh;
+ struct llist_head list;
+ struct sockaddr_in addr;
+ struct mgcp_config *cfg = ofd->data;
+ char buf[4096];
+
+ msg = osmux_recv(ofd, &addr);
+ if (!msg)
+ return -1;
+
+ /* not any further processing dummy messages */
+ if (msg->data[0] == MGCP_DUMMY_LOAD)
+ goto out;
+
+ osmux_snprintf(buf, sizeof(buf), msg);
+ LOGP(DMGCP, LOGL_DEBUG, "received OSMUX message "
+ "from BSC (len=%d) %s\n", msg->len, buf);
+
+ while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
+ struct mgcp_endpoint *endp;
+
+ /* Yes, we use MGCP_DEST_BTS to locate the origin */
+ endp = endpoint_lookup(cfg, osmuxh->circuit_id,
+ &addr.sin_addr, MGCP_DEST_BTS);
+ if (!endp) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Cannot find an endpoint for circuit_id=%d\n",
+ osmuxh->circuit_id);
+ goto out;
+ }
+
+ LOGP(DMGCP, LOGL_DEBUG,
+ "sending extracted RTP from OSMUX to MSC via endpoint=%u "
+ "(allocated=%d)\n", ENDPOINT_NUMBER(endp), endp->allocated);
+
+ osmux_xfrm_output(osmuxh, &endp->osmux_out, &list);
+ osmux_tx_sched(&list, scheduled_tx_net_cb, endp);
+ }
+out:
+ msgb_free(msg);
+ return 0;
+}
+
+int osmux_init(int role, struct mgcp_config *cfg)
+{
+ int ret;
+
+ switch(role) {
+ case OSMUX_ROLE_BSC:
+ osmux_fd.cb = osmux_read_from_bsc_nat_cb;
+ break;
+ case OSMUX_ROLE_BSC_NAT:
+ osmux_fd.cb = osmux_read_from_bsc_cb;
+ break;
+ default:
+ LOGP(DMGCP, LOGL_ERROR, "wrong role for OSMUX\n");
+ return -1;
+ }
+ osmux_fd.data = cfg;
+
+ ret = mgcp_create_bind("0.0.0.0", &osmux_fd, OSMUX_PORT);
+ if (ret < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "cannot bind OSMUX socket\n");
+ return ret;
+ }
+ osmux_fd.when |= BSC_FD_READ;
+
+ ret = osmo_fd_register(&osmux_fd);
+ if (ret < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "cannot register OSMUX socket\n");
+ return ret;
+ }
+ cfg->osmux_init = 1;
+
+ return 0;
+}
+
+int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role)
+{
+ /* If osmux is enabled, initialize the output handler. This handler is
+ * used to reconstruct the RTP flow from osmux. The RTP SSRC is
+ * allocated based on the circuit ID (endp->ci), which is unique in the
+ * local scope to the BSC/BSC-NAT. We use it to divide the RTP SSRC
+ * space (2^32) by the 256 possible circuit IDs, then randomly select
+ * one value from that window. Thus, we have no chance to have
+ * overlapping RTP SSRC traveling to the BTSes behind the BSC,
+ * similarly, for flows traveling to the MSC.
+ */
+ static const uint32_t rtp_ssrc_winlen = UINT32_MAX / 256;
+
+ if (!endp->cfg->osmux_init) {
+ if (osmux_init(role, endp->cfg) < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
+ return -1;
+ }
+ LOGP(DMGCP, LOGL_NOTICE, "OSMUX requested, ENABLING.\n");
+ }
+
+ osmux_xfrm_output_init(&endp->osmux_out,
+ (endp->ci * rtp_ssrc_winlen) +
+ (random() % rtp_ssrc_winlen));
+
+ switch (endp->cfg->role) {
+ case MGCP_BSC_NAT:
+ endp->type = MGCP_OSMUX_BSC_NAT;
+ break;
+ case MGCP_BSC:
+ endp->type = MGCP_OSMUX_BSC;
+ break;
+ }
+ endp->osmux = 1;
+
+ return 0;
+}
+
+/* We don't need to send the dummy load for osmux so often as another endpoint
+ * may have already punched the hole in the firewall. This approach is simple
+ * though.
+ */
+int osmux_send_dummy(struct mgcp_endpoint *endp)
+{
+ static char buf[] = { MGCP_DUMMY_LOAD };
+
+ LOGP(DMGCP, LOGL_DEBUG, "sending OSMUX dummy load to %s\n",
+ inet_ntoa(endp->net_end.addr));
+
+ return mgcp_udp_send(osmux_fd.fd, &endp->net_end.addr,
+ htons(OSMUX_PORT), buf, 1);
+}
diff --git a/openbsc/src/osmo-bsc_mgcp/Makefile.am b/openbsc/src/osmo-bsc_mgcp/Makefile.am
index 0456cf108..7b6262142 100644
--- a/openbsc/src/osmo-bsc_mgcp/Makefile.am
+++ b/openbsc/src/osmo-bsc_mgcp/Makefile.am
@@ -7,4 +7,5 @@ bin_PROGRAMS = osmo-bsc_mgcp
osmo_bsc_mgcp_SOURCES = mgcp_main.c
osmo_bsc_mgcp_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libmgcp/libmgcp.a -lrt \
- $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS)
+ $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMONETIF_LIBS)
diff --git a/openbsc/src/osmo-bsc_nat/Makefile.am b/openbsc/src/osmo-bsc_nat/Makefile.am
index aae6d6966..c9ea3e9a3 100644
--- a/openbsc/src/osmo-bsc_nat/Makefile.am
+++ b/openbsc/src/osmo-bsc_nat/Makefile.am
@@ -1,5 +1,5 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
-AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMONETIF_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
bin_PROGRAMS = osmo-bsc_nat
@@ -14,4 +14,5 @@ osmo_bsc_nat_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libctrl/libctrl.a \
-lrt $(LIBOSMOSCCP_LIBS) $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS)
+ $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) \
+ $(LIBOSMONETIF_LIBS)
diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c
index 3dad39628..22b8a3504 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c
@@ -262,12 +262,12 @@ static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp
int len;
len = snprintf(buf, sizeof(buf),
- "MDCX 23 %x@mgw MGCP 1.0\r\n"
+ "MDCX 23 %x@mgw MGCP 1.0%s\r\n"
"Z: noanswer\r\n"
"\r\n"
"c=IN IP4 %s\r\n"
"m=audio %d RTP/AVP 255\r\n",
- port,
+ port, bsc->cfg->osmux ? "\nX-Osmux: on" : "",
bsc->nat->mgcp_cfg->source_addr,
endp->bts_end.local_port);
if (len < 0) {
@@ -545,6 +545,7 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length,
sccp->bsc_endp, nat->mgcp_cfg->source_addr,
mgcp_endp->bts_end.local_port,
+ nat->mgcp_cfg->osmux ? sccp->bsc->cfg->osmux : 0,
&mgcp_endp->net_end.payload_type);
if (!bsc_msg) {
LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
@@ -559,6 +560,16 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
/* we need to update some bits */
if (state == MGCP_ENDP_CRCX) {
struct sockaddr_in sock;
+ struct mgcp_endpoint *endp = &nat->mgcp_cfg->trunk.endpoints[endpoint];
+
+ if (nat->mgcp_cfg->osmux ? sccp->bsc->cfg->osmux : 0) {
+ if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC_NAT) < 0) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Could not activate osmux in endpoint %d\n",
+ ENDPOINT_NUMBER(endp));
+ }
+ }
+
socklen_t len = sizeof(sock);
if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
@@ -687,8 +698,8 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1,
bsc->nat->mgcp_cfg->source_addr,
endp->net_end.local_port,
+ bsc->nat->mgcp_cfg->osmux ? bsc_endp->bsc->cfg->osmux : 0,
&endp->bts_end.payload_type);
-
if (!output) {
LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
return;
@@ -727,7 +738,7 @@ uint32_t bsc_mgcp_extract_ci(const char *str)
* Create a new MGCPCommand based on the input and endpoint from a message
*/
static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
- int endp, int len, int cr)
+ int endp, int len, int cr, int osmux)
{
int slen;
int ret;
@@ -741,14 +752,15 @@ static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
return;
}
- slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s",
- op, buf, endp, cr ? "\r\n" : "\n");
+ slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s%s",
+ op, buf, endp, osmux ? "\nX-Osmux: on" : "",
+ cr ? "\r\n" : "\n");
output->l3h = msgb_put(output, slen);
}
/* we need to replace some strings... */
struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint,
- const char *ip, int port,
+ const char *ip, int port, int osmux,
int *payload_type)
{
static const char crcx_str[] = "CRCX ";
@@ -787,11 +799,11 @@ struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint,
cr = len > 0 && token[len - 1] == '\r';
if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) {
- patch_mgcp(output, "CRCX", token, endpoint, len, cr);
+ patch_mgcp(output, "CRCX", token, endpoint, len, cr, osmux);
} else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) {
- patch_mgcp(output, "DLCX", token, endpoint, len, cr);
+ patch_mgcp(output, "DLCX", token, endpoint, len, cr, 0);
} else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) {
- patch_mgcp(output, "MDCX", token, endpoint, len, cr);
+ patch_mgcp(output, "MDCX", token, endpoint, len, cr, osmux);
} else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
output->l3h = msgb_put(output, strlen(ip_str));
memcpy(output->l3h, ip_str, strlen(ip_str));
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
index 261a194c3..d5903d87e 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
@@ -172,6 +172,8 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
if (bsc->paging_group != -1)
vty_out(vty, " paging group %d%s", bsc->paging_group, VTY_NEWLINE);
vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
+ if (bsc->osmux)
+ vty_out(vty, " osmux on%s", VTY_NEWLINE);
}
static int config_write_bsc(struct vty *vty)
@@ -1175,6 +1177,22 @@ DEFUN(show_ussd_connection,
return CMD_SUCCESS;
}
+#define OSMUX_STR "RTP multiplexing"
+DEFUN(cfg_bsc_osmux,
+ cfg_bsc_osmux_cmd,
+ "osmux (on|off)",
+ OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n")
+{
+ struct bsc_config *conf = vty->index;
+
+ if (strcmp(argv[0], "on") == 0)
+ conf->osmux = 1;
+ else if (strcmp(argv[0], "off") == 0)
+ conf->osmux = 0;
+
+ return CMD_SUCCESS;
+}
+
int bsc_nat_vty_init(struct bsc_nat *nat)
{
_nat = nat;
@@ -1260,6 +1278,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(NAT_BSC_NODE, &cfg_bsc_old_grp_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_paging_grp_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_no_paging_grp_cmd);
+ install_element(NAT_BSC_NODE, &cfg_bsc_osmux_cmd);
mgcp_vty_init();
diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am
index d773f2664..0d145a664 100644
--- a/openbsc/tests/bsc-nat/Makefile.am
+++ b/openbsc/tests/bsc-nat/Makefile.am
@@ -1,5 +1,5 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMONETIF_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
EXTRA_DIST = bsc_nat_test.ok bsc_data.c barr.cfg barr_dup.cfg prefixes.csv
@@ -21,4 +21,4 @@ bsc_nat_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lrt \
$(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \
- $(LIBOSMOABIS_LIBS)
+ $(LIBOSMOABIS_LIBS) $(LIBOSMONETIF_LIBS)
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index bed5b8079..e9567c708 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -630,7 +630,7 @@ static void test_mgcp_rewrite(void)
char *input = strdup(orig);
output = bsc_mgcp_rewrite(input, strlen(input), 0x1e,
- ip, port, &payload_type);
+ ip, port, 0, &payload_type);
if (payload_type != -1) {
fprintf(stderr, "Found media payload type %d in SDP data\n",
diff --git a/openbsc/tests/mgcp/Makefile.am b/openbsc/tests/mgcp/Makefile.am
index 71bf8c089..79e0bf49d 100644
--- a/openbsc/tests/mgcp/Makefile.am
+++ b/openbsc/tests/mgcp/Makefile.am
@@ -12,4 +12,4 @@ mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmgcp/libmgcp.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \
- $(LIBRARY_DL)
+ $(LIBRARY_DL) $(LIBOSMONETIF_LIBS)