patch-2.3.4 linux/drivers/isdn/hisax/isdnl2.c

Next file: linux/drivers/isdn/hisax/isdnl3.c
Previous file: linux/drivers/isdn/hisax/isdnl1.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.3/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
@@ -1,12 +1,42 @@
-/* $Id: isdnl2.c,v 2.7 1998/02/12 23:07:47 keil Exp $
+/* $Id: isdnl2.c,v 2.16 1998/11/15 23:55:01 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: isdnl2.c,v $
+ * Revision 2.16  1998/11/15 23:55:01  keil
+ * changes from 2.0
+ *
+ * Revision 2.15  1998/08/13 23:36:42  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.14  1998/06/19 15:19:18  keil
+ * fix LAPB tx_cnt for none I-frames
+ *
+ * Revision 2.13  1998/06/18 23:17:20  keil
+ * LAPB bugfix
+ *
+ * Revision 2.12  1998/05/25 14:10:12  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.11  1998/05/25 12:58:08  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.9  1998/04/10 10:35:30  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
+ * Revision 2.8  1998/03/07 22:57:04  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 2.7  1998/02/12 23:07:47  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -25,7 +55,7 @@
  * Old stuff is still in the separate branch.
  *
  * Revision 2.2  1997/07/31 11:49:05  keil
- * Eroor handling for no TEI assign
+ * Error handling for no TEI assign
  *
  * Revision 2.1  1997/07/27 21:34:38  keil
  * cosmetics
@@ -41,9 +71,9 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.7 $";
+const char *l2_revision = "$Revision: 2.16 $";
 
-static void l2m_debug(struct FsmInst *fi, char *s);
+static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
 static
 struct Fsm l2fsm =
@@ -91,7 +121,6 @@
 	EV_L2_MDL_ASSIGN,
 	EV_L2_MDL_REMOVE,
 	EV_L2_MDL_ERROR,
-	EV_L2_MDL_NOTEIPROC,
 	EV_L1_DEACTIVATE,
 	EV_L2_T200,
 	EV_L2_T203,
@@ -117,7 +146,6 @@
 	"EV_L2_MDL_ASSIGN",
 	"EV_L2_MDL_REMOVE",
 	"EV_L2_MDL_ERROR",
-	"EV_L2_MDL_NOTEIPROC",
 	"EV_L1_DEACTIVATE",
 	"EV_L2_T200",
 	"EV_L2_T203",
@@ -161,26 +189,6 @@
 	return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
 }
 
-static void
-discard_i_queue(struct PStack *st)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&st->l2.i_queue))) {
-		dev_kfree_skb(skb);
-	}
-}
-
-static void
-discard_ui_queue(struct PStack *st)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&st->l2.ui_queue))) {
-		dev_kfree_skb(skb);
-	}
-}
-
 inline void
 clear_exception(struct Layer2 *l2)
 {
@@ -224,20 +232,17 @@
 	}
 }
 
-static void
-enqueue_ui(struct PStack *st,
-	   struct sk_buff *skb)
-{
-	st->l2.l2l1(st, PH_DATA_REQ, skb);
-}
-
-static void
+inline static void
 enqueue_super(struct PStack *st,
 	      struct sk_buff *skb)
 {
-	st->l2.l2l1(st, PH_DATA_REQ, skb);
+	if (test_bit(FLG_LAPB, &st->l2.flag))
+		st->l1.bcs->tx_cnt += skb->len;
+	st->l2.l2l1(st, PH_DATA | REQUEST, skb);
 }
 
+#define enqueue_ui(a, b) enqueue_super(a, b)
+
 inline int
 IsUI(u_char * data, int ext)
 {
@@ -272,6 +277,16 @@
 }
 
 inline int
+IsSFrame(u_char * data, int ext)
+{
+	register u_char d = *data;
+	
+	if (!ext)
+		d &= 0xf;
+	return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
+}
+
+inline int
 IsSABMX(u_char * data, int ext)
 {
 	u_char d = data[0] & ~0x10;
@@ -393,15 +408,15 @@
 	switch (event) {
 		case EV_L2_UA:
 			if (get_PollFlagFree(st, skb))
-				st->ma.layer(st, MDL_ERROR_IND, (void *) 'C');
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C');
 			else
-				st->ma.layer(st, MDL_ERROR_IND, (void *) 'D');
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D');
 			break;
 		case EV_L2_DM:
 			if (get_PollFlagFree(st, skb))
-				st->ma.layer(st, MDL_ERROR_IND, (void *) 'B');
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
 			else {
-				st->ma.layer(st, MDL_ERROR_IND, (void *) 'E');
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
 				establishlink(fi);
 				test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
 			}
@@ -415,9 +430,16 @@
 	struct PStack *st = fi->userdata;
 	int state = fi->state;
 
-	FsmChangeState(fi, ST_L2_3); 
-	if (state == ST_L2_1)
-		st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
+	
+	if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
+		FsmChangeState(fi, ST_L2_4);
+		establishlink(fi);
+		test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+	} else {
+		FsmChangeState(fi, ST_L2_3);
+		if (state == ST_L2_1)
+			st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
+	}
 }
 
 static void
@@ -444,7 +466,7 @@
 	skb_queue_tail(&st->l2.ui_queue, skb);
 	if (fi->state == ST_L2_1) {
 		FsmChangeState(fi, ST_L2_2);
-		st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
+		st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
 	}
 	if (fi->state > ST_L2_3)
 		l2_send_ui(st);
@@ -458,10 +480,10 @@
 
 	skb_pull(skb, l2headersize(&st->l2, 1));
 	if (skb->len > st->l2.maxlen) { 
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
 		FreeSkb(skb);
 	} else
-		st->l2.l2l3(st, DL_UNIT_DATA, skb);
+		st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
 }
 
 static void
@@ -470,7 +492,7 @@
 	struct PStack *st = fi->userdata;
 
 	if (fi->state != ST_L2_4)
-		discard_i_queue(st);
+		discard_queue(&st->l2.i_queue);
 	if (fi->state != ST_L2_5)
 		establishlink(fi);
 	test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
@@ -482,13 +504,13 @@
 	struct PStack *st = fi->userdata;
 
 	if (fi->state == ST_L2_4) {
-		st->l2.l2man(st, DL_RELEASE, NULL);
+		st->l2.l2l3(st, DL_RELEASE  | CONFIRM, NULL);
 		return;
 	} else if (fi->state == ST_L2_5) {
 		test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
 		return;
 	}
-	discard_i_queue(st);
+	discard_queue(&st->l2.i_queue);
 	FsmChangeState(fi, ST_L2_6);
 	st->l2.rc = 0;
 	send_uframe(st, DISC | 0x10, CMD);
@@ -510,14 +532,14 @@
 	if (test_bit(FLG_ORIG, &st->l2.flag))
 		rsp = !rsp;
 	if (rsp) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
 		FreeSkb(skb);
 		if ((state == ST_L2_7) || (state == ST_L2_8))
 			establishlink(fi);
 		return;
 	}	
 	if (skb->len != (l2addrsize(&st->l2) + 1)) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 		FreeSkb(skb);
 		if ((state == ST_L2_7) || (state == ST_L2_8))
 			establishlink(fi);
@@ -532,9 +554,9 @@
 	if (ST_L2_5 == state)
 		return;
 	if (ST_L2_4 != state) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'F');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F');
 		if (st->l2.vs != st->l2.va) {
-			discard_i_queue(st);
+			discard_queue(&st->l2.i_queue);
 			est = 1;
 		} else
 			est = 0;
@@ -547,14 +569,14 @@
 	FsmChangeState(fi, ST_L2_7);
 	if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
 		FsmDelTimer(&st->l2.t200, 2);
-	FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
+	FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
 
 	if (est)
-		st->l2.l2man(st, DL_ESTABLISH, NULL);
+		st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
 
 	if (ST_L2_8 == state)
 		if (skb_queue_len(&st->l2.i_queue) && cansend(st))
-			st->l2.l2l1(st, PH_PULL_REQ, NULL);
+			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -571,14 +593,14 @@
 		rsp = !rsp;
 
 	if (rsp) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
 		FreeSkb(skb);
 		if ((state == ST_L2_7) || (state == ST_L2_8))
 			establishlink(fi);
 		return;
 	}	
 	if (skb->len != (l2addrsize(&st->l2) + 1)) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 		FreeSkb(skb);
 		if ((state == ST_L2_7) || (state == ST_L2_8))
 			establishlink(fi);
@@ -600,8 +622,11 @@
 			FsmDelTimer(&st->l2.t200, 2);
 	}
 	send_uframe(st, cmd | PollFlag, RSP);
-	if (rel)
-		st->l2.l2man(st, DL_RELEASE, NULL);
+	if (rel) {
+		if (test_bit(FLG_LAPB, &st->l2.flag))
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+		st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+	}
 }
 
 
@@ -610,7 +635,8 @@
 {
 	struct PStack *st = fi->userdata;
 	struct sk_buff *skb = arg;
-	u_char PollFlag, est = 1;
+	int pr=-1;
+	u_char PollFlag;
 	int state,rsp;
 
 	state = fi->state;
@@ -619,14 +645,14 @@
 		rsp = !rsp;
 
 	if (!rsp) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
 		FreeSkb(skb);
 		if ((state == ST_L2_7) || (state == ST_L2_8))
 			establishlink(fi);
 		return;
 	}	
 	if (skb->len != (l2addrsize(&st->l2) + 1)) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 		FreeSkb(skb);
 		if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
 			establishlink(fi);
@@ -643,30 +669,31 @@
 		FsmDelTimer(&st->l2.t200, 2);
 	if (fi->state == ST_L2_5) {
 		if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) {
-			discard_i_queue(st);
+			discard_queue(&st->l2.i_queue);
 			st->l2.rc = 0;
 			send_uframe(st, DISC | 0x10, CMD);
 			FsmChangeState(fi, ST_L2_6);
 			FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 4);
 			test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 		} else {
-			if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) {
-				if (st->l2.vs != st->l2.va)
-					discard_i_queue(st);
-				else
-					est = 0;
+			if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) {
+				pr = DL_ESTABLISH | CONFIRM;
+			} else if (st->l2.vs != st->l2.va) {
+				discard_queue(&st->l2.i_queue);
+				pr = DL_ESTABLISH | INDICATION;
 			}
 			st->l2.vs = 0;
 			st->l2.va = 0;
 			st->l2.vr = 0;
 			st->l2.sow = 0;
 			FsmChangeState(fi, ST_L2_7);
-			FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
-			if (est)
-				st->l2.l2man(st, DL_ESTABLISH, NULL);
+			if (pr > -1)
+				st->l2.l2l3(st, pr, NULL);
 		}
 	} else {		/* ST_L2_6 */
