[MERGED] osmo-msc[master]: mscsplit: various preparations to separate MSC from BSC

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Tue Aug 22 12:31:57 UTC 2017


Neels Hofmeyr has submitted this change and it was merged.

Change subject: mscsplit: various preparations to separate MSC from BSC
......................................................................


mscsplit: various preparations to separate MSC from BSC

Disable large parts of the code that depend on BSC presence. The code sections
disabled by #if BEFORE_MSCSPLIT shall be modified or dropped in the course of
adding the A-interface.

Don't set msg->lchan nor msg->dst.
Don't use lchan in libmsc.
Decouple lac from bts.

Prepare entry/exit point for MSC -> BSC and MSC -> RNC communication:
Add msc_ifaces.[hc], a_iface.c, with a general msc_tx_dtap() to redirect to
different interfaces depending on the actual subscriber connection.
While iu_tx() is going to be functional fairly soon, the a_tx() is going to be
just a dummy for some time (see comment).
Add Iu specific fields in gsm_subscriber_connection: the UE connection pointer
and an indicator for the Integrity Protection status on Iu (to be fully
implemented in later commits).
Add lac member to gsm_subscriber_connection, to allow decoupling from
bts->location_area_code. The conn->lac will actually be set in iu.c in an
upcoming commit ("add iucs.[hc]").

move to libcommon-cs: gsm48_extract_mi(), gsm48_paging_extract_mi().

libmsc: duplicate gsm0808 / gsm48 functions (towards BSC).
In osmo-nitb, libmsc would directly call the functions on the BSC level, not
always via the bsc_api. When separating libmsc from libbsc, some functions are
missing from the linkage.
Hence duplicate these functions to libmsc, add an msc_ prefix for clarity, also
add a _tx to gsm0808_cipher_mode():
* add msc_gsm0808_tx_cipher_mode() (dummy/stub)
* add msc_gsm48_tx_mm_serv_ack()
* add msc_gsm48_tx_mm_serv_rej()
Call these from libmsc instead of
* gsm0808_cipher_mode()
* gsm48_tx_mm_serv_ack()
* gsm48_tx_mm_serv_rej()
Also add a comment related to msc_gsm0808_tx_cipher_mode() in two places.

Remove internal RTP streaming code; OsmoNITB supported that, but for OsmoMSC,
this will be done with an external MGCP gateway.

Remove LCHAN_MODIFY from internal MNCC state machine.

Temporarily disable all paging to be able to link libmsc without libbsc.
Skip the paging part of channel_test because the paging is now disabled.
Employ fake paging shims in order for msc_vlr_tests to still work.

msc_compl_l3(): publish in .h, tweak return value.  Use new libmsc enum values
for return val, to avoid dependency on libbsc headers.  Make callable from
other scopes: publish in osmo_msc.h and remove 'static' in osmo_msc.c

add gsm_encr to subscr_conn
move subscr_request to gsm_subscriber.h
subscr_request_channel() -> subscr_request_conn()
move to libmsc: osmo_stats_vty_add_cmds()
gsm_04_08: remove apply_codec_restrictions()
gsm0408_test: use NULL for root ctx
move to libbsc: gsm_bts_neighbor()
move to libbsc: lchan_next_meas_rep()
move vty config for t3212 to network level (periodic lu)
remove unneccessary linking from some tests
remove handle_abisip_signal()
abis_rsl.c: don't use libvlr from libbsc

gsm_subscriber_connection: put the LAC here, so that it is available without
accessing conn->bts. In bsc_api.c, place this lac in conn for the sake of
transition: Iu and A will use this new field to pass the LAC around, but in a
completely separate OsmoBSC this is not actually needed. It can be removed
again from osmo-bsc.git when the time has come.

Siemens MRPCI: completely drop sending the MRPCI messages for now, they shall
be added in osmo-bsc once the A-Interface code has settled. See OS#2389.

Related: OS#1845 OS#2257 OS#2389
Change-Id: Id3705236350d5f69e447046b0a764bbabc3d493c
---
M include/openbsc/Makefile.am
M include/openbsc/gsm_04_08.h
M include/openbsc/gsm_data.h
M include/openbsc/gsm_subscriber.h
M include/openbsc/mncc.h
A include/openbsc/msc_ifaces.h
M include/openbsc/osmo_msc.h
M src/libbsc/abis_rsl.c
M src/libbsc/bsc_api.c
M src/libbsc/bsc_vty.c
M src/libbsc/gsm_04_08_utils.c
M src/libbsc/handover_decision.c
M src/libcommon-cs/common_cs.c
M src/libcommon-cs/common_cs_vty.c
M src/libcommon/gsm_data.c
M src/libcommon/talloc_ctx.c
M src/libmsc/Makefile.am
A src/libmsc/a_iface.c
M src/libmsc/gsm_04_08.c
M src/libmsc/gsm_04_11.c
M src/libmsc/gsm_subscriber.c
M src/libmsc/mncc_builtin.c
M src/libmsc/mncc_sock.c
A src/libmsc/msc_ifaces.c
M src/libmsc/osmo_msc.c
M src/libmsc/silent_call.c
M src/libmsc/smpp_openbsc.c
M src/libmsc/vty_interface_layer3.c
M tests/bsc/Makefile.am
M tests/channel/Makefile.am
M tests/db/Makefile.am
M tests/gsm0408/gsm0408_test.c
M tests/msc_vlr/Makefile.am
M tests/msc_vlr/msc_vlr_test_gsm_authen.err
M tests/msc_vlr/msc_vlr_test_gsm_ciph.err
M tests/msc_vlr/msc_vlr_test_no_authen.err
M tests/msc_vlr/msc_vlr_test_reject_concurrency.err
M tests/msc_vlr/msc_vlr_test_umts_authen.err
M tests/msc_vlr/msc_vlr_tests.c
39 files changed, 470 insertions(+), 1,071 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/include/openbsc/Makefile.am b/include/openbsc/Makefile.am
index 456a4a2..1dfe6c3 100644
--- a/include/openbsc/Makefile.am
+++ b/include/openbsc/Makefile.am
@@ -54,6 +54,7 @@
 	misdn.h \
 	mncc.h \
 	mncc_int.h \
+	msc_ifaces.h \
 	nat_rewrite_trie.h \
 	network_listen.h \
 	oap_client.h \
diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h
index c40d96d..6d6ead1 100644
--- a/include/openbsc/gsm_04_08.h
+++ b/include/openbsc/gsm_04_08.h
@@ -65,8 +65,6 @@
 int send_siemens_mrpci(struct gsm_lchan *lchan, uint8_t *classmark2_lv);
 int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type);
 int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, uint8_t *mi_type);
-int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
-			     struct msgb *msg, struct bsc_subscr *bsub);
 
 int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t lchan_mode);
 int gsm48_rx_rr_modif_ack(struct msgb *msg);
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
index fa2fed7..17b3d71 100644
--- a/include/openbsc/gsm_data.h
+++ b/include/openbsc/gsm_data.h
@@ -26,6 +26,7 @@
 struct bsc_subscr;
 struct vlr_instance;
 struct vlr_subscr;
+struct ue_conn_ctx;
 
 #define OBSC_LINKID_CB(__msgb)	(__msgb)->cb[3]
 
@@ -117,6 +118,12 @@
 	uint8_t classmark3[14]; /* if cm3 gets extended by spec, it will be truncated */
 };
 
+enum integrity_protection_state {
+	INTEGRITY_PROTECTION_NONE	= 0,
+	INTEGRITY_PROTECTION_IK		= 1,
+	INTEGRITY_PROTECTION_IK_CK	= 2,
+};
+
 /* active radio connection of a mobile subscriber */
 struct gsm_subscriber_connection {
 	/* global linked list of subscriber_connections */
@@ -176,6 +183,15 @@
 	enum ran_type via_ran;
 
 	struct gsm_classmark classmark;
+
+	uint16_t lac;
+	struct gsm_encr encr;
+
+	/* which Iu-CS connection, if any. */
+	struct {
+		struct ue_conn_ctx *ue_ctx;
+		int integrity_protection;
+	} iu;
 };
 
 
@@ -311,6 +327,12 @@
 };
 
 struct gsm_network {
+	/* TODO MSCSPLIT the gsm_network struct is basically a kitchen sink for
+	 * global settings and variables, "madly" mixing BSC and MSC stuff. Split
+	 * this in e.g. struct osmo_bsc and struct osmo_msc, with the things
+	 * these have in common, like country and network code, put in yet
+	 * separate structs and placed as members in osmo_bsc and osmo_msc. */
+
 	/* global parameters */
 	uint16_t country_code;
 	uint16_t network_code;
@@ -416,6 +438,9 @@
 	uint16_t gsup_server_port;
 
 	struct vlr_instance *vlr;
+
+	/* Periodic location update default value */
+	uint8_t t3212;
 };
 
 struct osmo_esme;
@@ -470,10 +495,6 @@
 extern void talloc_ctx_init(void *ctx_root);
 
 int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
-
-/* Get reference to a neighbor cell on a given BCCH ARFCN */
-struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
-				 uint16_t arfcn, uint8_t bsic);
 
 enum gsm_bts_type parse_btstype(const char *arg);
 const char *btstype2str(enum gsm_bts_type type);
@@ -557,7 +578,6 @@
 
 int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts);
 void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
-struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
 
 int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat);
 int gsm_bts_model_register(struct gsm_bts_model *model);
diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h
index c65b8a3..60eb0cd 100644
--- a/include/openbsc/gsm_subscriber.h
+++ b/include/openbsc/gsm_subscriber.h
@@ -19,8 +19,6 @@
 
 #define GSM_SUBSCRIBER_NO_EXPIRATION	0x0
 
-struct subscr_request;
-
 enum gsm_subscriber_field {
 	GSM_SUBSCRIBER_IMSI,
 	GSM_SUBSCRIBER_TMSI,
@@ -34,17 +32,35 @@
 	GSM_SUBSCRIBER_UPDATE_EQUIPMENT,
 };
 
-int subscr_update(struct vlr_subscr *vsub, struct gsm_bts *bts, int reason);
+/*
+ * Struct for pending channel requests. This is managed in the
+ * llist_head requests of each subscriber. The reference counting
+ * should work in such a way that a subscriber with a pending request
+ * remains in memory.
+ */
+struct subscr_request {
+       struct llist_head entry;
+
+       /* the callback data */
+       gsm_cbfn *cbfn;
+       void *param;
+};
+
+int subscr_update(struct vlr_subscr *vsub, int reason);
 
 /*
  * Paging handling with authentication
  */
-struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub,
-					      int channel_type,
-					      gsm_cbfn *cbfn, void *param);
+struct subscr_request *subscr_request_conn(struct vlr_subscr *vsub,
+					   int channel_type,
+					   gsm_cbfn *cbfn, void *param);
+
 void subscr_remove_request(struct subscr_request *req);
 
 int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
 			   struct msgb *msg, void *data, void *param);
 
