gbproxy: Parse Detach Request messages

GSM 24.008 also allows a P-TMSI field in Detach request messages.

This patch adds gbprox_parse_gmm_detach_req() to parse Detach Request
messages which sets the ptmsi field if the IE is present.

In addition, when power_off is set to 1 (MO only), the
invalidate_tlli field is set, since Detach Request message is
expected in this case.

The second detach test (see 'RA update') is modified to use
power_off instead of relying on a Detach Accept from the network.
To make this work, the PTMSI of the RA Update Accept is fixed to
match the TLLI of the Detach Request.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 64fb55b..dd7dead 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -959,6 +959,43 @@
 	return 1;
 }
 
+static int gbprox_parse_gmm_detach_req(uint8_t *data, size_t data_len,
+				       struct gbproxy_parse_context *parse_ctx)
+{
+	uint8_t *value;
+	size_t value_len;
+	int detach_type;
+	int power_off;
+
+	parse_ctx->llc_msg_name = "DETACH_REQ";
+
+	/* Skip spare half octet */
+	/* Get Detach type */
+	if (v_fixed_shift(&data, &data_len, 1, &value) <= 0)
+		/* invalid */
+		return 0;
+
+	detach_type = *value & 0x07;
+	power_off = *value & 0x08 ? 1 : 0;
+
+	if (!parse_ctx->to_bss) {
+		/* Mobile originated */
+
+		if (power_off)
+			parse_ctx->invalidate_tlli = 1;
+
+		/* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */
+		if (tlv_match(&data, &data_len,
+			      GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0)
+		{
+			if (is_mi_tmsi(value, value_len))
+				parse_ctx->ptmsi_enc = value;
+		}
+	}
+
+	return 1;
+}
+
 static int gbprox_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len,
 				       struct gbproxy_parse_context *parse_ctx)
 {
@@ -1157,12 +1194,9 @@
 
 	case GSM48_MT_GMM_ID_RESP:
 		return gbprox_parse_gmm_id_resp(data, data_len, parse_ctx);
-		break;
 
 	case GSM48_MT_GMM_DETACH_REQ:
-		/* TODO: Check power off if !to_bss, if yes invalidate */
-		parse_ctx->llc_msg_name = "DETACH_REQ";
-		break;
+		return gbprox_parse_gmm_detach_req(data, data_len, parse_ctx);
 
 	case GSM48_MT_GMM_DETACH_ACK:
 		parse_ctx->llc_msg_name = "DETACH_ACK";
@@ -1331,6 +1365,11 @@
 		     sep, mi_buf);
 		sep = ",";
 	}
+	if (parse_ctx->invalidate_tlli) {
+		LOGP(DGPRS, LOGL_DEBUG, "%s invalidate", sep);
+		sep = ",";
+	}
+
 	LOGP(DGPRS, LOGL_DEBUG, "\n");
 }
 
diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c
index 5363749..27454a2 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.c
+++ b/openbsc/tests/gbproxy/gbproxy_test.c
@@ -221,8 +221,8 @@
 	0x18, 0x00, 0x81, 0x00, 0x0e, 0x9d, 0x41, 0xc0,
 	0x19, 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54,
 	0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18,
-	0x05, 0xf4, 0xef, 0xe2, 0x81, 0x17, 0x17, 0x16,
-	0xc3, 0xbf, 0xcc
+	0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x17, 0x16,
+	0xd7, 0x59, 0x65
 };
 
 /* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Activate PDP Context Request */
@@ -239,7 +239,19 @@
 	0x00, 0x5a, 0xff, 0x02
 };
 
