handover: Fix the handover signalling for IP based BTSes

This was reported by Kevin when he was testing handover. The problem
is the order of the signal handlers for S_ABISIP_CRCX_ACK. Right now
the handover signal handler is called before the one inside the libmsc
gsm_04_08.c. This means S_HANDOVER_ACK is signalled _before_ there is a
rtp socket created for the channel. The result is that the MDCX will
never be sent and the called will not be properly switched _after_ the
handover detection.

I do not want to play with the order of signal handlers, remove the
CRCX ack handling from the handover_logic.c and force the NITB (and
later the BSC) to check if the lchan is involved with a handover and
do the switching in there. This means right now we do what two signal
handlers did in one.

Reproduced and tested with the FakeBTS Handover test.

Log message:
<0004> abis_rsl.c:1954 (bts=1,trx=0,ts=3,ss=0) IPAC_CRCX_ACK ...
<000c> gsm_04_08.c:1400 no RTP socket for new_lchan
<001a> rtp_proxy.c:533 rtp_socket_create(): success
<001a> rtp_proxy.c:615 rtp_socket_bind(rs=0x48703c8, IP=0.0.0.0): ...
This commit is contained in:
Holger Hans Peter Freyther 2012-12-26 10:17:42 +01:00
parent 006e3d87e0
commit c121bb3188
5 changed files with 36 additions and 49 deletions

View File

@ -11,4 +11,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts);
/* clear any operation for this connection */ /* clear any operation for this connection */
void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan); void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan);
/* Return the old lchan or NULL. This is meant for audio handling */
struct gsm_lchan *bsc_handover_pending(struct gsm_lchan *new_lchan);
#endif /* _HANDOVER_H */ #endif /* _HANDOVER_H */

View File

@ -226,16 +226,6 @@ struct msc_signal_data {
struct osmo_msc_data *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;
};
/* SS_CCCH signals */ /* SS_CCCH signals */
enum signal_ccch { enum signal_ccch {
S_CCCH_PAGING_LOAD, S_CCCH_PAGING_LOAD,

View File

@ -329,23 +329,6 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan)
return 0; return 0;
} }
static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan)
{
struct bsc_handover *ho;
struct ho_signal_data sig_ho;
ho = bsc_ho_by_new_lchan(new_lchan);
if (!ho) {
/* it is perfectly normal, we have CRCX even in non-HO cases */
return 0;
}
sig_ho.old_lchan = ho->old_lchan;
sig_ho.new_lchan = new_lchan;
osmo_signal_dispatch(SS_HO, S_HANDOVER_ACK, &sig_ho);
return 0;
}
static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data) void *handler_data, void *signal_data)
{ {
@ -369,14 +352,6 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal,
return ho_gsm48_ho_fail(lchan); return ho_gsm48_ho_fail(lchan);
} }
break; break;
case SS_ABISIP:
lchan = signal_data;
switch (signal) {
case S_ABISIP_CRCX_ACK:
return ho_ipac_crcx_ack(lchan);
break;
}
break;
default: default:
break; break;
} }
@ -384,8 +359,16 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal,
return 0; return 0;
} }
struct gsm_lchan *bsc_handover_pending(struct gsm_lchan *new_lchan)
{
struct bsc_handover *ho;
ho = bsc_ho_by_new_lchan(new_lchan);
if (!ho)
return NULL;
return ho->old_lchan;
}
static __attribute__((constructor)) void on_dso_load_ho_logic(void) static __attribute__((constructor)) void on_dso_load_ho_logic(void)
{ {
osmo_signal_register_handler(SS_LCHAN, ho_logic_sig_cb, NULL); osmo_signal_register_handler(SS_LCHAN, ho_logic_sig_cb, NULL);
osmo_signal_register_handler(SS_ABISIP, ho_logic_sig_cb, NULL);
} }

View File

