msc: Add and use gsm_subscriber_group

Currently every subcriber object directly refers to the gsm_network
which contains a flag shared by every related subscriber
(keep_subscr). This adds a dependency on gsm_network even if only the
function defined in gsm_subscriber_base.c are used.

This patch adds a new struct gsm_subscriber_group which contains the
keep_subscr flag and a back reference to the network object. The
latter is not dereferenced in gsm_subscriber_base.c, so it can safely
be set to NULL when only that part of the gsm_subscriber API is being
used. It also changes that API to use gsm_subscriber_group instead of
gsm_network parameters.

Since there are some places where a pointer to the gsm_network is
needed but where only a gsm_subscriber is available, a 'net' back
pointer is added to the group struct, too. Nevertheless subscr group
and network could be separated completely, but this is not the topic
of this commit.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 9129059..08f9a8e 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -709,7 +709,7 @@
 	vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
 	vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
 	vty_out(vty, " subscriber-keep-in-ram %d%s",
-		gsmnet->keep_subscr, VTY_NEWLINE);
+		gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
 
 	return CMD_SUCCESS;
 }
@@ -1510,7 +1510,7 @@
       "Delete unused subscribers\n" "Keep unused subscribers\n")
 {
 	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->keep_subscr = atoi(argv[0]);
+	gsmnet->subscr_group->keep_subscr = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c
index f6eb5af..cd96c1b 100644
--- a/openbsc/src/libbsc/chan_alloc.c
+++ b/openbsc/src/libbsc/chan_alloc.c
@@ -436,7 +436,7 @@
 struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
 {
 	struct gsm_bts *bts;
-	struct gsm_network *net = subscr->net;
+	struct gsm_network *net = subscr->group->net;
 	struct gsm_lchan *lchan;
 
 	llist_for_each_entry(bts, &net->bts_list, list) {
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 1d37020..5bb8ae2 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -19,6 +19,7 @@
 
 #include <openbsc/gsm_data.h>
 #include <openbsc/osmo_msc_data.h>
+#include <openbsc/gsm_subscriber.h>
 
 struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_code,
 				     int (*mncc_recv)(struct gsm_network *, struct msgb *))
@@ -35,10 +36,17 @@
 		return NULL;
 	}
 
+	net->subscr_group = talloc_zero(net, struct gsm_subscriber_group);
+	if (!net->subscr_group) {
+		talloc_free(net);
+		return NULL;
+	}
+
 	/* Init back pointer */
 	net->bsc_data->auto_off_timeout = -1;
 	net->bsc_data->network = net;
 	INIT_LLIST_HEAD(&net->bsc_data->mscs);
+	net->subscr_group->net = net;
 
 	net->country_code = country_code;
 	net->network_code = network_code;
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c
index 286c57b..f0518bb 100644
--- a/openbsc/src/libbsc/paging.c
+++ b/openbsc/src/libbsc/paging.c
@@ -389,7 +389,7 @@
 		 * location area of the _bts as reconfiguration of the
 		 * network is probably happening less often.
 		 */
-		bts = gsm_bts_by_lac(subscr->net, subscr->lac, bts);
+		bts = gsm_bts_by_lac(subscr->group->net, subscr->lac, bts);
 		if (!bts)
 			break;
 
diff --git a/openbsc/src/libcommon/gsm_subscriber_base.c b/openbsc/src/libcommon/gsm_subscriber_base.c
index 5e00443..3d01ca2 100644
--- a/openbsc/src/libcommon/gsm_subscriber_base.c
+++ b/openbsc/src/libcommon/gsm_subscriber_base.c
@@ -91,18 +91,18 @@
 	subscr->use_count--;
 	DEBUGP(DREF, "subscr %s usage decreased usage to: %d\n",
 			subscr->extension, subscr->use_count);
-	if (subscr->use_count <= 0 && !subscr->net->keep_subscr)
+	if (subscr->use_count <= 0 && !subscr->group->keep_subscr)
 		subscr_free(subscr);
 	return NULL;
 }
 
-struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
+struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp,
 					    const char *imsi)
 {
 	struct gsm_subscriber *subscr;
 
 	llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
-		if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net)
+		if (strcmp(subscr->imsi, imsi) == 0 && subscr->group == sgrp)
 			return subscr_get(subscr);
 	}
 
@@ -112,41 +112,43 @@
 
 	strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH);
 	subscr->imsi[GSM_IMSI_LENGTH - 1] = '\0';
