LAPD: keep sent/receive sequence numbers per SAPI, not just per TEI

If there are multiple SAPIs active on the same TEI, we need to keep
one set of sequence numbers for each SAPI, not just for the TEI.
diff --git a/openbsc/src/input/lapd.c b/openbsc/src/input/lapd.c
index 9bfc2cb..7bce6cc 100644
--- a/openbsc/src/input/lapd.c
+++ b/openbsc/src/input/lapd.c
@@ -118,12 +118,7 @@
 struct lapd_tei {
 	struct llist_head list;
 	struct lapd_instance *li;
-
 	uint8_t tei;
-	/* A valid N(R) value is one that is in the range V(A) ≤ N(R) ≤ V(S). */
-	int vs;			/* next to be transmitted */
-	int va;			/* last acked by peer */
-	int vr;			/* next expected to be received */
 	lapd_tei_state state;
 
 	struct llist_head sap_list;
@@ -137,6 +132,11 @@
 	uint8_t sapi;
 	enum lapd_sap_state state;
 
+	/* A valid N(R) value is one that is in the range V(A) ≤ N(R) ≤ V(S). */
+	int vs;			/* next to be transmitted */
+	int va;			/* last acked by peer */
+	int vr;			/* next expected to be received */
+
 	struct timer_list sabme_timer;	/* timer to re-transmit SABM message */
 };
 
@@ -162,8 +162,8 @@
  * The value of V(R) shall be incremented by one with the receipt of an error-free, in-sequence I frame
  * whose N(S) equals V(R).
  */