@ -2,7 +2,7 @@
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> /* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2008-2010 by Holger Hans Peter Freyther <zecke@selfish.org> * (C) 2008-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* *
* All Rights Reserved * All Rights Reserved
* *
@ -51,6 +51,7 @@
#include <openbsc/silent_call.h> #include <openbsc/silent_call.h>
#include <openbsc/bsc_api.h> #include <openbsc/bsc_api.h>
#include <openbsc/osmo_msc.h> #include <openbsc/osmo_msc.h>
#include <openbsc/handover.h>
#include <osmocom/abis/e1_input.h> #include <osmocom/abis/e1_input.h>
#include <osmocom/core/bitvec.h> #include <osmocom/core/bitvec.h>
@ -1378,14 +1379,10 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable); static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable);
/* handle audio path for handover */ /* handle audio path for handover */
static int handle_ho_signal(unsigned int subsys, unsigned int signal, static int switch_for_handover(struct gsm_lchan *old_lchan,
void *handler_data, void *signal_data) struct gsm_lchan *new_lchan)
{ {
struct rtp_socket *old_rs, *new_rs, *other_rs; 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) { if (ipacc_rtp_direct) {
LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n");
@ -1393,15 +1390,15 @@ static int handle_ho_signal(unsigned int subsys, unsigned int signal,
} }
/* RTP Proxy mode */ /* RTP Proxy mode */
new_rs = sig->new_lchan->abis_ip.rtp_socket; new_rs = new_lchan->abis_ip.rtp_socket;
old_rs = sig->old_lchan->abis_ip.rtp_socket; old_rs = old_lchan->abis_ip.rtp_socket;
if (!new_rs) { if (!new_rs) {
LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n"); LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n");
return -EIO; return -EIO;
} }
rsl_ipacc_mdcx_to_rtpsock(sig->new_lchan); rsl_ipacc_mdcx_to_rtpsock(new_lchan);
if (!old_rs) { if (!old_rs) {
LOGP(DHO, LOGL_ERROR, "no RTP socket for old_lchan\n"); LOGP(DHO, LOGL_ERROR, "no RTP socket for old_lchan\n");
@ -1413,7 +1410,7 @@ static int handle_ho_signal(unsigned int subsys, unsigned int signal,
new_rs->tx_action = old_rs->tx_action; new_rs->tx_action = old_rs->tx_action;
new_rs->transmit = old_rs->transmit; new_rs->transmit = old_rs->transmit;
switch (sig->old_lchan->abis_ip.rtp_socket->rx_action) { switch (old_lchan->abis_ip.rtp_socket->rx_action) {
case RTP_PROXY: case RTP_PROXY:
other_rs = old_rs->proxy.other_sock; other_rs = old_rs->proxy.other_sock;
rtp_socket_proxy(new_rs, other_rs); rtp_socket_proxy(new_rs, other_rs);
@ -1435,7 +1432,7 @@ static int handle_ho_signal(unsigned int subsys, unsigned int signal,
static int handle_abisip_signal(unsigned int subsys, unsigned int signal, static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data) void *handler_data, void *signal_data)
{ {
struct gsm_lchan *lchan = signal_data; struct gsm_lchan *lchan = signal_data, *old_lchan;
int rc; int rc;
struct gsm_network *net; struct gsm_network *net;
struct gsm_trans *trans; struct gsm_trans *trans;
@ -1476,6 +1473,17 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
tch_recv_mncc(net, trans->callref, 1); tch_recv_mncc(net, trans->callref, 1);
} }
} }
/*
* TODO: this appears to be too early? Why not until after
* the handover detect or the handover complete?
*
* 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);
break; break;
case S_ABISIP_DLCX_IND: case S_ABISIP_DLCX_IND:
/* the BTS tells us a RTP stream has been disconnected */ /* the BTS tells us a RTP stream has been disconnected */
@ -3253,6 +3261,5 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg)
*/ */
static __attribute__((constructor)) void on_dso_load_0408(void) static __attribute__((constructor)) void on_dso_load_0408(void)
{ {
osmo_signal_register_handler(SS_HO, handle_ho_signal, NULL);
osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, NULL); osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, NULL);
} }

View File

@ -45,6 +45,10 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
switch (signal) { switch (signal) {
case S_ABISIP_CRCX_ACK: case S_ABISIP_CRCX_ACK:
/*
* TODO: handle handover here... then the audio should go to
* the old mgcp port..
*/
/* we can ask it to connect now */ /* we can ask it to connect now */
LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n", LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
con->sccp_con->rtp_port, lchan->abis_ip.conn_id); con->sccp_con->rtp_port, lchan->abis_ip.conn_id);