[GPRS] SGSN: TMSI allocation
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index b7e0a1b..e8b1677 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -178,4 +178,6 @@
 extern struct llist_head sgsn_apn_ctxts;
 extern struct llist_head sgsn_pdp_ctxts;
 
+uint32_t sgsn_alloc_ptmsi(void);
+
 #endif /* _GPRS_SGSN_H */
diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h
index e314b56..5433e2b 100644
--- a/openbsc/include/openbsc/gsm_04_08_gprs.h
+++ b/openbsc/include/openbsc/gsm_04_08_gprs.h
@@ -63,11 +63,12 @@
 #define GPRS_UPD_T_PERIODIC		3
 
 enum gsm48_gprs_ie_mm {
-	GSM48_IE_GMM_TIMER_READY	= 0x17, /* 10.5.7.3 */
+	GSM48_IE_GMM_TIMER_READY	= 0x17,	/* 10.5.7.3 */
+	GSM48_IE_GMM_ALLOC_PTMSI	= 0x18,	/* 10.5.1.4 */
 	GSM48_IE_GMM_PTMSI_SIG		= 0x19,	/* 10.5.5.8 */
-	GSM48_IE_GMM_AUTH_RAND		= 0x21, /* 10.5.3.1 */
-	GSM48_IE_GMM_AUTH_SRES		= 0x22, /* 10.5.3.2 */
-	GSM48_IE_GMM_IMEISV		= 0x23, /* 10.5.1.4 */
+	GSM48_IE_GMM_AUTH_RAND		= 0x21,	/* 10.5.3.1 */
+	GSM48_IE_GMM_AUTH_SRES		= 0x22,	/* 10.5.3.2 */
+	GSM48_IE_GMM_IMEISV		= 0x23,	/* 10.5.1.4 */
 	GSM48_IE_GMM_DRX_PARAM		= 0x27,	/* 10.5.5.6 */
 	GSM48_IE_GMM_MS_NET_CAPA	= 0x31,	/* 10.5.5.12 */
 };
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index f22421a..9fee9e1 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -196,16 +196,16 @@
 };
 
 /* Chapter 9.4.2: Attach accept */
-static int gsm48_tx_gmm_att_ack(struct msgb *old_msg)
+static int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 	struct gsm48_attach_ack *aa;
-	struct gprs_ra_id ra_id;
+	char *ptsig, *mid;
 
 	DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n");
 
-	gmm_copy_id(msg, old_msg);
+	mmctx2msgid(msg, mm);
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM_GPRS;
@@ -216,23 +216,35 @@
 	aa->att_result = 1;	/* GPRS only */
 	aa->ra_upd_timer = GPRS_TMR_MINUTE | 10;
 	aa->radio_prio = 4;	/* lowest */
-	bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg));
-	gsm48_construct_ra(aa->ra_id.digits, &ra_id);
+	gsm48_construct_ra(aa->ra_id.digits, &mm->ra);
 
-	/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
+	/* Optional: P-TMSI signature */
+	msgb_v_put(msg, GSM48_IE_GMM_PTMSI_SIG);
+	ptsig = msgb_put(msg, 3);
+	ptsig[0] = mm->p_tmsi_sig >> 16;
+	ptsig[1] = mm->p_tmsi_sig >> 8;
+	ptsig[2] = mm->p_tmsi_sig & 0xff;
+
+	/* Optional: Negotiated Ready timer value */
+
+	/* Optional: Allocated P-TMSI */
+	msgb_v_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
+	mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
+	gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
+
+	/* Optional: MS-identity (combined attach) */
+	/* Optional: GMM cause (partial attach result for combined attach) */
+
 	return gsm48_gmm_sendmsg(msg, 0, NULL);
 }
 
 /* Chapter 9.4.5: Attach reject */
-static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, uint8_t gmm_cause)
+static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause)
 {
-	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
 	DEBUGP(DMM, "<- GPRS ATTACH REJECT\n");
 
-	gmm_copy_id(msg, old_msg);
-
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 	gh->proto_discr = GSM48_PDISC_MM_GPRS;
 	gh->msg_type = GSM48_MT_GMM_ATTACH_REJ;
@@ -240,15 +252,31 @@
 
 	return gsm48_gmm_sendmsg(msg, 0, NULL);
 }
+static int gsm48_tx_gmm_att_rej_oldmsg(const struct msgb *old_msg,
+					uint8_t gmm_cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	gmm_copy_id(msg, old_msg);
+	return _tx_gmm_att_rej(msg, gmm_cause);
+}
+static int gsm48_tx_gmm_att_rej(struct sgsn_mm_ctx *mm,
+				uint8_t gmm_cause)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	mmctx2msgid(msg, mm);
+	return _tx_gmm_att_rej(msg, gmm_cause);
+}
 
 /* Chapter 9.4.6.2 Detach accept */
-static gsm48_tx_gmm_det_ack(struct msgb *old_msg, uint8_t force_stby)
+static gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
 	DEBUGP(DMM, "<- GPRS DETACH ACCEPT\n");
 
+	mmctx2msgid(msg, mm);
+
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 	gh->proto_discr = GSM48_PDISC_MM_GPRS;
 	gh->msg_type = GSM48_MT_GMM_DETACH_ACK;
@@ -258,14 +286,14 @@
 }
 
 /* Transmit Chapter 9.4.12 Identity Request */