+int msc_fake_paging_request(struct vlr_subscr *vsub);
+void msc_fake_paging_request_stop(struct vlr_subscr *vsub);
+
 #endif /* _GSM_SUBSCR_H */
diff --git a/include/openbsc/mncc.h b/include/openbsc/mncc.h
index 49f0c8b..881e041 100644
--- a/include/openbsc/mncc.h
+++ b/include/openbsc/mncc.h
@@ -155,9 +155,6 @@
 	int		notify; /* 0..127 */
 	int		emergency;
 	char		imsi[16];
-
-	unsigned char	lchan_type;
-	unsigned char	lchan_mode;
 };
 
 struct gsm_data_frame {
@@ -179,7 +176,6 @@
 	uint32_t	called_offset;
 	uint32_t	signal_offset;
 	uint32_t	emergency_offset;
-	uint32_t	lchan_type_offset;
 };
 
 struct gsm_mncc_rtp {
diff --git a/include/openbsc/msc_ifaces.h b/include/openbsc/msc_ifaces.h
new file mode 100644
index 0000000..83aad92
--- /dev/null
+++ b/include/openbsc/msc_ifaces.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <osmocom/core/msgb.h>
+#include <openbsc/gsm_data.h>
+
+/* These are the interfaces of the MSC layer towards (from?) the BSC and RNC,
+ * i.e. in the direction towards the mobile device (MS aka UE).
+ *
+ * 2G will use the A-interface,
+ * 3G aka UMTS will use the Iu-interface (for the MSC, it's IuCS).
+ *
+ * To allow linking parts of the MSC code without having to include entire
+ * infrastructures of external libraries, the core transmitting and receiving
+ * functions are left unimplemented. For example, a unit test does not need to
+ * link against external ASN1 libraries if it is never going to encode actual
+ * outgoing messages. It is up to each building scope to implement real world
+ * functions or to plug mere dummy implementations.
+ *
+ * For example, msc_tx_dtap(conn, msg), depending on conn->via_iface, will call
+ * either iu_tx() or a_tx() [note: at time of writing, the A-interface is not
+ * yet implemented]. When you try to link against libmsc, you will find that
+ * the compiler complains about an undefined reference to iu_tx(). If you,
+ * however, link against libiu as well as the osmo-iuh libs (etc.), iu_tx() is
+ * available. A unit test may instead simply implement a dummy iu_tx() function
+ * and not link against osmo-iuh.
+ */
+
+/* Each main linkage must implement this function (see comment above). */
+extern int iu_tx(struct msgb *msg, uint8_t sapi);
+
+/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
+ * gets implemented, it should be in a separate lib (like libiu), this function
+ * should move there, and the following comment should remain here: "
+ * Each main linkage must implement this function (see comment above).
+ * " */
+extern int a_tx(struct msgb *msg);
+
+int msc_tx_dtap(struct gsm_subscriber_connection *conn,
+		struct msgb *msg);
+
+int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn);
+int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
+			     enum gsm48_reject_value value);
+
+/* TODO: specific to A interface, move this away */
+int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
+			       const uint8_t *key, int len, int include_imeisv);
diff --git a/include/openbsc/osmo_msc.h b/include/openbsc/osmo_msc.h
index 0642c91..5a26b60 100644
--- a/include/openbsc/osmo_msc.h
+++ b/include/openbsc/osmo_msc.h
@@ -51,6 +51,11 @@
 	return get_value_string(subscr_conn_from_names, val);
 }
 
+enum msc_compl_l3_rc {
+	MSC_CONN_ACCEPT = 0,
+	MSC_CONN_REJECT = 1,
+};
+
 
 struct bsc_api *msc_bsc_api();
 
diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c
index 7ae3eeb..441b386 100644
--- a/src/libbsc/abis_rsl.c
+++ b/src/libbsc/abis_rsl.c
@@ -1423,6 +1423,19 @@
 	}
 }
 
+static struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
+{
+	struct gsm_meas_rep *meas_rep;
+
+	meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
+	memset(meas_rep, 0, sizeof(*meas_rep));
+	meas_rep->lchan = lchan;
+	lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
+					% ARRAY_SIZE(lchan->meas_rep);
+
+	return meas_rep;
+}
+
 static int rsl_rx_meas_res(struct msgb *msg)
 {
 	struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c
index 947644e..c2828e3 100644
--- a/src/libbsc/bsc_api.c
+++ b/src/libbsc/bsc_api.c
@@ -264,6 +264,7 @@
 	conn->lchan = lchan;
 	conn->bts = lchan->ts->trx->bts;
 	conn->via_ran = RAN_GERAN_A;
+	conn->lac = conn->bts->location_area_code;
 	lchan->conn = conn;
 	llist_add_tail(&conn->entry, &net->subscr_conns);
 	return conn;
diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c
index 3bd56ea..722753a 100644
--- a/src/libbsc/bsc_vty.c
+++ b/src/libbsc/bsc_vty.c
@@ -593,18 +593,12 @@
 				(sp->penalty_time*20)+20, VTY_NEWLINE);
 	}
 
-	/* Is periodic LU enabled or disabled? */
-	if (bts->si_common.chan_desc.t3212 == 0)
-		vty_out(vty, "  no periodic location update%s", VTY_NEWLINE);
-	else
-		vty_out(vty, "  periodic location update %u%s",
-			bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE);
-
 	if (gsm_bts_get_radio_link_timeout(bts) < 0)
 		vty_out(vty, "  radio-link-timeout infinite%s", VTY_NEWLINE);
 	else
 		vty_out(vty, "  radio-link-timeout %d%s",
 			gsm_bts_get_radio_link_timeout(bts), VTY_NEWLINE);
+	
 	vty_out(vty, "  channel allocator %s%s",
 		bts->chan_alloc_reverse ? "descending" : "ascending",
 		VTY_NEWLINE);
@@ -841,6 +835,11 @@
 			vty_out(vty, " timezone %d %d%s",
 				gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE);
 	}
+	if (gsmnet->t3212 == 0)
+		vty_out(vty, " no periodic location update%s", VTY_NEWLINE);
+	else
+		vty_out(vty, " periodic location update %u%s",
+			gsmnet->t3212 * 6, VTY_NEWLINE);
 
 	return CMD_SUCCESS;
 }
@@ -2262,34 +2261,6 @@
 
 	bts->si_common.cell_ro_sel_par.present = 1;
 	bts->si_common.cell_ro_sel_par.penalty_time = 31;
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
-      "periodic location update <6-1530>",
-      "Periodic Location Updating Interval\n"
-      "Periodic Location Updating Interval\n"
-      "Periodic Location Updating Interval\n"
-      "Periodic Location Updating Interval in Minutes\n")
-{
-	struct gsm_bts *bts = vty->index;
-
-	bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 6;
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_no_per_loc_upd, cfg_bts_no_per_loc_upd_cmd,
-      "no periodic location update",
-      NO_STR
-      "Periodic Location Updating Interval\n"
-      "Periodic Location Updating Interval\n"
-      "Periodic Location Updating Interval\n")
-{
-	struct gsm_bts *bts = vty->index;
-
-	bts->si_common.chan_desc.t3212 = 0;
 
 	return CMD_SUCCESS;
 }
@@ -4129,7 +4100,6 @@
 	install_element_ve(&show_paging_group_cmd);
 
 	logging_vty_add_cmds(NULL);
-	osmo_stats_vty_add_cmds();
 
 	install_element(GSMNET_NODE, &cfg_net_neci_cmd);
 	install_element(GSMNET_NODE, &cfg_net_handover_cmd);
@@ -4189,8 +4159,6 @@
 	install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
 	install_element(BTS_NODE, &cfg_bts_rach_ac_class_cmd);
 	install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
-	install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
-	install_element(BTS_NODE, &cfg_bts_no_per_loc_upd_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
 	install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_bar_qualify_cmd);
diff --git a/src/libbsc/gsm_04_08_utils.c b/src/libbsc/gsm_04_08_utils.c
index 3447d27..7c5e0e9 100644
--- a/src/libbsc/gsm_04_08_utils.c
+++ b/src/libbsc/gsm_04_08_utils.c
@@ -270,61 +270,6 @@
 	return rsl_siemens_mrpci(lchan, &mrpci);
 }
 
-int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
-{
-	/* Check the size for the classmark */
-	if (length < 1 + *classmark2_lv)
-		return -1;
-
-	uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
-	if (length < 2 + *classmark2_lv + mi_lv[0])
-		return -2;
-
-	*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
-	return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
-}
-
-int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
-			    char *mi_string, uint8_t *mi_type)
-{
-	static const uint32_t classmark_offset =
-		offsetof(struct gsm48_pag_resp, classmark2);
-	uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
-	return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
-				mi_string, mi_type);
-}
-
-int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
-			     struct msgb *msg, struct bsc_subscr *bsub)
-{
-	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
-	struct gsm48_hdr *gh = msgb_l3(msg);
-	uint8_t *classmark2_lv = gh->data + 1;
-
-	if (is_siemens_bts(bts))
-		send_siemens_mrpci(msg->lchan, classmark2_lv);
-
-	if (!conn->bsub) {
-		conn->bsub = bsub;
-	} else if (conn->bsub != bsub) {
-		LOGP(DRR, LOGL_ERROR,
-		     "<- Channel already owned by someone else?\n");
-		bsc_subscr_put(bsub);
-		return -EINVAL;
-	} else {
-		DEBUGP(DRR, "<- Channel already owned by us\n");
-		bsc_subscr_put(bsub);
-		bsub = conn->bsub;
-	}
-
-	rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]);
-
-	/* Stop paging on the bts we received the paging response */
-	paging_request_stop(&bts->network->bts_list, conn->bts, bsub, conn,
-			    msg);
-	return 0;
-}
-
 /* Chapter 9.1.9: Ciphering Mode Command */
 int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv)
 {
diff --git a/src/libbsc/handover_decision.c b/src/libbsc/handover_decision.c
index 0f07bca..8d7e047 100644
--- a/src/libbsc/handover_decision.c
+++ b/src/libbsc/handover_decision.c
@@ -33,6 +33,27 @@
 #include <openbsc/handover.h>
 #include <osmocom/gsm/gsm_utils.h>
 
+/* Get reference to a neighbor cell on a given BCCH ARFCN */
+static struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
+					uint16_t arfcn, uint8_t bsic)
+{
+	struct gsm_bts *neigh;
+	/* FIXME: use some better heuristics here to determine which cell
+	 * using this ARFCN really is closest to the target cell.  For
+	 * now we simply assume that each ARFCN will only be used by one
+	 * cell */
+
+	llist_for_each_entry(neigh, &bts->network->bts_list, list) {
+		/* FIXME: this is probably returning the same bts again!? */
+		if (neigh->c0->arfcn == arfcn &&
+		    neigh->bsic == bsic)
+			return neigh;
+	}
+
+	return NULL;
+}
+
+
 /* issue handover to a cell identified by ARFCN and BSIC */
 static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
 				  uint16_t arfcn, uint8_t bsic)
