aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h1
-rw-r--r--openbsc/include/openbsc/sgsn.h4
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c47
-rw-r--r--openbsc/src/gprs/sgsn_vty.c35
-rw-r--r--openbsc/tests/sgsn/sgsn_test.c35
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);