[PATCH] openbsc[master]: add struct bsc_subscr, separating libbsc from gsm_subscriber

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Fri Feb 24 00:18:46 UTC 2017


Hello Harald Welte, Jenkins Builder, Holger Freyther,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/1682

to look at the new patch set (#7).

add struct bsc_subscr, separating libbsc from gsm_subscriber

In a future commit, gsm_subscriber will be replaced by vlr_subscr, and it will
not make sense to use vlr_subscr in libbsc. Thus we need a dedicated BSC
subscriber: struct bsc_subscr.

Add rf_policy arg to bsc_grace_paging_request() because the bsc_subscr will no
longer have a backpointer to gsm_network (used to be via subscr->group).

Create a separate logging filter for the new BSC subscriber. The implementation
of adjusting the filter context is added in libbsc to not introduce
bsc_subscr_get/_put() dependencies to libcommon.

During Paging Response, fetch a bsc_subscr from the mobile identity, like we do
for the gsm_subscriber. It looks like a duplication now, but will make sense
for the VLR as well as for future MSC split patches.

Naming: it was requested to not name the new struct bsc_sub, because 'sub' is
too ambiguous. At the same time it would be fine to have 'bsc_sub_' as function
prefix. Instead of struct bsc_subscriber and bsc_sub_ prefix, I decided to
match both up as struct bsc_subscr and bsc_subscr_ function prefix. It's fast
to type, relatively short, unambiguous, and the naming is consistent.

Add bsc_subscr unit test.

Related: OS#1592, OS#1594
Change-Id: Ia61cc00e8bb186b976939a4fc8f7cf9ce6aa3d8e
---
M openbsc/.gitignore
M openbsc/include/openbsc/Makefile.am
A openbsc/include/openbsc/bsc_subscriber.h
M openbsc/include/openbsc/debug.h
M openbsc/include/openbsc/gsm_04_08.h
M openbsc/include/openbsc/gsm_data.h
M openbsc/include/openbsc/osmo_bsc_grace.h
M openbsc/include/openbsc/paging.h
M openbsc/src/libbsc/Makefile.am
M openbsc/src/libbsc/abis_rsl.c
A openbsc/src/libbsc/bsc_subscriber.c
M openbsc/src/libbsc/bsc_vty.c
M openbsc/src/libbsc/gsm_04_08_utils.c
M openbsc/src/libbsc/paging.c
M openbsc/src/libcommon-cs/common_cs.c
M openbsc/src/libcommon/debug.c
M openbsc/src/libmsc/gsm_04_08.c
M openbsc/src/libmsc/gsm_subscriber.c
M openbsc/src/libmsc/vty_interface_layer3.c
M openbsc/src/osmo-bsc/osmo_bsc_bssap.c
M openbsc/src/osmo-bsc/osmo_bsc_filter.c
M openbsc/src/osmo-bsc/osmo_bsc_grace.c
M openbsc/src/osmo-bsc/osmo_bsc_vty.c
M openbsc/tests/channel/Makefile.am
M openbsc/tests/channel/channel_test.c
M openbsc/tests/subscr/Makefile.am
A openbsc/tests/subscr/bsc_subscr_test.c
A openbsc/tests/subscr/bsc_subscr_test.err
A openbsc/tests/subscr/bsc_subscr_test.ok
M openbsc/tests/testsuite.at
30 files changed, 611 insertions(+), 115 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/82/1682/7

diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index e3f25cb..4f8e7e6 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -79,6 +79,7 @@
 tests/mgcp/mgcp_transcoding_test
 tests/sgsn/sgsn_test
 tests/subscr/subscr_test
+tests/subscr/bsc_subscr_test
 tests/oap/oap_test
 tests/gtphub/gtphub_test
 tests/mm_auth/mm_auth_test
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index c10accd..0895096 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -10,6 +10,7 @@
 	bsc_nat_callstats.h \
 	bsc_nat_sccp.h \
 	bsc_rll.h \
+	bsc_subscriber.h \
 	bss.h \
 	bts_ipaccess_nanobts_omlattr.h \
 	chan_alloc.h \
diff --git a/openbsc/include/openbsc/bsc_subscriber.h b/openbsc/include/openbsc/bsc_subscriber.h
new file mode 100644
index 0000000..a750d6e
--- /dev/null
+++ b/openbsc/include/openbsc/bsc_subscriber.h
@@ -0,0 +1,43 @@
+/* GSM subscriber details for use in BSC land */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
+
+struct log_target;
+
+struct bsc_subscr {
+	struct llist_head entry;
+	int use_count;
+
+	char imsi[GSM23003_IMSI_MAX_DIGITS+1];
+	uint32_t tmsi;
+	uint16_t lac;
+};
+
+const char *bsc_subscr_name(struct bsc_subscr *bsub);
+
+struct bsc_subscr *bsc_subscr_have_by_imsi(struct llist_head *list,
+					   const char *imsi);
+struct bsc_subscr *bsc_subscr_have_by_tmsi(struct llist_head *list,
+					   uint32_t tmsi);
+
+struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list,
+					   const char *imsi);
+struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list,
+					   uint32_t tmsi);
+
+void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi);
+
+struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub,
+				   const char *file, int line);
+struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub,
+				   const char *file, int line);
+#define bsc_subscr_get(bsub) _bsc_subscr_get(bsub, __BASE_FILE__, __LINE__)
+#define bsc_subscr_put(bsub) _bsc_subscr_put(bsub, __BASE_FILE__, __LINE__)
+
+void log_set_filter_bsc_subscr(struct log_target *target,
+			       struct bsc_subscr *bsub);
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 6300020..74db723 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -42,6 +42,7 @@
 
 struct gsm_subscriber;
 
-void log_set_imsi_filter(struct log_target *target, struct gsm_subscriber *subscr);
+void log_set_filter_vlr_subscr(struct log_target *target,
+			       struct gsm_subscriber *vlr_subscr);
 
 extern const struct log_info log_info;
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index cb632f6..bdf4ed2 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -15,6 +15,7 @@
 struct gsm_subscriber_connection;
 struct amr_multirate_conf;
 struct amr_mode;
+struct bsc_subscr;
 
 #define GSM48_ALLOC_SIZE	2048
 #define GSM48_ALLOC_HEADROOM	256
@@ -78,7 +79,8 @@
 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 gsm_subscriber *subscr);
+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/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 460953e..dbc58ac 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -23,6 +23,7 @@
 
 struct mncc_sock_state;
 struct gsm_subscriber_group;
+struct bsc_subscr;
 
 #define OBSC_LINKID_CB(__msgb)	(__msgb)->cb[3]
 
@@ -112,6 +113,9 @@
 
 	/* To whom we are allocated at the moment */
 	struct gsm_subscriber *subscr;
+
+	/* libbsc subscriber information */
+	struct bsc_subscr *bsub;
 
 	/* LU expiration handling */
 	uint8_t expire_timer_stopped;