diff --git a/src/libcommon-cs/common_cs.c b/src/libcommon-cs/common_cs.c
index fc9caaf..8e19bb2 100644
--- a/src/libcommon-cs/common_cs.c
+++ b/src/libcommon-cs/common_cs.c
@@ -56,6 +56,9 @@
 	net->country_code = country_code;
 	net->network_code = network_code;
 
+	/* Use 30 min periodic update interval as sane default */
+	net->t3212 = 5;
+
 	INIT_LLIST_HEAD(&net->trans_list);
 	INIT_LLIST_HEAD(&net->upqueue);
 	INIT_LLIST_HEAD(&net->subscr_conns);
@@ -107,6 +110,30 @@
 	return msg;
 }
 
+int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
+{
+	/* Check the size for the classmark */
+	if (length < 1 + *classmark2_lv)
+		return -1;
+
+	uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
+	if (length < 2 + *classmark2_lv + mi_lv[0])
+		return -2;
+
+	*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
+	return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
+}
+
+int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
+			    char *mi_string, uint8_t *mi_type)
+{
+	static const uint32_t classmark_offset =
+		offsetof(struct gsm48_pag_resp, classmark2);
+	uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
+	return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
+				mi_string, mi_type);
+}
+
 uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref)
 {
 	const uint8_t rp_msg_ref = *next_rp_ref;
diff --git a/src/libcommon-cs/common_cs_vty.c b/src/libcommon-cs/common_cs_vty.c
index 86b4c53..1791687 100644
--- a/src/libcommon-cs/common_cs_vty.c
+++ b/src/libcommon-cs/common_cs_vty.c
@@ -284,6 +284,34 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_net_per_loc_upd, cfg_net_per_loc_upd_cmd,
+      "periodic location update <6-1530>",
+      "Periodic Location Updating Interval\n"
+      "Periodic Location Updating Interval\n"
+      "Periodic Location Updating Interval\n"
+      "Periodic Location Updating Interval in Minutes\n")
+{
+	struct gsm_network *net = vty->index;
+
+	net->t3212 = atoi(argv[0]) / 6;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_net_no_per_loc_upd, cfg_net_no_per_loc_upd_cmd,
+      "no periodic location update",
+      NO_STR
+      "Periodic Location Updating Interval\n"
+      "Periodic Location Updating Interval\n"
+      "Periodic Location Updating Interval\n")
+{
+	struct gsm_network *net = vty->index;
+
+	net->t3212 = 0;
+
+	return CMD_SUCCESS;
+}
+
 static struct gsm_network *vty_global_gsm_network = NULL;
 
 /* initialize VTY elements used in both BSC and MSC */
@@ -292,6 +320,8 @@
 {
 	OSMO_ASSERT(vty_global_gsm_network == NULL);
 	vty_global_gsm_network = network;
+
+	osmo_stats_vty_add_cmds();
 
 	install_element(CONFIG_NODE, &cfg_net_cmd);
 	install_node(&net_node, config_write_net);
@@ -310,6 +340,8 @@
 	install_element(GSMNET_NODE, &cfg_net_timezone_cmd);
 	install_element(GSMNET_NODE, &cfg_net_timezone_dst_cmd);
 	install_element(GSMNET_NODE, &cfg_net_no_timezone_cmd);
+	install_element(GSMNET_NODE, &cfg_net_per_loc_upd_cmd);
+	install_element(GSMNET_NODE, &cfg_net_no_per_loc_upd_cmd);
 	install_element(GSMNET_NODE, &cfg_net_dyn_ts_allow_tch_f_cmd);
 
 	return CMD_SUCCESS;
diff --git a/src/libcommon/gsm_data.c b/src/libcommon/gsm_data.c
index 7c717a4..f6fde37 100644
--- a/src/libcommon/gsm_data.c
+++ b/src/libcommon/gsm_data.c
@@ -71,25 +71,6 @@
 	return 0;
 }
 
-/* Get reference to a neighbor cell on a given BCCH ARFCN */
-struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
-				 uint16_t arfcn, uint8_t bsic)
-{
-	struct gsm_bts *neigh;
-	/* FIXME: use some better heuristics here to determine which cell
-	 * using this ARFCN really is closest to the target cell.  For
-	 * now we simply assume that each ARFCN will only be used by one
-	 * cell */
-
-	llist_for_each_entry(neigh, &bts->network->bts_list, list) {
-		if (neigh->c0->arfcn == arfcn &&
-		    neigh->bsic == bsic)
-			return neigh;
-	}
-
-	return NULL;
-}
-
 const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1] = {
 	{ GSM_BTS_TYPE_UNKNOWN,		"Unknown BTS Type" },
 	{ GSM_BTS_TYPE_BS11,		"Siemens BTS (BS-11 or compatible)" },
@@ -210,19 +191,6 @@
 	return 1;
 }
 
-struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
-{
-	struct gsm_meas_rep *meas_rep;
-
-	meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
-	memset(meas_rep, 0, sizeof(*meas_rep));
-	meas_rep->lchan = lchan;
-	lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
-					% ARRAY_SIZE(lchan->meas_rep);
-
-	return meas_rep;
-}
-
 int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat)
 {
 	OSMO_ASSERT(_NUM_BTS_FEAT < MAX_BTS_FEATURES);
@@ -322,7 +290,7 @@
 	bts->si_common.chan_desc.att = 1; /* attachment required */
 	bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */
 	bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */
-	bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */
+	bts->si_common.chan_desc.t3212 = net->t3212; /* Use network's current value */
 	gsm_bts_set_radio_link_timeout(bts, 32); /* Use RADIO LINK TIMEOUT of 32 */
 
 	llist_add_tail(&bts->list, &net->bts_list);
diff --git a/src/libcommon/talloc_ctx.c b/src/libcommon/talloc_ctx.c
index 5e3d9ae..c8e9cd3 100644
--- a/src/libcommon/talloc_ctx.c
+++ b/src/libcommon/talloc_ctx.c
@@ -44,7 +44,6 @@
 	tall_authciphop_ctx = talloc_named_const(ctx_root, 0, "auth_ciph_oper");
 	tall_gsms_ctx = talloc_named_const(ctx_root, 0, "sms");
 	tall_subscr_ctx = talloc_named_const(ctx_root, 0, "subscriber");
-	tall_sub_req_ctx = talloc_named_const(ctx_root, 0, "subscr_request");
 	tall_call_ctx = talloc_named_const(ctx_root, 0, "gsm_call");
 	tall_paging_ctx = talloc_named_const(ctx_root, 0, "paging_request");
 	tall_sigh_ctx = talloc_named_const(ctx_root, 0, "signal_handler");
diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am
index bb2a4a1..3c06514 100644
--- a/src/libmsc/Makefile.am
+++ b/src/libmsc/Makefile.am
@@ -23,6 +23,7 @@
 	$(NULL)
 
 libmsc_a_SOURCES = \
+	a_iface.c \
 	auth.c \
 	db.c \
 	gsm_04_08.c \
@@ -32,6 +33,7 @@
 	mncc.c \
 	mncc_builtin.c \
 	mncc_sock.c \
+	msc_ifaces.c \
 	rrlp.c \
 	silent_call.c \
 	sms_queue.c \
diff --git a/src/libmsc/a_iface.c b/src/libmsc/a_iface.c
new file mode 100644
index 0000000..1f471f9
--- /dev/null
+++ b/src/libmsc/a_iface.c
@@ -0,0 +1,45 @@
+/* A-interface implementation, from MSC to BSC */
+
+/* (C) 2016 by sysmocom s.m.f.c GmbH <info at sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+
+#include <openbsc/debug.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/msc_ifaces.h>
+#include <openbsc/debug.h>
+
+int a_tx(struct msgb *msg)
+{
+	LOGP(DMSC, LOGL_ERROR, "message to be sent to BSC, but A-interface"
+	     " not implemented.\n%s\n", osmo_hexdump(msg->data, msg->len));
+	return -1;
+}
+
+int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
+			       const uint8_t *key, int len, int include_imeisv)
+{
+	/* TODO generalize for A- and Iu interfaces, don't name after 08.08 */
+	LOGP(DMSC, LOGL_ERROR, "gsm0808_cipher_mode(): message to be sent to"
+	     " BSC, but A interface not yet implemented.\n");
+	return -1;
+}
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index 6cea242..21ffaaa 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -59,6 +59,7 @@
 #include <osmocom/abis/e1_input.h>
 #include <osmocom/core/bitvec.h>
 #include <openbsc/vlr.h>
+#include <openbsc/msc_ifaces.h>
 
 #include <osmocom/gsm/gsm48.h>
 #include <osmocom/gsm/gsm0480.h>
@@ -71,10 +72,9 @@
 
 #include <assert.h>
 
+
 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,
 			       uint32_t send_tmsi);
@@ -86,29 +86,6 @@
 	uint16_t mnc;
 	uint16_t lac;
 };
-
-static int apply_codec_restrictions(struct gsm_bts *bts,
-	struct gsm_mncc_bearer_cap *bcap)
-{
-	int i, j;
-
-	/* remove unsupported speech versions from list */
-	for (i = 0, j = 0; bcap->speech_ver[i] >= 0; i++) {
-		if (bcap->speech_ver[i] == GSM48_BCAP_SV_FR)
-			bcap->speech_ver[j++] = GSM48_BCAP_SV_FR;
-		if (bcap->speech_ver[i] == GSM48_BCAP_SV_EFR && bts->codec.efr)
-			bcap->speech_ver[j++] = GSM48_BCAP_SV_EFR;
-		if (bcap->speech_ver[i] == GSM48_BCAP_SV_AMR_F && bts->codec.amr)
-			bcap->speech_ver[j++] = GSM48_BCAP_SV_AMR_F;
-		if (bcap->speech_ver[i] == GSM48_BCAP_SV_HR && bts->codec.hr)
-			bcap->speech_ver[j++] = GSM48_BCAP_SV_HR;
-		if (bcap->speech_ver[i] == GSM48_BCAP_SV_AMR_H && bts->codec.amr)
-			bcap->speech_ver[j++] = GSM48_BCAP_SV_AMR_H;
-	}
-	bcap->speech_ver[j] = -1;
-
-	return 0;
-}
 
 static uint32_t new_callref = 0x80000001;
 
@@ -126,27 +103,6 @@
 	 * work that the caller no longer has to do */
 	if (trans) {
 		gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
-		msg->lchan = trans->conn->lchan;
-	}
-
-	if (msg->lchan) {
-		struct e1inp_sign_link *sign_link =
-				msg->lchan->ts->trx->rsl_link;
-
-		msg->dst = sign_link;
-		if (gsm48_hdr_pdisc(gh) == GSM48_PDISC_CC)
-			DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
-				"Sending '%s' to MS.\n",
-				sign_link->trx->bts->nr,
-				sign_link->trx->nr, msg->lchan->ts->nr,
-				gh->proto_discr & 0xf0,
-				gsm48_cc_msg_name(gh->msg_type));
-		else
-			DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
-				"Sending 0x%02x to MS.\n",
-				sign_link->trx->bts->nr,
-				sign_link->trx->nr, msg->lchan->ts->nr,
-				gh->proto_discr, gh->msg_type);
 	}
 
 	return gsm0808_submit_dtap(conn, msg, 0, 0);
