[gprs] LLC: Introduce the allocation and lookup of LLC Entities (LLE)
diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c
index 91b0239..aea40d3 100644
--- a/openbsc/src/gprs_llc.c
+++ b/openbsc/src/gprs_llc.c
@@ -1,6 +1,6 @@
 /* GPRS LLC protocol implementation as per 3GPP TS 04.64 */
 
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
  *
  * All Rights Reserved
  *
@@ -22,11 +22,13 @@
 
 #include <errno.h>
 
-#include <openbsc/gsm_data.h>
 #include <osmocore/msgb.h>
-#include <openbsc/debug.h>
 #include <osmocore/linuxlist.h>
 #include <osmocore/timer.h>
+#include <osmocore/talloc.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
 #include <openbsc/gprs_bssgp.h>
 #include <openbsc/gprs_llc.h>
 #include <openbsc/crc24.h>
@@ -61,6 +63,37 @@
 	unsigned int retrans_ctr;
 };
 
+static LLIST_HEAD(gprs_llc_lles);
+void *llc_tall_ctx;
+
+/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */
+static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint32_t sapi)
+{
+	struct gprs_llc_lle *lle;
+
+	llist_for_each_entry(lle, &gprs_llc_lles, list) {
+		if (lle->tlli == tlli && lle->sapi == sapi)
+			return lle;
+	}
+	return NULL;
+}
+
+static struct gprs_llc_lle *lle_alloc(uint32_t tlli, uint32_t sapi)
+{
+	struct gprs_llc_lle *lle;
+
+	lle = talloc_zero(llc_tall_ctx, struct gprs_llc_lle);
+	if (!lle)
+		return NULL;
+
+	lle->tlli = tlli;
+	lle->sapi = sapi;
+	lle->state = GPRS_LLS_UNASSIGNED;
+	llist_add(&lle->list, &gprs_llc_lles);
+
+	return lle;
+}
+
 enum gprs_llc_cmd {
 	GPRS_LLC_NULL,
 	GPRS_LLC_RR,
@@ -392,29 +425,51 @@
 	/* FIXME: parse sack frame */
 }
 
-/* receive an incoming LLC PDU */
+/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */
 int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
 {
 	struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msg->l3h;
 	struct gprs_llc_hdr *lh = msgb_llch(msg);
 	struct gprs_llc_hdr_parsed llhp;
 	struct gprs_llc_entity *lle;
-	int rc;
+	int rc = 0;
 
 	rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU));
-
-	/* FIXME: find LLC Entity */
+	/* FIXME */
 
 	gprs_llc_hdr_dump(&llhp);
+
+	/* find the LLC Entity for this TLLI+SAPI tuple */
+	lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi);
+	/* allocate a new LLE if needed */
+	if (!lle)
+		lle = lle_alloc(msgb_tlli(msg), llhp.sapi);
+
 	rc = gprs_llc_hdr_rx(&llhp, lle);
+	/* FIXME */
 
 	if (llhp.data) {
 		msgb_gmmh(msg) = llhp.data;
 		switch (llhp.sapi) {
 		case GPRS_SAPI_GMM:
 			rc = gsm0408_gprs_rcvmsg(msg);
+			break;
+		case GPRS_SAPI_TOM2:
+		case GPRS_SAPI_TOM8:
+			/* FIXME */
+		case GPRS_SAPI_SNDCP3:
+		case GPRS_SAPI_SNDCP5:
+		case GPRS_SAPI_SNDCP9:
+		case GPRS_SAPI_SNDCP11:
+			/* FIXME */
+		case GPRS_SAPI_SMS:
+			/* FIXME */
+		default:
+			LOGP(DGPRS, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi);
+			rc = -EINVAL;
+			break;
 		}
 	}
 
-	return 0;
+	return rc;
 }