-		st->l2.l2man(st, DL_RELEASE, NULL);
+		if (test_bit(FLG_LAPB, &st->l2.flag))
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+		st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
 		FsmChangeState(fi, ST_L2_4);
 	}
 }
@@ -685,14 +712,14 @@
 		rsp = !rsp;
 
 	if (!rsp) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
 		FreeSkb(skb);
 		if ((state == ST_L2_7) || (state == ST_L2_8))
 			establishlink(fi);
 		return;
 	}	
 	if (skb->len != (l2addrsize(&st->l2) + 1)) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 		FreeSkb(skb);
 		if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
 			establishlink(fi);
@@ -700,15 +727,41 @@
 	}
 	PollFlag = get_PollFlagFree(st, skb);
 	if (!PollFlag) {
-		establishlink(fi);
-		test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+		if (fi->state == ST_L2_4) {
+			establishlink(fi);
+			test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+			FsmChangeState(fi, ST_L2_5);
+		} else if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) {
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
+			establishlink(fi);
+		}
 	} else {
-		if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
-			FsmDelTimer(&st->l2.t200, 2);
-	 	if (fi->state == ST_L2_5 && !test_bit(FLG_L3_INIT, &st->l2.flag))
-			discard_i_queue(st);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-		FsmChangeState(fi, ST_L2_4);
+		switch (fi->state) {
+			case ST_L2_8:
+				 establishlink(fi);
+			case ST_L2_7:
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
+				break;
+			case ST_L2_4:
+				break;
+			case ST_L2_5:
+				if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+					FsmDelTimer(&st->l2.t200, 2);
+				discard_queue(&st->l2.i_queue);
+				if (test_bit(FLG_LAPB, &st->l2.flag))
+					st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+				st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+				FsmChangeState(fi, ST_L2_4);
+				break;
+			case ST_L2_6:
+				if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+					FsmDelTimer(&st->l2.t200, 2);
+				if (test_bit(FLG_LAPB, &st->l2.flag))
+					st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+				st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+				FsmChangeState(fi, ST_L2_4);
+				break;
+		}
 	}
 }
 