@@ -187,7 +143,6 @@
 /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
 int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause)
 {
-	struct gsm_bts *bts = conn->bts;
 	struct msgb *msg;
 
 	msg = gsm48_create_loc_upd_rej(cause);
@@ -196,11 +151,8 @@
 		return -1;
 	}
 
-	msg->lchan = conn->lchan;
-
-	LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
-	     "LAC=%u BTS=%u\n", vlr_subscr_name(conn->vsub),
-	     bts->location_area_code, bts->nr);
+	LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT\n",
+	     vlr_subscr_name(conn->vsub));
 
 	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
@@ -214,8 +166,6 @@
 	struct gsm48_loc_area_id *lai;
 	uint8_t *mid;
 
-	msg->lchan = conn->lchan;
-
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM;
 	gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
@@ -223,7 +173,7 @@
 	lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
 	gsm48_generate_lai(lai, conn->network->country_code,
 			   conn->network->network_code,
-			   conn->bts->location_area_code);
+			   conn->lac);
 
 	if (send_tmsi == GSM_RESERVED_TMSI) {
 		/* we did not allocate a TMSI to the MS, so we need to
@@ -257,8 +207,6 @@
 {
 	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
 	struct gsm48_hdr *gh;
-
-	msg->lchan = conn->lchan;
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 	gh->proto_discr = GSM48_PDISC_MM;
@@ -376,7 +324,7 @@
 			 &old_lai.plmn.mnc, &old_lai.lac);
 	new_lai.plmn.mcc = conn->network->country_code;
 	new_lai.plmn.mnc = conn->network->network_code;
-	new_lai.lac = conn->bts->location_area_code;
+	new_lai.lac = conn->lac;
 	DEBUGP(DMM, "LU/new-LAC: %u/%u\n", old_lai.lac, new_lai.lac);
 
 	lu_fsm = vlr_loc_update(conn->conn_fsm,
@@ -436,8 +384,6 @@
 	struct tm* local_time;
 	int tzunits;
 	int dst = 0;
-
-	msg->lchan = conn->lchan;
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM;
@@ -588,7 +534,6 @@
 	if (autn)
 		DEBUGP(DMM, "   AUTH REQ (autn = %s)\n", osmo_hexdump_nospc(autn, 16));
 
-	msg->lchan = conn->lchan;
 	gh->proto_discr = GSM48_PDISC_MM;
 	gh->msg_type = GSM48_MT_MM_AUTH_REQ;
 
@@ -663,7 +608,7 @@
  * b) Try to parse the TMSI. If we do not have one reject
  * c) Check that we know the subscriber with the TMSI otherwise reject
  *    with a HLR cause
- * d) Set the subscriber on the gsm_lchan and accept
+ * d) Set the subscriber on the conn and accept
  *
  * Keep this function non-static for direct invocation by unit tests.
  */
@@ -688,19 +633,19 @@
 
 	lai.plmn.mcc = conn->network->country_code;
 	lai.plmn.mnc = conn->network->network_code;
-	lai.lac = conn->bts->location_area_code;
+	lai.lac = conn->lac;
 
 	DEBUGP(DMM, "<- CM SERVICE REQUEST ");
 	if (msg->data_len < sizeof(struct gsm48_service_request*)) {
 		DEBUGPC(DMM, "wrong sized message\n");
-		return gsm48_tx_mm_serv_rej(conn,
-					    GSM48_REJECT_INCORRECT_MESSAGE);
+		return msc_gsm48_tx_mm_serv_rej(conn,
+						GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
 	if (msg->data_len < req->mi_len + 6) {
 		DEBUGPC(DMM, "does not fit in packet\n");
-		return gsm48_tx_mm_serv_rej(conn,
-					    GSM48_REJECT_INCORRECT_MESSAGE);
+		return msc_gsm48_tx_mm_serv_rej(conn,
+						GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
 	gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
@@ -716,8 +661,8 @@
 			mi_string);
 	} else {
 		DEBUGPC(DMM, "mi_type is not expected: %d\n", mi_type);
-		return gsm48_tx_mm_serv_rej(conn,
-					    GSM48_REJECT_INCORRECT_MESSAGE);
+		return msc_gsm48_tx_mm_serv_rej(conn,
+						GSM48_REJECT_INCORRECT_MESSAGE);
 	}
 
 	osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len));
@@ -739,9 +684,6 @@
 		/* logging already happened in msc_create_conn_fsm() */
 		return rc;
 	}
-
-	if (is_siemens_bts(conn->bts))
-		send_siemens_mrpci(msg->lchan, classmark2-1);
 
 	vlr_proc_acc_req(conn->conn_fsm,
 			 SUBSCR_CONN_E_ACCEPTED,
@@ -792,7 +734,6 @@
 		     gsm48_mi_type_name(mi_type), mi_string);
 		break;
 	}
-
 
 	/* TODO? We used to remember the subscriber's classmark1 here and
 	 * stored it in the old sqlite db, but now we store it in a conn that
@@ -1100,7 +1041,7 @@
 
 	lai.plmn.mcc = conn->network->country_code;
 	lai.plmn.mnc = conn->network->network_code;
-	lai.lac = conn->bts->location_area_code; /* (will be replaced by conn->lac soon) */
+	lai.lac = conn->lac;
 
 	resp = (struct gsm48_pag_resp *) &gh->data[0];
 	gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
@@ -1185,8 +1126,6 @@
 {
 	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 APP INF");
 	struct gsm48_hdr *gh;
-
-	msg->lchan = conn->lchan;
 
 	DEBUGP(DRR, "TX APPLICATION INFO id=0x%02x, len=%u\n",
 		apdu_id, apdu_len);
@@ -1279,8 +1218,6 @@
 	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 TX SIMPLE");
 	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 
-	msg->lchan = conn->lchan;
-
 	gh->proto_discr = pdisc;
 	gh->msg_type = msg_type;
 
@@ -1302,6 +1239,9 @@
 	struct msgb *msg;
 	unsigned char *data;
 
+#if BEFORE_MSCSPLIT
+	/* Re-enable this log output once we can obtain this information via
+	 * A-interface, see OS#2391. */
 	if (trans)
 		if (trans->conn && trans->conn->lchan)
 			DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
@@ -1319,6 +1259,9 @@
 	else
 		DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
 			"Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
+#else
+	DEBUGP(DCC, "Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
+#endif
 
 	mncc->msg_type = msg_type;
 
@@ -1362,8 +1305,6 @@
 	}
 	if (trans->cc.state != GSM_CSTATE_NULL)
 		new_cc_state(trans, GSM_CSTATE_NULL);
-	if (trans->conn)
-		trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
 }
 
 static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
@@ -1377,13 +1318,12 @@
 
 	OSMO_ASSERT(!transt->conn);
 
-	/* check all tranactions (without lchan) for subscriber */
 	switch (event) {
 	case GSM_PAGING_SUCCEEDED:
 		DEBUGP(DCC, "Paging subscr %s succeeded!\n",
 		       vlr_subscr_msisdn_or_name(transt->vsub));
 		OSMO_ASSERT(conn);
-		/* Assign lchan */
+		/* Assign conn */
 		transt->conn = conn;
 		/* send SETUP request to called party */
 		gsm48_cc_tx_setup(transt, &transt->cc.msg);
@@ -1410,235 +1350,6 @@
 	return 0;
 }
 
-static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable);
-
-/* handle audio path for handover */
-static int switch_for_handover(struct gsm_lchan *old_lchan,
-			struct gsm_lchan *new_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;
-	}
-
-	/* RTP Proxy mode */
-	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(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 (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;
-}
-
-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;
-	int rc;
-	struct gsm_network *net;
-	struct gsm_trans *trans;
-
-	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;
-
-	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;
-		llist_for_each_entry(trans, &net->trans_list, entry) {
-			if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) {
-				DEBUGP(DCC, "pending tch_recv_mncc request\n");
-				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.
-		 */
-		maybe_switch_for_handover(lchan);
-		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;
-	}
-
-	return 0;
-}
-
-/* map two ipaccess RTP streams onto each other */
-static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
-{
-	struct gsm_bts *bts = lchan->ts->trx->bts;
-	struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
-	enum gsm_chan_t lt = lchan->type, rt = remote_lchan->type;
-	enum gsm48_chan_mode lm = lchan->tch_mode, rm = remote_lchan->tch_mode;
-	int rc;
-
-	DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u,%s) and "
-	       "(bts=%u,trx=%u,ts=%u,%s)\n",
-	       bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
-	       get_value_string(gsm_chan_t_names, lt),
-	       remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr,
-	       get_value_string(gsm_chan_t_names, rt));
-
-	if (bts->type != remote_bts->type) {
-		LOGP(DCC, LOGL_ERROR, "Cannot switch calls between different BTS types yet\n");
-		return -EINVAL;
-	}
-
-	if (lt != rt) {
-		LOGP(DCC, LOGL_ERROR, "Cannot patch through call with different"
-		     " channel types: local = %s, remote = %s\n",
-		     get_value_string(gsm_chan_t_names, lt),
-		     get_value_string(gsm_chan_t_names, rt));
-		return -EBADSLT;
-	}
-
-	if (lm != rm) {
-		LOGP(DCC, LOGL_ERROR, "Cannot patch through call with different"
-		     " channel modes: local = %s, remote = %s\n",
-		     get_value_string(gsm48_chan_mode_names, lm),
-		     get_value_string(gsm48_chan_mode_names, rm));
-		return -EMEDIUMTYPE;
-	}
-
-	// todo: map between different bts types
-	switch (bts->type) {
-	case GSM_BTS_TYPE_NANOBTS:
-	case GSM_BTS_TYPE_OSMOBTS:
-		if (!ipacc_rtp_direct) {
-			if (!lchan->abis_ip.rtp_socket) {
-				LOGP(DHO, LOGL_ERROR, "no RTP socket for "
-					"lchan\n");
-				return -EIO;
-			}
-			if (!remote_lchan->abis_ip.rtp_socket) {
-				LOGP(DHO, LOGL_ERROR, "no RTP socket for "
-					"remote_lchan\n");
-				return -EIO;
-			}
-
-			/* connect the TCH's to our RTP proxy */
-			rc = rsl_ipacc_mdcx_to_rtpsock(lchan);
-			if (rc < 0)
-				return rc;
-			rc = rsl_ipacc_mdcx_to_rtpsock(remote_lchan);
-			if (rc < 0)
-				return rc;
-			/* connect them with each other */
-			rtp_socket_proxy(lchan->abis_ip.rtp_socket,
-					 remote_lchan->abis_ip.rtp_socket);
-		} else {
-			/* directly connect TCH RTP streams to each other */
-			rc = rsl_ipacc_mdcx(lchan, remote_lchan->abis_ip.bound_ip,
-						remote_lchan->abis_ip.bound_port,
-						remote_lchan->abis_ip.rtp_payload2);
-			if (rc < 0)
-				return rc;
-			rc = rsl_ipacc_mdcx(remote_lchan, lchan->abis_ip.bound_ip,
-						lchan->abis_ip.bound_port,
-						lchan->abis_ip.rtp_payload2);
-		}
-		break;
-	case GSM_BTS_TYPE_BS11:
-	case GSM_BTS_TYPE_RBS2000:
-	case GSM_BTS_TYPE_NOKIA_SITE:
-		trau_mux_map_lchan(lchan, remote_lchan);
-		break;
-	default:
-		LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 /* bridge channels of two transactions */
 static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge)
 {
@@ -1654,81 +1365,8 @@
 	/* Which subscriber do we want to track trans1 or trans2? */
 	log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub);
 