-/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request */
+/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request (MO) */
+/* normal detach, power_off = 1 */
+static const unsigned char bssgp_detach_po_req[44] = {
+	0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04,
+	0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
+	0x75, 0x30, 0x00, 0x80, 0x0e, 0x00, 0x15, 0x01,
+	0xc0, 0x19, 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4,
+	0xef, 0xe2, 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97,
+	0xcb, 0x84, 0x0c, 0xeb
+};
+
+/* Base Station Subsystem GPRS Protocol: GSM A-I/F DTAP - Detach Request (MO) */
+/* normal detach, power_off = 0 */
 static const unsigned char bssgp_detach_req[44] = {
 	0x01, 0xef, 0xe2, 0xb7, 0x00, 0x00, 0x00, 0x04,
 	0x08, 0x88, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60,
@@ -1060,13 +1072,9 @@
 
 	dump_peers(stdout, 0, 0, &gbcfg);
 
-	/* Detach */
-	send_ns_unitdata(nsi, "DETACH REQ", &bss_peer[0], 0x1002,
-			 bssgp_detach_req, sizeof(bssgp_detach_req));
-
-	send_ns_unitdata(nsi, "DETACH ACC", &sgsn_peer, 0x1002,
-			 bssgp_detach_acc, sizeof(bssgp_detach_acc));
-
+	/* Detach (power off -> no Detach Accept) */
+	send_ns_unitdata(nsi, "DETACH REQ (PWR OFF)", &bss_peer[0], 0x1002,
+			 bssgp_detach_po_req, sizeof(bssgp_detach_po_req));
 
 	dump_global(stdout, 0);
 	dump_peers(stdout, 0, 0, &gbcfg);
diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok
index 363a6e9..28d5016 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.ok
+++ b/openbsc/tests/gbproxy/gbproxy_test.ok
@@ -1780,14 +1780,14 @@
 result (RA UPD REQ) = 89
 
 PROCESSING RA UPD ACC from 0x05060708:32000
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 c3 bf cc 
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 
 
 CALLBACK, event 0, msg length 91, bvci 0x1002
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 c3 bf cc 
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 
 
 NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 91 (gprs_ns_sendmsg)
 MESSAGE to BSS at 0x01020304:1111, msg length 95
-00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 81 17 17 16 2e e5 fd 
+00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 9d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 0a 82 07 04 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 3a 03 54 
 
 result (RA UPD ACC) = 95
 
@@ -1809,33 +1809,20 @@
     RAID patched              (SGSN): 3
     APN patched                     : 3
     Attach Request count            : 1
-    TLLI cache size                 : 2
-    TLLI-Cache: 2
-      TLLI efe2b700, IMSI (none), AGE 0
-      TLLI efe28117, IMSI 12131415161718, AGE 0
-PROCESSING DETACH REQ from 0x01020304:1111
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 
+    TLLI cache size                 : 1
+    TLLI-Cache: 1
+      TLLI efe2b700, IMSI 12131415161718, AGE 0
+PROCESSING DETACH REQ (PWR OFF) from 0x01020304:1111
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb 
 
 CALLBACK, event 0, msg length 44, bvci 0x1002
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb 
 
 NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg)
 MESSAGE to SGSN at 0x05060708:32000, msg length 48
-00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 
+00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb 
 
-result (DETACH REQ) = 48
-
-PROCESSING DETACH ACC from 0x05060708:32000
-00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 
-
-CALLBACK, event 0, msg length 67, bvci 0x1002
-00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 
-
-NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg)
-MESSAGE to BSS at 0x01020304:1111, msg length 71
-00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 
-
-result (DETACH ACC) = 71
+result (DETACH REQ (PWR OFF)) = 48
 
 Gbproxy global:
 Peers:
@@ -1844,9 +1831,7 @@
     RAID patched              (SGSN): 3
     APN patched                     : 3
     Attach Request count            : 1
-    TLLI cache size                 : 1
-    TLLI-Cache: 1
-      TLLI efe28117, IMSI 12131415161718, AGE 0
+    TLLI-Cache: 0
 --- Bad cases ---
 
 TLLI is already detached, shouldn't patch
@@ -1884,10 +1869,9 @@
     RAID patched              (SGSN): 3
     APN patched                     : 3
     Attach Request count            : 1
-    TLLI cache size                 : 2
-    TLLI-Cache: 2
+    TLLI cache size                 : 1
+    TLLI-Cache: 1
       TLLI efe2b700, IMSI (none), AGE 0
-      TLLI efe28117, IMSI 12131415161718, AGE 0
 Test TLLI info expiry
 
 Test TLLI replacement: