From e15d59222031db3459db30fd1b01b9269d7a96bb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 Aug 2015 09:28:41 +0200 Subject: 64bit: Fix compiler warnings in regard to 64bit vty_interface_layer3.c:584:4: warning: format '%d' expects argument of type 'int', but argument 3 has type 'long unsigned int' [-Wformat=] sizeof(subscr->extension)-1, VTY_NEWLINE); --- openbsc/src/libmsc/vty_interface_layer3.c | 4 ++-- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 2 +- openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 1515aea0a..71fff936f 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -547,7 +547,7 @@ DEFUN(ena_subscr_name, if (strlen(name) > sizeof(subscr->name)-1) { vty_out(vty, - "%% NAME is too long, max. %d characters are allowed%s", + "%% NAME is too long, max. %zu characters are allowed%s", sizeof(subscr->name)-1, VTY_NEWLINE); return CMD_WARNING; } @@ -580,7 +580,7 @@ DEFUN(ena_subscr_extension, if (strlen(ext) > sizeof(subscr->extension)-1) { vty_out(vty, - "%% EXTENSION is too long, max. %d characters are allowed%s", + "%% EXTENSION is too long, max. %zu characters are allowed%s", sizeof(subscr->extension)-1, VTY_NEWLINE); return CMD_WARNING; } diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 5f703c290..1c03f27d4 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -156,7 +156,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what) return -1; } else if (slen > sizeof(addr)) { fprintf(stderr, "Gateway received message from outerspace: %zu %zu\n", - slen, sizeof(addr)); + (size_t) slen, sizeof(addr)); return -1; } diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c b/openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c index faceb59b5..9291c89e6 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c @@ -45,10 +45,10 @@ static void insert_rewrite_node(struct nat_rewrite_rule *rule, struct nat_rewrit { struct nat_rewrite_rule *new = &root->rule; - const size_t len = strlen(rule->prefix); + const int len = strlen(rule->prefix); int i; - if (len == 0) { + if (len <= 0) { LOGP(DNAT, LOGL_ERROR, "An empty prefix does not make sense.\n"); goto fail; } -- cgit v1.2.3 From 79f1592ce8119c43aec7aeda467147cdaa3e0ef8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 Aug 2015 11:21:29 +0200 Subject: paging: Move the silent_call code to use the subscriber request Coordinate with the normal subscriber channel requests instead of going to page ourselves. This might lead to getting a channel that is of a different type though. --- openbsc/src/libmsc/silent_call.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c index 010c2b4d2..e9ece1835 100644 --- a/openbsc/src/libmsc/silent_call.c +++ b/openbsc/src/libmsc/silent_call.c @@ -118,11 +118,10 @@ int silent_call_reroute(struct gsm_subscriber_connection *conn, struct msgb *msg /* initiate a silent call with a given subscriber */ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type) { - int rc; + struct subscr_request *req; - rc = paging_request(subscr->group->net, subscr, type, - paging_cb_silent, data); - return rc; + req = subscr_request_channel(subscr, type, paging_cb_silent, data); + return req != NULL; } /* end a silent call with a given subscriber */ -- cgit v1.2.3 From 48690861431c25ffc031f8cca87de728e7976644 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 Aug 2015 11:19:35 +0200 Subject: paging: In case paging failed stop it everywhere In case we can't page on a BTS then stop it everywhere. The callers of paging_request assume that this is kind of an atomic operation and we should help with that. --- openbsc/src/libbsc/paging.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 8bc10e670..6b46c6dfc 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -341,8 +341,10 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, break; rc = paging_request_bts(bts, subscr, type, cbfn, data); - if (rc < 0) + if (rc < 0) { + paging_request_stop(NULL, subscr, NULL, NULL); return rc; + } num_pages += rc; } while (1); -- cgit v1.2.3 From 6b38d012fbe782b2c6194aadc8bf54a19ec75244 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 Aug 2015 11:20:31 +0200 Subject: paging: Go through all BTS to stop paging As the comment says we should not rely that the paging occurs on the current LAC. We might page at more BTS. Walk all the BTS to stop paging. No callbacks will be issued by this stop operation. --- openbsc/src/libbsc/paging.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 6b46c6dfc..9ae28e0c4 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -391,28 +391,21 @@ void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr, struct gsm_subscriber_connection *conn, struct msgb *msg) { - struct gsm_bts *bts = NULL; + struct gsm_bts *bts; log_set_context(BSC_CTX_SUBSCR, subscr); + /* Stop this first and dispatch the request */ if (_bts) _paging_request_stop(_bts, subscr, conn, msg); - do { - /* - * FIXME: Don't use the lac of the subscriber... - * as it might have magically changed the lac.. use the - * location area of the _bts as reconfiguration of the - * network is probably happening less often. - */ - bts = gsm_bts_by_lac(subscr->group->net, subscr->lac, bts); - if (!bts) - break; - - /* Stop paging */ - if (bts != _bts) - _paging_request_stop(bts, subscr, NULL, NULL); - } while (1); + /* Make sure to cancel this everywhere else */ + llist_for_each_entry(bts, &subscr->group->net->bts_list, list) { + /* Sort of an optimization. */ + if (bts == _bts) + continue; + _paging_request_stop(bts, subscr, NULL, NULL); + } } void paging_update_buffer_space(struct gsm_bts *bts, uint16_t free_slots) -- cgit v1.2.3 From 804623838a0856ab4694c7eaac0e8ecd4138ceea Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 Aug 2015 11:18:23 +0200 Subject: paging: Stop paging everywhere before dispatching any signal --- openbsc/src/libmsc/gsm_subscriber.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 4559de581..145cbdd5d 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -84,6 +84,15 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, OSMO_ASSERT(subscr->is_paging); + /* + * Stop paging on all other BTS. E.g. if this is + * the first timeout on a BTS then the others will + * timeout soon as well. Let's just stop everything + * and forget we wanted to page. + */ + paging_request_stop(NULL, subscr, NULL, NULL); + subscr->is_paging = 0; + /* Inform parts of the system we don't know */ sig_data.subscr = subscr; sig_data.bts = conn ? conn->bts : NULL; @@ -96,15 +105,6 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, &sig_data ); - /* - * Stop paging on all other BTS. E.g. if this is - * the first timeout on a BTS then the others will - * timeout soon as well. Let's just stop everything - * and forget we wanted to page. - */ - paging_request_stop(NULL, subscr, NULL, NULL); - subscr->is_paging = 0; - llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) { llist_del(&request->entry); request->cbfn(hooknum, event, msg, data, request->param); -- cgit v1.2.3 From 2bab6495c6cc5157b8c8ab2c01d3d24740e13714 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 Aug 2015 11:34:35 +0200 Subject: paging: Forget we were paging after the dispatch So in case somebody is starting paging from within a paging expired callback we would dispatch the paging request right away with the same failure. --- openbsc/src/libmsc/gsm_subscriber.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 145cbdd5d..442e84c4c 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -91,7 +91,6 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, * and forget we wanted to page. */ paging_request_stop(NULL, subscr, NULL, NULL); - subscr->is_paging = 0; /* Inform parts of the system we don't know */ sig_data.subscr = subscr; @@ -112,6 +111,7 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, } /* balanced with the moment we start paging */ + subscr->is_paging = 0; subscr_put(subscr); return 0; } -- cgit v1.2.3 From 8e969e17cefe0bb99ef4c15710f3a68906a38851 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 4 Aug 2015 12:52:05 +0200 Subject: paging: Provide information about pending requests For debugging it is nice to know how many requests are pending. Simply count it and print it besides the paging part. --- openbsc/src/libmsc/vty_interface_layer3.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 71fff936f..f49c53a08 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -58,8 +58,10 @@ extern struct gsm_network *gsmnet_from_vty(struct vty *v); static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr) { int rc; + int reqs; struct gsm_auth_info ainfo; struct gsm_auth_tuple atuple; + struct llist_head *entry; char expire_time[200]; vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, @@ -107,8 +109,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr) "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu)); expire_time[sizeof(expire_time) - 1] = '\0'; vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE); - vty_out(vty, " Paging: %s paging%s", - subscr->is_paging ? "is" : "not", VTY_NEWLINE); + + reqs = 0; + llist_for_each(entry, &subscr->requests) + reqs += 1; + vty_out(vty, " Paging: %s paging Requests: %d%s", + subscr->is_paging ? "is" : "not", reqs, VTY_NEWLINE); vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE); } -- cgit v1.2.3 From 3479a7ca55d650404a7066ef586e887bcaae2500 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 4 Aug 2015 11:37:30 +0200 Subject: subscr: Fix potential subscr ref count issue In case the subscriber is currently busy we would omit the subscr_put. This seems to be very hard to hit as the subscr need to be active and at the same time be selected for the purge operation. --- openbsc/src/libmsc/gsm_subscriber.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 442e84c4c..57c10cf7e 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -353,6 +353,7 @@ static void subscr_expire_callback(void *data, long long unsigned int id) LOGP(DMM, LOGL_DEBUG, "Not expiring subscriber %s (ID %llu)\n", subscr_name(s), id); subscr_update_expire_lu(s, conn->bts); + subscr_put(s); return; } -- cgit v1.2.3 From 7f0f8c690f5122786454eb0b2f6f1a5a58a95574 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 4 Aug 2015 12:22:56 +0200 Subject: subscr: Fix subscr refcount issue in case of message error In case the SMPP payload didn't include the right fields we would leak the subscr reference count. --- openbsc/src/libmsc/smpp_openbsc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c index 057a9d048..a2fa0f4b5 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -110,6 +110,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net, /* ERROR: we cannot have both! */ LOGP(DLSMS, LOGL_ERROR, "SMPP Cannot have payload in " "TLV _and_ in the header\n"); + subscr_put(dest); return ESME_ROPTPARNOTALLWD; } sms_msg = t->value.octet; @@ -120,6 +121,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net, } else { LOGP(DLSMS, LOGL_ERROR, "SMPP neither message payload nor valid sm_length.\n"); + subscr_put(dest); return ESME_RINVPARLEN; } -- cgit v1.2.3 From 38b66fe3785595dabb59e9eec30d3809d64d54d6 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 14 Jul 2015 16:03:41 +0200 Subject: mncc: Update the protocol to match LCR This adds the protocol definition for the RTP bridge extension of Andreas Eversberg and bumps the protocol version. I added the missing mncc mappings from value to string. [ 5cf8fb10ea3addcae74d37f4dbf1c1be664df53e protocol extension 5dac90de38990b188f499c602bf18a4f232070e8 payload extension] --- openbsc/src/libmsc/mncc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/mncc.c b/openbsc/src/libmsc/mncc.c index 73db5f047..2767faa35 100644 --- a/openbsc/src/libmsc/mncc.c +++ b/openbsc/src/libmsc/mncc.c @@ -83,6 +83,9 @@ static struct mncc_names { {"MNCC_FRAME_RECV", 0x0201}, {"MNCC_FRAME_DROP", 0x0202}, {"MNCC_LCHAN_MODIFY", 0x0203}, + {"MNCC_RTP_CREATE", 0x0204}, + {"MNCC_RTP_CONNECT", 0x0205}, + {"MNCC_RTP_FREE", 0x0206}, {"GSM_TCHF_FRAME", 0x0300}, {"GSM_TCHF_FRAME_EFR", 0x0301}, -- cgit v1.2.3 From 05a09059145ff4bfb1a09ec50e22fb75f2f4ca1e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 4 Aug 2015 13:32:09 +0200 Subject: mncc: Implement the direct RTP mode for ip based systems For the LCR rtp-bridge audio should directly flow to the remote system. In contrast to the original patch audio will now flow directly from the BTS to the remote system. This assumes that BTS and the remote system are in the same network segment and can directly communicate. There are various limitations in the first iteration of the implementation: We could (and in the future) should delay the assignment but currently we are forced to pick the channel and move it to the audio state. In case we are located on a SDCCH we always need to change but if we are on a TCH we could send the ipa.CRCX and change the audio state a lot later. The net effect is that the audio codec selection needs to be done in the NITB code and not in the system connected to it. This only works with ip based systems. For E1 systems one could still use the RTP socket or even try to move this out of the process. There is no code for handover handling and it relies on the remote system dealing with the SSRC change of the system. --- openbsc/src/libmsc/gsm_04_08.c | 213 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 02ffe580b..f20eb0878 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -67,6 +67,8 @@ void *tall_locop_ctx; void *tall_authciphop_ctx; +static int tch_rtp_signal(struct gsm_lchan *lchan, int signal); + static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn); static int gsm48_tx_simple(struct gsm_subscriber_connection *conn, uint8_t pdisc, uint8_t msg_type); @@ -1519,6 +1521,10 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, if (subsys != SS_ABISIP) return 0; + /* RTP bridge handling */ + if (lchan->conn && lchan->conn->mncc_rtp_bridge) + return tch_rtp_signal(lchan, signal); + /* in case we use direct BTS-to-BTS RTP */ if (ipacc_rtp_direct) return 0; @@ -2905,11 +2911,211 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { struct gsm_mncc *mode = arg; + struct gsm_lchan *lchan = trans->conn->lchan; + + /* + * We were forced to make an assignment a lot earlier and + * we should avoid sending another assignment that might + * even lead to a different kind of lchan (TCH/F vs. TCH/H). + * In case of rtp-bridge it is too late to change things + * here. + */ + if (trans->conn->mncc_rtp_bridge && lchan->tch_mode != GSM48_CMODE_SIGN) + return 0; return gsm0808_assign_req(trans->conn, mode->lchan_mode, trans->conn->lchan->type != GSM_LCHAN_TCH_H); } +static void mncc_recv_rtp(struct gsm_network *net, uint32_t callref, + int cmd, uint32_t addr, uint16_t port, uint32_t payload_type, + uint32_t payload_msg_type) +{ + uint8_t data[sizeof(struct gsm_mncc)]; + struct gsm_mncc_rtp *rtp; + + memset(&data, 0, sizeof(data)); + rtp = (struct gsm_mncc_rtp *) &data[0]; + + rtp->callref = callref; + rtp->msg_type = cmd; + rtp->ip = addr; + rtp->port = port; + rtp->payload_type = payload_type; + rtp->payload_msg_type = payload_msg_type; + mncc_recvmsg(net, NULL, cmd, (struct gsm_mncc *)data); +} + +static void mncc_recv_rtp_sock(struct gsm_network *net, struct gsm_trans *trans, int cmd) +{ + struct gsm_lchan *lchan; + int msg_type; + + lchan = trans->conn->lchan; + switch (lchan->abis_ip.rtp_payload) { + case RTP_PT_GSM_FULL: + msg_type = GSM_TCHF_FRAME; + break; + case RTP_PT_GSM_EFR: + msg_type = GSM_TCHF_FRAME_EFR; + break; + case RTP_PT_GSM_HALF: + msg_type = GSM_TCHH_FRAME; + break; + case RTP_PT_AMR: + msg_type = GSM_TCH_FRAME_AMR; + break; + default: + LOGP(DMNCC, LOGL_ERROR, "%s unknown payload type %d\n", + gsm_lchan_name(lchan), lchan->abis_ip.rtp_payload); + msg_type = 0; + break; + } + + return mncc_recv_rtp(net, trans->callref, cmd, + lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port, + lchan->abis_ip.rtp_payload, + msg_type); +} + +static void mncc_recv_rtp_err(struct gsm_network *net, uint32_t callref, int cmd) +{ + return mncc_recv_rtp(net, callref, cmd, 0, 0, 0, 0); +} + +static int tch_rtp_create(struct gsm_network *net, uint32_t callref) +{ + struct gsm_bts *bts; + struct gsm_lchan *lchan; + struct gsm_trans *trans; + + /* Find callref */ + trans = trans_find_by_callref(net, callref); + if (!trans) { + LOGP(DMNCC, LOGL_ERROR, "RTP create for non-existing trans\n"); + mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE); + return -EIO; + } + log_set_context(BSC_CTX_SUBSCR, trans->subscr); + if (!trans->conn) { + LOGP(DMNCC, LOGL_NOTICE, "RTP create for trans without conn\n"); + mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE); + return 0; + } + + lchan = trans->conn->lchan; + bts = lchan->ts->trx->bts; + if (!is_ipaccess_bts(bts)) { + /* + * I want this to be straight forward and have no audio flow + * through the nitb/osmo-mss system. This currently means that + * this will not work with BS11/Nokia type BTS. We would need + * to have a trau<->rtp bridge for these but still preferable + * in another process. + */ + LOGP(DMNCC, LOGL_ERROR, "RTP create only works with IP systems\n"); + mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE); + return -EINVAL; + } + + trans->conn->mncc_rtp_bridge = 1; + /* + * *sigh* we need to pick a codec now. Pick the most generic one + * right now and hope we could fix that later on. This is very + * similiar to the above routine. + * TODO: Use the default codec version... + */ + if (lchan->tch_mode == GSM48_CMODE_SIGN) { + trans->conn->mncc_rtp_create_pending = 1; + /* TODO... transport or fix the default type... */ + return gsm0808_assign_req(trans->conn, GSM48_CMODE_SPEECH_V1, + lchan->type != GSM_LCHAN_TCH_H); + } + + mncc_recv_rtp_sock(trans->net, trans, MNCC_RTP_CREATE); + return 0; +} + +static int tch_rtp_connect(struct gsm_network *net, void *arg) +{ + struct gsm_lchan *lchan; + struct gsm_trans *trans; + struct gsm_mncc_rtp *rtp = arg; + + /* Find callref */ + trans = trans_find_by_callref(net, rtp->callref); + if (!trans) { + LOGP(DMNCC, LOGL_ERROR, "RTP connect for non-existing trans\n"); + mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT); + return -EIO; + } + log_set_context(BSC_CTX_SUBSCR, trans->subscr); + if (!trans->conn) { + LOGP(DMNCC, LOGL_ERROR, "RTP connect for trans without conn\n"); + mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT); + return 0; + } + + lchan = trans->conn->lchan; + + /* TODO: Check if payload_msg_type is compatible with what we have */ + if (rtp->payload_type != lchan->abis_ip.rtp_payload) { + LOGP(DMNCC, LOGL_ERROR, "RTP connect with different RTP payload\n"); + mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT); + } + + /* + * FIXME: payload2 can't be sent with MDCX as the osmo-bts code + * complains about both rtp and rtp payload2 being present in the + * same package! + */ + return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0); +} + +static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) +{ + struct gsm_network *net; + struct gsm_trans *tmp, *trans = NULL; + + net = lchan->ts->trx->bts->network; + llist_for_each_entry(tmp, &net->trans_list, entry) { + if (!tmp->conn) + continue; + if (tmp->conn->lchan != lchan) + continue; + trans = tmp; + break; + } + + if (!trans) { + LOGP(DMNCC, LOGL_ERROR, "%s IPA abis signal but no transaction.\n", + gsm_lchan_name(lchan)); + return 0; + } + + switch (signal) { + case S_ABISIP_CRCX_ACK: + if (lchan->conn->mncc_rtp_create_pending) { + lchan->conn->mncc_rtp_create_pending = 0; + LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP create ind.\n", + gsm_lchan_name(lchan)); + mncc_recv_rtp_sock(net, trans, MNCC_RTP_CREATE); + } + break; + case S_ABISIP_MDCX_ACK: + if (lchan->conn->mncc_rtp_bridge) { + LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP connect ind.\n", + gsm_lchan_name(lchan)); + mncc_recv_rtp_sock(net, trans, MNCC_RTP_CONNECT); + } + break; + } + + return 0; +} + + static struct downstate { uint32_t states; int type; @@ -2990,6 +3196,13 @@ 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: + return tch_rtp_create(net, data->callref); + case MNCC_RTP_CONNECT: + return tch_rtp_connect(net, arg); + case MNCC_RTP_FREE: + /* unused right now */ + return -EIO; case GSM_TCHF_FRAME: case GSM_TCHF_FRAME_EFR: case GSM_TCHH_FRAME: -- cgit v1.2.3 From 14a088a92162fd6abb3031e025ce59fba40af718 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 4 Aug 2015 14:41:21 +0200 Subject: mncc: Implement CRCX->MDCX for handover for direct rtp mode Implement sending MDCX on the newly allocated channel and send the data to the same destination as the currently connected one. This way the receiver can implement RTP RFC Appendix A.1 and deal with the new source. --- openbsc/src/libmsc/gsm_04_08.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index f20eb0878..f71d43c56 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1465,6 +1465,15 @@ static int switch_for_handover(struct gsm_lchan *old_lchan, { struct rtp_socket *old_rs, *new_rs, *other_rs; + /* Ask the new socket to send to the already known port. */ + if (new_lchan->conn->mncc_rtp_bridge) { + LOGP(DHO, LOGL_DEBUG, "Forwarding RTP\n"); + rsl_ipacc_mdcx(new_lchan, + old_lchan->abis_ip.connect_ip, + old_lchan->abis_ip.connect_port, 0); + return 0; + } + if (ipacc_rtp_direct) { LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); return 0; @@ -1509,11 +1518,19 @@ static int switch_for_handover(struct gsm_lchan *old_lchan, return 0; } +static void maybe_switch_for_handover(struct gsm_lchan *lchan) +{ + struct gsm_lchan *old_lchan; + old_lchan = bsc_handover_pending(lchan); + if (old_lchan) + switch_for_handover(old_lchan, lchan); +} + /* some other part of the code sends us a signal */ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { - struct gsm_lchan *lchan = signal_data, *old_lchan; + struct gsm_lchan *lchan = signal_data; int rc; struct gsm_network *net; struct gsm_trans *trans; @@ -1566,9 +1583,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, * Do we have a handover pending for this new lchan? In that * case re-route the audio from the old channel to the new one. */ - old_lchan = bsc_handover_pending(lchan); - if (old_lchan) - switch_for_handover(old_lchan, lchan); + maybe_switch_for_handover(lchan); break; case S_ABISIP_DLCX_IND: /* the BTS tells us a RTP stream has been disconnected */ @@ -3070,6 +3085,7 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg) * complains about both rtp and rtp payload2 being present in the * same package! */ + trans->conn->mncc_rtp_connect_pending = 1; return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0); } @@ -3082,7 +3098,7 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) llist_for_each_entry(tmp, &net->trans_list, entry) { if (!tmp->conn) continue; - if (tmp->conn->lchan != lchan) + if (tmp->conn->lchan != lchan && tmp->conn->ho_lchan != lchan) continue; trans = tmp; break; @@ -3102,9 +3118,15 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) gsm_lchan_name(lchan)); mncc_recv_rtp_sock(net, trans, MNCC_RTP_CREATE); } + /* + * TODO: this appears to be too early? Why not until after + * the handover detect or the handover complete? + */ + maybe_switch_for_handover(lchan); break; case S_ABISIP_MDCX_ACK: - if (lchan->conn->mncc_rtp_bridge) { + if (lchan->conn->mncc_rtp_connect_pending) { + lchan->conn->mncc_rtp_connect_pending = 0; LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP connect ind.\n", gsm_lchan_name(lchan)); mncc_recv_rtp_sock(net, trans, MNCC_RTP_CONNECT); -- cgit v1.2.3