-	/* through-connect channel */
-	return tch_map(trans1->conn->lchan, trans2->conn->lchan);
-}
-
-/* enable receive of channels to MNCC upqueue */
-static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
-{
-	struct gsm_trans *trans;
-	struct gsm_lchan *lchan;
-	struct gsm_bts *bts;
-	int rc;
-
-	/* Find callref */
-	trans = trans_find_by_callref(net, callref);
-	if (!trans)
-		return -EIO;
-	if (!trans->conn)
-		return 0;
-
-	log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
-	lchan = trans->conn->lchan;
-	bts = lchan->ts->trx->bts;
-
-	/* store receive state */
-	trans->tch_recv = enable;
-
-	switch (bts->type) {
-	case GSM_BTS_TYPE_NANOBTS:
-	case GSM_BTS_TYPE_OSMOBTS:
-		if (ipacc_rtp_direct) {
-			LOGP(DCC, LOGL_ERROR, "Error: RTP proxy is disabled\n");
-			return -EINVAL;
-		}
-		/* In case, we don't have a RTP socket to the BTS yet, the BTS
-		 * will not be connected to our RTP proxy and the socket will
-		 * not be assigned to the application interface. This method
-		 * will be called again, once the audio socket is created and
-		 * connected. */
-		if (!lchan->abis_ip.rtp_socket) {
-			DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable);
-			return 0;
-		}
-		if (enable) {
-			/* connect the TCH's to our RTP proxy */
-			rc = rsl_ipacc_mdcx_to_rtpsock(lchan);
-			if (rc < 0)
-				return rc;
-			/* assign socket to application interface */
-			rtp_socket_upstream(lchan->abis_ip.rtp_socket,
-				net, callref);
-		} else
-			rtp_socket_upstream(lchan->abis_ip.rtp_socket,
-				net, 0);
-		break;
-	case GSM_BTS_TYPE_BS11:
-	case GSM_BTS_TYPE_RBS2000:
-	case GSM_BTS_TYPE_NOKIA_SITE:
-		/* In case we don't have a TCH with correct mode, the TRAU muxer
-		 * will not be asigned to the application interface. This is
-		 * performed by switch_trau_mux() after successful handover or
-		 * assignment. */
-		if (lchan->tch_mode == GSM48_CMODE_SIGN) {
-			DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable);
-			return 0;
-		}
-		if (enable)
-			return trau_recv_lchan(lchan, callref);
-		return trau_mux_unmap(NULL, callref);
-		break;
-	default:
-		LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
-		return -EINVAL;
-	}
-
-	return 0;
+	/* future: msc_call_bridge(trans1, trans2); */
+	return -1;
 }
 
 static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
@@ -1868,7 +1506,7 @@
 
 	memset(&setup, 0, sizeof(struct gsm_mncc));
 	setup.callref = trans->callref;
-	setup.lchan_type = trans->conn->lchan->type;
+
 	tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
 	/* emergency setup is identified by msg_type */
 	if (msg_type == GSM48_MT_CC_EMERG_SETUP)
@@ -1884,7 +1522,6 @@
 		setup.fields |= MNCC_F_BEARER_CAP;
 		gsm48_decode_bearer_cap(&setup.bearer_cap,
 				  TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
-		apply_codec_restrictions(trans->conn->bts, &setup.bearer_cap);
 	}
 	/* facility */
 	if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
@@ -2024,7 +1661,7 @@
 
 	memset(&call_conf, 0, sizeof(struct gsm_mncc));
 	call_conf.callref = trans->callref;
-	call_conf.lchan_type = trans->conn->lchan->type;
+
 	tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
 #if 0
 	/* repeat */
@@ -2038,7 +1675,6 @@
 		call_conf.fields |= MNCC_F_BEARER_CAP;
 		gsm48_decode_bearer_cap(&call_conf.bearer_cap,
 				  TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
-		apply_codec_restrictions(trans->conn->bts, &call_conf.bearer_cap);
 	}
 	/* cause */
 	if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
@@ -2728,7 +2364,6 @@
 		modify.fields |= MNCC_F_BEARER_CAP;
 		gsm48_decode_bearer_cap(&modify.bearer_cap,
 				  TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
-		apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap);
 	}
 
 	new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
@@ -2771,7 +2406,6 @@
 		modify.fields |= MNCC_F_BEARER_CAP;
 		gsm48_decode_bearer_cap(&modify.bearer_cap,
 				  TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
-		apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap);
 	}
 
 	new_cc_state(trans, GSM_CSTATE_ACTIVE);
@@ -2812,7 +2446,6 @@
 		modify.fields |= GSM48_IE_BEARER_CAP;
 		gsm48_decode_bearer_cap(&modify.bearer_cap,
 				  TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
-		apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap);
 	}
 	/* cause */
 	if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
@@ -2915,229 +2548,6 @@
 	return mncc_recvmsg(trans->net, trans, MNCC_USERINFO_IND, &user);
 }
 
-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;
-	enum gsm48_chan_mode m;
-
-	/* 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(LOG_CTX_VLR_SUBSCR, trans->vsub);
-	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 routine above.
-	 * Fallback to the internal MNCC mode to select a route.
-	 */
-	if (lchan->tch_mode == GSM48_CMODE_SIGN) {
-		trans->conn->mncc_rtp_create_pending = 1;
-		m = mncc_codec_for_mode(lchan->type);
-		LOGP(DMNCC, LOGL_DEBUG, "RTP create: codec=%s, chan_type=%s\n",
-		     get_value_string(gsm48_chan_mode_names, m),
-		     get_value_string(gsm_chan_t_names, lchan->type));
-		return gsm0808_assign_req(trans->conn, m,
-				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(LOG_CTX_VLR_SUBSCR, trans->vsub);
-	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;
-	LOGP(DMNCC, LOGL_DEBUG, "RTP connect: codec=%s, chan_type=%s\n",
-		     get_value_string(gsm48_chan_mode_names,
-				      mncc_codec_for_mode(lchan->type)),
-		     get_value_string(gsm_chan_t_names, lchan->type));
-
-	/* 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;
@@ -3191,9 +2601,6 @@
 	 MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
 	{ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* 5.4.3.2 */
 	 MNCC_REL_REQ, gsm48_cc_tx_release},
-	/* special */
-	{ALL_STATES,
-	 MNCC_LCHAN_MODIFY, _gsm48_lchan_modify},
 };
 
 #define DOWNSLLEN \
@@ -3205,7 +2612,6 @@
 	int i, rc = 0;
 	struct gsm_trans *trans = NULL, *transt;
 	struct gsm_subscriber_connection *conn = NULL;
-	struct gsm_bts *bts = NULL;
 	struct gsm_mncc *data = arg, rel;
 
 	DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type));
@@ -3218,60 +2624,17 @@
 			disconnect_bridge(net, arg, -rc);
 		return rc;
 	case MNCC_FRAME_DROP:
-		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:
 	case GSM_TCH_FRAME_AMR:
-		/* Find callref */
-		trans = trans_find_by_callref(net, data->callref);
-		if (!trans) {
-			LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
-			return -EIO;
-		}
-		log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
-		if (!trans->conn) {
-			LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
-			return 0;
-		}
-		if (!trans->conn->lchan) {
-			LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without lchan\n");
-			return 0;
-		}
-		if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
-		 && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
-			/* This should be LOGL_ERROR or NOTICE, but
-			 * unfortuantely it happens for a couple of frames at
-			 * the beginning of every RTP connection */
-			LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
-			return 0;
-		}
-		bts = trans->conn->lchan->ts->trx->bts;
-		switch (bts->type) {
-		case GSM_BTS_TYPE_NANOBTS:
-		case GSM_BTS_TYPE_OSMOBTS:
-			if (!trans->conn->lchan->abis_ip.rtp_socket) {
-				DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
-				return 0;
-			}
-			return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
-		case GSM_BTS_TYPE_BS11:
-		case GSM_BTS_TYPE_RBS2000:
-		case GSM_BTS_TYPE_NOKIA_SITE:
-			return trau_send_frame(trans->conn->lchan, arg);
-		default:
-			LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
-		}
-		return -EINVAL;
+		LOGP(DMNCC, LOGL_ERROR, "RTP streams must be handled externally; %s not supported.\n",
+		     get_mncc_name(msg_type));
+		return -ENOTSUP;
 	}
 
 	memset(&rel, 0, sizeof(struct gsm_mncc));
@@ -3347,14 +2710,15 @@
 					 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
 			return -ENOMEM;
 		}
-		/* Find lchan */
+
+		/* Find conn */
 		conn = connection_for_subscr(vsub);
 
