summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-08 16:23:25 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-19 08:30:01 +0100
commita688976f10bfb0c14954a066aa133f28bce3a541 (patch)
tree4cc0642f3b953433a5064d4992dbdad51a67c4ac
parent743dec4c0c80383556efac60f03d307287ecf024 (diff)
gprs: Block other GSUP procedures during PURGE_MS
GSM 09.02, 19.4.1.4 mandates that no other MAP procedures shall be started until the PURGE_MS procedure has been completed. This patch implements this by adding corresponding state and checks to gprs_subscr_purge, gprs_subscr_location_update, and gprs_subscr_update_auth_info. If an Update Location or a Send Auth Info Req procedure is not started because of blocking, the retry mechanism is aborted to shorten the blocking time. The outstanding Purge MS procedure itself is not aborted. Sponsored-by: On-Waves ehf
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h12
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c56
-rw-r--r--openbsc/tests/sgsn/sgsn_test.c92
-rw-r--r--openbsc/tests/sgsn/sgsn_test.ok1
4 files changed, 160 insertions, 1 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 2b94096..d6a9bda 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -271,6 +271,13 @@ struct imsi_acl_entry {
char imsi[16+1];
};
+enum sgsn_subscriber_proc {
+ SGSN_SUBSCR_PROC_NONE = 0,
+ SGSN_SUBSCR_PROC_PURGE,
+ SGSN_SUBSCR_PROC_UPD_LOC,
+ SGSN_SUBSCR_PROC_UPD_AUTH,
+};
+
struct sgsn_subscriber_data {
struct sgsn_mm_ctx *mm;
struct gsm_auth_tuple auth_triplets[5];
@@ -278,6 +285,7 @@ struct sgsn_subscriber_data {
int error_cause;
struct osmo_timer_list timer;
int retries;
+ enum sgsn_subscriber_proc blocked_by;
};
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
@@ -324,6 +332,10 @@ void gprs_subscr_update(struct gsm_subscriber *subscr);
void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr);
int gprs_subscr_rx_gsup_message(struct msgb *msg);
+int gprs_subscr_purge(struct gsm_subscriber *subscr);
+int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr);
+int gprs_subscr_location_update(struct gsm_subscriber *subscr);
+
/* Called on subscriber data updates */
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx,
struct gsm_subscriber *subscr);
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 8399ea1..88e037e 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -76,6 +76,23 @@ static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
return rc;
}
+static int check_blocking(
+ struct gsm_subscriber *subscr,
+ enum sgsn_subscriber_proc what)
+{
+ if (subscr->sgsn_data->blocked_by == SGSN_SUBSCR_PROC_NONE ||
+ subscr->sgsn_data->blocked_by == what)
+ return 1;
+
+ return 0;
+}
+
+static void abort_blocking_procedure(struct gsm_subscriber *subscr)
+{
+ /* Best effort, stop retries at least */
+ subscr->sgsn_data->retries = SGSN_SUBSCR_MAX_RETRIES;
+}
+
static void sgsn_subscriber_timeout_cb(void *subscr_);
int gprs_subscr_purge(struct gsm_subscriber *subscr);
@@ -132,6 +149,10 @@ static void sgsn_subscriber_timeout_cb(void *subscr_)
return;
force_cleanup:
+ /* Make sure to clear blocking */
+ if (check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE))
+ subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
+
/* Make sure, the timer is cleaned up */
subscr->keep_in_ram = 0;
gprs_subscr_stop_timer(subscr);
@@ -544,17 +565,42 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
int gprs_subscr_purge(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
+ int rc;
+
+ if (!check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE)) {
+ LOGGSUBSCRP(
+ LOGL_NOTICE, subscr,
+ "Cannot purge MS subscriber, blocked\n");
+ return -EAGAIN;
+ }
+
+ /* GSM 09.02, 19.4.1.4 requires other MAP requests to be blocked until
+ * this procedure is completed
+ */
+ subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_PURGE;
LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
- return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
+ rc = gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
+ if (rc < 0)
+ subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
+
+ return rc;
}
int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
+ if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_AUTH)) {
+ LOGGSUBSCRP(
+ LOGL_NOTICE, subscr,
+ "Cannot start update auth info request procedure, blocked\n");
+ abort_blocking_procedure(subscr);
+ return -EAGAIN;
+ }
+
LOGGSUBSCRP(LOGL_INFO, subscr,
"subscriber auth info is not available\n");
@@ -566,6 +612,14 @@ int gprs_subscr_location_update(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
+ if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_LOC)) {
+ LOGGSUBSCRP(
+ LOGL_NOTICE, subscr,
+ "Cannot start update location procedure, blocked\n");
+ abort_blocking_procedure(subscr);
+ return -EAGAIN;
+ }
+
LOGGSUBSCRP(LOGL_INFO, subscr,
"subscriber data is not available\n");
diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c
index 8181061..d419f0a 100644
--- a/openbsc/tests/sgsn/sgsn_test.c
+++ b/openbsc/tests/sgsn/sgsn_test.c
@@ -546,6 +546,97 @@ static void test_subscriber_gsup(void)
update_subscriber_data_cb = __real_sgsn_update_subscriber_data;
}
+int my_gprs_gsup_client_send_dummy(struct gprs_gsup_client *gsupc, struct msgb *msg)
+{
+ msgb_free(msg);
+ return 0;
+};
+
+
+static void test_subscriber_blocking(void)
+{
+ struct gsm_subscriber *s1;
+ const char *imsi1 = "1234567890";
+ struct sgsn_mm_ctx *ctx;
+ struct gprs_ra_id raid = { 0, };
+ uint32_t local_tlli = 0xffeeddcc;
+ struct gprs_llc_llme *llme;
+ int rc;
+
+ printf("Testing subcriber procedure blocking\n");
+
+ gprs_gsup_client_send_cb = my_gprs_gsup_client_send_dummy;
+ sgsn->gsup_client = talloc_zero(tall_bsc_ctx, struct gprs_gsup_client);
+
+ /* Check for emptiness */
+ OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
+
+ /* Create a context */
+ OSMO_ASSERT(count(gprs_llme_list()) == 0);
+ ctx = alloc_mm_ctx(local_tlli, &raid);
+ llme = ctx->llme;
+ strncpy(ctx->imsi, imsi1, sizeof(ctx->imsi) - 1);
+
+ /* Allocate and attach a subscriber */
+ s1 = gprs_subscr_get_or_create_by_mmctx(ctx);
+ assert_subscr(s1, imsi1);
+
+ /* Start SendAuthInfoRequest procedure */
+ rc = gprs_subscr_query_auth_info(s1);
+ /* Not blocking */
+ OSMO_ASSERT(rc == 0);
+
+ /* Start UpdateLocation procedure */
+ rc = gprs_subscr_location_update(s1);
+ /* Blocking */
+ OSMO_ASSERT(rc == 0);
+
+ /* Start PurgeMS procedure */
+ rc = gprs_subscr_purge(s1);
+ /* Not blocking */
+ OSMO_ASSERT(rc == 0);
+ OSMO_ASSERT(s1->sgsn_data->blocked_by == SGSN_SUBSCR_PROC_PURGE);
+
+ /* Start PurgeMS procedure (retry) */
+ rc = gprs_subscr_purge(s1);
+ /* Not blocking */
+ OSMO_ASSERT(rc == 0);
+
+ /* Start SendAuthInfoRequest procedure */
+ rc = gprs_subscr_query_auth_info(s1);
+ /* Blocking */
+ OSMO_ASSERT(rc == -EAGAIN);
+
+ /* Start UpdateLocation procedure */
+ rc = gprs_subscr_location_update(s1);
+ /* Blocking */
+ OSMO_ASSERT(rc == -EAGAIN);
+
+ /* Unblock manually (normally done by the caller of gprs_subscr_purge) */
+ s1->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
+
+ /* Start SendAuthInfoRequest procedure */
+ rc = gprs_subscr_query_auth_info(s1);
+ /* Not blocking */
+ OSMO_ASSERT(rc == 0);
+
+ /* Start UpdateLocation procedure */
+ rc = gprs_subscr_location_update(s1);
+ /* Blocking */
+ OSMO_ASSERT(rc == 0);
+
+ subscr_put(s1);
+ sgsn_mm_ctx_free(ctx);
+ gprs_llgmm_assign(llme, local_tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
+
+ assert_no_subscrs();
+
+ gprs_gsup_client_send_cb = __real_gprs_gsup_client_send;
+ talloc_free(sgsn->gsup_client);
+ sgsn->gsup_client = NULL;
+}
+
+
/*
* Test that a GMM Detach will remove the MMCTX and the
* associated LLME.
@@ -1710,6 +1801,7 @@ int main(int argc, char **argv)
test_subscriber();
test_auth_triplets();
test_subscriber_gsup();
+ test_subscriber_blocking();
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 cff2920..e5df504 100644
--- a/openbsc/tests/sgsn/sgsn_test.ok
+++ b/openbsc/tests/sgsn/sgsn_test.ok
@@ -2,6 +2,7 @@ Testing LLME allocations
Testing core subscriber data API
Testing authentication triplet handling
Testing subcriber GSUP handling
+Testing subcriber procedure blocking
Testing GMM detach
Testing GMM detach (power off)
Testing GMM detach (no MMCTX)