diff options
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 2 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_sgsn.c | 38 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 136 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.ok | 4 |
4 files changed, 180 insertions, 0 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 24e286c70..b3f250dc5 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -369,6 +369,8 @@ void sgsn_inst_init(void); * ottherwise lost state (recovery procedure) */ int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn); +void drop_gmm_ctx_for_ms(const char *imsi); + char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len); /* diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index e5a54d9b4..8558029a1 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -667,6 +667,44 @@ static void drop_one_pdp(struct sgsn_pdp_ctx *pdp) } } +/* + * High-level function to be called for PDP deactivation initiated from SGSN VTY. + * When there are PDP contexts present for a MM context, PDP context will be + * deactivated along with GMM Detach(MM context deletion). + * If there are no PDP present, MM context will be deleted to avoid further + * PDP context activation for that MS. + */ +void drop_gmm_ctx_for_ms(const char *imsi) +{ + OSMO_ASSERT(imsi != NULL); + struct sgsn_mm_ctx *mm; + struct sgsn_pdp_ctx *pdp; + + /* Search the MM context subscriber */ + mm = sgsn_mm_ctx_by_imsi(imsi); + LOGMMCTXP(LOGL_INFO, mm, + "SGSN intiated Deactivate PDP request for %s\n", imsi); + if (mm) { + /* Search the PDP for this subscriber */ + if (llist_empty(&mm->pdp_list)) { + /* + * Deleting mm context for the subscriber when no PDP + * context is present. + */ + gsm0408_gprs_access_cancelled(mm, GMM_CAUSE_GPRS_NOTALLOWED); + LOGMMCTXP(LOGL_NOTICE, mm, "No PDP context to deactivate\n"); + } else { + llist_for_each_entry(pdp, &mm->pdp_list, list) { + gsm48_tx_gsm_deact_pdp_req(pdp, GSM_CAUSE_DEACT_REGULAR); + LOGPDPCTXP(LOGL_INFO, pdp, "PDP Deactivation " + "Successful\n"); + } + } + } else + LOGMMCTXP(LOGL_NOTICE, mm, + "No MM context to deactivate for %s\n", imsi); +} + /* High-level function to be called in case a GGSN has disappeared or * otherwise lost state (recovery procedure) */ int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn) diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index e7b74585b..6f01d4417 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -38,14 +38,17 @@ #include <osmocom/core/rate_ctr.h> #include <stdio.h> +#include <gtp.h> void *tall_bsc_ctx; +struct gsn_t gsn_ctx; static struct sgsn_instance sgsn_inst = { .config_file = "osmo_sgsn.cfg", .cfg = { .gtp_statedir = "./", .auth_policy = SGSN_AUTH_POLICY_CLOSED, }, + .gsn = &gsn_ctx, }; struct sgsn_instance *sgsn = &sgsn_inst; unsigned sgsn_tx_counter = 0; @@ -2363,6 +2366,138 @@ static void test_ggsn_selection(void) cleanup_test(); } +static void test_pdp_deactivation_with_pdp_ctx(void) +{ + struct apn_ctx *actxs[4]; + struct sgsn_ggsn_ctx *ggc, *ggcs[3]; + struct gsm_subscriber *s1; + const char *imsi1 = "1234567890"; + struct sgsn_mm_ctx *ctx; + struct gprs_ra_id raid = { 0, }; + uint32_t local_tlli = 0xffeeddcc; + enum gsm48_gsm_cause gsm_cause; + struct tlv_parsed tp; + uint8_t apn_enc[GSM_APN_LENGTH + 10]; + struct sgsn_subscriber_pdp_data *pdp_data; + char apn_str[GSM_APN_LENGTH]; + + printf("Testing Pdp deactivation for MS with pdp ctx\n"); + + gprs_gsup_client_send_cb = my_gprs_gsup_client_send_dummy; + + /* 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); + 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); + + struct sgsn_pdp_ctx *pdp; + + tp.lv[GSM48_IE_GSM_APN].len = 0; + tp.lv[GSM48_IE_GSM_APN].val = apn_enc; + + tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = 2; + tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = apn_enc; + + tp.lv[OSMO_IE_GSM_REQ_QOS].len = 14; + tp.lv[OSMO_IE_GSM_REQ_QOS].val = apn_enc; + + ggcs[0] = sgsn_ggsn_ctx_find_alloc(0); + + actxs[0] = sgsn_apn_ctx_find_alloc("test.apn", "123456"); + actxs[0]->ggsn = ggcs[0]; + + pdp_data = sgsn_subscriber_pdp_data_alloc(s1->sgsn_data); + pdp_data->context_id = 1; + pdp_data->pdp_type = 0x0121; + strncpy(pdp_data->apn_str, "*", sizeof(pdp_data->apn_str)-1); + + /* Resolve GGSNs */ + tp.lv[GSM48_IE_GSM_APN].len = + gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn"); + + ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); + + OSMO_ASSERT(ggc != NULL); + OSMO_ASSERT(ggc->id == 0); + + ggc = sgsn_ggsn_ctx_alloc(ggc->id); + /* Create a pdp context */ + pdp = sgsn_create_pdp_ctx(ggc, ctx, 5, &tp); + + /* Intiate PDP deactivation for imsi1 */ + drop_gmm_ctx_for_ms(imsi1); + gsm48_tx_gsm_deact_pdp_acc(pdp); + gsm0408_gprs_access_cancelled(ctx, GMM_CAUSE_GPRS_NOTALLOWED); + + /* Cleanup */ + + subscr_put(s1); + + sgsn_apn_ctx_free(actxs[0]); + sgsn_ggsn_ctx_free(ggcs[0]); + sgsn_ggsn_ctx_free(ggc); + talloc_free(pdp); + + cleanup_test(); +} + +static void test_pdp_deactivation_with_only_mm_ctx(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; + + printf("Testing Pdp deactivation for MS with only MM ctx\n"); + + gprs_gsup_client_send_cb = my_gprs_gsup_client_send_dummy; + + /* 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); + 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); + + /* Intiate PDP deactivation for imsi1 */ + drop_gmm_ctx_for_ms(imsi1); + + cleanup_test(); +} + +static void test_pdp_deactivation_without_mm_ctx(void) +{ + const char *imsi1 = "1234567890"; + + printf("Testing Pdp deactivation for MS without MM ctx\n"); + + /* Intiate PDP deactivation for imsi1 */ + drop_gmm_ctx_for_ms(imsi1); + + cleanup_test(); +} + +static void test_pdp_deactivation(void) +{ + printf("Testing pdp deactivation\n"); + + test_pdp_deactivation_with_pdp_ctx(); + test_pdp_deactivation_without_mm_ctx(); + test_pdp_deactivation_with_only_mm_ctx(); +} static struct log_info_cat gprs_categories[] = { [DMM] = { .name = "DMM", @@ -2454,6 +2589,7 @@ int main(int argc, char **argv) test_gmm_routing_areas(); test_apn_matching(); test_ggsn_selection(); + test_pdp_deactivation(); printf("Done\n"); talloc_report_full(osmo_sgsn_ctx, stderr); diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index c7a53b9e5..c36b64341 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -34,4 +34,8 @@ Testing routing area changes - RA Update Request (RA 2 -> RA 2) Testing APN matching Testing GGSN selection +Testing pdp deactivation +Testing Pdp deactivation for MS with pdp ctx +Testing Pdp deactivation for MS without MM ctx +Testing Pdp deactivation for MS with only MM ctx Done |