diff options
-rw-r--r-- | openbsc/src/gprs/gprs_gmm.c | 58 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 143 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.ok | 6 |
3 files changed, 198 insertions, 9 deletions
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index a966949a4..a2c30bee0 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -803,6 +803,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; uint16_t cid; + enum gsm48_gmm_cause reject_cause; + int rc; LOGP(DMM, LOGL_INFO, "-> GMM ATTACH REQUEST "); @@ -863,8 +865,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); #else ctx = sgsn_mm_ctx_alloc(0, &ra_id); - if (!ctx) - return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_NET_FAIL); + if (!ctx) { + reject_cause = GMM_CAUSE_NET_FAIL; + goto rejected; + } strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi)); #endif } @@ -891,7 +895,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, default: LOGP(DMM, LOGL_NOTICE, "Rejecting ATTACH REQUEST with " "MI type %u\n", mi_type); - return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_MS_ID_NOT_DERIVED); + reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED; + goto rejected; } /* Update MM Context with currient RA and Cell ID */ ctx->ra = ra_id; @@ -923,7 +928,22 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, err_inval: LOGPC(DMM, LOGL_INFO, "\n"); - return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_SEM_INCORR_MSG); + reject_cause = GMM_CAUSE_SEM_INCORR_MSG; + +rejected: + /* Send ATTACH REJECT */ + LOGMMCTXP(LOGL_NOTICE, ctx, + "Rejecting Attach Request with cause '%s' (%d)\n", + get_value_string(gmm_cause_names, reject_cause), reject_cause); + rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause); + if (ctx) + mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ"); + else + /* TLLI unassignment */ + gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL); + + return rc; + } /* Section 4.7.4.1 / 9.4.5.2 MO Detach request */ @@ -1061,6 +1081,8 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, struct gprs_ra_id old_ra_id; struct tlv_parsed tp; uint8_t upd_type; + enum gsm48_gmm_cause reject_cause; + int rc; /* Update Type 10.5.5.18 */ upd_type = *cur++ & 0x0f; @@ -1074,8 +1096,10 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* MS Radio Access Capability 10.5.5.12a */ ms_ra_acc_cap_len = *cur++; - if (ms_ra_acc_cap_len > 52) - return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_PROTO_ERR_UNSPEC); + if (ms_ra_acc_cap_len > 52) { + reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; + goto rejected; + } cur += ms_ra_acc_cap_len; /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status, @@ -1087,8 +1111,8 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, case GPRS_UPD_T_RA_LA: case GPRS_UPD_T_RA_LA_IMSI_ATT: LOGP(DMM, LOGL_NOTICE, "Update type %i unsupported in Mode III, is your SI13 corrupt?\n", upd_type); - return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_PROTO_ERR_UNSPEC); - break; + reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; + goto rejected; case GPRS_UPD_T_RA: case GPRS_UPD_T_PERIODIC: break; @@ -1104,7 +1128,8 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* The MS has to perform GPRS attach */ /* Device is still IMSI attached for CS but initiate GPRS ATTACH, * see GSM 04.08, 4.7.5.1.4 and G.6 */ - return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_IMPL_DETACHED); + reject_cause = GMM_CAUSE_IMPL_DETACHED; + goto rejected; } /* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */ @@ -1150,6 +1175,21 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* Send RA UPDATE ACCEPT */ return gsm48_tx_gmm_ra_upd_ack(mmctx); + +rejected: + /* Send RA UPDATE REJECT */ + LOGMMCTXP(LOGL_NOTICE, mmctx, + "Rejecting RA Update Request with cause '%s' (%d)\n", + get_value_string(gmm_cause_names, reject_cause), reject_cause); + rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause); + if (mmctx) + mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ"); + else + /* TLLI unassignment */ + gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0, + NULL); + + return rc; } static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg) diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 00259a571..1756888fe 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -404,6 +404,148 @@ static void test_gmm_attach(void) sgsn_acl_del("123456789012345", &sgsn->cfg); } +/* + * Test the GMM Rejects + */ +static void test_gmm_reject(void) +{ + struct gprs_ra_id raid = { 0, }; + struct sgsn_mm_ctx *ctx = NULL; + uint32_t foreign_tlli; + struct gprs_llc_lle *lle; + int idx; + + /* DTAP - Attach Request */ + /* Invalid MI length */ + static const unsigned char attach_req_inv_mi_len[] = { + 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x09, 0xf4, + 0xfb, 0xc5, 0x46, 0x79, 0xff, 0xff, 0xff, 0xff, 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 - Attach Request */ + /* Invalid MI type (IMEI) */ + static const unsigned char attach_req_inv_mi_type[] = { + 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x05, 0xf2, + 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 - Routing Area Update Request */ + static const unsigned char dtap_ra_upd_req[] = { + 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, + 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, + 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, + 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, + 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, + 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, + 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 + }; + + /* DTAP - Routing Area Update Request */ + /* Invalid type: GPRS_UPD_T_RA_LA_IMSI_ATT */ + static const unsigned char dtap_ra_upd_req_inv_type[] = { + 0x08, 0x08, 0x12, 0x11, 0x22, 0x33, 0x40, 0x50, + 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, + 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, + 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, + 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, + 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, + 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 + }; + + /* DTAP - Routing Area Update Request */ + /* Invalid cap length */ + static const unsigned char dtap_ra_upd_req_inv_cap_len[] = { + 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, + 0x60, 0x3d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, + 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, + 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, + 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, + 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 + }; + + struct test { + const char *title; + const unsigned char *msg; + unsigned msg_len; + unsigned num_resp; + + }; + static struct test tests[] = { + { + .title = "Attach Request (invalid MI length)", + .msg = attach_req_inv_mi_len, + .msg_len = sizeof(attach_req_inv_mi_len), + .num_resp = 1 /* Reject */ + + }, + { + .title = "Attach Request (invalid MI type)", + .msg = attach_req_inv_mi_type, + .msg_len = sizeof(attach_req_inv_mi_type), + .num_resp = 1 /* Reject */ + }, + { + .title = "Routing Area Update Request (valid)", + .msg = dtap_ra_upd_req, + .msg_len = sizeof(dtap_ra_upd_req), + .num_resp = 2 /* XID Reset + Reject */ + }, + { + .title = "Routing Area Update Request (invalid type)", + .msg = dtap_ra_upd_req_inv_type, + .msg_len = sizeof(dtap_ra_upd_req_inv_type), + .num_resp = 1 /* Reject */ + }, + { + .title = "Routing Area Update Request (invalid CAP length)", + .msg = dtap_ra_upd_req_inv_cap_len, + .msg_len = sizeof(dtap_ra_upd_req_inv_cap_len), + .num_resp = 1 /* Reject */ + }, + }; + + printf("Testing GMM reject\n"); + + /* reset the PRNG used by sgsn_alloc_ptmsi */ + srand(1); + + foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); + + OSMO_ASSERT(count(gprs_llme_list()) == 0); + + for (idx = 0; idx < ARRAY_SIZE(tests); idx++) { + const struct test *test = &tests[idx]; + printf(" - %s\n", test->title); + + /* Create a LLE/LLME */ + lle = gprs_lle_get_or_create(foreign_tlli, 3); + OSMO_ASSERT(count(gprs_llme_list()) == 1); + + /* Inject the Request message */ + send_0408_message(lle->llme, foreign_tlli, + test->msg, test->msg_len); + + /* We expect a Reject message */ + fprintf(stderr, "sgsn_tx_counter = %d (expected %d)\n", + sgsn_tx_counter, test->num_resp); + OSMO_ASSERT(sgsn_tx_counter == test->num_resp); + + /* verify that LLME/MM are removed */ + ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); + OSMO_ASSERT(ctx == NULL); + OSMO_ASSERT(count(gprs_llme_list()) == 0); + } +} + static struct log_info_cat gprs_categories[] = { [DMM] = { .name = "DMM", @@ -473,6 +615,7 @@ int main(int argc, char **argv) test_gmm_detach_no_mmctx(); test_gmm_status_no_mmctx(); test_gmm_attach(); + test_gmm_reject(); printf("Done\n"); return 0; } diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index c03bb1edb..d3b333f8a 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -4,4 +4,10 @@ Testing GMM detach (power off) Testing GMM detach (no MMCTX) Testing GMM Status (no MMCTX) Testing GMM attach +Testing GMM reject + - Attach Request (invalid MI length) + - Attach Request (invalid MI type) + - Routing Area Update Request (valid) + - Routing Area Update Request (invalid type) + - Routing Area Update Request (invalid CAP length) Done |