-	subscr->net = net;
+	subscr->group = sgrp;
 	return subscr;
 }
 
-struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_network *net, uint32_t tmsi)
+struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
+					     uint32_t tmsi)
 {
 	struct gsm_subscriber *subscr;
 
 	llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
-		if (subscr->tmsi == tmsi && subscr->net == net)
+		if (subscr->tmsi == tmsi && subscr->group == sgrp)
 			return subscr_get(subscr);
 	}
 
 	return NULL;
 }
 
-struct gsm_subscriber *subscr_active_by_imsi(struct gsm_network *net, const char *imsi)
+struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
+					     const char *imsi)
 {
 	struct gsm_subscriber *subscr;
 
 	llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
-		if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net)
+		if (strcmp(subscr->imsi, imsi) == 0 && subscr->group == sgrp)
 			return subscr_get(subscr);
 	}
 
 	return NULL;
 }
 
-int subscr_purge_inactive(struct gsm_network *net)
+int subscr_purge_inactive(struct gsm_subscriber_group *sgrp)
 {
 	struct gsm_subscriber *subscr, *tmp;
 	int purged = 0;
 
 	llist_for_each_entry_safe(subscr, tmp, subscr_bsc_active_subscribers(), entry) {
-		if (subscr->net == net && subscr->use_count <= 0) {
+		if (subscr->group == sgrp && subscr->use_count <= 0) {
 			subscr_free(subscr);
 			purged += 1;
 		}
diff --git a/openbsc/src/libmsc/ctrl_commands.c b/openbsc/src/libmsc/ctrl_commands.c
index 702a7ae..e48c6a3 100644
--- a/openbsc/src/libmsc/ctrl_commands.c
+++ b/openbsc/src/libmsc/ctrl_commands.c
@@ -67,9 +67,9 @@
 	imsi = strtok_r(tmp, ",", &saveptr);
 	msisdn = strtok_r(NULL, ",", &saveptr);
 
-	subscr = subscr_get_by_imsi(net, imsi);
+	subscr = subscr_get_by_imsi(net->subscr_group, imsi);
 	if (!subscr)
-		subscr = subscr_create_subscriber(net, imsi);
+		subscr = subscr_create_subscriber(net->subscr_group, imsi);
 	if (!subscr)
 		goto fail;
 
@@ -118,7 +118,7 @@
 	struct gsm_subscriber *subscr;
 	struct gsm_network *net = cmd->node;
 
-	subscr = subscr_get_by_imsi(net, cmd->value);
+	subscr = subscr_get_by_imsi(net->subscr_group, cmd->value);
 	if (!subscr) {
 		cmd->reply = "Failed to find subscriber";
 		return CTRL_CMD_ERROR;
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 656c661..bdecbb4 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -1470,7 +1470,7 @@
 		strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
 		sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
 	}
-	sms->receiver = subscr_get_by_extension(net, sms->dst.addr);
+	sms->receiver = subscr_get_by_extension(net->subscr_group, sms->dst.addr);
 
 	sms->src.npi = dbi_result_get_ulonglong(result, "src_npi");
 	sms->src.ton = dbi_result_get_ulonglong(result, "src_ton");
@@ -1597,7 +1597,7 @@
 		return NULL;
 	}
 
-	sms = sms_from_result(subscr->net, result);
+	sms = sms_from_result(subscr->group->net, result);
 
 	dbi_result_free(result);
 
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 8916fe6..ede6db3 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -255,7 +255,7 @@
 	if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
 		return 0;
 
-	switch (subscriber->net->auth_policy) {
+	switch (subscriber->group->net->auth_policy) {
 	case GSM_AUTH_POLICY_CLOSED:
 		return subscriber->authorized;
 	case GSM_AUTH_POLICY_TOKEN:
@@ -498,9 +498,11 @@
 	case GSM_MI_TYPE_IMSI:
 		/* look up subscriber based on IMSI, create if not found */
 		if (!conn->subscr) {
-			conn->subscr = subscr_get_by_imsi(net, mi_string);
+			conn->subscr = subscr_get_by_imsi(net->subscr_group,
+							  mi_string);
 			if (!conn->subscr)
-				conn->subscr = subscr_create_subscriber(net, mi_string);
+				conn->subscr = subscr_create_subscriber(
+					net->subscr_group, mi_string);
 		}
 		if (conn->loc_operation)
 			conn->loc_operation->waiting_for_imsi = 0;
@@ -610,15 +612,16 @@
 		conn->loc_operation->waiting_for_imei = 1;
 
 		/* look up subscriber based on IMSI, create if not found */
-		subscr = subscr_get_by_imsi(bts->network, mi_string);
+		subscr = subscr_get_by_imsi(bts->network->subscr_group, mi_string);
 		if (!subscr) {
-			subscr = subscr_create_subscriber(bts->network, mi_string);
+			subscr = subscr_create_subscriber(
+				bts->network->subscr_group, mi_string);
 		}
 		break;
 	case GSM_MI_TYPE_TMSI:
 		DEBUGPC(DMM, "\n");
 		/* look up the subscriber based on TMSI, request IMSI if it fails */
-		subscr = subscr_get_by_tmsi(bts->network,
+		subscr = subscr_get_by_tmsi(bts->network->subscr_group,
 					    tmsi_from_string(mi_string));
 		if (!subscr) {
 			/* send IDENTITY REQUEST message to get IMSI */
@@ -948,7 +951,7 @@
 	if (is_siemens_bts(bts))
 		send_siemens_mrpci(msg->lchan, classmark2-1);
 
-	subscr = subscr_get_by_tmsi(bts->network,
+	subscr = subscr_get_by_tmsi(bts->network->subscr_group,
 				    tmsi_from_string(mi_string));
 
 	/* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
@@ -995,12 +998,13 @@
 	switch (mi_type) {
 	case GSM_MI_TYPE_TMSI:
 		DEBUGPC(DMM, "\n");
-		subscr = subscr_get_by_tmsi(bts->network,
+		subscr = subscr_get_by_tmsi(bts->network->subscr_group,
 					    tmsi_from_string(mi_string));
 		break;
 	case GSM_MI_TYPE_IMSI:
 		DEBUGPC(DMM, "\n");
-		subscr = subscr_get_by_imsi(bts->network, mi_string);
+		subscr = subscr_get_by_imsi(bts->network->subscr_group,
+					    mi_string);
 		break;
 	case GSM_MI_TYPE_IMEI:
 	case GSM_MI_TYPE_IMEISV:
@@ -1145,11 +1149,12 @@
 
 	switch (mi_type) {
 	case GSM_MI_TYPE_TMSI:
-		subscr = subscr_get_by_tmsi(bts->network,
+		subscr = subscr_get_by_tmsi(bts->network->subscr_group,
 					    tmsi_from_string(mi_string));
 		break;
 	case GSM_MI_TYPE_IMSI:
-		subscr = subscr_get_by_imsi(bts->network, mi_string);
+		subscr = subscr_get_by_imsi(bts->network->subscr_group,
+					    mi_string);
 		break;
 	}
 
@@ -3040,10 +3045,11 @@
 		}
 		/* New transaction due to setup, find subscriber */
 		if (data->called.number[0])
-			subscr = subscr_get_by_extension(net,
+			subscr = subscr_get_by_extension(net->subscr_group,
 							data->called.number);
 		else
-			subscr = subscr_get_by_imsi(net, data->imsi);
+			subscr = subscr_get_by_imsi(net->subscr_group,
+						    data->imsi);
 
 		/* update the subscriber we deal with */
 		log_set_context(BSC_CTX_SUBSCR, subscr);
@@ -3107,7 +3113,8 @@
 			memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
 
 			/* Get a channel */
-			trans->paging_request = talloc_zero(subscr->net, struct gsm_network*);
+			trans->paging_request = talloc_zero(subscr->group->net,
+							    struct gsm_network*);
 			if (!trans->paging_request) {
 				LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
 				subscr_put(subscr);
@@ -3115,7 +3122,7 @@
 				return 0;
 			}
 
-			*trans->paging_request = subscr->net;
+			*trans->paging_request = subscr->group->net;
 			subscr_get_channel(subscr, RSL_CHANNEED_TCH_F, setup_trig_pag_evt, trans->paging_request);
 
 			subscr_put(subscr);
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 1c46b96..bc9d59e 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -392,7 +392,8 @@
 	send_signal(0, NULL, gsms, 0);
 
 	/* determine gsms->receiver based on dialled number */
-	gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dst.addr);
+	gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group,
+						 gsms->dst.addr);
 	if (!gsms->receiver) {
 #ifdef BUILD_SMPP
 		rc = smpp_try_deliver(gsms, conn);
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index bc6f3cf..c444fe0 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -78,12 +78,12 @@
 	REQ_STATE_DISPATCHED,
 };
 
-static struct gsm_subscriber *get_subscriber(struct gsm_network *net,
+static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
 						int type, const char *ident)
 {
 	struct gsm_subscriber *subscr = db_get_subscriber(type, ident);
 	if (subscr)
-		subscr->net = net;
+		subscr->group = sgrp;
 	return subscr;
 }
 
@@ -199,12 +199,13 @@
 {
 	struct subscr_request *request;
 	int rc;
+	struct gsm_network *net = subscr->group->net;
 
 	assert(!llist_empty(&subscr->requests));
 
 	request = (struct subscr_request *)subscr->requests.next;
 	request->state = REQ_STATE_PAGED;
-	rc = paging_request(subscr->net, subscr, request->channel_type,
+	rc = paging_request(net, subscr, request->channel_type,
 			    subscr_paging_cb, subscr);
 
 	/* paging failed, quit now */
@@ -275,16 +276,16 @@
 		subscr_send_paging_request(subscr);
 }
 
-struct gsm_subscriber *subscr_create_subscriber(struct gsm_network *net,
+struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
 					const char *imsi)
 {
 	struct gsm_subscriber *subscr = db_create_subscriber(imsi);
 	if (subscr)
-		subscr->net = net;
+		subscr->group = sgrp;
 	return subscr;
 }
 
-struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net,
+struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_subscriber_group *sgrp,
 					  uint32_t tmsi)
 {
 	char tmsi_string[14];
@@ -297,10 +298,10 @@
 	}
 
 	sprintf(tmsi_string, "%u", tmsi);
-	return get_subscriber(net, GSM_SUBSCRIBER_TMSI, tmsi_string);
+	return get_subscriber(sgrp, GSM_SUBSCRIBER_TMSI, tmsi_string);
 }
 
-struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net,
+struct gsm_subscriber *subscr_get_by_imsi(struct gsm_subscriber_group *sgrp,
 					  const char *imsi)
 {
 	struct gsm_subscriber *subscr;
@@ -310,10 +311,10 @@
 			return subscr_get(subscr);
 	}
 
-	return get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi);
+	return get_subscriber(sgrp, GSM_SUBSCRIBER_IMSI, imsi);
 }
 
-struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net,
+struct gsm_subscriber *subscr_get_by_extension(struct gsm_subscriber_group *sgrp,
 					       const char *ext)
 {
 	struct gsm_subscriber *subscr;
@@ -323,10 +324,10 @@
 			return subscr_get(subscr);
 	}
 
-	return get_subscriber(net, GSM_SUBSCRIBER_EXTENSION, ext);
+	return get_subscriber(sgrp, GSM_SUBSCRIBER_EXTENSION, ext);
 }
 
-struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
+struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
 					unsigned long long id)
 {
 	struct gsm_subscriber *subscr;
@@ -338,7 +339,7 @@
 			return subscr_get(subscr);
 	}
 
-	return get_subscriber(net, GSM_SUBSCRIBER_ID, buf);
+	return get_subscriber(sgrp, GSM_SUBSCRIBER_ID, buf);
 }
 
 int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts)
@@ -370,7 +371,7 @@
 	/* FIXME: Migrate pending requests from one BSC to another */
 	switch (reason) {
 	case GSM_SUBSCRIBER_UPDATE_ATTACHED:
-		s->net = bts->network;
+		s->group = bts->network->subscr_group;
 		/* Indicate "attached to LAC" */
 		s->lac = bts->location_area_code;
 
@@ -412,7 +413,7 @@
 static void subscr_expire_callback(void *data, long long unsigned int id)
 {
 	struct gsm_network *net = data;
-	struct gsm_subscriber *s = subscr_get_by_id(net, id);
+	struct gsm_subscriber *s = subscr_get_by_id(net->subscr_group, id);
 	struct gsm_subscriber_connection *conn = connection_for_subscr(s);
 
 	/*
@@ -438,9 +439,9 @@
 	subscr_put(s);
 }
 
-void subscr_expire(struct gsm_network *net)
+void subscr_expire(struct gsm_subscriber_group *sgrp)
 {
-	db_subscriber_expire(net, subscr_expire_callback);
+	db_subscriber_expire(sgrp->net, subscr_expire_callback);
 }
 
 int subscr_pending_requests(struct gsm_subscriber *sub)
diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c
index 4462dfc..010c2b4 100644
--- a/openbsc/src/libmsc/silent_call.c
+++ b/openbsc/src/libmsc/silent_call.c
@@ -120,7 +120,7 @@
 {
 	int rc;
 
-	rc = paging_request(subscr->net, subscr, type,
+	rc = paging_request(subscr->group->net, subscr, type,
 			    paging_cb_silent, data);
 	return rc;
 }
diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c
index 7e14c74..6861317 100644
--- a/openbsc/src/libmsc/smpp_openbsc.c
+++ b/openbsc/src/libmsc/smpp_openbsc.c
@@ -55,11 +55,11 @@
 
 	switch (npi) {
 	case NPI_Land_Mobile_E212:
-		subscr = subscr_get_by_imsi(net, addr);
+		subscr = subscr_get_by_imsi(net->subscr_group, addr);
 		break;
 	case NPI_ISDN_E163_E164:
 	case NPI_Private:
-		subscr = subscr_get_by_extension(net, addr);
+		subscr = subscr_get_by_extension(net->subscr_group, addr);
 		break;
 	default:
 		LOGP(DSMPP, LOGL_NOTICE, "Unsupported NPI: %u\n", npi);
diff --git a/openbsc/src/libmsc/sms_queue.c b/openbsc/src/libmsc/sms_queue.c
index 536bfdd..3ed8b56 100644
--- a/openbsc/src/libmsc/sms_queue.c
+++ b/openbsc/src/libmsc/sms_queue.c
@@ -135,7 +135,7 @@
 
 	pending->resend = 1;
 
-	smsq = pending->subscr->net->sms_queue;
+	smsq = pending->subscr->group->net->sms_queue;
 	if (osmo_timer_pending(&smsq->resend_pending))
 		return;
 
@@ -149,7 +149,7 @@
 	LOGP(DLSMS, LOGL_NOTICE, "Sending SMS %llu failed %d times.\n",
 	     pending->sms_id, pending->failed_attempts);
 
-	smsq = pending->subscr->net->sms_queue;
+	smsq = pending->subscr->group->net->sms_queue;
 	if (++pending->failed_attempts < smsq->max_fail)
 		return sms_pending_resend(pending);
 
@@ -285,7 +285,7 @@
  */
 static void sms_send_next(struct gsm_subscriber *subscr)
 {
-	struct gsm_sms_queue *smsq = subscr->net->sms_queue;
+	struct gsm_sms_queue *smsq = subscr->group->net->sms_queue;
 	struct gsm_sms_pending *pending;
 	struct gsm_sms *sms;
 
@@ -316,7 +316,7 @@
 
 no_pending_sms:
 	/* Try to send the SMS to avoid the queue being stuck */
-	sms_submit_pending(subscr->net->sms_queue);
+	sms_submit_pending(subscr->group->net->sms_queue);
 }
 
 /*
diff --git a/openbsc/src/libmsc/token_auth.c b/openbsc/src/libmsc/token_auth.c
index 45b5a8e..95fd9b3 100644
--- a/openbsc/src/libmsc/token_auth.c
+++ b/openbsc/src/libmsc/token_auth.c
@@ -59,7 +59,7 @@
 	if (signal != S_SUBSCR_ATTACHED)
 		return 0;
 
-	if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
+	if (subscr->group->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
 		return 0;
 
 	if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
@@ -82,7 +82,7 @@
 
 
 		/* FIXME: don't use ID 1 static */
-		sender = subscr_get_by_id(subscr->net, 1);
+		sender = subscr_get_by_id(subscr->group, 1);
 
 		sms = sms_from_text(subscr, sender, 0, sms_str);
 
@@ -136,7 +136,7 @@
 		return 0;
 
 
-	if (sms->receiver->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
+	if (sms->receiver->group->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
 		return 0;
 
 
diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c
index 4d3aeac..5621067 100644
--- a/openbsc/src/libmsc/transaction.c
+++ b/openbsc/src/libmsc/transaction.c
@@ -66,7 +66,7 @@
 			      uint32_t callref)
 {
 	struct gsm_trans *trans;
-	struct gsm_network *net = subscr->net;
+	struct gsm_network *net = subscr->group->net;
 
 	DEBUGP(DCC, "subscr=%p, net=%p\n", subscr, net);
 
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 8890099..f9213f5 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -169,7 +169,7 @@
 	}
 
 	sms_free(sms);
-	sms_queue_trigger(receiver->net->sms_queue);
+	sms_queue_trigger(receiver->group->net->sms_queue);
 	return CMD_SUCCESS;
 }
 
@@ -178,13 +178,13 @@
 						 const char *id)
 {
 	if (!strcmp(type, "extension"))
-		return subscr_get_by_extension(gsmnet, id);
+		return subscr_get_by_extension(gsmnet->subscr_group, id);
 	else if (!strcmp(type, "imsi"))
-		return subscr_get_by_imsi(gsmnet, id);
+		return subscr_get_by_imsi(gsmnet->subscr_group, id);
 	else if (!strcmp(type, "tmsi"))
-		return subscr_get_by_tmsi(gsmnet, atoi(id));
+		return subscr_get_by_tmsi(gsmnet->subscr_group, atoi(id));
 	else if (!strcmp(type, "id"))
-		return subscr_get_by_id(gsmnet, atoi(id));
+		return subscr_get_by_id(gsmnet->subscr_group, atoi(id));
 
 	return NULL;
 }
@@ -229,7 +229,7 @@
 	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	struct gsm_subscriber *subscr;
 
-	subscr = subscr_create_subscriber(gsmnet, argv[0]);
+	subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]);
 	if (!subscr) {
 		vty_out(vty, "%% No subscriber created for IMSI %s%s",
 			argv[0], VTY_NEWLINE);
@@ -779,7 +779,7 @@
 	struct gsm_network *net = gsmnet_from_vty(vty);
 	int purged;
 
-	purged = subscr_purge_inactive(net);
+	purged = subscr_purge_inactive(net->subscr_group);
 	vty_out(vty, "%d subscriber(s) were purged.%s", purged, VTY_NEWLINE);
 	return CMD_SUCCESS;
 }
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
index dda3157..a801e0e 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
@@ -167,7 +167,7 @@
 		LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
 	}
 
-	subscr = subscr_get_or_create(msc->network, mi_string);
+	subscr = subscr_get_or_create(msc->network->subscr_group, mi_string);
 	if (!subscr) {
 		LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string);
 		return -1;
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_filter.c b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
index 608f525..596bfbd 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_filter.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
@@ -78,11 +78,12 @@
 
 	switch (mi_type) {
 	case GSM_MI_TYPE_TMSI:
-		subscr = subscr_active_by_tmsi(conn->bts->network,
+		subscr = subscr_active_by_tmsi(conn->bts->network->subscr_group,
 					       tmsi_from_string(mi_string));
 		break;
 	case GSM_MI_TYPE_IMSI:
-		subscr = subscr_active_by_imsi(conn->bts->network, mi_string);
+		subscr = subscr_active_by_imsi(conn->bts->network->subscr_group,
+					       mi_string);
 		break;
 	default:
 		subscr = NULL;
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_grace.c b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
index 4e1c79e..aa268a4 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_grace.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
@@ -41,7 +41,7 @@
 {
 	struct gsm_bts *bts = NULL;
 
-	if (subscr->net->bsc_data->rf_ctrl->policy == S_RF_ON)
+	if (subscr->group->net->bsc_data->rf_ctrl->policy == S_RF_ON)
 		goto page;
 
 	/*
@@ -49,7 +49,7 @@
 	 * with NULL and iterate through all bts.
 	 */
 	do {
-		bts = gsm_bts_by_lac(subscr->net, subscr->lac, bts);
+		bts = gsm_bts_by_lac(subscr->group->net, subscr->lac, bts);
 		if (!bts)
 			break;
 
@@ -68,7 +68,8 @@
 	/* All bts are either off or in the grace period */
 	return 0;
 page:
-	return paging_request(subscr->net, subscr, chan_needed, NULL, msc);
+	return paging_request(subscr->group->net, subscr, chan_needed, NULL,
+			      msc);
 }
 
 static int handle_sub(struct gsm_lchan *lchan, const char *text)
diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c
index 031cb99..753fd88 100644
--- a/openbsc/src/osmo-nitb/bsc_hack.c
+++ b/openbsc/src/osmo-nitb/bsc_hack.c
@@ -228,7 +228,7 @@
 
 static void subscr_expire_cb(void *data)
 {
-	subscr_expire(bsc_gsmnet);
+	subscr_expire(bsc_gsmnet->subscr_group);
 	osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
 }