@@ -763,7 +816,7 @@
 {
 	struct PStack *st = fi->userdata;
 
-	st->ma.layer(st, MDL_ERROR_IND, (void *) 'J');
+	st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J');
 	establishlink(fi);
 }
 
@@ -785,11 +838,13 @@
 			if (p1 < 0)
 				p1 += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
 			p1 = (p1 + l2->sow) % l2->window;
+			if (test_bit(FLG_LAPB, &l2->flag))
+				st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0);
 			skb_queue_head(&l2->i_queue, l2->windowar[p1]);
 			l2->windowar[p1] = NULL;
 		}
 		restore_flags(flags);
-		st->l2.l2l1(st, PH_PULL_REQ, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	}
 }
 
@@ -818,9 +873,11 @@
 			PollFlag = (skb->data[1] & 0x1) == 0x1;
 			nr = skb->data[1] >> 1;
 		} else {
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+			if (skb->len >2) {
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+				establishlink(fi);
+			}
 			FreeSkb(skb);
-			establishlink(fi);
 			return;
 		}
 	} else {
@@ -828,7 +885,7 @@
 			PollFlag = (skb->data[0] & 0x10);
 			nr = (skb->data[0] >> 5) & 0x7;
 		} else {
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 			FreeSkb(skb);
 			establishlink(fi);
 			return;
@@ -839,7 +896,7 @@
 	if ((!rsp) && PollFlag)
 		enquiry_response(st);
 	if (rsp && PollFlag)
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'A');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
 	if (legalnr(st, nr)) {
 		if (typ == REJ) {
 			setva(st, nr);
@@ -862,13 +919,13 @@
 			test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 		}
 		if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
-			st->l2.l2l1(st, PH_PULL_REQ, NULL);
+			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	} else
 		nrerrorrecovery(fi);
 
 	if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) {
 		fi->userint &= ~LC_FLUSH_WAIT;
-		st->l2.l2man(st, DL_FLUSH, NULL);
+		st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL);
 	}
 }
 
