gprs_llc: Work on finding the right LLE/LLME in case of routing area update

Attempt to solve what f0901f0067e363c0ced6254db1b45a9771640412 tried to
solve without breaking the case of someone with a foreign TLLI from a
different network.

Lookup with the foreign TLLI converted to a local one in case we did
not find the TLLI and only then create a LLE/LLME on the fly for the
RX path.
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 57e557a..5a74a63 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -36,6 +36,54 @@
 #include <openbsc/crc24.h>
 #include <openbsc/sgsn.h>
 
+enum gprs_llc_cmd {
+	GPRS_LLC_NULL,
+	GPRS_LLC_RR,
+	GPRS_LLC_ACK,
+	GPRS_LLC_RNR,
+	GPRS_LLC_SACK,
+	GPRS_LLC_DM,
+	GPRS_LLC_DISC,
+	GPRS_LLC_UA,
+	GPRS_LLC_SABM,
+	GPRS_LLC_FRMR,
+	GPRS_LLC_XID,
+	GPRS_LLC_UI,
+};
+
+static const struct value_string llc_cmd_strs[] = {
+	{ GPRS_LLC_NULL,	"NULL" },
+	{ GPRS_LLC_RR,		"RR" },
+	{ GPRS_LLC_ACK,		"ACK" },
+	{ GPRS_LLC_RNR,		"RNR" },
+	{ GPRS_LLC_SACK,	"SACK" },
+	{ GPRS_LLC_DM,		"DM" },
+	{ GPRS_LLC_DISC,	"DISC" },
+	{ GPRS_LLC_UA,		"UA" },
+	{ GPRS_LLC_SABM,	"SABM" },
+	{ GPRS_LLC_FRMR,	"FRMR" },
+	{ GPRS_LLC_XID,		"XID" },
+	{ GPRS_LLC_UI,		"UI" },
+	{ 0, NULL }
+};
+
+struct gprs_llc_hdr_parsed {
+	uint8_t sapi;
+	uint8_t is_cmd:1,
+		 ack_req:1,
+		 is_encrypted:1;
+	uint32_t seq_rx;
+	uint32_t seq_tx;
+	uint32_t fcs;
+	uint32_t fcs_calc;
+	uint8_t *data;
+	uint16_t data_len;
+	uint16_t crc_length;
+	enum gprs_llc_cmd cmd;
+};
+
+static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
+
 /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU
  * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */
 static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
@@ -158,6 +206,47 @@
 	return NULL;
 }
 
+/* lookup LLC Entity for RX based on DLCI (TLLI+SAPI tuple) */
+static struct gprs_llc_lle *lle_for_rx_by_tlli_sapi(const uint32_t tlli,
+					uint8_t sapi, enum gprs_llc_cmd cmd)
+{
+	struct gprs_llc_lle *lle;
+
+	/* We already know about this TLLI */
+	lle = lle_by_tlli_sapi(tlli, sapi);
+	if (lle)
+		return lle;
+
+	/* Maybe it is a routing area update but we already know this sapi? */
+	if (gprs_tlli_type(tlli) == TLLI_FOREIGN) {
+		lle = lle_by_tlli_sapi(tlli_foreign2local(tlli), sapi);
+		if (lle) {
+			LOGP(DLLC, LOGL_NOTICE,
+				"LLC RX: Found a local entry for TLLI 0x%08x\n",
+				tlli);
+			return lle;
+		}
+	}
+
+	/* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
+	 * except UID and XID frames with SAPI=1 */
+	if (sapi == GPRS_SAPI_GMM &&
+		    (cmd == GPRS_LLC_XID || cmd == GPRS_LLC_UI)) {
+		struct gprs_llc_llme *llme;
+		/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
+		llme = llme_alloc(tlli);
+		LOGP(DLLC, LOGL_DEBUG, "LLC RX: unknown TLLI 0x%08x, "
+			"creating LLME on the fly\n", tlli);
+		lle = &llme->lle[sapi];
+		return lle;
+	}
+	
+	LOGP(DLLC, LOGL_NOTICE,
+		"unknown TLLI(0x%08x)/SAPI(%d): Silently dropping\n",
+		tlli, sapi);
+	return NULL;
+}
+
 static void lle_init(struct gprs_llc_llme *llme, uint8_t sapi)
 {
 	struct gprs_llc_lle *lle = &llme->lle[sapi];
@@ -197,52 +286,6 @@
 	talloc_free(llme);
 }
 
