diff options
author | Ciaby <ciaby@rhizomatica.org> | 2015-08-06 18:52:06 +0200 |
---|---|---|
committer | Ciaby <ciaby@rhizomatica.org> | 2015-08-06 18:54:22 +0200 |
commit | e0d60333a25d7c44ec0ba8956bc9716f536a2d1b (patch) | |
tree | 089f4dbf657c704a401dbe38823b7409f97b67fc /openbsc/src | |
parent | 43726c309318cd0165025c54b993fc12310ee2b2 (diff) | |
parent | 14a088a92162fd6abb3031e025ce59fba40af718 (diff) |
Merge branch 'zecke/features/rtp-bridge' into ciaby/2015-07-28ciaby/2015-08-06
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/libbsc/paging.c | 29 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 243 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_subscriber.c | 19 | ||||
-rw-r--r-- | openbsc/src/libmsc/mncc.c | 3 | ||||
-rw-r--r-- | openbsc/src/libmsc/silent_call.c | 7 | ||||
-rw-r--r-- | openbsc/src/libmsc/smpp_openbsc.c | 2 | ||||
-rw-r--r-- | openbsc/src/libmsc/vty_interface_layer3.c | 10 |
7 files changed, 277 insertions, 36 deletions
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index 8bc10e670..9ae28e0c4 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); @@ -389,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) diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 02ffe580b..f71d43c56 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); @@ -1463,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; @@ -1507,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; @@ -1519,6 +1538,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; @@ -1560,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 */ @@ -2905,11 +2926,218 @@ 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! + */ + trans->conn->mncc_rtp_connect_pending = 1; + 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 && tmp->conn->ho_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); + } + /* + * 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_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); + } + break; + } + + return 0; +} + + static struct downstate { uint32_t states; int type; @@ -2990,6 +3218,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: diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index ff77aa5cf..ccba360b0 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -99,6 +99,14 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, return 0; } + /* + * 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); + /* Inform parts of the system we don't know */ sig_data.subscr = subscr; sig_data.bts = conn ? conn->bts : NULL; @@ -111,15 +119,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); @@ -127,6 +126,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; } @@ -368,6 +368,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; } 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}, 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 */ 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; } 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); } |