@@ -883,7 +940,7 @@
 	if (!((fi->state == ST_L2_5) && test_bit(FLG_L3_INIT, &st->l2.flag)))
 		skb_queue_tail(&st->l2.i_queue, skb);
 	if (fi->state == ST_L2_7)
-		st->l2.l2l1(st, PH_PULL_REQ, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -891,17 +948,15 @@
 {
 	struct PStack *st = fi->userdata;
 	struct sk_buff *skb = arg;
-	struct IsdnCardState *sp = st->l1.hardware;
 	struct Layer2 *l2 = &(st->l2);
-	int PollFlag, ns, nr, i, hs, rsp;
-	char str[64];
+	int PollFlag, ns, nr, i, rsp;
 
 	rsp = *skb->data & 0x2;
 	if (test_bit(FLG_ORIG, &l2->flag))
 		rsp = !rsp;
 
 	if (rsp) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
 		FreeSkb(skb);
 		establishlink(fi);
 		return;
@@ -909,12 +964,10 @@
 	i = l2addrsize(l2);
 	if (test_bit(FLG_MOD128, &l2->flag)) {
 		if (skb->len <= (i + 1)) {
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
 			FreeSkb(skb);
-			establishlink(fi);
 			return;
 		} else if ((skb->len - i - 1) > l2->maxlen) { 
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
 			FreeSkb(skb);
 			establishlink(fi);
 			return;
@@ -924,12 +977,12 @@
 		nr = (skb->data[i + 1] >> 1) & 0x7f;
 	} else {
 		if (skb->len <= i) {
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 			FreeSkb(skb);
 			establishlink(fi);
 			return;
 		} else if ((skb->len - i) > l2->maxlen) { 
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
 			FreeSkb(skb);
 			establishlink(fi);
 			return;
@@ -944,20 +997,12 @@
 	} else if (l2->vr == ns) {
 		l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
 		test_and_clear_bit(FLG_REJEXC, &l2->flag);
-		if (test_bit(FLG_LAPD, &l2->flag))
-			if (sp->dlogflag) {
-				hs = l2headersize(l2, 0);
-				LogFrame(st->l1.hardware, skb->data, skb->len);
-				sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
-				dlogframe(st->l1.hardware, skb->data + hs,
-					  skb->len - hs, str);
-			}
 		if (PollFlag)
 			enquiry_response(st);
 		else
 			test_and_set_bit(FLG_ACK_PEND, &l2->flag);
 		skb_pull(skb, l2headersize(l2, 0));
-		st->l2.l2l3(st, DL_DATA, skb);
+		st->l2.l2l3(st, DL_DATA | INDICATION, skb);
 	} else {
 		/* n(s)!=v(r) */
 		FreeSkb(skb);
@@ -990,7 +1035,7 @@
 	}
 
 	if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
-		st->l2.l2l1(st, PH_PULL_REQ, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
 		enquiry_cr(st, RR, RSP, 0);
 }
@@ -1000,7 +1045,7 @@
 {
 	struct PStack *st = fi->userdata;
 
-	st->l2.tei = (int) arg;
+	st->l2.tei = (long) arg;
 
 	if (fi->state == ST_L2_3) {
 		establishlink(fi);
@@ -1012,12 +1057,6 @@
 }
 
 static void
-l2_no_tei(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L2_4);
-}
-
-static void
 l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
@@ -1028,9 +1067,11 @@
 	} else if (st->l2.rc == st->l2.N200) {
 		FsmChangeState(fi, ST_L2_4);
 		test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
-		discard_i_queue(st);
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'G');
-		st->l2.l2man(st, DL_RELEASE, NULL);
+		discard_queue(&st->l2.i_queue);
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
+		if (test_bit(FLG_LAPB, &st->l2.flag))
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+		st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 	} else {
 		st->l2.rc++;
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
@@ -1049,8 +1090,10 @@
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
 	} else if (st->l2.rc == st->l2.N200) {
 		FsmChangeState(fi, ST_L2_4);
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'H');
-		st->l2.l2man(st, DL_RELEASE, NULL);
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H');
+		if (test_bit(FLG_LAPB, &st->l2.flag))
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+		st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 	} else {
 		st->l2.rc++;
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
@@ -1146,14 +1189,14 @@
 		memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
 		FreeSkb(oskb);
 	}
-	st->l2.l2l1(st, PH_PULL_IND, skb);
+	st->l2.l2l1(st, PH_PULL | INDICATION, skb);
 	test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
 	if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
 		FsmDelTimer(&st->l2.t203, 13);
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
 	}
 	if (skb_queue_len(&l2->i_queue) && cansend(st))
