diff options
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/sgsn.h | 4 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_subscriber.c | 47 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_vty.c | 35 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 35 |
5 files changed, 119 insertions, 3 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index c92d1cc7b..e707c77d7 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -276,6 +276,7 @@ struct sgsn_subscriber_data { struct gsm_auth_tuple auth_triplets[5]; int auth_triplets_updated; int error_cause; + struct osmo_timer_list timer; }; #define LOGGSUBSCRP(level, subscr, fmt, args...) \ diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 78064dddc..8a4514627 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -7,6 +7,8 @@ #include <osmocom/gprs/gprs_ns.h> #include <openbsc/gprs_sgsn.h> +#define SGSN_TIMEOUT_NEVER (-1) + struct gprs_gsup_client; enum sgsn_auth_policy { @@ -31,6 +33,8 @@ struct sgsn_config { struct sockaddr_in gsup_server_addr; int gsup_server_port; + int subscriber_expiry_timeout; + int require_authentication; int require_update_location; }; diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c index 9fe6ad2f7..9d79f0006 100644 --- a/openbsc/src/gprs/gprs_subscriber.c +++ b/openbsc/src/gprs/gprs_subscriber.c @@ -73,6 +73,43 @@ static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg) return rc; } +static void sgsn_subscriber_timeout_cb(void *subscr_); +int gprs_subscr_purge(struct gsm_subscriber *subscr); + +void gprs_subscr_stop_timer(struct gsm_subscriber *subscr) +{ + if (subscr->sgsn_data->timer.data) { + osmo_timer_del(&subscr->sgsn_data->timer); + subscr->sgsn_data->timer.cb = NULL; + OSMO_ASSERT(subscr->sgsn_data->timer.data == subscr); + subscr->sgsn_data->timer.data = NULL; + subscr_put(subscr); + } +} + +void gprs_subscr_start_timer(struct gsm_subscriber *subscr, unsigned seconds) +{ + if (!subscr->sgsn_data->timer.data) { + subscr->sgsn_data->timer.cb = sgsn_subscriber_timeout_cb; + subscr->sgsn_data->timer.data = subscr_get(subscr); + } + + osmo_timer_schedule(&subscr->sgsn_data->timer, seconds, 0); +} + +static void sgsn_subscriber_timeout_cb(void *subscr_) +{ + struct gsm_subscriber *subscr = subscr_; + + LOGGSUBSCRP(LOGL_INFO, subscr, + "Expired, deleting subscriber entry\n"); + + /* Make sure, the timer is cleaned up */ + subscr->keep_in_ram = 0; + gprs_subscr_stop_timer(subscr); + /* The subscr is freed now, if the timer was the last user */ +} + static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx) { struct sgsn_subscriber_data *sdata; @@ -97,7 +134,7 @@ struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi) if (!subscr->sgsn_data) subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr); - subscr->keep_in_ram = 1; + gprs_subscr_stop_timer(subscr); return subscr; } @@ -116,8 +153,14 @@ void gprs_subscr_delete(struct gsm_subscriber *subscr) } if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) || - (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) + (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) { subscr->keep_in_ram = 0; + gprs_subscr_stop_timer(subscr); + } else if (sgsn->cfg.subscriber_expiry_timeout != SGSN_TIMEOUT_NEVER) { + gprs_subscr_start_timer(subscr, sgsn->cfg.subscriber_expiry_timeout); + } else { + subscr->keep_in_ram = 1; + } subscr_put(subscr); } diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 4deb2acb4..1241c17e5 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -151,6 +151,10 @@ static int config_write_sgsn(struct vty *vty) llist_for_each_entry(acl, &g_cfg->imsi_acl, list) vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE); + if (g_cfg->subscriber_expiry_timeout != SGSN_TIMEOUT_NEVER) + vty_out(vty, " subscriber-expiry-timeout %d%s", + g_cfg->subscriber_expiry_timeout, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -401,6 +405,7 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, char expire_time[200]; struct gsm_auth_tuple *at; int at_idx; + struct timeval tv; vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, subscr->authorized, VTY_NEWLINE); @@ -446,6 +451,17 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE); } + /* print the expiration time if the timer is active */ + if (osmo_timer_pending(&subscr->sgsn_data->timer)) { + osmo_timer_remaining(&subscr->sgsn_data->timer, NULL, &tv); + strftime(expire_time, sizeof(expire_time), + "%a, %d %b %Y %T %z", + localtime(&subscr->sgsn_data->timer.timeout.tv_sec)); + expire_time[sizeof(expire_time) - 1] = '\0'; + vty_out(vty, " Expires in: %ds (%s)%s", + (int)tv.tv_sec, expire_time, VTY_NEWLINE); + } + if (subscr->flags) vty_out(vty, " Flags: %s%s%s%s%s", subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT ? @@ -687,7 +703,24 @@ DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd, return CMD_SUCCESS; } +DEFUN(cfg_subscriber_expiry_timeout, cfg_subscriber_expiry_timeout_cmd, + "subscriber-expiry-timeout <0-999999>", + "Set the expiry time for unused subscriber entries\n" + "Expiry time in seconds\n") +{ + g_cfg->subscriber_expiry_timeout = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_no_subscriber_expiry_timeout, cfg_no_subscriber_expiry_timeout_cmd, + "no subscriber-expiry-timeout", + NO_STR "Set the expiry time for unused subscriber entries\n") +{ + g_cfg->subscriber_expiry_timeout = atoi(argv[0]); + + return CMD_SUCCESS; +} int sgsn_vty_init(void) { @@ -716,6 +749,8 @@ int sgsn_vty_init(void) install_element(SGSN_NODE, &cfg_auth_policy_cmd); install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd); install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd); + install_element(SGSN_NODE, &cfg_subscriber_expiry_timeout_cmd); + install_element(SGSN_NODE, &cfg_no_subscriber_expiry_timeout_cmd); return 0; } diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 78321ce0c..adaa32804 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -44,6 +44,7 @@ static struct sgsn_instance sgsn_inst = { .cfg = { .gtp_statedir = "./", .auth_policy = SGSN_AUTH_POLICY_CLOSED, + .subscriber_expiry_timeout = SGSN_TIMEOUT_NEVER, }, }; struct sgsn_instance *sgsn = &sgsn_inst; @@ -200,9 +201,11 @@ static void assert_subscr(const struct gsm_subscriber *subscr, const char *imsi) static void test_subscriber(void) { - struct gsm_subscriber *s1, *s2, *sfound; + struct gsm_subscriber *s1, *s2, *s3, *sfound; const char *imsi1 = "1234567890"; const char *imsi2 = "9876543210"; + const char *imsi3 = "5656565656"; + int saved_expiry_timeout = sgsn->cfg.subscriber_expiry_timeout; update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data; @@ -211,6 +214,7 @@ static void test_subscriber(void) /* Check for emptiness */ OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi3) == NULL); /* Allocate entry 1 */ s1 = gprs_subscr_get_or_create(imsi1); @@ -222,9 +226,13 @@ static void test_subscriber(void) s2 = gprs_subscr_get_or_create(imsi2); s2->flags |= GSM_SUBSCRIBER_FIRST_CONTACT; + /* Allocate entry 3 */ + s3 = gprs_subscr_get_or_create(imsi3); + /* Check entries */ assert_subscr(s1, imsi1); assert_subscr(s2, imsi2); + assert_subscr(s3, imsi3); /* Update entry 1 */ last_updated_subscr = NULL; @@ -251,12 +259,34 @@ static void test_subscriber(void) s1 = NULL; OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); assert_subscr(s2, imsi2); + assert_subscr(s3, imsi3); /* Free entry 2 (GSM_SUBSCRIBER_FIRST_CONTACT is set) */ gprs_subscr_delete(s2); s2 = NULL; OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); + assert_subscr(s3, imsi3); + + /* Try to delete entry 3 */ + OSMO_ASSERT(sgsn->cfg.subscriber_expiry_timeout == SGSN_TIMEOUT_NEVER); + gprs_subscr_delete(s3); + assert_subscr(s3, imsi3); + /* Process timeouts, this shouldn't delete s3 (SGSN_TIMEOUT_NEVER) */ + osmo_timers_update(); + assert_subscr(s3, imsi3); + s3 = subscr_get(s3); + + /* Free entry 3 (TIMEOUT == 0) */ + sgsn->cfg.subscriber_expiry_timeout = 0; + gprs_subscr_delete(s3); + assert_subscr(s3, imsi3); + /* Process timeouts, this should delete s3 */ + osmo_timers_update(); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi3) == NULL); + sgsn->cfg.subscriber_expiry_timeout = saved_expiry_timeout; OSMO_ASSERT(llist_empty(&active_subscribers)); @@ -862,6 +892,7 @@ static void test_gmm_attach_subscr(void) subscr = gprs_subscr_get_or_create("123456789012345"); subscr->authorized = 1; + subscr->keep_in_ram = 1; subscr_put(subscr); printf("Auth policy 'remote': "); @@ -895,6 +926,7 @@ static void test_gmm_attach_subscr_fake_auth(void) subscr = gprs_subscr_get_or_create("123456789012345"); subscr->authorized = 1; + subscr->keep_in_ram = 1; sgsn->cfg.require_authentication = 1; sgsn->cfg.require_update_location = 1; subscr_put(subscr); @@ -936,6 +968,7 @@ static void test_gmm_attach_subscr_real_auth(void) subscr = gprs_subscr_get_or_create("123456789012345"); subscr->authorized = 1; + subscr->keep_in_ram = 1; sgsn->cfg.require_authentication = 1; sgsn->cfg.require_update_location = 1; subscr_put(subscr); |