@@ -383,6 +387,11 @@
 	 * BTS|RNC specific timezone overrides for multi-tz networks in
 	 * OsmoCSCN, this should be tied to the location area code (LAC). */
 	struct gsm_tz tz;
+
+	/* List of all struct bsc_subscr used in libbsc. This llist_head is
+	 * allocated so that the llist_head pointer itself can serve as a
+	 * talloc context. */
+	struct llist_head *bsc_subscribers;
 };
 
 struct osmo_esme;
diff --git a/openbsc/include/openbsc/osmo_bsc_grace.h b/openbsc/include/openbsc/osmo_bsc_grace.h
index af77b2f..50477d7 100644
--- a/openbsc/include/openbsc/osmo_bsc_grace.h
+++ b/openbsc/include/openbsc/osmo_bsc_grace.h
@@ -22,10 +22,14 @@
 #define OSMO_BSC_GRACE_H
 
 #include <openbsc/gsm_data.h>
+#include <openbsc/signal.h>
 
 struct osmo_msc_data;
 
 int bsc_grace_allow_new_connection(struct gsm_network *net, struct gsm_bts *bts);
-int bsc_grace_paging_request(struct gsm_subscriber *sub, int type, struct osmo_msc_data *msc);
+int bsc_grace_paging_request(enum signal_rf rf_policy,
+			     struct bsc_subscr *subscr,
+			     int chan_needed,
+			     struct osmo_msc_data *msc);
 
 #endif
diff --git a/openbsc/include/openbsc/paging.h b/openbsc/include/openbsc/paging.h
index 689ff51..7dd8500 100644
--- a/openbsc/include/openbsc/paging.h
+++ b/openbsc/include/openbsc/paging.h
@@ -27,7 +27,7 @@
 #include <osmocom/core/timer.h>
 
 #include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
+#include <openbsc/bsc_subscriber.h>
 
 /**
  * A pending paging request
@@ -36,8 +36,8 @@
 	/* list_head for list of all paging requests */
 	struct llist_head entry;
 	/* the subscriber which we're paging. Later gsm_paging_request
-	 * should probably become a part of the gsm_subscriber struct? */
-	struct gsm_subscriber *subscr;
+	 * should probably become a part of the bsc_subsrc struct? */
+	struct bsc_subscr *bsub;
 	/* back-pointer to the BTS on which we are paging */
 	struct gsm_bts *bts;
 	/* what kind of channel type do we ask the MS to establish */
@@ -55,13 +55,14 @@
 };
 
 /* schedule paging request */
-int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
+int paging_request(struct gsm_network *network, struct bsc_subscr *bsub,
 		   int type, gsm_cbfn *cbfn, void *data);
-int paging_request_bts(struct gsm_bts *bts, struct gsm_subscriber *subscr,
-		int type, gsm_cbfn *cbfn, void *data);
+int paging_request_bts(struct gsm_bts *bts, struct bsc_subscr *bsub,
+		       int type, gsm_cbfn *cbfn, void *data);
 
 /* stop paging requests */
-void paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
+void paging_request_stop(struct llist_head *bts_list,
+			 struct gsm_bts *_bts, struct bsc_subscr *bsub,
 			 struct gsm_subscriber_connection *conn,
 			 struct msgb *msg);
 
@@ -71,6 +72,6 @@
 /* pending paging requests */
 unsigned int paging_pending_requests_nr(struct gsm_bts *bts);
 
-void *paging_get_data(struct gsm_bts *bts, struct gsm_subscriber *subscr);
+void *paging_get_data(struct gsm_bts *bts, struct bsc_subscr *bsub);
 
 #endif
diff --git a/openbsc/src/libbsc/Makefile.am b/openbsc/src/libbsc/Makefile.am
index b8e77e6..fd8f37a 100644
--- a/openbsc/src/libbsc/Makefile.am
+++ b/openbsc/src/libbsc/Makefile.am
@@ -24,6 +24,7 @@
 	abis_om2000_vty.c \
 	abis_rsl.c \
 	bsc_rll.c \
