diff options
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 12 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_subscriber.c | 56 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 92 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.ok | 1 |
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) |