sgsn: Change Auth&Ciph timer handling

Currently mmctx_timer_start is called from within
gsm48_tx_gmm_auth_ciph_req which differs from the way e.g. the
identification procedure is implemented. It also makes it more
difficult to restart the procedure after timeout, which is not
implemented yet. In addition, the timer is not properly stopped when
an AUTH & CIPH response is received.

This patch removes this timer start from gsm48_tx_gmm_auth_ciph_req,
adds the retransmission of Auth & Ciph requests to the timer callback
function, and properly stops the timer in
gsm48_rx_gmm_auth_ciph_resp.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 4572ac2..1ffeb9f 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -10,6 +10,8 @@
 
 #include <osmocom/crypt/gprs_cipher.h>
 
+#include <openbsc/gsm_data.h>
+
 #define GSM_IMSI_LENGTH 17
 #define GSM_IMEI_LENGTH 17
 #define GSM_EXTENSION_LENGTH 15
@@ -84,7 +86,8 @@
 	uint32_t		sac_age;/* Iu: Service Area Code age */
 	/* VLR number */
 	uint32_t		new_sgsn_addr;
-	/* Authentication Triplets */
+	/* Authentication Triplet */
+	struct gsm_auth_tuple	auth_triplet;
 	/* Kc */
 	/* Iu: CK, IK, KSI */
 	/* CKSN */
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index 8820396..6f54194 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -571,9 +571,6 @@
 		m_cksn[0] = (GSM48_IE_GMM_CIPH_CKSN << 4) | (key_seq & 0x07);
 	}
 
-	/* Start T3360 */
-	mmctx_timer_start(mm, 3360, GSM0408_T3360_SECS);
-
 	/* FIXME: make sure we don't send any other messages to the MS */
 
 	return gsm48_gmm_sendmsg(msg, 1, mm);
@@ -604,7 +601,8 @@
 	struct gsm48_auth_ciph_resp *acr = (struct gsm48_auth_ciph_resp *)gh->data;
 	struct tlv_parsed tp;
 
-	/* FIXME: Stop T3360 */
+	/* Stop T3360 */
+	mmctx_timer_stop(ctx, 3360);
 
 	tlv_parse(&tp, &gsm48_gmm_att_tlvdef, acr->data,
 			(msg->data + msg->len) - acr->data, 0, 0);
@@ -1332,6 +1330,7 @@
 static void mmctx_timer_cb(void *_mm)
 {
 	struct sgsn_mm_ctx *mm = _mm;
+	struct gsm_auth_tuple *at;
 
 	mm->num_T_exp++;
 
@@ -1367,7 +1366,16 @@
 			mm_ctx_cleanup_free(mm, "T3360");
 			break;
 		}
-		/* FIXME: re-transmit the respective msg and re-start timer */
+		/* Re-transmit the respective msg and re-start timer */
+		if (mm->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
+			LOGMMCTXP(LOGL_ERROR, mm,
+				  "timeout: invalid auth triplet reference\n");
+			mm_ctx_cleanup_free(mm, "T3360");
+			break;
+		}
+		at = &mm->auth_triplet;
+
+		gsm48_tx_gmm_auth_ciph_req(mm, at->rand, at->key_seq, GPRS_ALGO_GEA0);
 		osmo_timer_schedule(&mm->timer, GSM0408_T3360_SECS, 0);
 		break;
 	case 3370:	/* waiting for IDENTITY RESPONSE */
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 62cdf0a..39bfa84 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -167,6 +167,7 @@
 	memcpy(&ctx->ra, raid, sizeof(ctx->ra));
 	ctx->tlli = tlli;
 	ctx->mm_state = GMM_DEREGISTERED;
+	ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
 	ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
 	INIT_LLIST_HEAD(&ctx->pdp_list);