-enum gprs_llc_cmd {
-	GPRS_LLC_NULL,
-	GPRS_LLC_RR,
-	GPRS_LLC_ACK,
-	GPRS_LLC_RNR,
-	GPRS_LLC_SACK,
-	GPRS_LLC_DM,
-	GPRS_LLC_DISC,
-	GPRS_LLC_UA,
-	GPRS_LLC_SABM,
-	GPRS_LLC_FRMR,
-	GPRS_LLC_XID,
-	GPRS_LLC_UI,
-};
-
-static const struct value_string llc_cmd_strs[] = {
-	{ GPRS_LLC_NULL,	"NULL" },
-	{ GPRS_LLC_RR,		"RR" },
-	{ GPRS_LLC_ACK,		"ACK" },
-	{ GPRS_LLC_RNR,		"RNR" },
-	{ GPRS_LLC_SACK,	"SACK" },
-	{ GPRS_LLC_DM,		"DM" },
-	{ GPRS_LLC_DISC,	"DISC" },
-	{ GPRS_LLC_UA,		"UA" },
-	{ GPRS_LLC_SABM,	"SABM" },
-	{ GPRS_LLC_FRMR,	"FRMR" },
-	{ GPRS_LLC_XID,		"XID" },
-	{ GPRS_LLC_UI,		"UI" },
-	{ 0, NULL }
-};
-
-struct gprs_llc_hdr_parsed {
-	uint8_t sapi;
-	uint8_t is_cmd:1,
-		 ack_req:1,
-		 is_encrypted:1;
-	uint32_t seq_rx;
-	uint32_t seq_tx;
-	uint32_t fcs;
-	uint32_t fcs_calc;
-	uint8_t *data;
-	uint16_t data_len;
-	uint16_t crc_length;
-	enum gprs_llc_cmd cmd;
-};
-
 #define LLC_ALLOC_SIZE 16384
 #define UI_HDR_LEN	3
 #define N202		4
@@ -360,6 +403,8 @@
 
 	/* look-up or create the LL Entity for this (TLLI, SAPI) tuple */
 	lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi);
+	if (!lle) 
+		lle = lle_by_tlli_sapi(tlli_foreign2local(msgb_tlli(msg)), sapi);
 	if (!lle) {
 		struct gprs_llc_llme *llme;
 		LOGP(DLLC, LOGL_ERROR, "LLC TX: unknown TLLI 0x%08x, "
@@ -766,25 +811,9 @@
 	}
 
 	/* find the LLC Entity for this TLLI+SAPI tuple */
-	lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi);
-
-	/* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
-	 * except UID and XID frames with SAPI=1 */
-	if (!lle) {
-		if (llhp.sapi == GPRS_SAPI_GMM &&
-		    (llhp.cmd == GPRS_LLC_XID || llhp.cmd == GPRS_LLC_UI)) {
-			struct gprs_llc_llme *llme;
-			/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
-			llme = llme_alloc(msgb_tlli(msg));
-			LOGP(DLLC, LOGL_DEBUG, "LLC RX: unknown TLLI 0x%08x, "
-				"creating LLME on the fly\n", msgb_tlli(msg));
-			lle = &llme->lle[llhp.sapi];
-		} else {
-			LOGP(DLLC, LOGL_NOTICE,
-				"unknown TLLI/SAPI: Silently dropping\n");
-			return 0;
-		}
-	}
+	lle = lle_for_rx_by_tlli_sapi(msgb_tlli(msg), llhp.sapi, llhp.cmd);
+	if (!lle)
+		return 0;
 
 	/* decrypt information field + FCS, if needed! */
 	if (llhp.is_encrypted) {