-		st->l2.l2l1(st, PH_PULL_REQ, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -1179,7 +1222,7 @@
 			PollFlag = (skb->data[1] & 0x1) == 0x1;
 			nr = skb->data[1] >> 1;
 		} else {
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 			FreeSkb(skb);
 			establishlink(fi);
 			return;
@@ -1189,7 +1232,7 @@
 			PollFlag = (skb->data[0] & 0x10);
 			nr = (skb->data[0] >> 5) & 0x7;
 		} else {
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 			FreeSkb(skb);
 			establishlink(fi);
 			return;
@@ -1213,10 +1256,10 @@
 			invoke_retransmission(st, nr);
 			FsmChangeState(fi, ST_L2_7);
 			if (skb_queue_len(&l2->i_queue) && cansend(st))
-				st->l2.l2l1(st, PH_PULL_REQ, NULL);
+				st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 			else if (fi->userint & LC_FLUSH_WAIT) {
 				fi->userint &= ~LC_FLUSH_WAIT;
-				st->l2.l2man(st, DL_FLUSH, NULL);
+				st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL);
 			}
 		}
 	} else {
@@ -1233,30 +1276,25 @@
 {
 	struct PStack *st = fi->userdata;
 	struct sk_buff *skb = arg;
-	char tmp[64];
 
 	skb_pull(skb, l2addrsize(&st->l2) + 1);
 	if (test_bit(FLG_MOD128, &st->l2.flag)) {
 		if (skb->len < 5)
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
-		else {
-			sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+		else
+			l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x",
 				skb->data[0], skb->data[1], skb->data[2],
 				skb->data[3], skb->data[4]);
-			l2m_debug(&st->l2.l2m, tmp);
-		}
 	} else {
 		if (skb->len < 3)
-			st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
-		else {
-			sprintf(tmp, "FRMR information %2x %2x %2x",
+			st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+		else
+			l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x",
 				skb->data[0], skb->data[1], skb->data[2]);
-			l2m_debug(&st->l2.l2m, tmp);
-		}
 	}
 	if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) ||		/* I or S */
 	    (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) {
-		st->ma.layer(st, MDL_ERROR_IND, (void *) 'K');
+		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K');
 		establishlink(fi);
 		test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
 	}
