sgsn: Send detach(re-attach) instead of gmm status if TLLI unknown

The osmo-sgsn sends Status messages (or nothing in case of non
GMM/GSM) when the TLLI is unknown. This prevents the MS from
reconnecting.

This patch adds the initiation of an MT detach procedure to force a
re-attach to set up a valid LLE context if an LLE or an MM context
cannot be found. Since this can also be triggered by non-GMM SAPI
messages, a GPRS application callback sgsn_force_reattach_oldmsg is
added which in turn calls the GMM layer to generate the GSM 04.08
specific messages.

Note that the MS can be left in REGISTERED state after initially
wanting to detach itself, since it will receive a Detach Req
(re-attach) when sending a DEACT PDP CTX REQ after the SGSN or
gbproxy (P-TMSI patching enabled) has been restarted. This same
behaviour has been observed with another SGSN.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index c88d162..0b4613e 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -608,8 +608,19 @@
 
 	/* find the LLC Entity for this TLLI+SAPI tuple */
 	lle = lle_for_rx_by_tlli_sapi(msgb_tlli(msg), llhp.sapi, llhp.cmd);
-	if (!lle)
+	if (!lle) {
+		switch (llhp.sapi) {
+		case GPRS_SAPI_SNDCP3:
+		case GPRS_SAPI_SNDCP5:
+		case GPRS_SAPI_SNDCP9:
+		case GPRS_SAPI_SNDCP11:
+			/* Ask an upper layer for help. */
+			return sgsn_force_reattach_oldmsg(msg);
+		default:
+			break;
+		}
 		return 0;
+	}
 
 	/* decrypt information field + FCS, if needed! */
 	if (llhp.is_encrypted) {
@@ -773,6 +784,25 @@
 	return gprs_llc_tx_xid(lle, msg, 1);
 }
 
+int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi)
+{
+	struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
+	int random = rand();
+
+	/* First XID component must be RESET */
+	msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
+	/* randomly select new IOV-UI */
+	msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
+
+	/* FIXME: Start T200, wait for XID response */
+
+	msgb_tlli(msg) = msgb_tlli(oldmsg);
+	msgb_bvci(msg) = msgb_bvci(oldmsg);
+	msgb_nsei(msg) = msgb_nsei(oldmsg);
+
+	return gprs_llc_tx_u(msg, sapi, 1, GPRS_LLC_U_XID, 1);
+}
+
 int gprs_llc_init(const char *cipher_plugin_path)
 {
 	return gprs_cipher_load(cipher_plugin_path);