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
add struct bsc_sub, separating libbsc from gsm_subscriber
Prepare for replacing gsm_subscriber with vlr_subscriber. vlr_subscriber will
no longer make sense to be used in libbsc, so have a dedicated BSC subscriber
struct.
Related: #1592, #1594
Change-Id: Ia61cc00e8bb186b976939a4fc8f7cf9ce6aa3d8e
---
M openbsc/include/openbsc/Makefile.am
A openbsc/include/openbsc/bsc_subscriber.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/libmsc/gsm_subscriber.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/subscr_test.c
M openbsc/tests/subscr/subscr_test.ok
22 files changed, 416 insertions(+), 123 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/82/1682/2
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 2466ce8..16693d7 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..4d27c8c
--- /dev/null
+++ b/openbsc/include/openbsc/bsc_subscriber.h
@@ -0,0 +1,32 @@
+/* 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 bsc_sub {
+ struct llist_head entry;
+ int use_count;
+
+ char imsi[GSM23003_IMSI_MAX_DIGITS+1];
+ uint32_t tmsi;
+ uint16_t lac;
+};
+
+const char *bsc_sub_name(struct bsc_sub *bsub);
+
+struct bsc_sub *bsc_sub_have_by_imsi(struct llist_head *list, const char *imsi);
+struct bsc_sub *bsc_sub_have_by_tmsi(struct llist_head *list, uint32_t tmsi);
+
+struct bsc_sub *bsc_sub_find_by_imsi(struct llist_head *list, const char *imsi);
+struct bsc_sub *bsc_sub_find_by_tmsi(struct llist_head *list, uint32_t tmsi);
+
+void bsc_sub_set_imsi(struct bsc_sub *bsub, const char *imsi);
+
+struct bsc_sub *_bsc_sub_get(struct bsc_sub *bsub, const char *file, int line);
+struct bsc_sub *_bsc_sub_put(struct bsc_sub *bsub, const char *file, int line);
+#define bsc_sub_get(bsub) _bsc_sub_get(bsub, __BASE_FILE__, __LINE__)
+#define bsc_sub_put(bsub) _bsc_sub_put(bsub, __BASE_FILE__, __LINE__)
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index fd0b89d..c515569 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_sub;
#define GSM48_ALLOC_SIZE 2048
#define GSM48_ALLOC_HEADROOM 256
@@ -77,7 +78,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_sub *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 d477284..9cb46a4 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_sub;
#define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3]
@@ -115,6 +116,9 @@
/* To whom we are allocated at the moment */
struct gsm_subscriber *subscr;
+
+ /* libbsc subscriber information */
+ struct bsc_sub *bsub;
/* LU expiration handling */
uint8_t expire_timer_stopped;
@@ -386,6 +390,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_sub 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..125b52a 100644
--- a/openbsc/include/openbsc/osmo_bsc_grace.h
+++ b/openbsc/include/openbsc/osmo_bsc_grace.h
@@ -22,10 +22,12 @@
#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_sub *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..22fe080 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_sub struct? */
+ struct bsc_sub *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_sub *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_sub *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_sub *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_sub *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 8a6b111..59c5b75 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -1333,10 +1333,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_sub_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..01e4058
--- /dev/null
+++ b/openbsc/src/libbsc/bsc_subscriber.c
@@ -0,0 +1,144 @@
+/* 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_sub *bsc_sub_alloc(struct llist_head *list)
+{
+ struct bsc_sub *bsub;
+
+ bsub = talloc_zero(list, struct bsc_sub);
+ if (!bsub)
+ return NULL;
+
+ llist_add_tail(&bsub->entry, list);
+ bsub->use_count = 1;
+
+ return bsub;
+}
+
+struct bsc_sub *bsc_sub_find_by_imsi(struct llist_head *list, const char *imsi)
+{
+ struct bsc_sub *bsub;
+
+ if (!imsi || !*imsi)
+ return NULL;
+
+ llist_for_each_entry(bsub, list, entry) {
+ if (!strcmp(bsub->imsi, imsi))
+ return bsc_sub_get(bsub);
+ }
+ return NULL;
+}
+
+struct bsc_sub *bsc_sub_find_by_tmsi(struct llist_head *list, uint32_t tmsi)
+{
+ struct bsc_sub *bsub;
+
+ if (tmsi == GSM_RESERVED_TMSI)
+ return NULL;
+
+ llist_for_each_entry(bsub, list, entry) {
+ if (bsub->tmsi == tmsi)
+ return bsc_sub_get(bsub);
+ }
+ return NULL;
+}
+
+void bsc_sub_set_imsi(struct bsc_sub *bsub, const char *imsi)
+{
+ if (!bsub)
+ return;
+ strncpy(bsub->imsi, imsi, sizeof(bsub->imsi));
+}
+
+struct bsc_sub *bsc_sub_have_by_imsi(struct llist_head *list, const char *imsi)
+{
+ struct bsc_sub *bsub;
+ bsub = bsc_sub_find_by_imsi(list, imsi);
+ if (bsub)
+ return bsub;
+ bsub = bsc_sub_alloc(list);
+ bsc_sub_set_imsi(bsub, imsi);
+ return bsub;
+}
+
+struct bsc_sub *bsc_sub_have_by_tmsi(struct llist_head *list, uint32_t tmsi)
+{
+ struct bsc_sub *bsub;
+ bsub = bsc_sub_find_by_tmsi(list, tmsi);
+ if (bsub)
+ return bsub;
+ bsub = bsc_sub_alloc(list);
+ bsub->tmsi = tmsi;
+ return bsub;
+}
+
+const char *bsc_sub_name(struct bsc_sub *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_sub_free(struct bsc_sub *bsub)
+{
+ llist_del(&bsub->entry);
+ talloc_free(bsub);
+}
+
+struct bsc_sub *_bsc_sub_get(struct bsc_sub *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_sub_name(bsub), bsub->use_count);
+ return bsub;
+}
+
+struct bsc_sub *_bsc_sub_put(struct bsc_sub *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_sub_name(bsub), bsub->use_count);
+ if (bsub->use_count <= 0)
+ bsc_sub_free(bsub);
+ return NULL;
+}
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 01ee4df..3f6b68e 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -1009,6 +1009,16 @@
vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
}
+static void bsc_sub_dump_vty(struct vty *vty, struct bsc_sub *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,
@@ -1304,7 +1314,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_sub_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..6e9b608 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_sub *bsub)
{
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
struct gsm48_hdr *gh = msgb_l3(msg);
@@ -292,22 +292,23 @@
if (is_siemens_bts(bts))
send_siemens_mrpci(msg->lchan, classmark2_lv);
- if (!conn->subscr) {
- conn->subscr = subscr;
- } else if (conn->subscr != subscr) {
+ if (!conn->bsub) {
+ conn->bsub = bsub;
+ } else if (conn->bsub != bsub) {
LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
- subscr_put(subscr);
+ bsc_sub_put(bsub);
return -EINVAL;
} else {
DEBUGP(DRR, "<- Channel already owned by us\n");
- subscr_put(subscr);
- subscr = conn->subscr;
+ bsc_sub_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 fcb4deb..fa7e925 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_sub_put(to_be_deleted->bsub);
talloc_free(to_be_deleted);
}
@@ -77,20 +78,17 @@
if (!bts->oml_link)
return;
- log_set_context(BSC_CTX_SUBSCR, request->subscr);
+ LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%08x'\n",
+ request->bsub->imsi, request->bsub->tmsi);
- LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
- request->subscr->imsi, request->subscr->tmsi);
-
- 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(BSC_CTX_SUBSCR, NULL);
}
static void paging_schedule_if_needed(struct gsm_bts_paging_state *paging_bts)
@@ -236,11 +234,12 @@
}
static int paging_pending_request(struct gsm_bts_paging_state *bts,
- struct gsm_subscriber *subscr) {
+ struct bsc_sub *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;
}
@@ -254,10 +253,8 @@
gsm_cbfn *cbfn;
int msg;
- log_set_context(BSC_CTX_SUBSCR, req->subscr);
-
LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
- req, req->subscr->imsi);
+ req, bsc_sub_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]);
@@ -276,21 +273,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_sub *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_sub_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_sub_name(bsub), bts->nr);
req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
- req->subscr = subscr_get(subscr);
+ req->bsub = bsc_sub_get(bsub);
req->bts = bts;
req->chan_type = type;
req->cbfn = cbfn;
@@ -304,8 +302,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_sub *bsub,
+ int type, gsm_cbfn *cbfn, void *data)
{
int rc;
@@ -316,15 +314,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_sub *bsub,
int type, gsm_cbfn *cbfn, void *data)
{
struct gsm_bts *bts = NULL;
@@ -336,13 +333,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;
@@ -356,7 +354,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_sub *bsub,
struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
@@ -366,8 +364,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;
@@ -376,35 +374,38 @@
req = NULL;
if (conn && cbfn) {
- LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
+ LOGP(DPAG, LOGL_DEBUG,
+ "Stop paging on bts %d, calling cbfn.\n",
+ bts->nr);
cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
- msg, conn, param);
+ msg, conn, param);
} else
- LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
+ LOGP(DPAG, LOGL_DEBUG,
+ "Stop paging on bts %d silently.\n",
+ 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_sub *bsub,
struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct gsm_bts *bts;
- log_set_context(BSC_CTX_SUBSCR, subscr);
-
/* 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);
}
}
@@ -433,12 +434,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_sub *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/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index 4ec0ead..f20dfc8 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_sub *bsub;
OSMO_ASSERT(subscr->is_paging);
+
+ /* TODO MSC split */
/*
* Stop paging on all other BTS. E.g. if this is
@@ -91,7 +94,11 @@
* timeout soon as well. Let's just stop everything
* and forget we wanted to page.
*/
- paging_request_stop(NULL, subscr, NULL, NULL);
+ bsub = bsc_sub_have_by_imsi(conn->network->bsc_subscribers, subscr->imsi);
+ bsub->tmsi = subscr->tmsi;
+ bsub->lac = subscr->lac;
+ paging_request_stop(&conn->network->bts_list, NULL, bsub, NULL, NULL);
+ bsc_sub_put(bsub);
/* Inform parts of the system we don't know */
sig_data.subscr = subscr;
@@ -169,13 +176,19 @@
{
int rc;
struct subscr_request *request;
+ struct bsc_sub *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);
+ bsub = bsc_sub_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_sub_put(bsub);
if (rc <= 0) {
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
subscr_name(subscr), rc);
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
index f38c97f..a880f51 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_sub *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_sub_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..64f3fef 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_sub *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_sub *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_sub_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_sub_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_sub *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_sub_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_sub *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_sub_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..4699be6 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_sub *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_sub *subscr, int chan_needed,
+ struct osmo_msc_data *msc)
{
struct gsm_bts *bts = NULL;
@@ -84,10 +83,10 @@
/**
* 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_sub *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 8f0d883..ba4e159 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>
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..0bae94c 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -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/subscr_test.c b/openbsc/tests/subscr/subscr_test.c
index 2a5d0e1..a290a88 100644
--- a/openbsc/tests/subscr/subscr_test.c
+++ b/openbsc/tests/subscr/subscr_test.c
@@ -19,53 +19,109 @@
*/
#include <openbsc/debug.h>
-#include <openbsc/db.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_11.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>
-static struct gsm_network dummy_net;
-static struct gsm_subscriber_group dummy_sgrp;
+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_subscr(const struct bsc_sub *bsub, const char *imsi)
+{
+ struct bsc_sub *sfound;
+ OSMO_ASSERT(bsub);
+ OSMO_ASSERT(strcmp(bsub->imsi, imsi) == 0);
+
+ sfound = bsc_sub_find_by_imsi(bsc_subscribers, imsi);
+ OSMO_ASSERT(sfound == bsub);
+
+ bsc_sub_put(sfound);
+}
+
static void test_subscr(void)
{
- struct gsm_subscriber *subscr;
- const char *imsi = "1234567890";
+ struct bsc_sub *s1, *s2, *s3;
+ const char *imsi1 = "1234567890";
+ const char *imsi2 = "9876543210";
+ const char *imsi3 = "5656565656";
- printf("Test subscriber allocation and deletion\n");
+ printf("Test BSC subscriber allocation and deletion\n");
- /* Don't keep subscr */
+ /* Check for emptiness */
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 0, "%d");
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi1) == NULL);
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi2) == NULL);
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi3) == NULL);
- dummy_sgrp.keep_subscr = 0;
+ /* Allocate entry 1 */
+ s1 = bsc_sub_have_by_imsi(bsc_subscribers, imsi1);
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d");
+ assert_subscr(s1, imsi1);
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d");
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi2) == NULL);
- OSMO_ASSERT(llist_empty(&active_subscribers));
+ /* Allocate entry 2 */
+ s2 = bsc_sub_have_by_imsi(bsc_subscribers, imsi2);
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 2, "%d");
- subscr = subscr_get_or_create(&dummy_sgrp, imsi);
+ /* Allocate entry 3 */
+ s3 = bsc_sub_have_by_imsi(bsc_subscribers, imsi3);
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 3, "%d");
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 1);
+ /* Check entries */
+ assert_subscr(s1, imsi1);
+ assert_subscr(s2, imsi2);
+ assert_subscr(s3, imsi3);
- subscr_put(subscr);
+ /* Free entry 1 */
+ bsc_sub_put(s1);
+ s1 = NULL;
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 2, "%d");
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi1) == NULL);
- OSMO_ASSERT(llist_empty(&active_subscribers));
+ assert_subscr(s2, imsi2);
+ assert_subscr(s3, imsi3);
+ /* Free entry 2 */
+ bsc_sub_put(s2);
+ s2 = NULL;
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d");
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi1) == NULL);
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi2) == NULL);
+ assert_subscr(s3, imsi3);
+
+ /* Free entry 3 */
+ bsc_sub_put(s3);
+ s3 = NULL;
+ VERBOSE_ASSERT(llist_count(bsc_subscribers), == 0, "%d");
+ OSMO_ASSERT(bsc_sub_find_by_imsi(bsc_subscribers, imsi3) == NULL);
+
+ OSMO_ASSERT(llist_empty(bsc_subscribers));
+
+#if 0
/* Keep subscr */
dummy_sgrp.keep_subscr = 1;
subscr = subscr_get_or_create(&dummy_sgrp, imsi);
- OSMO_ASSERT(!llist_empty(&active_subscribers));
+ OSMO_ASSERT(!llist_empty(&bsc_subscribers));
OSMO_ASSERT(subscr->use_count == 1);
subscr_put(subscr);
- OSMO_ASSERT(!llist_empty(&active_subscribers));
+ OSMO_ASSERT(!llist_empty(&bsc_subscribers));
OSMO_ASSERT(subscr->use_count == 0);
subscr_get(subscr);
@@ -73,16 +129,16 @@
subscr_purge_inactive(&dummy_sgrp);
- OSMO_ASSERT(!llist_empty(&active_subscribers));
+ OSMO_ASSERT(!llist_empty(&bsc_subscribers));
OSMO_ASSERT(subscr->use_count == 1);
subscr_put(subscr);
- OSMO_ASSERT(!llist_empty(&active_subscribers));
+ OSMO_ASSERT(!llist_empty(&bsc_subscribers));
OSMO_ASSERT(subscr->use_count == 0);
subscr_purge_inactive(&dummy_sgrp);
- OSMO_ASSERT(llist_empty(&active_subscribers));
+ OSMO_ASSERT(llist_empty(&bsc_subscribers));
/* Test force_no_keep */
@@ -92,13 +148,14 @@
OSMO_ASSERT(subscr);
subscr->keep_in_ram = 1;
- OSMO_ASSERT(!llist_empty(&active_subscribers));
+ OSMO_ASSERT(!llist_empty(&bsc_subscribers));
OSMO_ASSERT(subscr->use_count == 1);
subscr->keep_in_ram = 0;
subscr_put(subscr);
- OSMO_ASSERT(llist_empty(&active_subscribers));
+ OSMO_ASSERT(llist_empty(&bsc_subscribers));
+#endif
}
int main()
@@ -106,9 +163,12 @@
printf("Testing 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);
- dummy_net.subscr_group = &dummy_sgrp;
- dummy_sgrp.net = &dummy_net;
+ bsc_subscribers = talloc_zero(NULL, struct llist_head);
+ INIT_LLIST_HEAD(bsc_subscribers);
test_subscr();
diff --git a/openbsc/tests/subscr/subscr_test.ok b/openbsc/tests/subscr/subscr_test.ok
index 72a3769..13e8dfa 100644
--- a/openbsc/tests/subscr/subscr_test.ok
+++ b/openbsc/tests/subscr/subscr_test.ok
@@ -1,3 +1,11 @@
Testing subscriber core code.
-Test subscriber allocation and deletion
+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
--
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: 2
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>