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): ...
diff --git a/openbsc/include/openbsc/handover.h b/openbsc/include/openbsc/handover.h
index 9d9a90b..bd0d8ad 100644
--- a/openbsc/include/openbsc/handover.h
+++ b/openbsc/include/openbsc/handover.h
@@ -11,4 +11,7 @@
 /* clear any operation for this connection */
 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 */
diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h
index 598d470..fd13ac7 100644
--- a/openbsc/include/openbsc/signal.h
+++ b/openbsc/include/openbsc/signal.h
@@ -226,16 +226,6 @@
 	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 */
 enum signal_ccch {
 	S_CCCH_PAGING_LOAD,
diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c
index d2cd5ef..9cf26af 100644
--- a/openbsc/src/libbsc/handover_logic.c
+++ b/openbsc/src/libbsc/handover_logic.c
@@ -329,23 +329,6 @@
 	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,
 			   void *handler_data, void *signal_data)
 {
@@ -369,14 +352,6 @@
 			return ho_gsm48_ho_fail(lchan);
 		}
 		break;
-	case SS_ABISIP:
-		lchan = signal_data;
-		switch (signal) {
-		case S_ABISIP_CRCX_ACK:
-			return ho_ipac_crcx_ack(lchan);
-			break;
-		}
-		break;
 	default:
 		break;
 	}
@@ -384,8 +359,16 @@
 	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)
 {
 	osmo_signal_register_handler(SS_LCHAN, ho_logic_sig_cb, NULL);
-	osmo_signal_register_handler(SS_ABISIP, ho_logic_sig_cb, NULL);
 }
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index d1dfa4a..65e6fcc 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -2,7 +2,7 @@
  * 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-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2008-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
  *
  * All Rights Reserved
  *
@@ -51,6 +51,7 @@
 #include <openbsc/silent_call.h>
 #include <openbsc/bsc_api.h>
 #include <openbsc/osmo_msc.h>
+#include <openbsc/handover.h>
 #include <osmocom/abis/e1_input.h>
 #include <osmocom/core/bitvec.h>
 
@@ -1378,14 +1379,10 @@
 static int tch_recv_mncc(struct gsm_network *net, uint32_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)
+static int switch_for_handover(struct gsm_lchan *old_lchan,
+			struct gsm_lchan *new_lchan)
 {
 	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");
@@ -1393,15 +1390,15 @@
 	}
 
 	/* RTP Proxy mode */
-	new_rs = sig->new_lchan->abis_ip.rtp_socket;
-	old_rs = sig->old_lchan->abis_ip.rtp_socket;
+	new_rs = new_lchan->abis_ip.rtp_socket;
+	old_rs = 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);
+	rsl_ipacc_mdcx_to_rtpsock(new_lchan);
 
 	if (!old_rs) {
 		LOGP(DHO, LOGL_ERROR, "no RTP socket for old_lchan\n");
@@ -1413,7 +1410,7 @@
 	new_rs->tx_action = old_rs->tx_action;
 	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:
 		other_rs = old_rs->proxy.other_sock;
 		rtp_socket_proxy(new_rs, other_rs);
@@ -1435,7 +1432,7 @@
 static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
 				 void *handler_data, void *signal_data)
 {
-	struct gsm_lchan *lchan = signal_data;
+	struct gsm_lchan *lchan = signal_data, *old_lchan;
 	int rc;
 	struct gsm_network *net;
 	struct gsm_trans *trans;
@@ -1476,6 +1473,17 @@
 				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;
 	case S_ABISIP_DLCX_IND:
 		/* the BTS tells us a RTP stream has been disconnected */
@@ -3253,6 +3261,5 @@
  */
 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);
 }
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_audio.c b/openbsc/src/osmo-bsc/osmo_bsc_audio.c
index ed0ece7..660d884 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_audio.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_audio.c
@@ -45,6 +45,10 @@
 
 	switch (signal) {
 	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 */
 		LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
 		     con->sccp_con->rtp_port, lchan->abis_ip.conn_id);