aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 2b94096f6..d6a9bdada 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 8399ea137..88e037e9d 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 818106190..d419f0a92 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 cff29205d..e5df50482 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)