-static int gsm48_tx_gmm_id_req(struct msgb *old_msg, uint8_t id_type)
+static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 
 	DEBUGP(DMM, "-> GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type);
 
-	gmm_copy_id(msg, old_msg);
+	mmctx2msgid(msg, mm);
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
 	gh->proto_discr = GSM48_PDISC_MM_GPRS;
@@ -277,17 +305,17 @@
 }
 
 /* Check if we can already authorize a subscriber */
-static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg)
+static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
 {
 	if (strlen(ctx->imei) && strlen(ctx->imsi)) {
 		ctx->mm_state = GMM_REGISTERED_NORMAL;
-		return gsm48_tx_gmm_att_ack(msg);
+		return gsm48_tx_gmm_att_ack(ctx);
 	} 
 	if (!strlen(ctx->imei))
-		return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMEI);
+		return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMEI);
 
 	if (!strlen(ctx->imsi))
-		return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMSI);
+		return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMSI);
 
 	return 0;
 }
@@ -325,15 +353,14 @@
 
 	DEBUGPC(DMM, "\n");
 	/* Check if we can let the mobile station enter */
-	return gsm48_gmm_authorize(ctx, msg);
+	return gsm48_gmm_authorize(ctx);
 }
 
 static void attach_rej_cb(void *data)
 {
 	struct sgsn_mm_ctx *ctx = data;
 
-	/* FIXME: determine through which BTS/TRX to send this */
-	//gsm48_tx_gmm_att_rej(ctx->tlli, GMM_CAUSE_MS_ID_NOT_DERIVED);
+	gsm48_tx_gmm_att_rej(ctx, GMM_CAUSE_MS_ID_NOT_DERIVED);
 	ctx->mm_state = GMM_DEREGISTERED;
 	/* FIXME: release the context */
 }
@@ -413,7 +440,7 @@
 			/* As a temorary hack, we simply assume that the IMSI exists */
 			ctx = sgsn_mm_ctx_alloc(0, &ra_id);
 			if (!ctx)
-				return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_NET_FAIL);
+				return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_NET_FAIL);
 			strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
 #endif
 		}
@@ -433,6 +460,7 @@
 			ctx->tlli = msgb_tlli(msg);
 			msgid2mmctx(ctx, msg);
 		}
+		ctx->p_tmsi = tmsi;
 		break;
 	default:
 		return 0;
@@ -441,16 +469,18 @@
 	ctx->ra = ra_id;
 	ctx->cell_id = cid;
 
-	/* FIXME: allocate a new P-TMSI (+ P-TMSI signature) */
+	/* Allocate a new P-TMSI (+ P-TMSI signature) */
+	ctx->p_tmsi = sgsn_alloc_ptmsi();
+
 	/* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */
 
 	DEBUGPC(DMM, "\n");
 
-	return ctx ? gsm48_gmm_authorize(ctx, msg) : 0;
+	return ctx ? gsm48_gmm_authorize(ctx) : 0;
 
 err_inval:
 	DEBUGPC(DMM, "\n");
-	return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_SEM_INCORR_MSG);
+	return gsm48_tx_gmm_att_rej_oldmsg(msg, GMM_CAUSE_SEM_INCORR_MSG);
 }
 
 /* Section 4.7.4.1 / 9.4.5.2 MO Detach request */
@@ -472,20 +502,19 @@
 	ctx->mm_state = GMM_DEREGISTERED;
 
 	/* force_stby = 0 */
-	return gsm48_tx_gmm_det_ack(msg, 0);
+	return gsm48_tx_gmm_det_ack(ctx, 0);
 }
 
 /* Chapter 9.4.15: Routing area update accept */
-static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg)
+static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
 {
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 	struct gsm48_ra_upd_ack *rua;
-	struct gprs_ra_id ra_id;
 
 	DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n");
 
-	gmm_copy_id(msg, old_msg);
+	mmctx2msgid(msg, mm);
 
 	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM_GPRS;
@@ -496,8 +525,7 @@
 	rua->upd_result = 0;	/* RA updated */
 	rua->ra_upd_timer = GPRS_TMR_MINUTE | 10;
 
-	bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg));
-	gsm48_construct_ra(rua->ra_id.digits, &ra_id);
+	gsm48_construct_ra(rua->ra_id.digits, &mm->ra);
 
 	/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
 	return gsm48_gmm_sendmsg(msg, 0, NULL);
@@ -574,7 +602,7 @@
 	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
 
 	DEBUGPC(DMM, " ACCEPT\n");
-	return gsm48_tx_gmm_ra_upd_ack(msg);
+	return gsm48_tx_gmm_ra_upd_ack(mmctx);
 }
 
 static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
@@ -838,6 +866,7 @@
 		pdp->ti = transaction_id;
 		
 	}
+	return 0;
 #else
 	return gsm48_tx_gsm_act_pdp_acc(mmctx, transaction_id, act_req);
 #endif
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 2671796..af8f896 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -251,3 +251,18 @@
 	return actx;
 }
 #endif
+
+uint32_t sgsn_alloc_ptmsi(void)
+{
+	struct sgsn_mm_ctx *mm;
+	uint32_t ptmsi;
+
+restart:
+	ptmsi = rand();
+	llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
+		if (mm->p_tmsi == ptmsi)
+			goto restart;
+	}
+
+	return ptmsi;
+}