From 98647ca0ef59430f3cd7ddb7530d85db7fa2688f Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 11 Nov 2014 14:47:38 +0100 Subject: sgsn: Add gsm0408_gprs_access_cancelled This function is called to delete an established MM context silently without invoking a detach procedure. It is called when a subscriber is cancelled by the HLR. This generally happens, when an MS has moved to another routing area and has to use another SGSN. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gprs_gmm.h | 1 + openbsc/src/gprs/gprs_gmm.c | 27 +++++++++ openbsc/src/gprs/sgsn_auth.c | 5 +- openbsc/tests/sgsn/sgsn_test.c | 117 +++++++++++++++++++++++++++++++++++++ openbsc/tests/sgsn/sgsn_test.ok | 1 + 5 files changed, 150 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h index e22706b84..02030b075 100644 --- a/openbsc/include/openbsc/gprs_gmm.h +++ b/openbsc/include/openbsc/gprs_gmm.h @@ -15,6 +15,7 @@ int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx); int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg); void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx); void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx); +void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx); int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli); int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli, diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 60a17ce95..4f19454a6 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -756,6 +756,33 @@ void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *ctx) } } +void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *ctx) +{ + switch (ctx->mm_state) { +#if 0 + case GMM_COMMON_PROC_INIT: + LOGP(DMM, LOGL_NOTICE, + "Cancelled, rejecting ATTACH REQUEST, IMSI=%s\n", + ctx->imsi); + gsm48_tx_gmm_att_rej(ctx, GMM_CAUSE_IMPL_DETACHED); + break; + case GMM_REGISTERED_NORMAL: + case GMM_REGISTERED_SUSPENDED: + LOGP(DMM, LOGL_NOTICE, + "Cancelled, detaching, IMSI=%s\n", + ctx->imsi); + gsm48_tx_gmm_detach_req( + ctx, GPRS_DET_T_MT_REATT_NOTREQ, GMM_CAUSE_IMPL_DETACHED); + break; +#endif + default: + LOGP(DMM, LOGL_INFO, + "Cancelled, deleting context, IMSI=%s\n", + ctx->imsi); + } + mm_ctx_cleanup_free(ctx, "access cancelled"); +} + /* Parse Chapter 9.4.13 Identity Response */ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg) { diff --git a/openbsc/src/gprs/sgsn_auth.c b/openbsc/src/gprs/sgsn_auth.c index 071bdab84..1f11948f1 100644 --- a/openbsc/src/gprs/sgsn_auth.c +++ b/openbsc/src/gprs/sgsn_auth.c @@ -184,7 +184,10 @@ void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) gsm0408_gprs_access_granted(mmctx); break; case SGSN_AUTH_REJECTED: - gsm0408_gprs_access_denied(mmctx); + if (subscr && (subscr->flags & GPRS_SUBSCRIBER_CANCELLED) != 0) + gsm0408_gprs_access_cancelled(mmctx); + else + gsm0408_gprs_access_denied(mmctx); break; default: break; diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 981a557ce..26d81a7f1 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -733,6 +733,122 @@ static void test_gmm_reject(void) } } +/* + * Test cancellation of attached MM contexts + */ +static void test_gmm_cancel(void) +{ + struct gprs_ra_id raid = { 0, }; + struct sgsn_mm_ctx *ctx = NULL; + struct sgsn_mm_ctx *ictx; + uint32_t ptmsi1; + uint32_t foreign_tlli; + uint32_t local_tlli = 0; + struct gprs_llc_lle *lle; + const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; + + /* DTAP - Attach Request */ + /* The P-TMSI is not known by the SGSN */ + static const unsigned char attach_req[] = { + 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x05, 0xf4, + 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, + 0x19, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, + 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, + 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00 + }; + + /* DTAP - Identity Response IMEI */ + static const unsigned char ident_resp_imei[] = { + 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, + 0x56 + }; + + /* DTAP - Identity Response IMSI */ + static const unsigned char ident_resp_imsi[] = { + 0x08, 0x16, 0x08, 0x19, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32, + 0x54 + }; + + /* DTAP - Attach Complete */ + static const unsigned char attach_compl[] = { + 0x08, 0x03 + }; + + printf("Testing cancellation\n"); + + sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_OPEN; + + /* reset the PRNG used by sgsn_alloc_ptmsi */ + srand(1); + + ptmsi1 = sgsn_alloc_ptmsi(); + OSMO_ASSERT(ptmsi1 != GSM_RESERVED_TMSI); + + /* reset the PRNG, so that the same P-TMSI sequence will be generated + * again */ + srand(1); + + foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); + + /* Create a LLE/LLME */ + OSMO_ASSERT(count(gprs_llme_list()) == 0); + lle = gprs_lle_get_or_create(foreign_tlli, 3); + OSMO_ASSERT(count(gprs_llme_list()) == 1); + + /* inject the attach request */ + send_0408_message(lle->llme, foreign_tlli, + attach_req, ARRAY_SIZE(attach_req)); + + ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); + OSMO_ASSERT(ctx != NULL); + OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT); + + /* we expect an identity request (IMEI) */ + OSMO_ASSERT(sgsn_tx_counter == 1); + + /* inject the identity response (IMEI) */ + send_0408_message(ctx->llme, foreign_tlli, + ident_resp_imei, ARRAY_SIZE(ident_resp_imei)); + + /* we expect an identity request (IMSI) */ + OSMO_ASSERT(sgsn_tx_counter == 1); + + /* inject the identity response (IMSI) */ + send_0408_message(ctx->llme, foreign_tlli, + ident_resp_imsi, ARRAY_SIZE(ident_resp_imsi)); + + /* check that the MM context has not been removed due to a failed + * authorization */ + OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid)); + + OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT); + + /* we expect an attach accept/reject */ + OSMO_ASSERT(sgsn_tx_counter == 1); + + /* this has been randomly assigned by the SGSN */ + local_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); + + /* inject the attach complete */ + send_0408_message(ctx->llme, local_tlli, + attach_compl, ARRAY_SIZE(attach_compl)); + + OSMO_ASSERT(ctx->mm_state == GMM_REGISTERED_NORMAL); + + /* we don't expect a response */ + OSMO_ASSERT(sgsn_tx_counter == 0); + + /* cancel */ + gsm0408_gprs_access_cancelled(ctx); + + /* verify that things are gone */ + OSMO_ASSERT(count(gprs_llme_list()) == 0); + ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); + OSMO_ASSERT(!ictx); + + sgsn->cfg.auth_policy = saved_auth_policy; +} + /* * Test the dynamic allocation of P-TMSIs */ @@ -997,6 +1113,7 @@ int main(int argc, char **argv) test_gmm_attach_acl(); test_gmm_attach_subscr(); test_gmm_reject(); + test_gmm_cancel(); test_gmm_ptmsi_allocation(); printf("Done\n"); return 0; diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index 86dd0a211..4b061a5f9 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -13,6 +13,7 @@ Testing GMM reject - Routing Area Update Request (valid) - Routing Area Update Request (invalid type) - Routing Area Update Request (invalid CAP length) +Testing cancellation Testing P-TMSI allocation - sgsn_alloc_ptmsi - Repeated Attach Request -- cgit v1.2.3