+	bsc_subscriber.c \
 	paging.c \
 	bts_ericsson_rbs2000.c \
 	bts_ipaccess_nanobts.c \
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c
index 1cae832..5939e75 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -1332,10 +1332,10 @@
 static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
 {
 	int i;
-	char *name = "";
+	const char *name = "";
 
 	if (lchan && lchan->conn)
-		name = subscr_name(lchan->conn->subscr);
+		name = bsc_subscr_name(lchan->conn->bsub);
 
 	DEBUGP(DMEAS, "[%s] MEASUREMENT RESULT NR=%d ", name, mr->nr);
 
diff --git a/openbsc/src/libbsc/bsc_subscriber.c b/openbsc/src/libbsc/bsc_subscriber.c
new file mode 100644
index 0000000..7dcf1c2
--- /dev/null
+++ b/openbsc/src/libbsc/bsc_subscriber.c
@@ -0,0 +1,168 @@
+/* GSM subscriber details for use in BSC land */
+
+/*
+ * (C) 2016 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ *
+ * Author: Neels Hofmeyr <nhofmeyr 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 <talloc.h>
+#include <string.h>
+#include <limits.h>
+
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/logging.h>
+
+#include <openbsc/bsc_subscriber.h>
+#include <openbsc/debug.h>
+
+static struct bsc_subscr *bsc_subscr_alloc(struct llist_head *list)
+{
+	struct bsc_subscr *bsub;
+
+	bsub = talloc_zero(list, struct bsc_subscr);
+	if (!bsub)
+		return NULL;
+
+	llist_add_tail(&bsub->entry, list);
+	bsub->use_count = 1;
+
+	return bsub;
+}
+
+struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list,
+					   const char *imsi)
+{
+	struct bsc_subscr *bsub;
+
+	if (!imsi || !*imsi)
+		return NULL;
+
+	llist_for_each_entry(bsub, list, entry) {
+		if (!strcmp(bsub->imsi, imsi))
+			return bsc_subscr_get(bsub);
+	}
+	return NULL;
+}
+
+struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list,
+					   uint32_t tmsi)
+{
+	struct bsc_subscr *bsub;
+
+	if (tmsi == GSM_RESERVED_TMSI)
+		return NULL;
+
+	llist_for_each_entry(bsub, list, entry) {
+		if (bsub->tmsi == tmsi)
+			return bsc_subscr_get(bsub);
+	}
+	return NULL;
+}
+
+void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi)
+{
+	if (!bsub)
+		return;
+	strncpy(bsub->imsi, imsi, sizeof(bsub->imsi));
+}
+
+struct bsc_subscr *bsc_subscr_have_by_imsi(struct llist_head *list,
+					   const char *imsi)
+{
+	struct bsc_subscr *bsub;
+	bsub = bsc_subscr_find_by_imsi(list, imsi);
+	if (bsub)
+		return bsub;
+	bsub = bsc_subscr_alloc(list);
+	bsc_subscr_set_imsi(bsub, imsi);
+	return bsub;
+}
+
+struct bsc_subscr *bsc_subscr_have_by_tmsi(struct llist_head *list,
+					   uint32_t tmsi)
+{
+	struct bsc_subscr *bsub;
+	bsub = bsc_subscr_find_by_tmsi(list, tmsi);
+	if (bsub)
+		return bsub;
+	bsub = bsc_subscr_alloc(list);
+	bsub->tmsi = tmsi;
+	return bsub;
+}
+
+const char *bsc_subscr_name(struct bsc_subscr *bsub)
+{
+	static char buf[32];
+	if (!bsub)
+		return "unknown";
+	if (bsub->imsi[0])
+		snprintf(buf, sizeof(buf), "IMSI:%s", bsub->imsi);
+	else
+		snprintf(buf, sizeof(buf), "TMSI:0x%08x", bsub->tmsi);
+	return buf;
+}
+
+static void bsc_subscr_free(struct bsc_subscr *bsub)
+{
+	llist_del(&bsub->entry);
+	talloc_free(bsub);
+}
+
+struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub,
+				   const char *file, int line)
+{
+	OSMO_ASSERT(bsub->use_count < INT_MAX);
+	bsub->use_count++;
+	LOGPSRC(DREF, LOGL_DEBUG, file, line,
+		"BSC subscr %s usage increases to: %d\n",
+		bsc_subscr_name(bsub), bsub->use_count);
+	return bsub;
+}
+
+struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub,
+				   const char *file, int line)
+{
+	bsub->use_count--;
+	LOGPSRC(DREF, bsub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR,
+		file, line,
+		"BSC subscr %s usage decreases to: %d\n",
+		bsc_subscr_name(bsub), bsub->use_count);
+	if (bsub->use_count <= 0)
+		bsc_subscr_free(bsub);
+	return NULL;
+}
+
+void log_set_filter_bsc_subscr(struct log_target *target,
+			       struct bsc_subscr *bsc_subscr)
+{
+	struct bsc_subscr **fsub = (void*)&target->filter_data[LOG_FLT_BSC_SUBSCR];
+
+	/* free the old data */
+	if (*fsub) {
+		bsc_subscr_put(*fsub);
+		*fsub = NULL;
+	}
+
+	if (bsc_subscr) {
+		target->filter_map |= (1 << LOG_FLT_BSC_SUBSCR);
+		*fsub = bsc_subscr_get(bsc_subscr);
+	} else
+		target->filter_map &= ~(1 << LOG_FLT_BSC_SUBSCR);
+}
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 73acebd..21d0701 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -1023,6 +1023,16 @@
 	vty_out(vty, "    Use count: %u%s", subscr->use_count, VTY_NEWLINE);
 }
 
+static void bsc_subscr_dump_vty(struct vty *vty, struct bsc_subscr *bsub)
+{
+	if (strlen(bsub->imsi))
+		vty_out(vty, "    IMSI: %s%s", bsub->imsi, VTY_NEWLINE);
+	if (bsub->tmsi != GSM_RESERVED_TMSI)
+		vty_out(vty, "    TMSI: 0x%08x%s", bsub->tmsi,
+			VTY_NEWLINE);
+	vty_out(vty, "    Use count: %d%s", bsub->use_count, VTY_NEWLINE);
+}
+
 static void meas_rep_dump_uni_vty(struct vty *vty,
 				  struct gsm_meas_rep_unidir *mru,
 				  const char *prefix,
@@ -1318,7 +1328,7 @@
 static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
 {
 	vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
-	subscr_dump_vty(vty, pag->subscr);
+	bsc_subscr_dump_vty(vty, pag->bsub);
 }
 
 static void bts_paging_dump_vty(struct vty *vty, struct gsm_bts *bts)
diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c
index 98f0790..4a53b31 100644
--- a/openbsc/src/libbsc/gsm_04_08_utils.c
+++ b/openbsc/src/libbsc/gsm_04_08_utils.c
@@ -283,7 +283,7 @@
 }
 
 int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
-			     struct msgb *msg, struct gsm_subscriber *subscr)
+			     struct msgb *msg, struct bsc_subscr *bsub)
 {
 	struct gsm_bts *bts = msg->lchan->ts->trx->bts;
 	struct gsm48_hdr *gh = msgb_l3(msg);
@@ -292,22 +292,24 @@
 	if (is_siemens_bts(bts))
 		send_siemens_mrpci(msg->lchan, classmark2_lv);
 
-	if (!conn->subscr) {
-		conn->subscr = subscr;
-	} else if (conn->subscr != subscr) {
-		LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
-		subscr_put(subscr);
+	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");
-		subscr_put(subscr);
-		subscr = conn->subscr;
+		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(conn->bts, subscr, conn, msg);
+	paging_request_stop(&bts->network->bts_list, conn->bts, bsub, conn,
+			    msg);
 	return 0;
 }
 
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c
index eb37a33..bd23d89 100644
--- a/openbsc/src/libbsc/paging.c
+++ b/openbsc/src/libbsc/paging.c
@@ -42,6 +42,7 @@
 #include <osmocom/gsm/gsm48.h>
 #include <osmocom/gsm/gsm0502.h>
 
+#include <openbsc/bsc_subscriber.h>
 #include <openbsc/paging.h>
 #include <openbsc/debug.h>
 #include <openbsc/signal.h>
@@ -58,11 +59,11 @@
  * Kill one paging request update the internal list...
  */
 static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
-				struct gsm_paging_request *to_be_deleted)
+				  struct gsm_paging_request *to_be_deleted)
 {
 	osmo_timer_del(&to_be_deleted->T3113);
 	llist_del(&to_be_deleted->entry);
-	subscr_put(to_be_deleted->subscr);
+	bsc_subscr_put(to_be_deleted->bsub);
 	talloc_free(to_be_deleted);
 }
 
@@ -77,21 +78,21 @@
 	if (!bts->oml_link)
 		return;
 
-	log_set_context(LOG_CTX_VLR_SUBSCR, request->subscr);
+	log_set_context(LOG_CTX_BSC_SUBSCR, request->bsub);
 
 	LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: %s tmsi: "
-	     "0x%x for ch. type %d (attempt %d)\n", request->subscr->imsi,
-	     request->subscr->tmsi, request->chan_type, request->attempts);
+	     "0x%08x for ch. type %d (attempt %d)\n", request->bsub->imsi,
+	     request->bsub->tmsi, request->chan_type, request->attempts);
 
-	if (request->subscr->tmsi == GSM_RESERVED_TMSI)
-		mi_len = gsm48_generate_mid_from_imsi(mi, request->subscr->imsi);
+	if (request->bsub->tmsi == GSM_RESERVED_TMSI)
+		mi_len = gsm48_generate_mid_from_imsi(mi, request->bsub->imsi);
 	else
