aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmsc/gsm_04_08.c
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-01-16 09:29:28 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2017-12-01 03:37:42 +0100
commit3948ede88b65e8d01131cd96b92101d82da1ba49 (patch)
treeb439c5d531a06e6e45c4f0a468b3c689de90b266 /src/libmsc/gsm_04_08.c
parent43c30d0e439053881070d5ceb70f46cfecf5c221 (diff)
Adding traffic forwarding via RTP to remote application
Instead of forwarding traffic through MNCC interface, traffic can now be forwarded to a given RTP destination. A special MNCC message is used for that. 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.
Diffstat (limited to 'src/libmsc/gsm_04_08.c')
-rw-r--r--src/libmsc/gsm_04_08.c175
1 files changed, 139 insertions, 36 deletions
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index eea073614..649a77090 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -1323,8 +1323,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 L4 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);
@@ -1442,6 +1449,7 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
new_rs->receive = old_rs->receive;
break;
case RTP_NONE:
+ case RTP_RECV_L4:
break;
}
@@ -1648,6 +1656,129 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
return 0;
}
+/* handle RTP requests of L4 */
+static int mncc_rtp(struct gsm_network *net, uint32_t callref, struct gsm_mncc_rtp *mncc)
+{
+ struct rtp_socket *rs;
+ struct gsm_trans *trans;
+ int rc;
+
+ /* Find callref */
+ trans = trans_find_by_callref(net, callref);
+ if (!trans) {
+ LOGP(DCC, LOGL_ERROR, "Unknown transaction for callref=%d\n", callref);
+ return -EINVAL;
+ }
+
+ rs = trans->cc.rs;
+
+ switch (mncc->msg_type) {
+ case MNCC_RTP_CREATE:
+ /* use RTP instead of MNCC socket, for traffic
+ * open L4 RTP socket */
+ if (rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP already created.\n");
+ return -EIO;
+ }
+ rs = trans->cc.rs = rtp_socket_create();
+ if (!rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP socket creation failed.\n");
+ /* reply with IP/port = 0 */
+ mncc->ip = 0;
+ mncc->port = 0;
+ mncc_recvmsg(net, trans, MNCC_RTP_CREATE, (struct gsm_mncc *)mncc);
+ return -EIO;
+ }
+ rs->rx_action = RTP_RECV_L4;
+ rs->receive.net = net;
+ rs->receive.callref = callref;
+ /* reply with bound IP/port */
+ mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
+ mncc->port = ntohs(rs->rtp.sin_local.sin_port);
+ mncc_recvmsg(net, trans, MNCC_RTP_CREATE, (struct gsm_mncc *)mncc);
+ break;
+ case MNCC_RTP_CONNECT:
+ if (!rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
+ return -EIO;
+ }
+ rc = rtp_socket_connect(trans->cc.rs, mncc->ip, mncc->port);
+ if (rc < 0) {
+ LOGP(DCC, LOGL_ERROR, "RTP socket connect failed.\n");
+ /* reply with IP/port = 0 */
+ mncc->ip = 0;
+ mncc->port = 0;
+ mncc_recvmsg(net, trans, MNCC_RTP_CONNECT, (struct gsm_mncc *)mncc);
+ return -EIO;
+ }
+ /* reply with local IP/port */
+ mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
+ mncc->port = ntohs(rs->rtp.sin_local.sin_port);
+ mncc_recvmsg(net, trans, MNCC_RTP_CONNECT, (struct gsm_mncc *)mncc);
+ break;
+ case MNCC_RTP_FREE:
+ if (!rs) {
+ LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
+ return -EIO;
+ }
+ rtp_socket_free(trans->cc.rs);
+ trans->cc.rs = NULL;
+ /* reply */
+ mncc_recvmsg(net, trans, MNCC_RTP_FREE, (struct gsm_mncc *)mncc);
+ break;
+ }
+
+ return 0;
+}
+
+/* handle tch frame from L4 */
+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) {
+ /* 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\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;
+ }
+ 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);
+ case GSM_BTS_TYPE_BS11:
+ case GSM_BTS_TYPE_RBS2000:
+ case GSM_BTS_TYPE_NOKIA_SITE:
+ return trau_send_frame(trans->conn->lchan, data);
+ default:
+ LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
+ }
+ return -EINVAL;
+}
+
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
{
DEBUGP(DCC, "-> STATUS ENQ\n");
@@ -2880,7 +3011,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));
@@ -2893,41 +3023,14 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
return tch_recv_mncc(net, data->callref, 0);
case MNCC_FRAME_RECV:
return tch_recv_mncc(net, data->callref, 1);
+ case MNCC_RTP_CREATE:
+ case MNCC_RTP_CONNECT:
+ case MNCC_RTP_FREE:
+ return mncc_rtp(net, data->callref, (struct gsm_mncc_rtp *) arg);
case GSM_TCHF_FRAME:
- /* 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) {
- /* 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\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;
+ case GSM_TCHF_FRAME_EFR:
+ case GSM_TCHF_FRAME_HR:
+ return tch_frame_down(net, data->callref, (struct gsm_data_frame *) arg);
}
memset(&rel, 0, sizeof(struct gsm_mncc));