From f6bd340df6bcac716da78da8e35f379a7b853027 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 23 Dec 2010 23:34:43 +0100 Subject: GPRS/GMM: Correctly look up MM Context in RA Update If a MS changes RA, the RA will arrive in the new cell using the old TLLI (masked as foreign TLLI). So we need to look-up the TLLI in a special way, using the old RA as indicated in the 04.08 GMM message. There is still another bug remaining: As we somehow create a new LLC, the sequence numbers of our responses start from 0 again, which is not what the MS expects. This needs to be fixed in a follow-up patch. --- openbsc/src/gprs/gprs_gmm.c | 1 + openbsc/src/gprs/gprs_sgsn.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 817092e31..82a4ca85b 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -899,6 +899,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, } /* Look-up the MM context based on old RA-ID and TLLI */ + mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id); if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) { /* The MS has to perform GPRS attach */ DEBUGPC(DMM, " REJECT\n"); diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index ae18ea0fa..48a00b822 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -82,6 +82,12 @@ static int ra_id_equals(const struct gprs_ra_id *id1, id1->lac == id2->lac && id1->rac == id2->rac); } +/* See 03.02 Chapter 2.6 */ +static inline uint32_t tlli_foreign(uint32_t tlli) +{ + return ((tlli | 0x80000000) & ~0x40000000); +} + /* look-up a SGSN MM context based on TLLI + RAI */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, const struct gprs_ra_id *raid) @@ -96,7 +102,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, } tlli_type = gprs_tlli_type(tlli); - if (tlli_type == TLLI_LOCAL) { + switch (tlli_type) { + case TLLI_LOCAL: llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { if ((ctx->p_tmsi | 0xC0000000) == tlli || (ctx->p_tmsi_old && (ctx->p_tmsi_old | 0xC0000000) == tlli)) { @@ -104,6 +111,16 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, return ctx; } } + break; + case TLLI_FOREIGN: + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (tlli == tlli_foreign(ctx->tlli) && + ra_id_equals(raid, &ctx->ra)) + return ctx; + } + break; + default: + break; } return NULL; -- cgit v1.2.3