-#define	LAPD_NS(teip) (teip->vs)
-#define	LAPD_NR(teip) (teip->vr)
+#define	LAPD_NS(sap) (sap->vs)
+#define	LAPD_NR(sap) (sap->vr)
 
 /* 3.5.2.4    Send sequence number N(S)
  * Only I frames contain N(S), the send sequence number of transmitted I frames. At the time that an in-
@@ -316,6 +316,7 @@
 	int pf, ns, nr;
 	uint8_t *contents;
 	struct lapd_tei *teip;
+	struct lapd_sap *sap;
 
 	uint8_t resp[8];
 	int l = 0;
@@ -419,23 +420,28 @@
 		lapd_tei_receive(li, contents, *ilen);
 
 	teip = teip_from_tei(li, tei);
-
-	DEBUGP(DMI, "<- %c %s sapi %x tei %3d cmd %x pf %x ns %3d nr %3d "
-	     "ilen %d teip %p vs %d va %d vr %d len %d\n",
-	     lapd_msg_types[typ], lapd_cmd_types[cmd], sapi, tei, command, pf,
-	     ns, nr, *ilen, teip, teip ? teip->vs : -1, teip ? teip->va : -1,
-	     teip ? teip->vr : -1, len);
-
 	if (!teip) {
 		LOGP(DMI, LOGL_NOTICE, "Unknown TEI %u\n", tei);
 		return NULL;
 	}
 
+	sap = lapd_sap_find(teip, sapi);
+	if (!sap) {
+		LOGP(DMI, LOGL_INFO, "No SAP for TEI=%u / SAPI=%u, "
+			"allocating\n", tei, sapi);
+		sap = lapd_sap_alloc(teip, sapi);
+	}
+
+	DEBUGP(DMI, "<- %c %s sapi %x tei %3d cmd %x pf %x ns %3d nr %3d "
+	     "ilen %d teip %p vs %d va %d vr %d len %d\n",
+	     lapd_msg_types[typ], lapd_cmd_types[cmd], sapi, tei, command, pf,
+	     ns, nr, *ilen, teip, sap->vs, sap->va, sap->vr, len);
+
 	switch (cmd) {
 	case LAPD_CMD_I:
-		if (ns != teip->vr) {
-			DEBUGP(DMI, "ns %d != vr %d\n", ns, teip->vr);
-			if (ns == ((teip->vr - 1) & 0x7f)) {
+		if (ns != sap->vr) {
+			DEBUGP(DMI, "ns %d != vr %d\n", ns, sap->vr);
+			if (ns == ((sap->vr - 1) & 0x7f)) {
 				DEBUGP(DMI, "DOUBLE FRAME, ignoring\n");
 				cmd = 0;	// ignore
 			} else {
@@ -443,16 +449,16 @@
 			};
 		} else {
 			//printf("IN SEQUENCE\n");
-			teip->vr = (ns + 1) & 0x7f;	// FIXME: hack!
+			sap->vr = (ns + 1) & 0x7f;	// FIXME: hack!
 		};
 
 		break;
 	case LAPD_CMD_UI:
 		break;
 	case LAPD_CMD_SABME:
-		teip->vs = 0;
-		teip->vr = 0;
-		teip->va = 0;
+		sap->vs = 0;
+		sap->vr = 0;
+		sap->va = 0;
 
 		// ua
 		resp[l++] = data[0];
@@ -469,10 +475,10 @@
 				DEBUGP(DMI, "rr in strange state, send rej\n");
 
 				// rej
-				resp[l++] = (teip-> sapi << 2) | (li->network_side ? 0 : 2);
+				resp[l++] = (sap-> sapi << 2) | (li->network_side ? 0 : 2);
 				resp[l++] = (tei << 1) | 1;
 				resp[l++] = 0x09;	//rej
-				resp[l++] = ((teip->vr + 1) << 1) | 0;
+				resp[l++] = ((sap->vr + 1) << 1) | 0;
 				li->transmit_cb(resp, l, li->cbdata);
 				pf = 0;	// dont reply
 #endif
@@ -482,15 +488,15 @@
 		*prim = LAPD_MPH_ACTIVATE_IND;
 		break;
 	case LAPD_CMD_UA:
-		teip->vs = 0;
-		teip->vr = 0;
-		teip->va = 0;
+		sap->vs = 0;
+		sap->vr = 0;
+		sap->va = 0;
 		lapd_tei_set_state(teip, LAPD_TEI_ACTIVE);
 		lapd_sap_set_state(teip, sapi, SAP_STATE_ACTIVE);
 		*prim = LAPD_MPH_ACTIVATE_IND;
 		break;
 	case LAPD_CMD_RR:
-		teip->va = (nr & 0x7f);
+		sap->va = (nr & 0x7f);
 #if 0
 		if (teip->state != LAPD_TEI_ACTIVE) {
 			if (teip->state == LAPD_TEI_ASSIGNED) {
@@ -502,11 +508,11 @@
 				DEBUGP(DMI, "rr in strange " "state, send rej\n");
 
 				// rej
-				resp[l++] = (teip-> sapi << 2) | (li->network_side ? 0 : 2);
+				resp[l++] = (sap-> sapi << 2) | (li->network_side ? 0 : 2);
 				resp[l++] = (tei << 1) | 1;
 				resp[l++] = 0x09;	//rej
 				resp[l++] =
-				    ((teip->vr + 1) << 1) | 0;
+				    ((sap->vr + 1) << 1) | 0;
 				li->transmit_cb(resp, l, li->cbdata);
 				pf = 0;	// dont reply
 #endif
@@ -518,7 +524,7 @@
 			resp[l++] = data[0];
 			resp[l++] = (tei << 1) | 1;
 			resp[l++] = 0x01;	// rr
-			resp[l++] = (LAPD_NR(teip) << 1) | (data[3] & 1);	// pf bit from req
+			resp[l++] = (LAPD_NR(sap) << 1) | (data[3] & 1);	// pf bit from req
 
 			li->transmit_cb(resp, l, li->cbdata);
 
@@ -558,7 +564,7 @@
 		resp[l++] = data[0];
 		resp[l++] = (tei << 1) | 1;
 		resp[l++] = 0x01;	// rr
-		resp[l++] = (LAPD_NR(teip) << 1) | (data[3] & 1);	// pf bit from req
+		resp[l++] = (LAPD_NR(sap) << 1) | (data[3] & 1);	// pf bit from req
 
 		li->transmit_cb(resp, l, li->cbdata);
 
@@ -652,9 +658,8 @@
 void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
 		   uint8_t *data, unsigned int len)
 {
-	//printf("lapd_transmit %d, %d\n", tei, len);
-	//hexdump(data, len);
 	struct lapd_tei *teip = teip_from_tei(li, tei);
+	struct lapd_sap *sap;
 
 	if (!teip) {
 		LOGP(DMI, LOGL_ERROR, "Cannot transmit on non-existing "
@@ -662,6 +667,13 @@
 		return;
 	}
 
+	sap = lapd_sap_find(teip, sapi);
+	if (!sap) {
+		LOGP(DMI, LOGL_INFO, "Tx on unknown SAPI=%u in TEI=%u, "
+			"allocating\n", sapi, tei);
+		sap = lapd_sap_alloc(teip, sapi);
+	}
+
 	/* prepend stuff */
 	uint8_t buf[10000];
 	memset(buf, 0, sizeof(buf));
@@ -670,10 +682,10 @@
 
 	buf[0] = (sapi << 2) | (li->network_side ? 2 : 0);
 	buf[1] = (tei << 1) | 1;
-	buf[2] = (LAPD_NS(teip) << 1);
-	buf[3] = (LAPD_NR(teip) << 1) | 0;
+	buf[2] = (LAPD_NS(sap) << 1);
+	buf[3] = (LAPD_NR(sap) << 1) | 0;
 
-	teip->vs = (teip->vs + 1) & 0x7f;
+	sap->vs = (sap->vs + 1) & 0x7f;
 
 	li->transmit_cb(buf, len, li->cbdata);
 };