@@ -1268,14 +1306,14 @@
 {
 	struct PStack *st = fi->userdata;
 
-	discard_i_queue(st);
-	discard_ui_queue(st);
+	discard_queue(&st->l2.i_queue);
+	discard_queue(&st->l2.ui_queue);
 	st->l2.tei = -1;
 	if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
 		FsmDelTimer(&st->l2.t200, 18);
 	FsmDelTimer(&st->l2.t203, 19);
 	if (fi->state != ST_L2_4)
-		st->l2.l2man(st, DL_RELEASE, NULL);
+		st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1283,33 +1321,45 @@
 l2_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
+	int rel = DL_RELEASE | INDICATION;
+	
 	
-	discard_i_queue(st);
-	discard_ui_queue(st);
+	discard_queue(&st->l2.i_queue);
+	discard_queue(&st->l2.ui_queue);
 	if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
 		FsmDelTimer(&st->l2.t200, 18);
 	FsmDelTimer(&st->l2.t203, 19);
-	test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
 	clear_exception(&st->l2);
 	switch (fi->state) {
+		case ST_L2_1:
+			if (!test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+				break;
 		case ST_L2_3:
-			st->l2.l2man(st, DL_RELEASE, NULL);
+			st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 		case ST_L2_2:
 			FsmChangeState(fi, ST_L2_1);
 			break;
-		case ST_L2_5:
 		case ST_L2_6:
+			rel = DL_RELEASE | CONFIRM;
+		case ST_L2_5:
+			if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
+				rel = DL_RELEASE | CONFIRM;
 		case ST_L2_7:
 		case ST_L2_8:
-			st->l2.l2man(st, DL_RELEASE, NULL);
+			st->l2.l2l3(st, rel, NULL);
 			FsmChangeState(fi, ST_L2_4);
 			break;
+		case ST_L2_4:
+			if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+				st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+			break;
 	}
+	test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
+	test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
 }
 
 static struct FsmNode L2FnList[] HISAX_INITDATA =
 {
-	{ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei},
 	{ST_L2_1, EV_L2_DL_ESTABLISH, l2_dl_establish},
 	{ST_L2_2, EV_L2_DL_ESTABLISH, l2_dl_establish},
 	{ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish},
@@ -1359,8 +1409,8 @@
 	{ST_L2_4, EV_L2_DM, l2_got_dm},
 	{ST_L2_5, EV_L2_DM, l2_got_dm},
 	{ST_L2_6, EV_L2_DM, l2_got_dm},
-	{ST_L2_7, EV_L2_DM, l2_mdl_error},
-	{ST_L2_8, EV_L2_DM, l2_mdl_error},
+	{ST_L2_7, EV_L2_DM, l2_got_dm},
+	{ST_L2_8, EV_L2_DM, l2_got_dm},
 	{ST_L2_1, EV_L2_UI, l2_got_ui},
 	{ST_L2_2, EV_L2_UI, l2_got_ui},
 	{ST_L2_3, EV_L2_UI, l2_got_ui},
@@ -1381,6 +1431,7 @@
 	{ST_L2_8, EV_L2_T200, l2_st78_tout_200},
 	{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
 	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+	{ST_L2_1, EV_L1_DEACTIVATE, l2_persistant_da},
 	{ST_L2_2, EV_L1_DEACTIVATE, l2_persistant_da},
 	{ST_L2_3, EV_L1_DEACTIVATE, l2_persistant_da},
 	{ST_L2_4, EV_L1_DEACTIVATE, l2_persistant_da},
@@ -1400,19 +1451,19 @@
 	int ret = 1, len;
 
 	switch (pr) {
-		case (PH_DATA_IND):
+		case (PH_DATA | INDICATION):
 			datap = skb->data;
 			len = l2addrsize(&st->l2);
 			if (skb->len > len)
 				datap += len;
 			else {
-				st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
 				FreeSkb(skb);
 				return;
 			}
 			if (!(*datap & 1))	/* I-Frame */
 				ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
-			else if ((*datap & 3) == 1)	/* S-Frame */
+			else if (IsSFrame(datap, test_bit(FLG_MOD128, &st->l2.flag)))
 				ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb);
 			else if (IsUI(datap, test_bit(FLG_MOD128, &st->l2.flag)))
 				ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
@@ -1427,23 +1478,39 @@
 			else if (IsFRMR(datap, test_bit(FLG_MOD128, &st->l2.flag)))
 				ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
 			else {
-				ret = 0;
-				st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
-				FreeSkb(skb);
+				ret = 1;
+				if ((st->l2.l2m.state == ST_L2_7) ||
+					(st->l2.l2m.state == ST_L2_8))
+					establishlink(&st->l2.l2m);
+				st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
 			}
 			if (ret) {
 				FreeSkb(skb);
 			}
 			break;
-		case (PH_PULL_CNF):
+		case (PH_PULL | CONFIRM):
 			FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
 			break;
-		case (PH_PAUSE_IND):
+		case (PH_PAUSE | INDICATION):
 			test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
 			break;
-		case (PH_PAUSE_CNF):
+		case (PH_PAUSE | CONFIRM):
 			test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag);
 			break;
+		case (PH_ACTIVATE | CONFIRM):
+		case (PH_ACTIVATE | INDICATION):
+			test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag);
+			if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+				FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+			break;
+		case (PH_DEACTIVATE | INDICATION):
+		case (PH_DEACTIVATE | CONFIRM):
+			test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
+			FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
+			break;
+		default:
+			l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr);
+			break;
 	}
 }
 