-		/* If subscriber has no lchan */
+		/* If subscriber has no conn */
 		if (!conn) {
 			/* find transaction with this subscriber already paging */
 			llist_for_each_entry(transt, &net->trans_list, entry) {
-				/* Transaction of our lchan? */
+				/* Transaction of our conn? */
 				if (transt == trans ||
 				    transt->vsub != vsub)
 					continue;
@@ -3372,7 +2736,7 @@
 			memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
 
 			/* Request a channel */
-			trans->paging_request = subscr_request_channel(
+			trans->paging_request = subscr_request_conn(
 							vsub,
 							RSL_CHANNEED_TCH_F,
 							setup_trig_pag_evt,
@@ -3386,7 +2750,8 @@
 			vlr_subscr_put(vsub);
 			return 0;
 		}
-		/* Assign lchan */
+
+		/* Assign conn */
 		trans->conn = msc_subscr_conn_get(conn);
 		vlr_subscr_put(vsub);
 	} else {
@@ -3399,7 +2764,7 @@
 
 	/* if paging did not respond yet */
 	if (!conn) {
-		DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
+		DEBUGP(DCC, "(sub %s) "
 			"Received '%s' from MNCC in paging state\n",
 			vlr_subscr_msisdn_or_name(trans->vsub),
 			get_mncc_name(msg_type));
@@ -3414,9 +2779,8 @@
 		return rc;
 	}
 
-	DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
+	DEBUGP(DCC, "(ti %02x sub %s) "
 		"Received '%s' from MNCC in state %d (%s)\n",
-		conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr,
 		trans->transaction_id,
 		vlr_subscr_msisdn_or_name(trans->conn->vsub),
 		get_mncc_name(msg_type), trans->cc.state,
@@ -3513,12 +2877,16 @@
 	/* Find transaction */
 	trans = trans_find_by_id(conn, GSM48_PDISC_CC, transaction_id);
 
+#if BEFORE_MSCSPLIT
+	/* Re-enable this log output once we can obtain this information via
+	 * A-interface, see OS#2391. */
 	DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
 		"Received '%s' from MS in state %d (%s)\n",
 		conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr,
 		transaction_id, vlr_subscr_msisdn_or_name(conn->vsub),
 		gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0,
 		gsm48_cc_state_name(trans?(trans->cc.state):0));
+#endif
 
 	/* Create transaction */
 	if (!trans) {
@@ -3836,11 +3204,18 @@
 			 net->gsup_server_port);
 }
 
-/*
- * This will be run by the linker when loading the DSO. We use it to
- * do system initialization, e.g. registration of signal handlers.
- */
-static __attribute__((constructor)) void on_dso_load_0408(void)
+/* This is a temporary shim merely to ensure that the unit tests still work. It
+ * shall be removed as soon as Iu and A interface paging is implemented. */
+int msc_fake_paging_request(struct vlr_subscr *vsub)
 {
-	osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, NULL);
+	LOGP(DMM, LOGL_ERROR, "Paging currently not implemented in the MSC.\n");
+	OSMO_ASSERT(false);
+}
+
+/* This is a temporary shim merely to ensure that the unit tests still work. It
+ * shall be removed as soon as Iu and A interface paging is implemented. */
+void msc_fake_paging_request_stop(struct vlr_subscr *vsub)
+{
+	LOGP(DMM, LOGL_ERROR, "Paging currently not implemented in the MSC.\n");
+	OSMO_ASSERT(false);
 }
diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c
index 6ad944b..3255a3b 100644
--- a/src/libmsc/gsm_04_11.c
+++ b/src/libmsc/gsm_04_11.c
@@ -878,7 +878,7 @@
 }
 
 /* Take a SMS in gsm_sms structure and send it through an already
- * existing lchan. We also assume that the caller ensured this lchan already
+ * existing conn. We also assume that the caller ensured this conn already
  * has a SAPI3 RLL connection! */
 int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
 {
@@ -1004,7 +1004,7 @@
 	struct gsm_subscriber_connection *conn;
 	void *res;
 
-	/* check if we already have an open lchan to the subscriber.
+	/* check if we already have an open conn to the subscriber.
 	 * if yes, send the SMS this way */
 	conn = connection_for_subscr(vsub);
 	if (conn) {
@@ -1016,8 +1016,8 @@
 	/* if not, we have to start paging */
 	LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n",
 	     vlr_subscr_name(vsub));
-	res = subscr_request_channel(vsub, RSL_CHANNEED_SDCCH,
-				     paging_cb_send_sms, sms);
+	res = subscr_request_conn(vsub, RSL_CHANNEED_SDCCH, paging_cb_send_sms,
+				  sms);
 	if (!res) {
 		send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
 		sms_free(sms);
diff --git a/src/libmsc/gsm_subscriber.c b/src/libmsc/gsm_subscriber.c
index e9b2e0e..69d79b0 100644
--- a/src/libmsc/gsm_subscriber.c
+++ b/src/libmsc/gsm_subscriber.c
@@ -41,43 +41,6 @@
 #include <openbsc/chan_alloc.h>
 #include <openbsc/vlr.h>
 
-void *tall_sub_req_ctx;
-
-int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
-                         gsm_cbfn *cb, void *cb_data);
-
-
-/*
- * Struct for pending channel requests. This is managed in the
- * llist_head requests of each subscriber. The reference counting
- * should work in such a way that a subscriber with a pending request
- * remains in memory.
- */
-struct subscr_request {
-	struct llist_head entry;
-
-	/* the callback data */
-	gsm_cbfn *cbfn;
-	void *param;
-};
-
-static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribers,
-						struct vlr_subscr *vsub)
-{
-	struct bsc_subscr *sub;
-	/* TODO MSC split -- creating a BSC subscriber directly from MSC data
-	 * structures in RAM. At some point the MSC will send a message to the
-	 * BSC instead. */
-	sub = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, vsub->imsi);
-	sub->tmsi = vsub->tmsi;
-	sub->lac = vsub->lac;
-	return sub;
-}
-
-/*
- * We got the channel assigned and can now hand this channel
- * over to one of our callbacks.
- */
 int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
 			   struct msgb *msg, void *data, void *param)
 {
@@ -85,22 +48,12 @@
 	struct gsm_subscriber_connection *conn = data;
 	struct vlr_subscr *vsub = param;
 	struct paging_signal_data sig_data;
-	struct bsc_subscr *bsub;
-	struct gsm_network *net;
 
 	OSMO_ASSERT(vsub && vsub->cs.is_paging);
-	net = vsub->vlr->user_ctx;
 
-	/*
-	 * 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.
-	 */
-
-	bsub = vlr_subscr_to_bsc_sub(conn->network->bsc_subscribers, vsub);
-	paging_request_stop(&net->bts_list, NULL, bsub, NULL, NULL);
-	bsc_subscr_put(bsub);
+	/* FIXME: implement stop paging in libmsc;
+	 * faking it for the unit tests to still work */
+	msc_fake_paging_request_stop(vsub);
 
 	/* Inform parts of the system we don't know */
 	sig_data.vsub	= vsub;
@@ -126,22 +79,21 @@
 	return 0;
 }
 
-struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub,
-					      int channel_type,
-					      gsm_cbfn *cbfn, void *param)
+struct subscr_request *subscr_request_conn(struct vlr_subscr *vsub, int channel_type, gsm_cbfn *cbfn,
+					   void *param)
 {
 	int rc;
 	struct subscr_request *request;
-	struct bsc_subscr *bsub;
-	struct gsm_network *net = vsub->vlr->user_ctx;
 
 	/* Start paging.. we know it is async so we can do it before */
 	if (!vsub->cs.is_paging) {
 		LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
 		     vlr_subscr_name(vsub));
-		bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub);
-		rc = paging_request(net, bsub, channel_type, NULL, NULL);
-		bsc_subscr_put(bsub);
+
+		/* FIXME: implement paging in libmsc;
+		 * faking it for the unit tests to still work */
+		rc = msc_fake_paging_request(vsub);
+
 		if (rc <= 0) {
 			LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
 			     vlr_subscr_name(vsub), rc);
diff --git a/src/libmsc/mncc_builtin.c b/src/libmsc/mncc_builtin.c
index 067cc92..ac6e734 100644
--- a/src/libmsc/mncc_builtin.c
+++ b/src/libmsc/mncc_builtin.c
@@ -65,21 +65,6 @@
 	return NULL;
 }
 
-uint8_t mncc_codec_for_mode(int lchan_type)
-{
-	/* FIXME: check codec capabilities of the phone */
-
-	if (lchan_type != GSM_LCHAN_TCH_H)
-		return mncc_int.def_codec[0];
-	else
-		return mncc_int.def_codec[1];
-}
-
-static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
-{
-	return mncc_codec_for_mode(setup->lchan_type);
-}
-
 /* on incoming call, look up database and send setup to remote subscr. */
 static int mncc_setup_ind(struct gsm_call *call, int msg_type,
 			  struct gsm_mncc *setup)
@@ -137,9 +122,7 @@
 	/* modify mode */
 	memset(&mncc, 0, sizeof(struct gsm_mncc));
 	mncc.callref = call->callref;
-	mncc.lchan_mode = determine_lchan_mode(setup);
-	DEBUGP(DMNCC, "(call %x) Modify channel mode: %s\n", call->callref,
-	       get_value_string(gsm48_chan_mode_names, mncc.lchan_mode));
+	DEBUGP(DMNCC, "(call %x) Modify channel mode\n", call->callref);
 	mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
 
 	/* send setup to remote */
@@ -206,10 +189,6 @@
 	bridge.callref[0] = call->callref;
 	bridge.callref[1] = call->remote_ref;
 	DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
-
-	/* in direct mode, we always have to bridge the channels */
-	if (ipacc_rtp_direct)
-		return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
 
 	/* proxy mode */
 	if (!net->handover.active) {
@@ -279,28 +258,6 @@
 	return 0;
 }
 
-/* receiving a (speech) traffic frame from the BSC code */
-static int mncc_rcv_data(struct gsm_call *call, int msg_type,
-			 struct gsm_data_frame *dfr)
-{
-	struct gsm_trans *remote_trans;
-
-	remote_trans = trans_find_by_callref(call->net, call->remote_ref);
-
-	/* this shouldn't really happen */
-	if (!remote_trans || !remote_trans->conn) {
-		LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
-		return -EIO;
-	}
-
-	/* RTP socket of remote end has meanwhile died */
-	if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
-		return -EIO;
-
-	return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
-}
-
-
 /* Internal MNCC handler input function (from CC -> MNCC -> here) */
 int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
 {
@@ -346,7 +303,8 @@
 	}
 
 	if (mncc_is_data_frame(msg_type)) {
-		rc = mncc_rcv_data(call, msg_type, arg);
+		LOGP(DMNCC, LOGL_ERROR, "(call %x) Received data frame, which is not supported.\n",
+		     call->callref);
 		goto out_free;
 	}
 
@@ -364,7 +322,6 @@
 		break;
 	case MNCC_CALL_CONF_IND:
 		/* we now need to MODIFY the channel */
-		data->lchan_mode = determine_lchan_mode(data);
 		mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
 		break;
 	case MNCC_ALERT_IND:
diff --git a/src/libmsc/mncc_sock.c b/src/libmsc/mncc_sock.c
index 0efe3a1..0c696f2 100644
--- a/src/libmsc/mncc_sock.c
+++ b/src/libmsc/mncc_sock.c
@@ -224,7 +224,6 @@
 	hello->called_offset = offsetof(struct gsm_mncc, called);
 	hello->signal_offset = offsetof(struct gsm_mncc, signal);
 	hello->emergency_offset = offsetof(struct gsm_mncc, emergency);
-	hello->lchan_type_offset = offsetof(struct gsm_mncc, lchan_type);
 
 	msgb_enqueue(&mncc->net->upqueue, msg);
 	mncc->conn_bfd.when |= BSC_FD_WRITE;
