aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-02-14 15:51:57 +0100
committerHarald Welte <laforge@gnumonks.org>2011-02-14 15:51:57 +0100
commita0fe72de6f7d4c6cd7b6508b7e819e94f8c29989 (patch)
tree5cf70e61f3bc1e96b644d77a1d793b7c961a63b8
parentfdb71949db46cbb1356d1db7365126c504dcc005 (diff)
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.
-rw-r--r--openbsc/src/input/lapd.c84
1 files changed, 48 insertions, 36 deletions
diff --git a/openbsc/src/input/lapd.c b/openbsc/src/input/lapd.c
index 9bfc2cb4a..7bce6cc51 100644
--- a/openbsc/src/input/lapd.c
+++ b/openbsc/src/input/lapd.c
@@ -118,12 +118,7 @@ const char *lapd_msg_types = "?ISU";
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 @@ struct lapd_sap {
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 @@ struct lapd_sap {
* 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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
};
} 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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
*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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
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 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
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 @@ int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
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 @@ void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
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 @@ void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
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);
};