gbproxy: Send DETACH_ACC if the IMSI has not been acquired

If IMSI acquisition is enabled and the gbproxy receives a Detach
request from the MS, it cannot pass it to the SGSN since the
acquisition has not yet been completed.

This patch implements the generation of a Detach Accept message and
for this case and updates the TLLI state accordingly.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 344e164..ee80375 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -110,6 +110,17 @@
 	gh->data[0] = id_type;
 }
 
+/* Transmit Chapter 9.4.6.2 Detach Accept (mobile originated detach) */
+static void gprs_put_mo_detach_acc(struct msgb *msg)
+{
+	struct gsm48_hdr *gh;
+
+	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;
+	gh->data[0] = 0; /* no force to standby */
+}
+
 static void gprs_push_llc_ui(struct msgb *msg,
 			     int is_uplink, unsigned sapi, unsigned nu)
 {
@@ -348,6 +359,21 @@
 	msgb_free(idreq_msg);
 }
 
+static void gbproxy_tx_detach_acc(struct gbproxy_peer *peer,
+				  struct gbproxy_tlli_info* tlli_info,
+				  uint16_t bvci)
+{
+	struct msgb *detacc_msg;
+
+	/* Send DETACH ACC */
+	detacc_msg = gsm48_msgb_alloc();
+	gprs_put_mo_detach_acc(detacc_msg);
+	gprs_push_llc_ui(detacc_msg, 0, GPRS_SAPI_GMM,
+			 (tlli_info->imsi_acq_retries + 256) % 512);
+	gprs_push_bssgp_dl_unitdata(detacc_msg, tlli_info->tlli.current);
+	gbprox_relay2peer(detacc_msg, peer, bvci);
+	msgb_free(detacc_msg);
+}
 
 /* Return != 0 iff msg still needs to be processed */
 static int gbproxy_imsi_acquisition(struct gbproxy_peer *peer,
@@ -365,16 +391,38 @@
 	if (!tlli_info->imsi_acq_pending && tlli_info->imsi_len > 0)
 		return 1;
 
-	if (parse_ctx->g48_hdr &&
-	    parse_ctx->g48_hdr->msg_type == GSM48_MT_GMM_ATTACH_REQ)
-	{
-		if (gbproxy_restart_imsi_acquisition(tlli_info)) {
-			LOGP(DLLC, LOGL_INFO,
-			     "NSEI=%d(BSS) IMSI acquisition was in progress "
-			     "when receiving an ATTACH_REQ.\n",
-			     msgb_nsei(msg));
+	if (parse_ctx->g48_hdr)
+		switch (parse_ctx->g48_hdr->msg_type)
+		{
+		case GSM48_MT_GMM_ATTACH_REQ:
+			if (gbproxy_restart_imsi_acquisition(tlli_info)) {
+				LOGP(DLLC, LOGL_INFO,
+				     "NSEI=%d(BSS) IMSI acquisition was in progress "
+				     "when receiving an ATTACH_REQ.\n",
+				     msgb_nsei(msg));
+			}
+			break;
+		case GSM48_MT_GMM_DETACH_REQ:
+			/* Nothing has been sent to the SGSN yet */
+			if (tlli_info->imsi_acq_pending) {
+				LOGP(DLLC, LOGL_INFO,
+				     "NSEI=%d(BSS) IMSI acquisition was in progress "
+				     "when receiving a DETACH_REQ.\n",
+				     msgb_nsei(msg));
+			}
+			if (!parse_ctx->invalidate_tlli) {
+				LOGP(DLLC, LOGL_INFO,
+				     "NSEI=%d(BSS) IMSI not yet acquired, "
+				     "faking a DETACH_ACC.\n",
+				     msgb_nsei(msg));
+				gbproxy_tx_detach_acc(peer, tlli_info, msgb_bvci(msg));
+				parse_ctx->invalidate_tlli = 1;
+			}
+			gbproxy_reset_imsi_acquisition(tlli_info);
+			gbproxy_update_tlli_state_after(peer, tlli_info, now,
+							parse_ctx);
+			return 0;
 		}
-	}
 
 	if (tlli_info->imsi_acq_pending && tlli_info->imsi_len > 0) {
 		int is_ident_resp =
diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok
index 0711292..5e7931c 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.ok
+++ b/openbsc/tests/gbproxy/gbproxy_test.ok
@@ -3076,6 +3076,10 @@
 CALLBACK, event 0, msg length 44, bvci 0x1002
 00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 1d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb aa cc a3 
 
+NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg)
+MESSAGE to BSS at 0x01020304:1111, msg length 28
+00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 05 08 06 00 29 4a 68 
+
 result (DETACH REQ) = 0
 
 Peers:
@@ -3086,9 +3090,7 @@
     TLLI patched              (SGSN): 9
     P-TMSI patched            (SGSN): 1
     Attach Request count            : 3
-    TLLI cache size                 : 1
-    TLLI-Cache: 1
-      TLLI 8000dead -> 7eb52dfb, IMSI (none), AGE 0, STORED 2, IMSI acquisition in progress
+    TLLI-Cache: 0
 PROCESSING DETACH REQ (unknown TLLI) from 0x01020304:1111
 00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 21 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb ca 4d 70 
 
@@ -3097,7 +3099,7 @@
 
 NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg)
 MESSAGE to BSS at 0x01020304:1111, msg length 28
-00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 
+00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 06 00 11 f5 c0 
 
 result (DETACH REQ (unknown TLLI)) = 0
 
@@ -3109,10 +3111,7 @@
     TLLI patched              (SGSN): 9
     P-TMSI patched            (SGSN): 1
     Attach Request count            : 3
-    TLLI cache size                 : 2
-    TLLI-Cache: 2
-      TLLI 8000beef -> 7e23ef54, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress
-      TLLI 8000dead -> 7eb52dfb, IMSI (none), AGE 0, STORED 2, IMSI acquisition in progress
+    TLLI-Cache: 0
 Gbproxy global:
     Invalid Routing Area Identifier : 1
     BSSGP protocol error      (SGSN): 1