-		mi_len = gsm48_generate_mid_from_tmsi(mi, request->subscr->tmsi);
+		mi_len = gsm48_generate_mid_from_tmsi(mi, request->bsub->tmsi);
 
 	page_group = gsm0502_calc_paging_group(&bts->si_common.chan_desc,
-						str_to_imsi(request->subscr->imsi));
+					       str_to_imsi(request->bsub->imsi));
 	gsm0808_page(bts, page_group, mi_len, mi, request->chan_type);
-	log_set_context(LOG_CTX_VLR_SUBSCR, NULL);
+	log_set_context(LOG_CTX_BSC_SUBSCR, NULL);
 }
 
 static void paging_schedule_if_needed(struct gsm_bts_paging_state *paging_bts)
@@ -237,11 +238,12 @@
 }
 
 static int paging_pending_request(struct gsm_bts_paging_state *bts,
-				struct gsm_subscriber *subscr) {
+				  struct bsc_subscr *bsub)
+{
 	struct gsm_paging_request *req;
 
 	llist_for_each_entry(req, &bts->pending_requests, entry) {
-		if (subscr == req->subscr)
+		if (bsub == req->bsub)
 			return 1;
 	}
 
@@ -255,10 +257,10 @@
 	gsm_cbfn *cbfn;
 	int msg;
 
-	log_set_context(LOG_CTX_VLR_SUBSCR, req->subscr);
+	log_set_context(LOG_CTX_BSC_SUBSCR, req->bsub);
 
 	LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
-		req, req->subscr->imsi);
+	     req, bsc_subscr_name(req->bsub));
 
 	/* must be destroyed before calling cbfn, to prevent double free */
 	rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]);
@@ -277,21 +279,22 @@
 
 }
 
-static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
-			    int type, gsm_cbfn *cbfn, void *data)
+static int _paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub,
+			   int type, gsm_cbfn *cbfn, void *data)
 {
 	struct gsm_bts_paging_state *bts_entry = &bts->paging;
 	struct gsm_paging_request *req;
 
-	if (paging_pending_request(bts_entry, subscr)) {
-		LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi);
+	if (paging_pending_request(bts_entry, bsub)) {
+		LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n",
+		     bsc_subscr_name(bsub));
 		return -EEXIST;
 	}
 
-	LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n",
-		subscr->id, bts->nr);
+	LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %s on bts %d.\n",
+	     bsc_subscr_name(bsub), bts->nr);
 	req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
-	req->subscr = subscr_get(subscr);
+	req->bsub = bsc_subscr_get(bsub);
 	req->bts = bts;
 	req->chan_type = type;
 	req->cbfn = cbfn;
@@ -305,8 +308,8 @@
 	return 0;
 }
 
-int paging_request_bts(struct gsm_bts *bts, struct gsm_subscriber *subscr,
-		int type, gsm_cbfn *cbfn, void *data)
+int paging_request_bts(struct gsm_bts *bts, struct bsc_subscr *bsub,
+		       int type, gsm_cbfn *cbfn, void *data)
 {
 	int rc;
 
@@ -317,15 +320,14 @@
 	/* maybe it is the first time we use it */
 	paging_init_if_needed(bts);
 
-
 	/* Trigger paging, pass any error to the caller */
-	rc = _paging_request(bts, subscr, type, cbfn, data);
+	rc = _paging_request(bts, bsub, type, cbfn, data);
 	if (rc < 0)
 		return rc;
 	return 1;
 }
 
-int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
+int paging_request(struct gsm_network *network, struct bsc_subscr *bsub,
 		   int type, gsm_cbfn *cbfn, void *data)
 {
 	struct gsm_bts *bts = NULL;
@@ -337,13 +339,14 @@
 	do {
 		int rc;
 
-		bts = gsm_bts_by_lac(network, subscr->lac, bts);
+		bts = gsm_bts_by_lac(network, bsub->lac, bts);
 		if (!bts)
 			break;
 
-		rc = paging_request_bts(bts, subscr, type, cbfn, data);
+		rc = paging_request_bts(bts, bsub, type, cbfn, data);
 		if (rc < 0) {
-			paging_request_stop(NULL, subscr, NULL, NULL);
+			paging_request_stop(&network->bts_list, NULL, bsub,
+					    NULL, NULL);
 			return rc;
 		}
 		num_pages += rc;
@@ -357,7 +360,7 @@
 
 
 /* we consciously ignore the type of the request here */
-static void _paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
+static void _paging_request_stop(struct gsm_bts *bts, struct bsc_subscr *bsub,
 				 struct gsm_subscriber_connection *conn,
 				 struct msgb *msg)
 {
@@ -367,8 +370,8 @@
 	paging_init_if_needed(bts);
 
 	llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests,
-				 entry) {
-		if (req->subscr == subscr) {
+				  entry) {
+		if (req->bsub == bsub) {
 			gsm_cbfn *cbfn = req->cbfn;
 			void *param = req->cbfn_param;
 
@@ -377,35 +380,36 @@
 			req = NULL;
 
 			if (conn && cbfn) {
-				LOGP(DPAG, LOGL_DEBUG, "Stop paging %s on bts %d, calling cbfn.\n", subscr->imsi, bts->nr);
+				LOGP(DPAG, LOGL_DEBUG, "Stop paging %s on bts %d, calling cbfn.\n", bsub->imsi, bts->nr);
 				cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
-					  msg, conn, param);
+				     msg, conn, param);
 			} else
-				LOGP(DPAG, LOGL_DEBUG, "Stop paging %s on bts %d silently.\n", subscr->imsi, bts->nr);
+				LOGP(DPAG, LOGL_DEBUG, "Stop paging %s on bts %d silently.\n", bsub->imsi, bts->nr);
 			break;
 		}
 	}
 }
 
 /* Stop paging on all other bts' */
