summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-01-16 09:29:28 +0100
committerAndreas Eversberg <jolly@eversberg.eu>2015-12-27 20:00:40 +0100
commit990b41308770426eec50cbee6ac5f270f93afee2 (patch)
tree74721fb3daae417805c32a04a00a43dcc993b9f3
parentcdc548cb0ac79a6eef3903872cc6e73eaf6f59ae (diff)
Add traffic forwarding via RTP to remote application
Instead of forwarding traffic through MNCC interface, traffic can be forwarded to a given RTP peer directly. A special MNCC message is used to control the peer's destination. The traffic can still be forwarded through MNCC interface when this special MNCC message is not used. It also works with E1 based BTSs. In conjunction with LCR's "rtp-bridge" feature, the RTP traffic can be directly exchanged with a remote SIP endpoint, so that the traffic is not forwarded by LCR itself. This way the performance of handling traffic only depends on OpenBSC and the remote SIP endpoint. Also the traffic is exchanged with the SIP endpoint without transcoding, to have maximum performance. Increment MNCC version to 5.
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h2
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h5
-rw-r--r--openbsc/include/openbsc/transaction.h2
-rw-r--r--openbsc/src/ipaccess/ipaccess-config.c6
-rw-r--r--openbsc/src/libbsc/bsc_api.c1
-rw-r--r--openbsc/src/libbsc/handover_logic.c1
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c93
-rw-r--r--openbsc/src/libmsc/mncc_sock.c14
-rw-r--r--openbsc/src/libmsc/transaction.c1
-rw-r--r--openbsc/src/libtrau/rtp_proxy.c20
-rw-r--r--openbsc/src/libtrau/trau_mux.c14
-rw-r--r--openbsc/src/utils/bs11_config.c6
-rw-r--r--openbsc/tests/abis/abis_test.c6
-rw-r--r--openbsc/tests/gbproxy/gbproxy_test.c5
14 files changed, 130 insertions, 46 deletions
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 02d67f7..8680401 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -6,6 +6,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <openbsc/meas_rep.h>
+#include <openbsc/mncc.h>
struct msgb;
struct gsm_bts;
@@ -92,5 +93,6 @@ void release_security_operation(struct gsm_subscriber_connection *conn);
void allocate_security_operation(struct gsm_subscriber_connection *conn);
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, struct amr_mode *modes);
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data);
#endif
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index 52ffefd..a5f6a2b 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -40,8 +40,9 @@
enum rtp_rx_action {
RTP_NONE,
- RTP_PROXY,
- RTP_RECV_UPSTREAM,
+ RTP_PROXY, /* forward from BTS to BTS */
+ RTP_RECV_UPSTREAM, /* forward to application */
+ RTP_RECV_APP, /* receive RTP frames from application */
};
enum rtp_tx_action {
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 6ef1612..f1b6d11 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -31,6 +31,7 @@ struct gsm_trans {
/* reference from MNCC or other application */
uint32_t callref;
+ uint32_t callref_keep; /* to remember callref, even if it is removed */
/* if traffic channel receive was requested */
int tch_recv;
@@ -49,6 +50,7 @@ struct gsm_trans {
int T308_second; /* used to send release again */
struct osmo_timer_list timer;
struct gsm_mncc msg; /* stores setup/disconnect/release message */
+ struct rtp_socket *rs; /* application traffic via RTP */
} cc;
struct {
struct gsm411_smc_inst smc_inst;
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index 31da056..83fc020 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -87,6 +87,12 @@ static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00,
static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
*/
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
+
extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
extern struct e1inp_line_ops ipaccess_e1inp_line_ops;
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c
index 504f044..7e9e2c1 100644
--- a/openbsc/src/libbsc/bsc_api.c
+++ b/openbsc/src/libbsc/bsc_api.c
@@ -31,6 +31,7 @@
#include <openbsc/handover.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_04_08.h>
+#include <osmocom/abis/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c
index 2b8c386..d807914 100644
--- a/openbsc/src/libbsc/handover_logic.c
+++ b/openbsc/src/libbsc/handover_logic.c
@@ -39,6 +39,7 @@
#include <openbsc/signal.h>
#include <osmocom/core/talloc.h>
#include <openbsc/transaction.h>
+#include <osmocom/abis/trau_frame.h>
#include <openbsc/trau_mux.h>
struct bsc_handover {
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 9d7e2aa..7e8134e 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1406,8 +1406,15 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
}
if (trans->cc.state != GSM_CSTATE_NULL)
new_cc_state(trans, GSM_CSTATE_NULL);
+ /* Be sure to unmap upstream traffic for our callref only. */
if (trans->conn)
- trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
+ trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref_keep);
+
+ /* free application RTP socket */
+ if (trans->cc.rs) {
+ rtp_socket_free(trans->cc.rs);
+ trans->cc.rs = NULL;
+ }
}
static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
@@ -1508,6 +1515,7 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
new_rs->receive = old_rs->receive;
break;
case RTP_NONE:
+ case RTP_RECV_APP:
break;
}
@@ -1753,6 +1761,47 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
return 0;
}
+/* handle tch frame from application */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ struct gsm_trans *trans;
+ struct gsm_bts *bts;
+
+ /* Find callref */
+ trans = trans_find_by_callref(net, data->callref);
+ if (!trans) {
+ LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
+ return -EIO;
+ }
+ if (!trans->conn) {
+ LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
+ return 0;
+ }
+ if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
+ && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
+ /* This should be LOGL_ERROR or NOTICE, but
+ * unfortuantely it happens for a couple of frames at
+ * the beginning of every RTP connection */
+ LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
+ return 0;
+ }
+ bts = trans->conn->lchan->ts->trx->bts;
+ if (!is_e1_bts(bts)) {
+ if (!trans->conn->lchan->abis_ip.rtp_socket) {
+ DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
+ return 0;
+ }
+ if (trans->conn->lchan->abis_ip.rtp_socket->receive.callref != callref) {
+ /* Drop frame, if not our callref. This happens, if
+ * the call is on hold or retrieved by another
+ * transaction. */
+ return 0;
+ }
+ return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, data);
+ } else
+ return trau_send_frame(trans->conn->lchan, data);
+}
+
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
{
DEBUGP(DCC, "-> STATUS ENQ\n");
@@ -3201,7 +3250,6 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
int i, rc = 0;
struct gsm_trans *trans = NULL, *transt;
struct gsm_subscriber_connection *conn = NULL;
- struct gsm_bts *bts = NULL;
struct gsm_mncc *data = arg, rel;
DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type));
@@ -3225,46 +3273,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
case GSM_TCHF_FRAME_EFR:
case GSM_TCHH_FRAME:
case GSM_TCH_FRAME_AMR:
- /* Find callref */
- trans = trans_find_by_callref(net, data->callref);
- if (!trans) {
- LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
- return -EIO;
- }
- log_set_context(BSC_CTX_SUBSCR, trans->subscr);
- if (!trans->conn) {
- LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
- return 0;
- }
- if (!trans->conn->lchan) {
- LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without lchan\n");
- return 0;
- }
- if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
- && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
- /* This should be LOGL_ERROR or NOTICE, but
- * unfortuantely it happens for a couple of frames at
- * the beginning of every RTP connection */
- LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
- return 0;
- }
- bts = trans->conn->lchan->ts->trx->bts;
- switch (bts->type) {
- case GSM_BTS_TYPE_NANOBTS:
- case GSM_BTS_TYPE_OSMO_SYSMO:
- if (!trans->conn->lchan->abis_ip.rtp_socket) {
- DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
- return 0;
- }
- return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
- case GSM_BTS_TYPE_BS11:
- case GSM_BTS_TYPE_RBS2000:
- case GSM_BTS_TYPE_NOKIA_SITE:
- return trau_send_frame(trans->conn->lchan, arg);
- default:
- LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
- }
- return -EINVAL;
+ return tch_frame_down(net, data->callref, (struct gsm_data_frame *) arg);
}
memset(&rel, 0, sizeof(struct gsm_mncc));
diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c
index dd0a44f..adb56fc 100644
--- a/openbsc/src/libmsc/mncc_sock.c
+++ b/openbsc/src/libmsc/mncc_sock.c
@@ -37,6 +37,8 @@
#include <openbsc/debug.h>
#include <openbsc/mncc.h>
#include <openbsc/gsm_data.h>
+#include <openbsc/transaction.h>
+#include <openbsc/rtp_proxy.h>
struct mncc_sock_state {
struct gsm_network *net;
@@ -50,6 +52,18 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg)
struct gsm_mncc *mncc_in = (struct gsm_mncc *) msgb_data(msg);
int msg_type = mncc_in->msg_type;
+ /* application uses RTP for this transaction, we send our data via RTP,
+ * otherwise we send it through MNCC interface */
+ if (mncc_is_data_frame(msg_type)) {
+ struct gsm_trans *trans = trans_find_by_callref(net, mncc_in->callref);
+
+ if (trans && trans->cc.rs) {
+ rtp_send_frame(trans->cc.rs, (struct gsm_data_frame *) mncc_in);
+ msgb_free(msg);
+ return 0;
+ }
+ }
+
/* Check if we currently have a MNCC handler connected */
if (net->mncc_state->conn_bfd.fd < 0) {
LOGP(DMNCC, LOGL_ERROR, "mncc_sock receives %s for external CC app "
diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c
index a750362..9790318 100644
--- a/openbsc/src/libmsc/transaction.c
+++ b/openbsc/src/libmsc/transaction.c
@@ -80,6 +80,7 @@ struct gsm_trans *trans_alloc(struct gsm_network *net,
trans->protocol = protocol;
trans->transaction_id = trans_id;
trans->callref = callref;
+ trans->callref_keep = callref;
trans->net = net;
llist_add_tail(&trans->entry, &net->trans_list);
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index 8c982c9..65ac409 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -430,7 +430,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
other_rss->bfd.when |= BSC_FD_WRITE;
break;
- case RTP_RECV_UPSTREAM:
+ case RTP_RECV_UPSTREAM: /* from BTS to application */
if (!rs->receive.callref || !rs->receive.net) {
rc = -EIO;
goto out_free;
@@ -459,6 +459,24 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
trau_tx_to_mncc(rs->receive.net, new_msg);
break;
+ case RTP_RECV_APP: /* from remote application */
+ if (!rs->receive.callref || !rs->receive.net) {
+ rc = -EIO;
+ goto out_free;
+ }
+ if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
+ rc = ENOTSUP;
+ goto out_free;
+ }
+ rc = rtp_decode(msg, rs->receive.callref, &new_msg);
+ if (rc < 0)
+ goto out_free;
+ msgb_free(msg);
+ tch_frame_down(rs->receive.net, rs->receive.callref,
+ (struct gsm_data_frame *) new_msg->data);
+ msgb_free(new_msg);
+ break;
+
case RTP_NONE: /* if socket exists, but disabled by app */
msgb_free(msg);
break;
diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c
index b37c765..02934fe 100644
--- a/openbsc/src/libtrau/trau_mux.c
+++ b/openbsc/src/libtrau/trau_mux.c
@@ -171,7 +171,9 @@ int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
llist_del(&ue->list);
return 0;
}
- if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
+ /* Only release, if no callref is given. We must ensure that
+ * only the transaction's upstream is removed, if exists. */
+ if (ss && !callref && !memcmp(&ue->src, ss, sizeof(*ss))) {
llist_del(&ue->list);
return 0;
}
@@ -503,11 +505,21 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
uint8_t trau_bits_out[TRAU_FRAME_BITS];
struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
struct subch_mux *mx;
+ struct upqueue_entry *ue;
struct decoded_trau_frame tf;
mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
if (!mx)
return -EINVAL;
+ if (!(ue = lookup_trau_upqueue(dst_e1_ss))) {
+ /* Call might be on hold, so we drop frames. */
+ return 0;
+ }
+ if (ue->callref != frame->callref) {
+ /* Slot has different transaction, due to
+ * another call. (Ours is on hold.) */
+ return 0;
+ }
switch (frame->msg_type) {
case GSM_TCHF_FRAME:
diff --git a/openbsc/src/utils/bs11_config.c b/openbsc/src/utils/bs11_config.c
index 0d13e25..f6bbfa8 100644
--- a/openbsc/src/utils/bs11_config.c
+++ b/openbsc/src/utils/bs11_config.c
@@ -83,6 +83,12 @@ struct osmo_counter *osmo_counter_alloc(const char *name)
return NULL;
}
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
+
int handle_serial_msg(struct msgb *rx_msg);
/* create all objects for an initial configuration */
diff --git a/openbsc/tests/abis/abis_test.c b/openbsc/tests/abis/abis_test.c
index 53e8a4c..40cea35 100644
--- a/openbsc/tests/abis/abis_test.c
+++ b/openbsc/tests/abis/abis_test.c
@@ -27,6 +27,12 @@
#include <openbsc/abis_nm.h>
#include <openbsc/debug.h>
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
+
static const uint8_t simple_config[] = {
/*0, 13, */
66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c
index 0ba827f..a5179ef 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.c
+++ b/openbsc/tests/gbproxy/gbproxy_test.c
@@ -465,6 +465,11 @@ static const unsigned char llc_ui_ll11_dns_resp_dl[] = {
0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e, 0x6f,
0x76, 0x65, 0x72, 0xc0, 0x14, 0xaa, 0xdf, 0x31
};
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+ return 0;
+}
static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text,
struct sockaddr_in *peer, const unsigned char* data,