sgsn: Cleanup after RA Update Reject / Attach Reject

Currently, the LLME is not cleaned up after sending an RA Update
Reject. This happens after entering a routing area from outside,
since in that case the SGSN sends an RA Update Reject (implicitly
detached) which causes the MS to restart the attach procedure.
The LLME is also not updated if an Attach Request with message errors
(encoding, invalid MI type) is received or if an MM context cannot be
allocated.

This patch changes gsm48_rx_gmm_ra_upd_req and gsm48_rx_gmm_att_req
to unassign the LLME or free the MM context (if available) after a
Reject message has been sent.

Ticket: OW#1324
Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2014-11-06 13:43:41 +01:00 committed by Holger Hans Peter Freyther
parent 106f547733
commit 80d07e30c7
3 changed files with 198 additions and 9 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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