aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/src/gprs/gprs_gmm.c1
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c19
2 files changed, 19 insertions, 1 deletions
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;