diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 3363db556..8baada3fd 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -46,6 +46,7 @@ enum signal_subsystems { SS_IPAC_NWL, SS_RF, SS_MSC, + SS_HO, }; /* SS_PAGING signals */ @@ -211,5 +212,15 @@ struct msc_signal_data { struct osmo_msc_data *data; }; +/* handover */ +enum signal_ho { + S_HANDOVER_ACK, +}; + +struct ho_signal_data { + struct gsm_lchan *old_lchan; + struct gsm_lchan *new_lchan; +}; + #endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index cc69a729d..c86fc26c9 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -22,7 +22,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \ input/misdn.c input/ipaccess.c handover_logic.c \ talloc_ctx.c system_information.c rest_octets.c \ - rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \ + bts_siemens_bs11.c bts_ipaccess_nanobts.c \ bts_unknown.c bsc_version.c bsc_api.c bsc_vty.c meas_rep.c gsm_04_80.c libmsc_a_SOURCES = gsm_subscriber.c db.c \ @@ -30,7 +30,7 @@ libmsc_a_SOURCES = gsm_subscriber.c db.c \ gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c ussd.c silent_call.c \ handover_decision.c auth.c \ - osmo_msc.c + osmo_msc.c rtp_proxy.c libvty_a_SOURCES = common_vty.c diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index aa3d78a58..261181f01 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1768,32 +1768,9 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) ipac_parse_rtp(lchan, &tv); - /* in case we don't use direct BTS-to-BTS RTP */ - if (!ipacc_rtp_direct) { - int rc; - /* the BTS has successfully bound a TCH to a local ip/port, - * which means we can connect our UDP socket to it */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - - lchan->abis_ip.rtp_socket = rtp_socket_create(); - if (!lchan->abis_ip.rtp_socket) - goto out_err; - - rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, - lchan->abis_ip.bound_ip, - lchan->abis_ip.bound_port); - if (rc < 0) - goto out_err; - } - dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); return 0; -out_err: - return -EIO; } static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) @@ -1817,7 +1794,6 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; - struct gsm_lchan *lchan = msg->lchan; rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1825,12 +1801,6 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) print_rsl_cause(LOGL_DEBUG, TLVP_VAL(&tv, RSL_IE_CAUSE), TLVP_LEN(&tv, RSL_IE_CAUSE)); - /* the BTS tells us a RTP stream has been disconnected */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - dispatch_signal(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan); return 0; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e364a1719..b5ab8aae6 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1452,6 +1452,60 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable); +/* handle audio path for handover */ +static int handle_ho_signal(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct rtp_socket *old_rs, *new_rs, *other_rs; + struct ho_signal_data *sig = signal_data; + + if (subsys != SS_HO || signal != S_HANDOVER_ACK) + return 0; + + if (ipacc_rtp_direct) { + LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); + return 0; + } + + /* RTP Proxy mode */ + new_rs = sig->new_lchan->abis_ip.rtp_socket; + old_rs = sig->old_lchan->abis_ip.rtp_socket; + + if (!new_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n"); + return -EIO; + } + + rsl_ipacc_mdcx_to_rtpsock(sig->new_lchan); + + if (!old_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socket for old_lchan\n"); + return -EIO; + } + + /* copy rx_action and reference to other sock */ + new_rs->rx_action = old_rs->rx_action; + new_rs->tx_action = old_rs->tx_action; + new_rs->transmit = old_rs->transmit; + + switch (sig->old_lchan->abis_ip.rtp_socket->rx_action) { + case RTP_PROXY: + other_rs = old_rs->proxy.other_sock; + rtp_socket_proxy(new_rs, other_rs); + /* delete reference to other end socket to prevent + * rtp_socket_free() from removing the inverse reference */ + old_rs->proxy.other_sock = NULL; + break; + case RTP_RECV_UPSTREAM: + new_rs->receive = old_rs->receive; + break; + case RTP_NONE: + break; + } + + return 0; +} + /* 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) @@ -1470,6 +1524,24 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, switch (signal) { case S_ABISIP_CRCX_ACK: + /* in case we don't use direct BTS-to-BTS RTP */ + /* the BTS has successfully bound a TCH to a local ip/port, + * which means we can connect our UDP socket to it */ + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; + } + + lchan->abis_ip.rtp_socket = rtp_socket_create(); + if (!lchan->abis_ip.rtp_socket) + return -EIO; + + rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, + lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port); + if (rc < 0) + return -EIO; + /* check if any transactions on this lchan still have * a tch_recv_mncc request pending */ net = lchan->ts->trx->bts->network; @@ -1479,6 +1551,14 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, tch_recv_mncc(net, trans->callref, 1); } } + break; + case S_ABISIP_DLCX_IND: + /* the BTS tells us a RTP stream has been disconnected */ + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; + } + break; } @@ -3226,5 +3306,6 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) */ static __attribute__((constructor)) void on_dso_load_0408(void) { + register_signal_handler(SS_HO, handle_ho_signal, NULL); register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL); } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 8e8b9db10..44a69331c 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -332,7 +332,7 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan) { struct bsc_handover *ho; - struct rtp_socket *old_rs, *new_rs, *other_rs; + struct ho_signal_data sig_ho; ho = bsc_ho_by_new_lchan(new_lchan); if (!ho) { @@ -340,47 +340,9 @@ static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan) return 0; } - if (ipacc_rtp_direct) { - LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); - return 0; - } - - /* RTP Proxy mode */ - new_rs = new_lchan->abis_ip.rtp_socket; - old_rs = ho->old_lchan->abis_ip.rtp_socket; - - if (!new_rs) { - LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n"); - return -EIO; - } - - rsl_ipacc_mdcx_to_rtpsock(new_lchan); - - if (!old_rs) { - LOGP(DHO, LOGL_ERROR, "no RTP socket for old_lchan\n"); - return -EIO; - } - - /* copy rx_action and reference to other sock */ - new_rs->rx_action = old_rs->rx_action; - new_rs->tx_action = old_rs->tx_action; - new_rs->transmit = old_rs->transmit; - - switch (ho->old_lchan->abis_ip.rtp_socket->rx_action) { - case RTP_PROXY: - other_rs = old_rs->proxy.other_sock; - rtp_socket_proxy(new_rs, other_rs); - /* delete reference to other end socket to prevent - * rtp_socket_free() from removing the inverse reference */ - old_rs->proxy.other_sock = NULL; - break; - case RTP_RECV_UPSTREAM: - new_rs->receive = old_rs->receive; - break; - case RTP_NONE: - break; - } - + sig_ho.old_lchan = ho->old_lchan; + sig_ho.new_lchan = new_lchan; + dispatch_signal(SS_HO, S_HANDOVER_ACK, &sig_ho); return 0; }