diff --git a/src/libmsc/msc_ifaces.c b/src/libmsc/msc_ifaces.c
new file mode 100644
index 0000000..001fcba
--- /dev/null
+++ b/src/libmsc/msc_ifaces.c
@@ -0,0 +1,84 @@
+/* Implementation for MSC decisions which interface to send messages out on. */
+
+/* (C) 2016 by sysmocom s.m.f.c GmbH <info at sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <osmocom/core/logging.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/msc_ifaces.h>
+
+static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+	switch (conn->via_ran) {
+	/* FUTURE 
+	case RAN_GERAN_A:
+		msg->dst = conn;
+		return a_tx(msg);
+
+	case RAN_UTRAN_IU:
+		msg->dst = conn->iu.ue_ctx;
+		return iu_tx(msg, 0);
+	*/
+	default:
+		LOGP(DMSC, LOGL_ERROR,
+		     "msc_tx(): conn->via_ran invalid (%d)\n",
+		     conn->via_ran);
+		return -1;
+	}
+}
+
+
+int msc_tx_dtap(struct gsm_subscriber_connection *conn,
+		struct msgb *msg)
+{
+	return msc_tx(conn, msg);
+}
+
+
+/* 9.2.5 CM service accept */
+int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
+{
+	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+
+	gh->proto_discr = GSM48_PDISC_MM;
+	gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
+
+	DEBUGP(DMM, "-> CM SERVICE ACCEPT\n");
+
+	return msc_tx_dtap(conn, msg);
+}
+
+/* 9.2.6 CM service reject */
+int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
+			     enum gsm48_reject_value value)
+{
+	struct msgb *msg;
+
+	msg = gsm48_create_mm_serv_rej(value);
+	if (!msg) {
+		LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n");
+		return -1;
+	}
+
+	DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
+
+	return msc_tx_dtap(conn, msg);
+}
diff --git a/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c
index 95e5818..c847b78 100644
--- a/src/libmsc/osmo_msc.c
+++ b/src/libmsc/osmo_msc.c
@@ -21,6 +21,7 @@
  *
  */
 
+#include <openbsc/osmo_msc.h>
 #include <openbsc/bsc_api.h>
 #include <openbsc/debug.h>
 #include <openbsc/transaction.h>
@@ -69,9 +70,10 @@
 	osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, NULL);
 }
 
-/* Receive a COMPLETE LAYER3 INFO from BSC */
-static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
-			uint16_t chosen_channel)
+/* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or
+ * MSC_CONN_REJECT */
+static int msc_compl_l3(struct gsm_subscriber_connection *conn,
+			struct msgb *msg, uint16_t chosen_channel)
 {
 	/* Ownership of the gsm_subscriber_connection is still a bit mucky
 	 * between libbsc and libmsc. In libmsc, we use ref counting, but not
@@ -87,7 +89,7 @@
 		/* keep the use_count reserved, libbsc will discard. If we
 		 * released the ref count and discarded here, libbsc would
 		 * double-free. And we will not change bsc_api semantics. */
-		return BSC_API_CONN_POL_REJECT;
+		return MSC_CONN_REJECT;
 	}
 	DEBUGP(DMM, "compl_l3: Keeping conn\n");
 
@@ -96,7 +98,7 @@
 
 	/* If this should be kept, the conn->conn_fsm has placed a use_count */
 	msc_subscr_conn_put(conn);
-	return BSC_API_CONN_POL_ACCEPT;
+	return MSC_CONN_ACCEPT;
 
 #if 0
 	/*
@@ -105,14 +107,14 @@
 	 * pending transaction or ongoing operation.
 	 */
 	if (conn->silent_call)
-		return BSC_API_CONN_POL_ACCEPT;
-	if (conn->sec_operation || conn->anch_operation)
-		return BSC_API_CONN_POL_ACCEPT;
+		return MSC_CONN_ACCEPT;
+	if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
+		return MSC_CONN_ACCEPT;
 	if (trans_has_conn(conn))
-		return BSC_API_CONN_POL_ACCEPT;
+		return MSC_CONN_ACCEPT;
 
 	LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
-	return BSC_API_CONN_POL_REJECT;
+	return MSC_CONN_REJECT;
 #endif
 }
 
diff --git a/src/libmsc/silent_call.c b/src/libmsc/silent_call.c
index 6f3fbf2..5fad4f4 100644
--- a/src/libmsc/silent_call.c
+++ b/src/libmsc/silent_call.c
@@ -52,8 +52,12 @@
 
 	switch (event) {
 	case GSM_PAGING_SUCCEEDED:
+#if BEFORE_MSCSPLIT
+		/* Re-enable this log output once we can obtain this information via
+		 * A-interface, see OS#2391. */
 		DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
 			conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
+#endif
 		conn->silent_call = 1;
 		msc_subscr_conn_get(conn);
 		/* increment lchan reference count */
@@ -126,7 +130,10 @@
 {
 	struct subscr_request *req;
 
-	req = subscr_request_channel(vsub, type, paging_cb_silent, data);
+	/* FIXME the VTY command allows selecting a silent call channel type.
+	 * This doesn't apply to the situation after MSCSPLIT with an
+	 * A-interface. */
+	req = subscr_request_conn(vsub, type, paging_cb_silent, data);
 	return req != NULL;
 }
 
@@ -143,8 +150,12 @@
 	if (!conn->silent_call)
 		return -EINVAL;
 
+#if BEFORE_MSCSPLIT
+	/* Re-enable this log output once we can obtain this information via
+	 * A-interface, see OS#2391. */
 	DEBUGPC(DLSMS, "Stopping silent call using Timeslot %u on ARFCN %u\n",
 		conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
+#endif
 
 	conn->silent_call = 0;
 	msc_subscr_conn_put(conn);
diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c
index f06eb7d..24a4653 100644
--- a/src/libmsc/smpp_openbsc.c
+++ b/src/libmsc/smpp_openbsc.c
@@ -423,6 +423,8 @@
 	build_tlv(req_tlv, &tlv);
 }
 
+#if BEFORE_MSCSPLIT
+/* We currently have no lchan information. Re-add after A-interface, see OS#2390. */
 /* Append the Osmocom vendor-specific additional TLVs to a SMPP msg */
 static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
 {
@@ -461,6 +463,7 @@
 				   (uint8_t *)vsub->imei, imei_len+1);
 	}
 }
+#endif
 
 struct {
 	uint32_t smpp_status_code;
@@ -680,8 +683,11 @@
 		memcpy(deliver.short_message, sms->user_data, deliver.sm_length);
 	}
 
+#if BEFORE_MSCSPLIT
+	/* We currently have no lchan information. Re-add after A-interface, see OS#2390. */
 	if (esme->acl && esme->acl->osmocom_ext && conn->lchan)
 		append_osmo_tlvs(&deliver.tlv, conn->lchan);
+#endif
 
 	ret = smpp_tx_deliver(esme, &deliver);
 	if (ret < 0)
diff --git a/src/libmsc/vty_interface_layer3.c b/src/libmsc/vty_interface_layer3.c
index c393a8f..0106f91 100644
--- a/src/libmsc/vty_interface_layer3.c
+++ b/src/libmsc/vty_interface_layer3.c
@@ -553,57 +553,6 @@
 	return CMD_WARNING;
 }
 
