diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-11-12 10:12:11 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-12-09 09:23:11 +0100 |
commit | 33b6dadc884ec1060e401ba097523086ac34b552 (patch) | |
tree | d9b98c7a8f84f941b2830b81c03290ac020fa4cc | |
parent | 70d8e31a748026a92e5739147411dcf512df7205 (diff) |
sgsn: Add gprs_subscriber.c
This patch adds GPRS specific functions for gsm_subscriber objects
(allocation, retrieval, deletion) and subscriber data
requests/updates. The sgsn_update_subscriber_data callback is used to
notify the sgsn about updates and is extended by a parameter that
passes a reference to a gsm_subscriber.
Sponsored-by: On-Waves ehf
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 17 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_subscriber.h | 1 | ||||
-rw-r--r-- | openbsc/src/gprs/Makefile.am | 2 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_sgsn.c | 3 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_subscriber.c | 144 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_main.c | 3 | ||||
-rw-r--r-- | openbsc/tests/sgsn/Makefile.am | 5 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 98 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.ok | 1 |
9 files changed, 267 insertions, 7 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 3e80ae21f..b1358131a 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -287,8 +287,23 @@ int sgsn_auth_request(struct sgsn_mm_ctx *mm); enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm); void sgsn_auth_update(struct sgsn_mm_ctx *mm); +/* + * GPRS subscriber data + */ +#define GPRS_SUBSCRIBER_UPDATE_PENDING (1 << 16) +#define GPRS_SUBSCRIBER_CANCELLED (1 << 17) + +void gprs_subscr_init(struct sgsn_instance *sgi); +int gprs_subscr_request_update(struct sgsn_mm_ctx *mmctx); +void gprs_subscr_delete(struct gsm_subscriber *subscr); +struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi); +struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi); +void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr); +void gprs_subscr_update(struct gsm_subscriber *subscr); + /* Called on subscriber data updates */ -void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx); +void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx, + struct gsm_subscriber *subscr); int gprs_sndcp_vty_init(void); struct sgsn_instance; diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 46fc87f51..195fa0fd0 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -13,6 +13,7 @@ #define GSM_MAX_EXTEN 49999 #define GSM_SUBSCRIBER_FIRST_CONTACT 0x00000001 +/* gprs_sgsn.h defines additional flags including and above bit 16 (0x10000) */ #define tmsi_from_string(str) strtoul(str, NULL, 10) #define GSM_SUBSCRIBER_NO_EXPIRATION 0x0 diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 75eafddd3..f937362a4 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -22,7 +22,7 @@ osmo_gbproxy_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ - sgsn_ctrl.c sgsn_auth.c + sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c osmo_sgsn_LDADD = \ $(top_builddir)/src/libcommon/libcommon.a \ -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 39bfa84bc..71cd742df 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -452,7 +452,8 @@ int sgsn_force_reattach_oldmsg(struct msgb *oldmsg) return gsm0408_gprs_force_reattach_oldmsg(oldmsg); } -void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx) +void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx, + struct gsm_subscriber *subscr) { OSMO_ASSERT(mmctx); diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c new file mode 100644 index 000000000..78fa3e1e8 --- /dev/null +++ b/openbsc/src/gprs/gprs_subscriber.c @@ -0,0 +1,144 @@ +/* MS subscriber data handling */ + +/* (C) 2014 by sysmocom s.f.m.c. GmbH + * + * 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 <openbsc/gsm_subscriber.h> + +#include <openbsc/sgsn.h> +#include <openbsc/gprs_sgsn.h> +#include <openbsc/gprs_gmm.h> + +#include <openbsc/debug.h> + +extern void *tall_bsc_ctx; + +void gprs_subscr_init(struct sgsn_instance *sgi) +{ +} + +struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi) +{ + struct gsm_subscriber *subscr; + + subscr = subscr_get_or_create(NULL, imsi); + if (!subscr) + return NULL; + + subscr->keep_in_ram = 1; + + return subscr; +} + +struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi) +{ + return subscr_active_by_imsi(NULL, imsi); +} + +void gprs_subscr_delete(struct gsm_subscriber *subscr) +{ + if (subscr->mm) { + subscr_put(subscr->mm->subscr); + subscr->mm->subscr = NULL; + subscr->mm = NULL; + } + + if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) || + (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) + subscr->keep_in_ram = 0; + + subscr_put(subscr); +} + +void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr) +{ + subscr->authorized = 0; + subscr->flags |= GPRS_SUBSCRIBER_CANCELLED; + + gprs_subscr_update(subscr); + + gprs_subscr_delete(subscr); +} + +int gprs_subscr_query(struct gsm_subscriber *subscr) +{ + /* TODO: Implement remote query to MSC, ... */ + + LOGMMCTXP(LOGL_INFO, subscr->mm, + "subscriber data is not available (remote query NYI)\n"); + return -ENOTSUP; +} + +void gprs_subscr_update(struct gsm_subscriber *subscr) +{ + LOGMMCTXP(LOGL_DEBUG, subscr->mm, "Updating subscriber data\n"); + + subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_PENDING; + subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT; + + sgsn_update_subscriber_data(subscr->mm, subscr); +} + +int gprs_subscr_request_update(struct sgsn_mm_ctx *mmctx) +{ + struct gsm_subscriber *subscr = NULL; + int need_update = 0; + int rc; + + LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n"); + + if (mmctx->subscr) { + subscr = subscr_get(mmctx->subscr); + } else if (mmctx->imsi[0]) { + subscr = gprs_subscr_get_by_imsi(mmctx->imsi); + need_update = 1; + } + + if (!subscr) { + subscr = gprs_subscr_get_or_create(mmctx->imsi); + subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT; + need_update = 1; + } + + if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) { + strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1); + subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0; + need_update = 1; + } + + if (subscr->lac != mmctx->ra.lac) { + subscr->lac = mmctx->ra.lac; + need_update = 1; + } + + if (need_update) { + subscr->flags |= GPRS_SUBSCRIBER_UPDATE_PENDING; + if (!mmctx->subscr) { + subscr->mm = mmctx; + mmctx->subscr = subscr_get(subscr); + } + + rc = gprs_subscr_query(subscr); + subscr_put(subscr); + return rc; + } + gprs_subscr_update(subscr); + subscr_put(subscr); + return 0; +} diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 0310cb2b2..141eacf94 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -58,9 +58,6 @@ #include "../../bscconfig.h" -/* this is here for the vty... it will never be called */ -void subscr_put() { abort(); } - #define _GNU_SOURCE #include <getopt.h> diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index f822aac44..0e5d009e8 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -6,6 +6,9 @@ EXTRA_DIST = sgsn_test.ok noinst_PROGRAMS = sgsn_test sgsn_test_SOURCES = sgsn_test.c +sgsn_test_LDFLAGS = \ + -Wl,--wrap=sgsn_update_subscriber_data + sgsn_test_LDADD = \ $(top_builddir)/src/gprs/gprs_llc_parse.o \ $(top_builddir)/src/gprs/gprs_llc.o \ @@ -16,6 +19,8 @@ sgsn_test_LDADD = \ $(top_builddir)/src/gprs/sgsn_vty.o \ $(top_builddir)/src/gprs/sgsn_libgtp.o \ $(top_builddir)/src/gprs/sgsn_auth.o \ + $(top_builddir)/src/gprs/gprs_subscriber.o \ + $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOGB_LIBS) \ diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 533c393c8..2eb6f388f 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -23,6 +23,7 @@ #include <openbsc/sgsn.h> #include <openbsc/gprs_gmm.h> #include <openbsc/debug.h> +#include <openbsc/gsm_subscriber.h> #include <osmocom/gprs/gprs_bssgp.h> @@ -55,6 +56,18 @@ int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, return 0; } +/* override, requires '-Wl,--wrap=sgsn_update_subscriber_data' */ +void __real_sgsn_update_subscriber_data(struct sgsn_mm_ctx *, struct gsm_subscriber *); +void (*update_subscriber_data_cb)(struct sgsn_mm_ctx *, struct gsm_subscriber *) = + &__real_sgsn_update_subscriber_data; + +void __wrap_sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx, + struct gsm_subscriber *subscr) +{ + (*update_subscriber_data_cb)(mmctx, subscr); +} + + static int count(struct llist_head *head) { struct llist_head *cur; @@ -146,6 +159,88 @@ static void test_llme(void) OSMO_ASSERT(count(gprs_llme_list()) == 0); } +struct gsm_subscriber *last_updated_subscr = NULL; +void my_dummy_sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx, + struct gsm_subscriber *subscr) +{ + fprintf(stderr, "Called %s, mmctx = %p, subscr = %p\n", + __func__, mmctx, subscr); + last_updated_subscr = subscr; +} + +static void test_subscriber(void) +{ + struct gsm_subscriber *s1, *s2, *s1found, *s2found; + const char *imsi1 = "1234567890"; + const char *imsi2 = "9876543210"; + + update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data; + + printf("Testing core subscriber data API\n"); + + /* Check for emptiness */ + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); + + /* Allocate entry 1 */ + s1 = gprs_subscr_get_or_create(imsi1); + s1->flags |= GSM_SUBSCRIBER_FIRST_CONTACT; + s1found = gprs_subscr_get_by_imsi(imsi1); + OSMO_ASSERT(s1found == s1); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); + subscr_put(s1found); + + /* Allocate entry 2 */ + s2 = gprs_subscr_get_or_create(imsi2); + s2->flags |= GSM_SUBSCRIBER_FIRST_CONTACT; + s1found = gprs_subscr_get_by_imsi(imsi1); + s2found = gprs_subscr_get_by_imsi(imsi2); + OSMO_ASSERT(s1found == s1); + OSMO_ASSERT(s2found == s2); + subscr_put(s1found); + subscr_put(s2found); + + /* Update entry 1 */ + last_updated_subscr = NULL; + gprs_subscr_update(s1); + OSMO_ASSERT(last_updated_subscr == s1); + + /* Because of the update, it won't be freed on delete now */ + gprs_subscr_delete(s1); + s1found = gprs_subscr_get_by_imsi(imsi1); + OSMO_ASSERT(s1found != NULL); + s1 = s1found; + + /* Cancel it, so that delete will free it. + * Refcount it to make sure s1 won't be freed here */ + last_updated_subscr = NULL; + gprs_subscr_put_and_cancel(subscr_get(s1)); + OSMO_ASSERT(last_updated_subscr == s1); + + /* Cancelled entries are still being found */ + s1found = gprs_subscr_get_by_imsi(imsi1); + OSMO_ASSERT(s1found != NULL); + subscr_put(s1found); + + /* Free entry 1 */ + gprs_subscr_delete(s1); + s1 = NULL; + s2found = gprs_subscr_get_by_imsi(imsi2); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); + OSMO_ASSERT(s2found == s2); + subscr_put(s2found); + + /* Free entry 2 */ + gprs_subscr_delete(s2); + s2 = NULL; + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); + + OSMO_ASSERT(llist_empty(&active_subscribers)); + + update_subscriber_data_cb = __real_sgsn_update_subscriber_data; +} + /* * Test that a GMM Detach will remove the MMCTX and the * associated LLME. @@ -778,7 +873,6 @@ static void test_gmm_ptmsi_allocation(void) sgsn->cfg.auth_policy = saved_auth_policy; } - static struct log_info_cat gprs_categories[] = { [DMM] = { .name = "DMM", @@ -841,8 +935,10 @@ int main(int argc, char **argv) tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb"); sgsn_auth_init(); + gprs_subscr_init(sgsn); test_llme(); + test_subscriber(); test_gmm_detach(); test_gmm_detach_power_off(); test_gmm_detach_no_mmctx(); diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index db9631193..1ee80be76 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -1,4 +1,5 @@ Testing LLME allocations +Testing core subscriber data API Testing GMM detach Testing GMM detach (power off) Testing GMM detach (no MMCTX) |