@@ -1451,45 +1518,46 @@
 isdnl2_l3l2(struct PStack *st, int pr, void *arg)
 {
 	switch (pr) {
-		case (DL_DATA):
+		case (DL_DATA | REQUEST):
 			if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
 				dev_kfree_skb((struct sk_buff *) arg);
 			}
 			break;
-		case (DL_UNIT_DATA):
+		case (DL_UNIT_DATA | REQUEST):
 			if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
 				dev_kfree_skb((struct sk_buff *) arg);
 			}
 			break;
-	}
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr, void *arg)
-{
-	switch (pr) {
-		case (DL_ESTABLISH):
-			FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+		case (DL_ESTABLISH | REQUEST):
+			if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) {
+				if (test_bit(FLG_LAPD, &st->l2.flag) ||
+					test_bit(FLG_ORIG, &st->l2.flag)) {
+					FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+				}
+			} else {
+				if (test_bit(FLG_LAPD, &st->l2.flag) ||
+					test_bit(FLG_ORIG, &st->l2.flag)) {
+					test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
+				}
+				st->l2.l2l1(st, PH_ACTIVATE, NULL);
+			}
 			break;
-		case (DL_RELEASE):
+		case (DL_RELEASE | REQUEST):
+			if (test_bit(FLG_LAPB, &st->l2.flag)) {
+				st->l2.l2l1(st, PH_DEACTIVATE, NULL);
+			}
 			FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
 			break;
-		case (MDL_NOTEIPROC):
-			FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
-			break;
-		case (DL_FLUSH):
+		case (DL_FLUSH | REQUEST):
 			(&st->l2.l2m)->userint |= LC_FLUSH_WAIT;
 			break;
-		case (PH_DEACTIVATE_IND):
-			FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
-			break;
-		case (MDL_ASSIGN_REQ):
+		case (MDL_ASSIGN | REQUEST):
 			FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
 			break;
-		case (MDL_REMOVE_REQ):
+		case (MDL_REMOVE | REQUEST):
 			FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
 			break;
-		case (MDL_ERROR_REQ):
+		case (MDL_ERROR | RESPONSE):
 			FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg);
 			break;
 	}
