SGSN: Avoid duplicate MM contexts in case MS and SGSN disagree on P-TMSI
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index fb1b288..b470c53 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -119,6 +119,7 @@
 /* Allocate a new SGSN MM context */
 struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
 					const struct gprs_ra_id *raid);
+void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm);
 
 
 enum pdp_ctx_state {
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index ee6e366..4f1fe05 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -594,6 +594,19 @@
 		/* we already have a mm context with current TLLI, but no
 		 * P-TMSI / IMSI yet.  What we now need to do is to fill
 		 * this initial context with data from the HLR */
+		if (strlen(ctx->imsi) == 0) {
+			/* Check if we already have a MM context for this IMSI */
+			struct sgsn_mm_ctx *ictx;
+			ictx = sgsn_mm_ctx_by_imsi(mi_string);
+			if (ictx) {
+				DEBUGP(DMM, "Deleting old MM Context for same IMSI ",
+				       "p_tmsi_old=0x%08x, p_tmsi_new=0x%08x\n",
+					ictx->p_tmsi, ctx->p_tmsi);
+				gprs_llgmm_assign(ictx->llme, ictx->tlli,
+						  0xffffffff, GPRS_ALGO_GEA0, NULL);
+				sgsn_mm_ctx_free(ictx);
+			}
+		}
 		strncpy(ctx->imsi, mi_string, sizeof(ctx->imei));
 		break;
 	case GSM_MI_TYPE_IMEI:
@@ -704,6 +717,8 @@
 		if (!ctx)
 			ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
 		if (!ctx) {
+			/* Allocate a context as most of our code expects one.
+			 * Context will not have an IMSI ultil ID RESP is received */
 			ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
 			ctx->p_tmsi = tmsi;
 		}
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index f558003..142ff47 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -173,6 +173,21 @@
 	return ctx;
 }
 
+void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
+{
+	struct sgsn_pdp_ctx *pdp, *pdp2;
+
+	/* Unlink from global list of MM contexts */
+	llist_del(&mm->list);
+
+	/* Free all PDP contexts */
+	llist_for_each_entry_safe(pdp, pdp2, &mm->pdp_list, list)
+		sgsn_pdp_ctx_free(pdp);
+	
+	rate_ctr_group_free(mm->ctrg);
+
+	talloc_free(mm);
+}
 
 /* look up PDP context by MM context and NSAPI */
 struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,