-void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
+void paging_request_stop(struct llist_head *bts_list,
+			 struct gsm_bts *_bts, struct bsc_subscr *bsub,
 			 struct gsm_subscriber_connection *conn,
 			 struct msgb *msg)
 {
 	struct gsm_bts *bts;
 
-	log_set_context(LOG_CTX_VLR_SUBSCR, subscr);
+	log_set_context(LOG_CTX_BSC_SUBSCR, bsub);
 
 	/* Stop this first and dispatch the request */
 	if (_bts)
-		_paging_request_stop(_bts, subscr, conn, msg);
+		_paging_request_stop(_bts, bsub, conn, msg);
 
 	/* Make sure to cancel this everywhere else */
-	llist_for_each_entry(bts, &subscr->group->net->bts_list, list) {
+	llist_for_each_entry(bts, bts_list, list) {
 		/* Sort of an optimization. */
 		if (bts == _bts)
 			continue;
-		_paging_request_stop(bts, subscr, NULL, NULL);
+		_paging_request_stop(bts, bsub, NULL, NULL);
 	}
 }
 
@@ -434,12 +438,12 @@
 /**
  * Find any paging data for the given subscriber at the given BTS.
  */
-void *paging_get_data(struct gsm_bts *bts, struct gsm_subscriber *subscr)
+void *paging_get_data(struct gsm_bts *bts, struct bsc_subscr *bsub)
 {
 	struct gsm_paging_request *req;
 
 	llist_for_each_entry(req, &bts->paging.pending_requests, entry)
-		if (req->subscr == subscr)
+		if (req->bsub == bsub)
 			return req->cbfn_param;
 
 	return NULL;
diff --git a/openbsc/src/libcommon-cs/common_cs.c b/openbsc/src/libcommon-cs/common_cs.c
index 3149580..7905802 100644
--- a/openbsc/src/libcommon-cs/common_cs.c
+++ b/openbsc/src/libcommon-cs/common_cs.c
@@ -70,6 +70,9 @@
 	INIT_LLIST_HEAD(&net->upqueue);
 	INIT_LLIST_HEAD(&net->subscr_conns);
 
+	net->bsc_subscribers = talloc_zero(net, struct llist_head);
+	INIT_LLIST_HEAD(net->bsc_subscribers);
+
 	/* init statistics */
 	net->msc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0);
 	net->active_calls = osmo_counter_alloc("msc.active_calls");
diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c
index 4d7bfed..0f82211 100644
--- a/openbsc/src/libcommon/debug.c
+++ b/openbsc/src/libcommon/debug.c
@@ -180,11 +180,16 @@
 static int filter_fn(const struct log_context *ctx, struct log_target *tar)
 {
 	const struct gsm_subscriber *subscr = ctx->ctx[LOG_CTX_VLR_SUBSCR];
+	const struct bsc_subscr *bsub = ctx->ctx[LOG_CTX_BSC_SUBSCR];
 	const struct gprs_nsvc *nsvc = ctx->ctx[LOG_CTX_GB_NSVC];
 	const struct gprs_nsvc *bvc = ctx->ctx[LOG_CTX_GB_BVC];
 
 	if ((tar->filter_map & (1 << LOG_FLT_VLR_SUBSCR)) != 0
 	    && subscr && subscr == tar->filter_data[LOG_FLT_VLR_SUBSCR])
+		return 1;
+
+	if ((tar->filter_map & (1 << LOG_FLT_BSC_SUBSCR)) != 0
+	    && bsub && bsub == tar->filter_data[LOG_FLT_BSC_SUBSCR])
 		return 1;
 
 	/* Filter on the NS Virtual Connection */
@@ -206,7 +211,8 @@
 	.num_cat = ARRAY_SIZE(default_categories),
 };
 
-void log_set_imsi_filter(struct log_target *target, struct gsm_subscriber *subscr)
+void log_set_filter_vlr_subscr(struct log_target *target,
+			       struct gsm_subscriber *vlr_subscr)
 {
 	struct gsm_subscriber **fsub = (void*)&target->filter_data[LOG_FLT_VLR_SUBSCR];
 
@@ -216,9 +222,9 @@
 		*fsub = NULL;
 	}
 
-	if (subscr) {
+	if (vlr_subscr) {
 		target->filter_map |= (1 << LOG_FLT_VLR_SUBSCR);
-		*fsub = subscr_get(subscr);
+		*fsub = subscr_get(vlr_subscr);
 	} else
 		target->filter_map &= ~(1 << LOG_FLT_VLR_SUBSCR);
 }
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index be43956..82568a1 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1433,6 +1433,8 @@
 	uint8_t mi_type;
 	char mi_string[GSM48_MI_SIZE];
 	struct gsm_subscriber *subscr = NULL;
+	struct bsc_subscr *bsub;
+	uint32_t tmsi;
 	int rc = 0;
 
 	resp = (struct gsm48_pag_resp *) &gh->data[0];
@@ -1443,8 +1445,8 @@
 
 	switch (mi_type) {
 	case GSM_MI_TYPE_TMSI:
-		subscr = subscr_get_by_tmsi(conn->network->subscr_group,
-					    tmsi_from_string(mi_string));
+		tmsi = tmsi_from_string(mi_string);
+		subscr = subscr_get_by_tmsi(conn->network->subscr_group, tmsi);
 		break;
 	case GSM_MI_TYPE_IMSI:
 		subscr = subscr_get_by_imsi(conn->network->subscr_group,
@@ -1457,6 +1459,19 @@
 		/* FIXME: request id? close channel? */
 		return -EINVAL;
 	}
+
+	if (!conn->subscr) {
+		conn->subscr = subscr;
+	} else if (conn->subscr != subscr) {
+		LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
+		subscr_put(subscr);
+		return -EINVAL;
+	} else {
+		DEBUGP(DRR, "<- Channel already owned by us\n");
+		subscr_put(subscr);
+		subscr = conn->subscr;
+	}
+
 	log_set_context(LOG_CTX_VLR_SUBSCR, subscr);
 	DEBUGP(DRR, "<- Channel was requested by %s\n",
 		subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
@@ -1465,10 +1480,18 @@
 	memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
 	db_sync_equipment(&subscr->equipment);
 
+	/* 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. */
+	bsub = bsc_subscr_have_by_imsi(conn->network->bsc_subscribers,
+				       subscr->imsi);
+	bsub->tmsi = subscr->tmsi;
+	bsub->lac = subscr->lac;
+
 	/* We received a paging */
 	conn->expire_timer_stopped = 1;
 
-	rc = gsm48_handle_paging_resp(conn, msg, subscr);
+	rc = gsm48_handle_paging_resp(conn, msg, bsub);
 	return rc;
 }
 
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index 568f1c5..73e6d79 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -82,8 +82,11 @@
 	struct gsm_subscriber_connection *conn = data;
 	struct gsm_subscriber *subscr = param;
 	struct paging_signal_data sig_data;
+	struct bsc_subscr *bsub;
+	struct gsm_network *net;
 
-	OSMO_ASSERT(subscr->is_paging);
+	OSMO_ASSERT(subscr && subscr->is_paging);
+	net = subscr->group->net;
 
 	/*
 	 * Stop paging on all other BTS. E.g. if this is
@@ -91,7 +94,15 @@
 	 * timeout soon as well. Let's just stop everything
 	 * and forget we wanted to page.
 	 */
-	paging_request_stop(NULL, subscr, NULL, NULL);
+
+	/* 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. */
+	bsub = bsc_subscr_have_by_imsi(net->bsc_subscribers, subscr->imsi);
+	bsub->tmsi = subscr->tmsi;
+	bsub->lac = subscr->lac;
+	paging_request_stop(&net->bts_list, NULL, bsub, NULL, NULL);
+	bsc_subscr_put(bsub);
 
 	/* Inform parts of the system we don't know */
 	sig_data.subscr = subscr;
@@ -169,13 +180,23 @@
 {
 	int rc;
 	struct subscr_request *request;
+	struct bsc_subscr *bsub;
+	struct gsm_network *net = subscr->group->net;
 
 	/* Start paging.. we know it is async so we can do it before */
 	if (!subscr->is_paging) {
 		LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
 			subscr_name(subscr));
-		rc = paging_request(subscr->group->net, subscr, channel_type,
-				    subscr_paging_cb, subscr);
+		/* 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. */
+		bsub = bsc_subscr_have_by_imsi(net->bsc_subscribers,
+					       subscr->imsi);
+		bsub->tmsi = subscr->tmsi;
+		bsub->lac = subscr->lac;
+		rc = paging_request(net, bsub, channel_type, subscr_paging_cb,
+				    subscr);
+		bsc_subscr_put(bsub);
 		if (rc <= 0) {
 			LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
 				subscr_name(subscr), rc);
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index ddec2e3..c6a8929 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -34,6 +34,7 @@
 #include <osmocom/core/linuxlist.h>
 #include <openbsc/gsm_data.h>
 #include <openbsc/gsm_subscriber.h>
+#include <openbsc/bsc_subscriber.h>
 #include <openbsc/silent_call.h>
 #include <openbsc/gsm_04_11.h>
 #include <osmocom/abis/e1_input.h>
@@ -1033,21 +1034,26 @@
 	LOGGING_STR FILTER_STR
       "Filter log messages by IMSI\n" "IMSI to be used as filter\n")
 {
-	struct gsm_subscriber *subscr;
+	struct gsm_subscriber *vlr_subscr;
+	struct bsc_subscr *bsc_subscr;
 	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	struct log_target *tgt = osmo_log_vty2tgt(vty);
+	const char *imsi = argv[0];
 
 	if (!tgt)
 		return CMD_WARNING;
 
-	subscr = subscr_get_by_imsi(gsmnet->subscr_group, argv[0]);
-	if (!subscr) {
+	vlr_subscr = subscr_get_by_imsi(gsmnet->subscr_group, imsi);
+	bsc_subscr = bsc_subscr_find_by_imsi(gsmnet->bsc_subscribers, imsi);
+
+	if (!vlr_subscr && !bsc_subscr) {
 		vty_out(vty, "%%no subscriber with IMSI(%s)%s",
 			argv[0], VTY_NEWLINE);
 		return CMD_WARNING;
 	}
 
-	log_set_imsi_filter(tgt, subscr);
+	log_set_filter_vlr_subscr(tgt, vlr_subscr);
+	log_set_filter_bsc_subscr(tgt, bsc_subscr);
 	return CMD_SUCCESS;
 }
 
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
index f38c97f..efdc9bd 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
@@ -20,9 +20,10 @@
 
 #include <openbsc/osmo_bsc.h>
 #include <openbsc/osmo_bsc_grace.h>
+#include <openbsc/osmo_bsc_rf.h>
 #include <openbsc/osmo_msc_data.h>
 #include <openbsc/debug.h>
-#include <openbsc/gsm_subscriber.h>
+#include <openbsc/bsc_subscriber.h>
 #include <openbsc/mgcp.h>
 #include <openbsc/paging.h>
 
@@ -99,7 +100,7 @@
 static int bssmap_handle_paging(struct osmo_msc_data *msc,
 				struct msgb *msg, unsigned int payload_length)
 {
-	struct gsm_subscriber *subscr;
+	struct bsc_subscr *subscr;
 	struct tlv_parsed tp;
 	char mi_string[GSM48_MI_SIZE];
 	uint32_t tmsi = GSM_RESERVED_TMSI;
@@ -157,7 +158,8 @@
 		LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
 	}
 
-	subscr = subscr_get_or_create(msc->network->subscr_group, mi_string);
+	subscr = bsc_subscr_have_by_imsi(msc->network->bsc_subscribers,
+				      mi_string);
 	if (!subscr) {
 		LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string);
 		return -1;
@@ -167,7 +169,8 @@
 	subscr->tmsi = tmsi;
 
 	LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
-	bsc_grace_paging_request(subscr, chan_needed, msc);
+	bsc_grace_paging_request(msc->network->bsc_data->rf_ctrl->policy,
+				 subscr, chan_needed, msc);
 	return 0;
 }
 
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_filter.c b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
index d5ca2fd..8301bfb 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_filter.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
@@ -21,6 +21,7 @@
 #include <openbsc/osmo_msc_data.h>
 #include <openbsc/gsm_04_80.h>
 #include <openbsc/gsm_subscriber.h>
+#include <openbsc/bsc_subscriber.h>
 #include <openbsc/debug.h>
 #include <openbsc/paging.h>
 
@@ -54,14 +55,14 @@
 }
 
 /* extract a subscriber from the paging response */
-static struct gsm_subscriber *extract_sub(struct gsm_subscriber_connection *conn,
-					  struct msgb *msg)
+static struct bsc_subscr *extract_sub(struct gsm_subscriber_connection *conn,
+				   struct msgb *msg)
 {
 	uint8_t mi_type;
 	char mi_string[GSM48_MI_SIZE];
 	struct gsm48_hdr *gh;
 	struct gsm48_pag_resp *resp;
-	struct gsm_subscriber *subscr;
+	struct bsc_subscr *subscr;
 
 	if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
 		LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
@@ -78,12 +79,12 @@
 
 	switch (mi_type) {
 	case GSM_MI_TYPE_TMSI:
-		subscr = subscr_active_by_tmsi(conn->bts->network->subscr_group,
-					       tmsi_from_string(mi_string));
+		subscr = bsc_subscr_find_by_tmsi(conn->network->bsc_subscribers,
+					      tmsi_from_string(mi_string));
 		break;
 	case GSM_MI_TYPE_IMSI:
-		subscr = subscr_active_by_imsi(conn->bts->network->subscr_group,
-					       mi_string);
+		subscr = bsc_subscr_find_by_imsi(conn->network->bsc_subscribers,
+					      mi_string);
 		break;
 	default:
 		subscr = NULL;
@@ -96,15 +97,16 @@
 /* we will need to stop the paging request */
 static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
 {
-	struct gsm_subscriber *subscr = extract_sub(conn, msg);
+	struct bsc_subscr *subscr = extract_sub(conn, msg);
 
 	if (!subscr) {
 		LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
 		return -1;
 	}
 
-	paging_request_stop(conn->bts, subscr, conn, msg);
-	subscr_put(subscr);
+	paging_request_stop(&conn->network->bts_list, conn->bts, subscr, conn,
+			    msg);
+	bsc_subscr_put(subscr);
 	return 0;
 }
 
@@ -130,7 +132,7 @@
 	uint8_t mtype;
 	struct osmo_bsc_data *bsc;
 	struct osmo_msc_data *msc, *pag_msc;
-	struct gsm_subscriber *subscr;
+	struct bsc_subscr *subscr;
 	int is_emerg = 0;
 
 	bsc = conn->bts->network->bsc_data;
@@ -183,7 +185,7 @@
 	}
 
 	pag_msc = paging_get_data(conn->bts, subscr);
-	subscr_put(subscr);
+	bsc_subscr_put(subscr);
 
 	llist_for_each_entry(msc, &bsc->mscs, entry) {
 		if (msc != pag_msc)
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_grace.c b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
index 6409a3a..eef88b4 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_grace.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
@@ -22,7 +22,7 @@
 #include <openbsc/osmo_bsc_rf.h>
 #include <openbsc/osmo_msc_data.h>
 #include <openbsc/gsm_04_80.h>
-#include <openbsc/gsm_subscriber.h>
+#include <openbsc/bsc_subscriber.h>
 #include <openbsc/paging.h>
 #include <openbsc/signal.h>
 
@@ -34,8 +34,8 @@
 }
 
 
-static int normal_paging(struct gsm_subscriber *subscr, int chan_needed,
-			struct osmo_msc_data *msc)
+static int normal_paging(struct bsc_subscr *subscr, int chan_needed,
+			 struct osmo_msc_data *msc)
 {
 	/* we can't page by lac.. we need to page everything */
 	if (msc->core_lac != -1) {
@@ -47,12 +47,11 @@
 		return 0;
 	}
 
-	return paging_request(subscr->group->net, subscr, chan_needed, NULL,
-			      msc);
+	return paging_request(msc->network, subscr, chan_needed, NULL, msc);
 }
 
-static int locked_paging(struct gsm_subscriber *subscr, int chan_needed,
-			struct osmo_msc_data *msc)
+static int locked_paging(struct bsc_subscr *subscr, int chan_needed,
+			 struct osmo_msc_data *msc)
 {
 	struct gsm_bts *bts = NULL;
 
@@ -84,10 +83,12 @@
 /**
  * Try to not page if everything the cell is not on.
  */
-int bsc_grace_paging_request(struct gsm_subscriber *subscr, int chan_needed,
-				struct osmo_msc_data *msc)
+int bsc_grace_paging_request(enum signal_rf rf_policy,
+			     struct bsc_subscr *subscr,
+			     int chan_needed,
+			     struct osmo_msc_data *msc)
 {
-	if (subscr->group->net->bsc_data->rf_ctrl->policy == S_RF_ON)
+	if (rf_policy == S_RF_ON)
 		return normal_paging(subscr, chan_needed, msc);
 	return locked_paging(subscr, chan_needed, msc);
 }
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
index 86ccec4..9171968 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
@@ -22,7 +22,7 @@
 #include <openbsc/osmo_bsc.h>
 #include <openbsc/osmo_msc_data.h>
 #include <openbsc/vty.h>
-#include <openbsc/gsm_subscriber.h>
+#include <openbsc/bsc_subscriber.h>
 #include <openbsc/debug.h>
 #include <openbsc/bsc_msg_filter.h>
 
@@ -861,20 +861,19 @@
 	LOGGING_STR FILTER_STR
       "Filter log messages by IMSI\n" "IMSI to be used as filter\n")
 {
-	struct gsm_subscriber *subscr;
+	struct bsc_subscr *bsc_subscr;
 	struct log_target *tgt = osmo_log_vty2tgt(vty);
+	const char *imsi = argv[0];
 
-	if (!tgt)
-		return CMD_WARNING;
+	bsc_subscr = bsc_subscr_find_by_imsi(bsc_gsmnet->bsc_subscribers, imsi);
 
-	subscr = subscr_get_or_create(bsc_gsmnet->subscr_group, argv[0]);
-	if (!subscr) {
+	if (!bsc_subscr) {
 		vty_out(vty, "%%no subscriber with IMSI(%s)%s",
-			argv[0], VTY_NEWLINE);
+			imsi, VTY_NEWLINE);
 		return CMD_WARNING;
 	}
 
-	log_set_imsi_filter(tgt, subscr);
+	log_set_filter_bsc_subscr(tgt, bsc_subscr);
 	return CMD_SUCCESS;
 }
 
diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am
index 5e9583f..ca470ac 100644
--- a/openbsc/tests/channel/Makefile.am
+++ b/openbsc/tests/channel/Makefile.am
@@ -24,8 +24,8 @@
 	$(NULL)
 
 channel_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/libcommon/libcommon.a \
 	$(LIBOSMOCORE_LIBS) \
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index c69c701..88293d0 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -49,7 +49,7 @@
 }
 
 /* mock object for testing, directly invoke the cb... maybe later through the timer */
-int paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscriber, int type, gsm_cbfn *cbfn, void *data)
+int paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
 {
 	s_data = data;
 	s_cbfn = cbfn;
@@ -72,6 +72,7 @@
 		exit(1);
 	bts = gsm_bts_alloc(network);
 	bts->location_area_code = 23;
+	s_conn.network = network;
 
 	/* Create a dummy subscriber */
 	struct gsm_subscriber *subscr = subscr_alloc();
diff --git a/openbsc/tests/subscr/Makefile.am b/openbsc/tests/subscr/Makefile.am
index ad8b20c..6342444 100644
--- a/openbsc/tests/subscr/Makefile.am
+++ b/openbsc/tests/subscr/Makefile.am
@@ -19,10 +19,13 @@
 
 EXTRA_DIST = \
 	subscr_test.ok \
+	bsc_subscr_test.ok \
+	bsc_subscr_test.err \
 	$(NULL)
 
 noinst_PROGRAMS = \
 	subscr_test \
+	bsc_subscr_test \
 	$(NULL)
 
 subscr_test_SOURCES = \
@@ -40,3 +43,19 @@
 	$(LIBSMPP34_LIBS) \
 	$(LIBOSMOVTY_LIBS) \
 	$(NULL)
+
+bsc_subscr_test_SOURCES = \
+	bsc_subscr_test.c \
+	$(NULL)
+
+bsc_subscr_test_LDADD = \
+	$(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 \
+	$(LIBOSMOCORE_LIBS) \
+	$(LIBOSMOABIS_LIBS) \
+	$(LIBOSMOGSM_LIBS) \
+	$(LIBSMPP34_LIBS) \
+	$(LIBOSMOVTY_LIBS) \
+	$(NULL)
diff --git a/openbsc/tests/subscr/bsc_subscr_test.c b/openbsc/tests/subscr/bsc_subscr_test.c
new file mode 100644
index 0000000..43de723
--- /dev/null
+++ b/openbsc/tests/subscr/bsc_subscr_test.c
@@ -0,0 +1,130 @@
+/* (C) 2008 by Jan Luebbe <jluebbe at debian.org>
+ * (C) 2009 by Holger Hans Peter Freyther <zecke at selfish.org>
+ * (C) 2014 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * 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 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 <openbsc/debug.h>
+#include <openbsc/bsc_subscriber.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+struct llist_head *bsc_subscribers;
+
+#define VERBOSE_ASSERT(val, expect_op, fmt) \
+	do { \
+		printf(#val " == " fmt "\n", (val)); \
+		OSMO_ASSERT((val) expect_op); \
+	} while (0);
+
+static void assert_bsc_subscr(const struct bsc_subscr *bsub, const char *imsi)
+{
+	struct bsc_subscr *sfound;
+	OSMO_ASSERT(bsub);
+	OSMO_ASSERT(strcmp(bsub->imsi, imsi) == 0);
+
+	sfound = bsc_subscr_find_by_imsi(bsc_subscribers, imsi);
+	OSMO_ASSERT(sfound == bsub);
+
+	bsc_subscr_put(sfound);
+}
+
+static void test_bsc_subscr(void)
+{
+	struct bsc_subscr *s1, *s2, *s3;
+	const char *imsi1 = "1234567890";
+	const char *imsi2 = "9876543210";
+	const char *imsi3 = "5656565656";
+
+	printf("Test BSC subscriber allocation and deletion\n");
+
+	/* Check for emptiness */
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 0, "%d");
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi1) == NULL);
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi2) == NULL);
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi3) == NULL);
+
+	/* Allocate entry 1 */
+	s1 = bsc_subscr_have_by_imsi(bsc_subscribers, imsi1);
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d");
+	assert_bsc_subscr(s1, imsi1);
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d");
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi2) == NULL);
+
+	/* Allocate entry 2 */
+	s2 = bsc_subscr_have_by_imsi(bsc_subscribers, imsi2);
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 2, "%d");
+
+	/* Allocate entry 3 */
+	s3 = bsc_subscr_have_by_imsi(bsc_subscribers, imsi3);
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 3, "%d");
+
+	/* Check entries */
+	assert_bsc_subscr(s1, imsi1);
+	assert_bsc_subscr(s2, imsi2);
+	assert_bsc_subscr(s3, imsi3);
+
+	/* Free entry 1 */
+	bsc_subscr_put(s1);
+	s1 = NULL;
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 2, "%d");
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi1) == NULL);
+
+	assert_bsc_subscr(s2, imsi2);
+	assert_bsc_subscr(s3, imsi3);
+
+	/* Free entry 2 */
+	bsc_subscr_put(s2);
+	s2 = NULL;
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d");
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi1) == NULL);
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi2) == NULL);
+	assert_bsc_subscr(s3, imsi3);
+
+	/* Free entry 3 */
+	bsc_subscr_put(s3);
+	s3 = NULL;
+	VERBOSE_ASSERT(llist_count(bsc_subscribers), == 0, "%d");
+	OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi3) == NULL);
+
+	OSMO_ASSERT(llist_empty(bsc_subscribers));
+}
+
+int main()
+{
+	printf("Testing BSC subscriber core code.\n");
+	osmo_init_logging(&log_info);
+	log_set_print_filename(osmo_stderr_target, 0);
+	log_set_print_timestamp(osmo_stderr_target, 0);
+	log_set_use_color(osmo_stderr_target, 0);
+	log_set_print_category(osmo_stderr_target, 1);
+	log_set_category_filter(osmo_stderr_target, DREF, 1, LOGL_DEBUG);
+
+	bsc_subscribers = talloc_zero(NULL, struct llist_head);
+	INIT_LLIST_HEAD(bsc_subscribers);
+
+	test_bsc_subscr();
+
+	printf("Done\n");
+	return 0;
+}
diff --git a/openbsc/tests/subscr/bsc_subscr_test.err b/openbsc/tests/subscr/bsc_subscr_test.err
new file mode 100644
index 0000000..a66317a
--- /dev/null
+++ b/openbsc/tests/subscr/bsc_subscr_test.err
@@ -0,0 +1,17 @@
+DREF BSC subscr IMSI:1234567890 usage increases to: 2
+DREF BSC subscr IMSI:1234567890 usage decreases to: 1
+DREF BSC subscr IMSI:1234567890 usage increases to: 2
+DREF BSC subscr IMSI:1234567890 usage decreases to: 1
+DREF BSC subscr IMSI:9876543210 usage increases to: 2
+DREF BSC subscr IMSI:9876543210 usage decreases to: 1
+DREF BSC subscr IMSI:5656565656 usage increases to: 2
+DREF BSC subscr IMSI:5656565656 usage decreases to: 1
+DREF BSC subscr IMSI:1234567890 usage decreases to: 0
+DREF BSC subscr IMSI:9876543210 usage increases to: 2
+DREF BSC subscr IMSI:9876543210 usage decreases to: 1
+DREF BSC subscr IMSI:5656565656 usage increases to: 2
+DREF BSC subscr IMSI:5656565656 usage decreases to: 1
+DREF BSC subscr IMSI:9876543210 usage decreases to: 0
+DREF BSC subscr IMSI:5656565656 usage increases to: 2
+DREF BSC subscr IMSI:5656565656 usage decreases to: 1
+DREF BSC subscr IMSI:5656565656 usage decreases to: 0
diff --git a/openbsc/tests/subscr/bsc_subscr_test.ok b/openbsc/tests/subscr/bsc_subscr_test.ok
new file mode 100644
index 0000000..0f6a8be
--- /dev/null
+++ b/openbsc/tests/subscr/bsc_subscr_test.ok
@@ -0,0 +1,11 @@
+Testing BSC subscriber core code.
+Test BSC subscriber allocation and deletion
+llist_count(bsc_subscribers) == 0
+llist_count(bsc_subscribers) == 1
+llist_count(bsc_subscribers) == 1
+llist_count(bsc_subscribers) == 2
+llist_count(bsc_subscribers) == 3
+llist_count(bsc_subscribers) == 2
+llist_count(bsc_subscribers) == 1
+llist_count(bsc_subscribers) == 0
+Done
diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at
index 01737a3..280aeb2 100644
--- a/openbsc/tests/testsuite.at
+++ b/openbsc/tests/testsuite.at
@@ -13,6 +13,13 @@
 AT_CHECK([$abs_top_builddir/tests/subscr/subscr_test], [], [expout], [ignore])
 AT_CLEANUP
 
+AT_SETUP([bsc_subscr])
+AT_KEYWORDS([bsc_subscr])
+cat $abs_srcdir/subscr/bsc_subscr_test.ok > expout
+cat $abs_srcdir/subscr/bsc_subscr_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/subscr/bsc_subscr_test], [], [expout], [experr])
+AT_CLEANUP
+
 AT_SETUP([db])
 AT_KEYWORDS([db])
 cat $abs_srcdir/db/db_test.ok > expout

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

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Ia61cc00e8bb186b976939a4fc8f7cf9ce6aa3d8e
Gerrit-PatchSet: 7
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Holger Freyther <holger at freyther.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>


More information about the gerrit-log mailing list