@@ -1500,20 +1568,20 @@
 {
 	FsmDelTimer(&st->l2.t200, 15);
 	FsmDelTimer(&st->l2.t203, 16);
-	discard_i_queue(st);
-	discard_ui_queue(st);
+	discard_queue(&st->l2.i_queue);
+	discard_queue(&st->l2.ui_queue);
 	ReleaseWin(&st->l2);
 }
 
 static void
-l2m_debug(struct FsmInst *fi, char *s)
+l2m_debug(struct FsmInst *fi, char *fmt, ...)
 {
+	va_list args;
 	struct PStack *st = fi->userdata;
-	char tm[32], str[256];
 
-	jiftime(tm, jiffies);
-	sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
-	HiSax_putstatus(st->l1.hardware, str);
+	va_start(args, fmt);
+	VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args);
+	va_end(args);
 }
 
 void
@@ -1521,7 +1589,6 @@
 {
 	st->l1.l1l2 = isdnl2_l1l2;
 	st->l3.l3l2 = isdnl2_l3l2;
-	st->ma.manl2 = isdnl2_manl2;
 
 	skb_queue_head_init(&st->l2.i_queue);
 	skb_queue_head_init(&st->l2.ui_queue);
@@ -1529,6 +1596,9 @@
 	st->l2.debug = 0;
 
 	st->l2.l2m.fsm = &l2fsm;
+	if (test_bit(FLG_LAPB, &st->l2.flag))
+		st->l2.l2m.state = ST_L2_4;
+	else
 	st->l2.l2m.state = ST_L2_1;
 	st->l2.l2m.debug = 0;
 	st->l2.l2m.userdata = st;
@@ -1540,9 +1610,27 @@
 	FsmInitTimer(&st->l2.l2m, &st->l2.t203);
 }
 
+static void
+transl2_l3l2(struct PStack *st, int pr, void *arg)
+{
+	switch (pr) {
+		case (DL_DATA | REQUEST):
+		case (DL_UNIT_DATA | REQUEST):
+			st->l2.l2l1(st, PH_DATA | REQUEST, arg);
+			break;
+		case (DL_ESTABLISH | REQUEST):
+			st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+			break;
+		case (DL_RELEASE | REQUEST):
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+			break;
+	}
+}
+
 void
 setstack_transl2(struct PStack *st)
 {
+	st->l3.l3l2 = transl2_l3l2;
 }
 
 void

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)