-DEFUN(ena_subscr_handover,
-      ena_subscr_handover_cmd,
-      "subscriber " SUBSCR_TYPES " ID handover BTS_NR",
-	SUBSCR_HELP "Handover the active connection\n"
-	"Number of the BTS to handover to\n")
-{
-	int ret;
-	struct gsm_subscriber_connection *conn;
-	struct gsm_bts *bts;
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	struct vlr_subscr *vsub =
-			get_vsub_by_argv(gsmnet, argv[0], argv[1]);
-
-	if (!vsub) {
-		vty_out(vty, "%% No subscriber found for %s %s.%s",
-			argv[0], argv[1], VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	conn = connection_for_subscr(vsub);
-	if (!conn) {
-		vty_out(vty, "%% No active connection for subscriber %s %s.%s",
-			argv[0], argv[1], VTY_NEWLINE);
-		vlr_subscr_put(vsub);
-		return CMD_WARNING;
-	}
-
-	bts = gsm_bts_num(gsmnet, atoi(argv[2]));
-	if (!bts) {
-		vty_out(vty, "%% BTS with number(%d) could not be found.%s",
-			atoi(argv[2]), VTY_NEWLINE);
-		vlr_subscr_put(vsub);
-		return CMD_WARNING;
-	}
-
-	/* now start the handover */
-	ret = bsc_handover_start(conn->lchan, bts);
-	if (ret != 0) {
-		vty_out(vty, "%% Handover failed with errno %d.%s",
-			ret, VTY_NEWLINE);
-	} else {
-		vty_out(vty, "%% Handover started from %s",
-			gsm_lchan_name(conn->lchan));
-		vty_out(vty, " to %s.%s", gsm_lchan_name(conn->ho_lchan),
-			VTY_NEWLINE);
-	}
-
-	vlr_subscr_put(vsub);
-	return CMD_SUCCESS;
-}
-
 #define A3A8_ALG_TYPES "(none|xor|comp128v1)"
 #define A3A8_ALG_HELP 			\
 	"Use No A3A8 algorithm\n"	\
@@ -652,9 +601,7 @@
 
 	switch (signal) {
 	case S_SCALL_SUCCESS:
-		vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s",
-			sigdata->conn->lchan->ts->trx->arfcn, sigdata->conn->lchan->ts->nr,
-			VTY_NEWLINE);
+		vty_out(vty, "%% silent call success%s", VTY_NEWLINE);
 		break;
 	case S_SCALL_EXPIRED:
 		vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE);
@@ -670,7 +617,6 @@
 {
 	struct gsm_network *net = gsmnet_from_vty(vty);
 
-	openbsc_vty_print_statistics(vty, net);
 	vty_out(vty, "Location Update         : %lu attach, %lu normal, %lu periodic%s",
 		net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current,
 		net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current,
@@ -1055,7 +1001,6 @@
 	install_element(ENABLE_NODE, &ena_subscr_extension_cmd);
 	install_element(ENABLE_NODE, &ena_subscr_authorized_cmd);
 	install_element(ENABLE_NODE, &ena_subscr_a3a8_cmd);
-	install_element(ENABLE_NODE, &ena_subscr_handover_cmd);
 	install_element(ENABLE_NODE, &subscriber_purge_cmd);
 	install_element(ENABLE_NODE, &smsqueue_trigger_cmd);
 	install_element(ENABLE_NODE, &smsqueue_max_cmd);
diff --git a/tests/bsc/Makefile.am b/tests/bsc/Makefile.am
index 9de4145..904bdfc 100644
--- a/tests/bsc/Makefile.am
+++ b/tests/bsc/Makefile.am
@@ -32,7 +32,6 @@
 
 bsc_test_LDADD = \
 	$(top_builddir)/src/libbsc/libbsc.a \
-	$(top_builddir)/src/libmsc/libmsc.a \
 	$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
 	$(top_builddir)/src/libmgcp/libmgcp.a \
 	$(top_builddir)/src/libtrau/libtrau.a \
diff --git a/tests/channel/Makefile.am b/tests/channel/Makefile.am
index c7164b4..dd78bdc 100644
--- a/tests/channel/Makefile.am
+++ b/tests/channel/Makefile.am
@@ -24,7 +24,6 @@
 	$(NULL)
 
 channel_test_LDADD = \
-	$(top_builddir)/src/libmsc/libmsc.a \
 	$(top_builddir)/src/libbsc/libbsc.a \
 	$(top_builddir)/src/libvlr/libvlr.a \
 	$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
diff --git a/tests/db/Makefile.am b/tests/db/Makefile.am
index 0eed5cd..df421d8 100644
--- a/tests/db/Makefile.am
+++ b/tests/db/Makefile.am
@@ -32,9 +32,7 @@
 	$(NULL)
 
 db_test_LDADD = \
-	$(top_builddir)/src/libbsc/libbsc.a \
 	$(top_builddir)/src/libmsc/libmsc.a \
-	$(top_builddir)/src/libbsc/libbsc.a \
 	$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
 	$(top_builddir)/src/libtrau/libtrau.a \
 	$(top_builddir)/src/libcommon/libcommon.a \
diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c
index 5a8c6ca..1b326ee 100644
--- a/tests/gsm0408/gsm0408_test.c
+++ b/tests/gsm0408/gsm0408_test.c
@@ -182,7 +182,7 @@
 static inline void test_si2q_u(void)
 {
 	struct gsm_bts *bts;
-	struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+	struct gsm_network *network = bsc_network_init(NULL, 1, 1, NULL);
 	printf("Testing SYSINFO_TYPE_2quater UARFCN generation:\n");
 
 	if (!network)
@@ -210,7 +210,7 @@
 static inline void test_si2q_e(void)
 {
 	struct gsm_bts *bts;
-	struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+	struct gsm_network *network = bsc_network_init(NULL, 1, 1, NULL);
 	printf("Testing SYSINFO_TYPE_2quater EARFCN generation:\n");
 
 	if (!network)
diff --git a/tests/msc_vlr/Makefile.am b/tests/msc_vlr/Makefile.am
index ebbfb5c..71450af 100644
--- a/tests/msc_vlr/Makefile.am
+++ b/tests/msc_vlr/Makefile.am
@@ -60,8 +60,8 @@
 	-Wl,--wrap=gsup_client_create \
 	-Wl,--wrap=gsup_client_send \
 	-Wl,--wrap=gsm0808_submit_dtap \
-	-Wl,--wrap=paging_request \
-	-Wl,--wrap=paging_request_stop \
+	-Wl,--wrap=msc_fake_paging_request \
+	-Wl,--wrap=msc_fake_paging_request_stop \
 	-Wl,--wrap=gsm340_gen_scts \
 	-Wl,--wrap=RAND_bytes \
 	$(NULL)
diff --git a/tests/msc_vlr/msc_vlr_test_gsm_authen.err b/tests/msc_vlr/msc_vlr_test_gsm_authen.err
index 09ff4ae..4ae4968 100644
--- a/tests/msc_vlr/msc_vlr_test_gsm_authen.err
+++ b/tests/msc_vlr/msc_vlr_test_gsm_authen.err
@@ -270,9 +270,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:46071
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -351,7 +350,6 @@
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 5
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -734,9 +732,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
+  BTS/BSC sends out paging request to MSISDN:46071
   paging_expecting_tmsi == 0x03020100
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -815,7 +812,6 @@
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 5
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -1762,9 +1758,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:42342 usage increases to: 3
 DMM Subscriber MSISDN:42342 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000010650 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000010650 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:42342
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:42342 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:42342 usage decreases to: 3
@@ -1843,7 +1838,6 @@
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000010650 usage decreases to: 0
 DREF VLR subscr MSISDN:42342 usage increases to: 5
 DREF MSISDN:42342: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005802443f2000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
diff --git a/tests/msc_vlr/msc_vlr_test_gsm_ciph.err b/tests/msc_vlr/msc_vlr_test_gsm_ciph.err
index f43d6f1..1a9c39f 100644
--- a/tests/msc_vlr/msc_vlr_test_gsm_ciph.err
+++ b/tests/msc_vlr/msc_vlr_test_gsm_ciph.err
@@ -287,9 +287,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:46071
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -387,7 +386,6 @@
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 5
 DREF MSISDN:46071: MSC conn use + 1 == 2
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -786,9 +784,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
+  BTS/BSC sends out paging request to MSISDN:46071
   paging_expecting_tmsi == 0x03020100
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -886,7 +883,6 @@
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 5
 DREF MSISDN:46071: MSC conn use + 1 == 2
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
diff --git a/tests/msc_vlr/msc_vlr_test_no_authen.err b/tests/msc_vlr/msc_vlr_test_no_authen.err
index 651ac29..ec1c4e2 100644
--- a/tests/msc_vlr/msc_vlr_test_no_authen.err
+++ b/tests/msc_vlr/msc_vlr_test_no_authen.err
@@ -186,9 +186,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:46071
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -227,7 +226,6 @@
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 6
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -528,9 +526,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
+  BTS/BSC sends out paging request to MSISDN:46071
   paging_expecting_tmsi == 0x03020100
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -569,7 +566,6 @@
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(50462976){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 6
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
diff --git a/tests/msc_vlr/msc_vlr_test_reject_concurrency.err b/tests/msc_vlr/msc_vlr_test_reject_concurrency.err
index c51d08a..bebb16b 100644
--- a/tests/msc_vlr/msc_vlr_test_reject_concurrency.err
+++ b/tests/msc_vlr/msc_vlr_test_reject_concurrency.err
@@ -1188,9 +1188,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:46071
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -1225,7 +1224,6 @@
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 6
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -1403,9 +1401,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:46071
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -1440,7 +1437,6 @@
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 6
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -1635,9 +1631,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 3
 DMM Subscriber MSISDN:46071 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000004620 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:46071
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:46071 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:46071 usage decreases to: 3
@@ -1672,7 +1667,6 @@
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000004620){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000004620 usage decreases to: 0
 DREF VLR subscr MSISDN:46071 usage increases to: 6
 DREF MSISDN:46071: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005806470f1000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
diff --git a/tests/msc_vlr/msc_vlr_test_umts_authen.err b/tests/msc_vlr/msc_vlr_test_umts_authen.err
index bfb4a8e..744004a 100644
--- a/tests/msc_vlr/msc_vlr_test_umts_authen.err
+++ b/tests/msc_vlr/msc_vlr_test_umts_authen.err
@@ -253,9 +253,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:42342 usage increases to: 3
 DMM Subscriber MSISDN:42342 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000010650 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000010650 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:42342
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:42342 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:42342 usage decreases to: 3
@@ -335,7 +334,6 @@
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000010650 usage decreases to: 0
 DREF VLR subscr MSISDN:42342 usage increases to: 5
 DREF MSISDN:42342: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005802443f2000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
@@ -665,9 +663,8 @@
   llist_count(&vsub->cs.requests) == 0
 DREF VLR subscr MSISDN:42342 usage increases to: 3
 DMM Subscriber MSISDN:42342 not paged yet.
-  BTS/BSC sends out paging request to IMSI:901700000010650 for channel type 1
-  strcmp(paging_expecting_imsi, sub->imsi) == 0
-DREF BSC subscr IMSI:901700000010650 usage decreases to: 0
+  BTS/BSC sends out paging request to MSISDN:42342
+  strcmp(paging_expecting_imsi, vsub->imsi) == 0
 DREF VLR subscr MSISDN:42342 usage increases to: 4
   llist_count(&vsub->cs.requests) == 1
 DREF VLR subscr MSISDN:42342 usage decreases to: 3
@@ -747,7 +744,6 @@
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: Received Event SUBSCR_CONN_E_ACCEPTED
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: SUBSCR_CONN_FROM_PAGING_RESP
 DVLR Subscr_Conn(901700000010650){SUBSCR_CONN_S_NEW}: state_chg to SUBSCR_CONN_S_ACCEPTED
-DREF BSC subscr IMSI:901700000010650 usage decreases to: 0
 DREF VLR subscr MSISDN:42342 usage increases to: 5
 DREF MSISDN:42342: MSC conn use + 1 == 3
 - DTAP --> MS: 09015801000791447758100650004c0005802443f2000007101000000000445079da1e1ee7416937485e9ea7c965373d1d6683c270383b3d0ed3d36ff71c949e83c22072799e9687c5ec32a81d96afcbf4b4fb0c7ac3e9e9b7db05
diff --git a/tests/msc_vlr/msc_vlr_tests.c b/tests/msc_vlr/msc_vlr_tests.c
index a878be7..a40f1e5 100644
--- a/tests/msc_vlr/msc_vlr_tests.c
+++ b/tests/msc_vlr/msc_vlr_tests.c
@@ -252,33 +252,25 @@
 	paging_expecting_imsi = NULL;
 }
 
-/* override, requires '-Wl,--wrap=paging_request' */
-int __real_paging_request(struct gsm_network *network, struct bsc_subscr *sub,
-			  int type, gsm_cbfn *cbfn, void *data);
-int __wrap_paging_request(struct gsm_network *network, struct bsc_subscr *sub,
-			  int type, gsm_cbfn *cbfn, void *data)
+/* override, requires '-Wl,--wrap=msc_fake_paging_request' */
+int __real_msc_fake_paging_request(struct vlr_subscr *vsub);
+int __wrap_msc_fake_paging_request(struct vlr_subscr *vsub)
 {
-	log("BTS/BSC sends out paging request to %s for channel type %d",
-	    bsc_subscr_name(sub), type);
+	log("BTS/BSC sends out paging request to %s",
+	    vlr_subscr_name(vsub));
 	OSMO_ASSERT(paging_expecting_imsi || (paging_expecting_tmsi != GSM_RESERVED_TMSI));
 	if (paging_expecting_imsi)
-		VERBOSE_ASSERT(strcmp(paging_expecting_imsi, sub->imsi), == 0, "%d");
+		VERBOSE_ASSERT(strcmp(paging_expecting_imsi, vsub->imsi), == 0, "%d");
 	if (paging_expecting_tmsi != GSM_RESERVED_TMSI)
-		VERBOSE_ASSERT(paging_expecting_tmsi, == sub->tmsi, "0x%08x");
+		VERBOSE_ASSERT(paging_expecting_tmsi, == vsub->tmsi, "0x%08x");
 	paging_sent = true;
 	paging_stopped = false;
 	return 1;
 }
 
-/* override, requires '-Wl,--wrap=paging_request_stop' */
-void __real_paging_request_stop(struct gsm_bts *_bts,
-				struct vlr_subscr *vsub,
-				struct gsm_subscriber_connection *conn,
-				struct msgb *msg);
-void __wrap_paging_request_stop(struct gsm_bts *_bts,
-				struct vlr_subscr *vsub,
-				struct gsm_subscriber_connection *conn,
-				struct msgb *msg)
+/* override, requires '-Wl,--wrap=msc_fake_paging_request_stop' */
+void __real_msc_fake_paging_request_stop(struct vlr_subscr *vsub);
+void __wrap_msc_fake_paging_request_stop(struct vlr_subscr *vsub)
 {
 	paging_stopped = true;
 }

-- 
To view, visit https://gerrit.osmocom.org/3345
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Id3705236350d5f69e447046b0a764bbabc3d493c
Gerrit-PatchSet: 4
Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list