xref: /openbmc/linux/drivers/isdn/mISDN/layer2.c (revision 0f817a5e)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21b2b03f8SKarsten Keil /*
31b2b03f8SKarsten Keil  *
41b2b03f8SKarsten Keil  * Author	Karsten Keil <kkeil@novell.com>
51b2b03f8SKarsten Keil  *
61b2b03f8SKarsten Keil  * Copyright 2008  by Karsten Keil <kkeil@novell.com>
71b2b03f8SKarsten Keil  */
81b2b03f8SKarsten Keil 
95b834354SHannes Eder #include <linux/mISDNif.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
115b834354SHannes Eder #include "core.h"
121b2b03f8SKarsten Keil #include "fsm.h"
131b2b03f8SKarsten Keil #include "layer2.h"
141b2b03f8SKarsten Keil 
15dfa96ec1SHannes Eder static u_int *debug;
161b2b03f8SKarsten Keil 
171b2b03f8SKarsten Keil static
181b2b03f8SKarsten Keil struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL};
191b2b03f8SKarsten Keil 
201b2b03f8SKarsten Keil static char *strL2State[] =
211b2b03f8SKarsten Keil {
221b2b03f8SKarsten Keil 	"ST_L2_1",
231b2b03f8SKarsten Keil 	"ST_L2_2",
241b2b03f8SKarsten Keil 	"ST_L2_3",
251b2b03f8SKarsten Keil 	"ST_L2_4",
261b2b03f8SKarsten Keil 	"ST_L2_5",
271b2b03f8SKarsten Keil 	"ST_L2_6",
281b2b03f8SKarsten Keil 	"ST_L2_7",
291b2b03f8SKarsten Keil 	"ST_L2_8",
301b2b03f8SKarsten Keil };
311b2b03f8SKarsten Keil 
321b2b03f8SKarsten Keil enum {
331b2b03f8SKarsten Keil 	EV_L2_UI,
341b2b03f8SKarsten Keil 	EV_L2_SABME,
351b2b03f8SKarsten Keil 	EV_L2_DISC,
361b2b03f8SKarsten Keil 	EV_L2_DM,
371b2b03f8SKarsten Keil 	EV_L2_UA,
381b2b03f8SKarsten Keil 	EV_L2_FRMR,
391b2b03f8SKarsten Keil 	EV_L2_SUPER,
401b2b03f8SKarsten Keil 	EV_L2_I,
411b2b03f8SKarsten Keil 	EV_L2_DL_DATA,
421b2b03f8SKarsten Keil 	EV_L2_ACK_PULL,
431b2b03f8SKarsten Keil 	EV_L2_DL_UNITDATA,
441b2b03f8SKarsten Keil 	EV_L2_DL_ESTABLISH_REQ,
451b2b03f8SKarsten Keil 	EV_L2_DL_RELEASE_REQ,
461b2b03f8SKarsten Keil 	EV_L2_MDL_ASSIGN,
471b2b03f8SKarsten Keil 	EV_L2_MDL_REMOVE,
481b2b03f8SKarsten Keil 	EV_L2_MDL_ERROR,
491b2b03f8SKarsten Keil 	EV_L1_DEACTIVATE,
501b2b03f8SKarsten Keil 	EV_L2_T200,
511b2b03f8SKarsten Keil 	EV_L2_T203,
528423e6b2SKarsten Keil 	EV_L2_T200I,
538423e6b2SKarsten Keil 	EV_L2_T203I,
541b2b03f8SKarsten Keil 	EV_L2_SET_OWN_BUSY,
551b2b03f8SKarsten Keil 	EV_L2_CLEAR_OWN_BUSY,
561b2b03f8SKarsten Keil 	EV_L2_FRAME_ERROR,
571b2b03f8SKarsten Keil };
581b2b03f8SKarsten Keil 
591b2b03f8SKarsten Keil #define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1)
601b2b03f8SKarsten Keil 
611b2b03f8SKarsten Keil static char *strL2Event[] =
621b2b03f8SKarsten Keil {
631b2b03f8SKarsten Keil 	"EV_L2_UI",
641b2b03f8SKarsten Keil 	"EV_L2_SABME",
651b2b03f8SKarsten Keil 	"EV_L2_DISC",
661b2b03f8SKarsten Keil 	"EV_L2_DM",
671b2b03f8SKarsten Keil 	"EV_L2_UA",
681b2b03f8SKarsten Keil 	"EV_L2_FRMR",
691b2b03f8SKarsten Keil 	"EV_L2_SUPER",
701b2b03f8SKarsten Keil 	"EV_L2_I",
711b2b03f8SKarsten Keil 	"EV_L2_DL_DATA",
721b2b03f8SKarsten Keil 	"EV_L2_ACK_PULL",
731b2b03f8SKarsten Keil 	"EV_L2_DL_UNITDATA",
741b2b03f8SKarsten Keil 	"EV_L2_DL_ESTABLISH_REQ",
751b2b03f8SKarsten Keil 	"EV_L2_DL_RELEASE_REQ",
761b2b03f8SKarsten Keil 	"EV_L2_MDL_ASSIGN",
771b2b03f8SKarsten Keil 	"EV_L2_MDL_REMOVE",
781b2b03f8SKarsten Keil 	"EV_L2_MDL_ERROR",
791b2b03f8SKarsten Keil 	"EV_L1_DEACTIVATE",
801b2b03f8SKarsten Keil 	"EV_L2_T200",
811b2b03f8SKarsten Keil 	"EV_L2_T203",
828423e6b2SKarsten Keil 	"EV_L2_T200I",
838423e6b2SKarsten Keil 	"EV_L2_T203I",
841b2b03f8SKarsten Keil 	"EV_L2_SET_OWN_BUSY",
851b2b03f8SKarsten Keil 	"EV_L2_CLEAR_OWN_BUSY",
861b2b03f8SKarsten Keil 	"EV_L2_FRAME_ERROR",
871b2b03f8SKarsten Keil };
881b2b03f8SKarsten Keil 
891b2b03f8SKarsten Keil static void
l2m_debug(struct FsmInst * fi,char * fmt,...)901b2b03f8SKarsten Keil l2m_debug(struct FsmInst *fi, char *fmt, ...)
911b2b03f8SKarsten Keil {
921b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
93020f01ebSJoe Perches 	struct va_format vaf;
941b2b03f8SKarsten Keil 	va_list va;
951b2b03f8SKarsten Keil 
961b2b03f8SKarsten Keil 	if (!(*debug & DEBUG_L2_FSM))
971b2b03f8SKarsten Keil 		return;
98020f01ebSJoe Perches 
991b2b03f8SKarsten Keil 	va_start(va, fmt);
100020f01ebSJoe Perches 
101020f01ebSJoe Perches 	vaf.fmt = fmt;
102020f01ebSJoe Perches 	vaf.va = &va;
103020f01ebSJoe Perches 
104f45ebf3aSKarsten Keil 	printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n",
105f45ebf3aSKarsten Keil 	       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf);
106020f01ebSJoe Perches 
1071b2b03f8SKarsten Keil 	va_end(va);
1081b2b03f8SKarsten Keil }
1091b2b03f8SKarsten Keil 
1101b2b03f8SKarsten Keil inline u_int
l2headersize(struct layer2 * l2,int ui)1111b2b03f8SKarsten Keil l2headersize(struct layer2 *l2, int ui)
1121b2b03f8SKarsten Keil {
1131b2b03f8SKarsten Keil 	return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
1141b2b03f8SKarsten Keil 		(test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
1151b2b03f8SKarsten Keil }
1161b2b03f8SKarsten Keil 
1171b2b03f8SKarsten Keil inline u_int
l2addrsize(struct layer2 * l2)1181b2b03f8SKarsten Keil l2addrsize(struct layer2 *l2)
1191b2b03f8SKarsten Keil {
1201b2b03f8SKarsten Keil 	return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1;
1211b2b03f8SKarsten Keil }
1221b2b03f8SKarsten Keil 
1231b2b03f8SKarsten Keil static u_int
l2_newid(struct layer2 * l2)1241b2b03f8SKarsten Keil l2_newid(struct layer2 *l2)
1251b2b03f8SKarsten Keil {
1261b2b03f8SKarsten Keil 	u_int	id;
1271b2b03f8SKarsten Keil 
1281b2b03f8SKarsten Keil 	id = l2->next_id++;
1291b2b03f8SKarsten Keil 	if (id == 0x7fff)
1301b2b03f8SKarsten Keil 		l2->next_id = 1;
1311b2b03f8SKarsten Keil 	id <<= 16;
1321b2b03f8SKarsten Keil 	id |= l2->tei << 8;
1331b2b03f8SKarsten Keil 	id |= l2->sapi;
1341b2b03f8SKarsten Keil 	return id;
1351b2b03f8SKarsten Keil }
1361b2b03f8SKarsten Keil 
1371b2b03f8SKarsten Keil static void
l2up(struct layer2 * l2,u_int prim,struct sk_buff * skb)1381b2b03f8SKarsten Keil l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb)
1391b2b03f8SKarsten Keil {
1401b2b03f8SKarsten Keil 	int	err;
1411b2b03f8SKarsten Keil 
1421b2b03f8SKarsten Keil 	if (!l2->up)
1431b2b03f8SKarsten Keil 		return;
1441b2b03f8SKarsten Keil 	mISDN_HEAD_PRIM(skb) = prim;
1451b2b03f8SKarsten Keil 	mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr;
1461b2b03f8SKarsten Keil 	err = l2->up->send(l2->up, skb);
1471b2b03f8SKarsten Keil 	if (err) {
148f45ebf3aSKarsten Keil 		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
149f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), err);
1501b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
1511b2b03f8SKarsten Keil 	}
1521b2b03f8SKarsten Keil }
1531b2b03f8SKarsten Keil 
1541b2b03f8SKarsten Keil static void
l2up_create(struct layer2 * l2,u_int prim,int len,void * arg)1551b2b03f8SKarsten Keil l2up_create(struct layer2 *l2, u_int prim, int len, void *arg)
1561b2b03f8SKarsten Keil {
1571b2b03f8SKarsten Keil 	struct sk_buff	*skb;
1581b2b03f8SKarsten Keil 	struct mISDNhead *hh;
1591b2b03f8SKarsten Keil 	int		err;
1601b2b03f8SKarsten Keil 
1611b2b03f8SKarsten Keil 	if (!l2->up)
1621b2b03f8SKarsten Keil 		return;
1631b2b03f8SKarsten Keil 	skb = mI_alloc_skb(len, GFP_ATOMIC);
1641b2b03f8SKarsten Keil 	if (!skb)
1651b2b03f8SKarsten Keil 		return;
1661b2b03f8SKarsten Keil 	hh = mISDN_HEAD_P(skb);
1671b2b03f8SKarsten Keil 	hh->prim = prim;
1681b2b03f8SKarsten Keil 	hh->id = (l2->ch.nr << 16) | l2->ch.addr;
1691b2b03f8SKarsten Keil 	if (len)
17059ae1d12SJohannes Berg 		skb_put_data(skb, arg, len);
1711b2b03f8SKarsten Keil 	err = l2->up->send(l2->up, skb);
1721b2b03f8SKarsten Keil 	if (err) {
173f45ebf3aSKarsten Keil 		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
174f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), err);
1751b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
1761b2b03f8SKarsten Keil 	}
1771b2b03f8SKarsten Keil }
1781b2b03f8SKarsten Keil 
1791b2b03f8SKarsten Keil static int
l2down_skb(struct layer2 * l2,struct sk_buff * skb)1801b2b03f8SKarsten Keil l2down_skb(struct layer2 *l2, struct sk_buff *skb) {
1811b2b03f8SKarsten Keil 	int ret;
1821b2b03f8SKarsten Keil 
1831b2b03f8SKarsten Keil 	ret = l2->ch.recv(l2->ch.peer, skb);
1841b2b03f8SKarsten Keil 	if (ret && (*debug & DEBUG_L2_RECV))
185f45ebf3aSKarsten Keil 		printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n",
186f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), ret);
1871b2b03f8SKarsten Keil 	return ret;
1881b2b03f8SKarsten Keil }
1891b2b03f8SKarsten Keil 
1901b2b03f8SKarsten Keil static int
l2down_raw(struct layer2 * l2,struct sk_buff * skb)1911b2b03f8SKarsten Keil l2down_raw(struct layer2 *l2, struct sk_buff *skb)
1921b2b03f8SKarsten Keil {
1931b2b03f8SKarsten Keil 	struct mISDNhead *hh = mISDN_HEAD_P(skb);
1941b2b03f8SKarsten Keil 
1951b2b03f8SKarsten Keil 	if (hh->prim == PH_DATA_REQ) {
1961b2b03f8SKarsten Keil 		if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
1971b2b03f8SKarsten Keil 			skb_queue_tail(&l2->down_queue, skb);
1981b2b03f8SKarsten Keil 			return 0;
1991b2b03f8SKarsten Keil 		}
2001b2b03f8SKarsten Keil 		l2->down_id = mISDN_HEAD_ID(skb);
2011b2b03f8SKarsten Keil 	}
2021b2b03f8SKarsten Keil 	return l2down_skb(l2, skb);
2031b2b03f8SKarsten Keil }
2041b2b03f8SKarsten Keil 
2051b2b03f8SKarsten Keil static int
l2down(struct layer2 * l2,u_int prim,u_int id,struct sk_buff * skb)2061b2b03f8SKarsten Keil l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb)
2071b2b03f8SKarsten Keil {
2081b2b03f8SKarsten Keil 	struct mISDNhead *hh = mISDN_HEAD_P(skb);
2091b2b03f8SKarsten Keil 
2101b2b03f8SKarsten Keil 	hh->prim = prim;
2111b2b03f8SKarsten Keil 	hh->id = id;
2121b2b03f8SKarsten Keil 	return l2down_raw(l2, skb);
2131b2b03f8SKarsten Keil }
2141b2b03f8SKarsten Keil 
2151b2b03f8SKarsten Keil static int
l2down_create(struct layer2 * l2,u_int prim,u_int id,int len,void * arg)2161b2b03f8SKarsten Keil l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg)
2171b2b03f8SKarsten Keil {
2181b2b03f8SKarsten Keil 	struct sk_buff	*skb;
2191b2b03f8SKarsten Keil 	int		err;
2201b2b03f8SKarsten Keil 	struct mISDNhead *hh;
2211b2b03f8SKarsten Keil 
2221b2b03f8SKarsten Keil 	skb = mI_alloc_skb(len, GFP_ATOMIC);
2231b2b03f8SKarsten Keil 	if (!skb)
2241b2b03f8SKarsten Keil 		return -ENOMEM;
2251b2b03f8SKarsten Keil 	hh = mISDN_HEAD_P(skb);
2261b2b03f8SKarsten Keil 	hh->prim = prim;
2271b2b03f8SKarsten Keil 	hh->id = id;
2281b2b03f8SKarsten Keil 	if (len)
22959ae1d12SJohannes Berg 		skb_put_data(skb, arg, len);
2301b2b03f8SKarsten Keil 	err = l2down_raw(l2, skb);
2311b2b03f8SKarsten Keil 	if (err)
2321b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
2331b2b03f8SKarsten Keil 	return err;
2341b2b03f8SKarsten Keil }
2351b2b03f8SKarsten Keil 
2361b2b03f8SKarsten Keil static int
ph_data_confirm(struct layer2 * l2,struct mISDNhead * hh,struct sk_buff * skb)2371b2b03f8SKarsten Keil ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) {
2381b2b03f8SKarsten Keil 	struct sk_buff *nskb = skb;
2391b2b03f8SKarsten Keil 	int ret = -EAGAIN;
2401b2b03f8SKarsten Keil 
2411b2b03f8SKarsten Keil 	if (test_bit(FLG_L1_NOTREADY, &l2->flag)) {
2421b2b03f8SKarsten Keil 		if (hh->id == l2->down_id) {
2431b2b03f8SKarsten Keil 			nskb = skb_dequeue(&l2->down_queue);
2441b2b03f8SKarsten Keil 			if (nskb) {
2451b2b03f8SKarsten Keil 				l2->down_id = mISDN_HEAD_ID(nskb);
2461b2b03f8SKarsten Keil 				if (l2down_skb(l2, nskb)) {
2471b2b03f8SKarsten Keil 					dev_kfree_skb(nskb);
2481b2b03f8SKarsten Keil 					l2->down_id = MISDN_ID_NONE;
2491b2b03f8SKarsten Keil 				}
2501b2b03f8SKarsten Keil 			} else
2511b2b03f8SKarsten Keil 				l2->down_id = MISDN_ID_NONE;
2521b2b03f8SKarsten Keil 			if (ret) {
2531b2b03f8SKarsten Keil 				dev_kfree_skb(skb);
2541b2b03f8SKarsten Keil 				ret = 0;
2551b2b03f8SKarsten Keil 			}
2561b2b03f8SKarsten Keil 			if (l2->down_id == MISDN_ID_NONE) {
2571b2b03f8SKarsten Keil 				test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
2581b2b03f8SKarsten Keil 				mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
2591b2b03f8SKarsten Keil 			}
2601b2b03f8SKarsten Keil 		}
2611b2b03f8SKarsten Keil 	}
2621b2b03f8SKarsten Keil 	if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
2631b2b03f8SKarsten Keil 		nskb = skb_dequeue(&l2->down_queue);
2641b2b03f8SKarsten Keil 		if (nskb) {
2651b2b03f8SKarsten Keil 			l2->down_id = mISDN_HEAD_ID(nskb);
2661b2b03f8SKarsten Keil 			if (l2down_skb(l2, nskb)) {
2671b2b03f8SKarsten Keil 				dev_kfree_skb(nskb);
2681b2b03f8SKarsten Keil 				l2->down_id = MISDN_ID_NONE;
2691b2b03f8SKarsten Keil 				test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
2701b2b03f8SKarsten Keil 			}
2711b2b03f8SKarsten Keil 		} else
2721b2b03f8SKarsten Keil 			test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
2731b2b03f8SKarsten Keil 	}
2741b2b03f8SKarsten Keil 	return ret;
2751b2b03f8SKarsten Keil }
2761b2b03f8SKarsten Keil 
2778423e6b2SKarsten Keil static void
l2_timeout(struct FsmInst * fi,int event,void * arg)2788423e6b2SKarsten Keil l2_timeout(struct FsmInst *fi, int event, void *arg)
2798423e6b2SKarsten Keil {
2808423e6b2SKarsten Keil 	struct layer2 *l2 = fi->userdata;
2818423e6b2SKarsten Keil 	struct sk_buff *skb;
2828423e6b2SKarsten Keil 	struct mISDNhead *hh;
2838423e6b2SKarsten Keil 
2848423e6b2SKarsten Keil 	skb = mI_alloc_skb(0, GFP_ATOMIC);
2858423e6b2SKarsten Keil 	if (!skb) {
286f45ebf3aSKarsten Keil 		printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n",
287f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
288f45ebf3aSKarsten Keil 		       l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
2898423e6b2SKarsten Keil 		return;
2908423e6b2SKarsten Keil 	}
2918423e6b2SKarsten Keil 	hh = mISDN_HEAD_P(skb);
2928423e6b2SKarsten Keil 	hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
2938423e6b2SKarsten Keil 	hh->id = l2->ch.nr;
2948423e6b2SKarsten Keil 	if (*debug & DEBUG_TIMER)
295f45ebf3aSKarsten Keil 		printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n",
296f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
297f45ebf3aSKarsten Keil 		       l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
2988423e6b2SKarsten Keil 	if (l2->ch.st)
2998423e6b2SKarsten Keil 		l2->ch.st->own.recv(&l2->ch.st->own, skb);
3008423e6b2SKarsten Keil }
3018423e6b2SKarsten Keil 
3021b2b03f8SKarsten Keil static int
l2mgr(struct layer2 * l2,u_int prim,void * arg)3031b2b03f8SKarsten Keil l2mgr(struct layer2 *l2, u_int prim, void *arg) {
3041b2b03f8SKarsten Keil 	long c = (long)arg;
3051b2b03f8SKarsten Keil 
306f45ebf3aSKarsten Keil 	printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n",
307f45ebf3aSKarsten Keil 	       mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c);
3081b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag) &&
3091b2b03f8SKarsten Keil 	    !test_bit(FLG_FIXED_TEI, &l2->flag)) {
3101b2b03f8SKarsten Keil 		switch (c) {
3111b2b03f8SKarsten Keil 		case 'C':
3121b2b03f8SKarsten Keil 		case 'D':
3131b2b03f8SKarsten Keil 		case 'G':
3141b2b03f8SKarsten Keil 		case 'H':
3151b2b03f8SKarsten Keil 			l2_tei(l2, prim, (u_long)arg);
3161b2b03f8SKarsten Keil 			break;
3171b2b03f8SKarsten Keil 		}
3181b2b03f8SKarsten Keil 	}
3191b2b03f8SKarsten Keil 	return 0;
3201b2b03f8SKarsten Keil }
3211b2b03f8SKarsten Keil 
3221b2b03f8SKarsten Keil static void
set_peer_busy(struct layer2 * l2)3231b2b03f8SKarsten Keil set_peer_busy(struct layer2 *l2) {
3241b2b03f8SKarsten Keil 	test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
3251b2b03f8SKarsten Keil 	if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
3261b2b03f8SKarsten Keil 		test_and_set_bit(FLG_L2BLOCK, &l2->flag);
3271b2b03f8SKarsten Keil }
3281b2b03f8SKarsten Keil 
3291b2b03f8SKarsten Keil static void
clear_peer_busy(struct layer2 * l2)3301b2b03f8SKarsten Keil clear_peer_busy(struct layer2 *l2) {
3311b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
3321b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
3331b2b03f8SKarsten Keil }
3341b2b03f8SKarsten Keil 
3351b2b03f8SKarsten Keil static void
InitWin(struct layer2 * l2)3361b2b03f8SKarsten Keil InitWin(struct layer2 *l2)
3371b2b03f8SKarsten Keil {
3381b2b03f8SKarsten Keil 	int i;
3391b2b03f8SKarsten Keil 
3401b2b03f8SKarsten Keil 	for (i = 0; i < MAX_WINDOW; i++)
3411b2b03f8SKarsten Keil 		l2->windowar[i] = NULL;
3421b2b03f8SKarsten Keil }
3431b2b03f8SKarsten Keil 
3441b2b03f8SKarsten Keil static int
freewin(struct layer2 * l2)3451b2b03f8SKarsten Keil freewin(struct layer2 *l2)
3461b2b03f8SKarsten Keil {
3471b2b03f8SKarsten Keil 	int i, cnt = 0;
3481b2b03f8SKarsten Keil 
3491b2b03f8SKarsten Keil 	for (i = 0; i < MAX_WINDOW; i++) {
3501b2b03f8SKarsten Keil 		if (l2->windowar[i]) {
3511b2b03f8SKarsten Keil 			cnt++;
3521b2b03f8SKarsten Keil 			dev_kfree_skb(l2->windowar[i]);
3531b2b03f8SKarsten Keil 			l2->windowar[i] = NULL;
3541b2b03f8SKarsten Keil 		}
3551b2b03f8SKarsten Keil 	}
3561b2b03f8SKarsten Keil 	return cnt;
3571b2b03f8SKarsten Keil }
3581b2b03f8SKarsten Keil 
3591b2b03f8SKarsten Keil static void
ReleaseWin(struct layer2 * l2)3601b2b03f8SKarsten Keil ReleaseWin(struct layer2 *l2)
3611b2b03f8SKarsten Keil {
3621b2b03f8SKarsten Keil 	int cnt = freewin(l2);
3631b2b03f8SKarsten Keil 
3641b2b03f8SKarsten Keil 	if (cnt)
3651b2b03f8SKarsten Keil 		printk(KERN_WARNING
3661b2b03f8SKarsten Keil 		       "isdnl2 freed %d skbuffs in release\n", cnt);
3671b2b03f8SKarsten Keil }
3681b2b03f8SKarsten Keil 
3691b2b03f8SKarsten Keil inline unsigned int
cansend(struct layer2 * l2)3701b2b03f8SKarsten Keil cansend(struct layer2 *l2)
3711b2b03f8SKarsten Keil {
3721b2b03f8SKarsten Keil 	unsigned int p1;
3731b2b03f8SKarsten Keil 
3741b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag))
3751b2b03f8SKarsten Keil 		p1 = (l2->vs - l2->va) % 128;
3761b2b03f8SKarsten Keil 	else
3771b2b03f8SKarsten Keil 		p1 = (l2->vs - l2->va) % 8;
3781b2b03f8SKarsten Keil 	return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag);
3791b2b03f8SKarsten Keil }
3801b2b03f8SKarsten Keil 
3811b2b03f8SKarsten Keil inline void
clear_exception(struct layer2 * l2)3821b2b03f8SKarsten Keil clear_exception(struct layer2 *l2)
3831b2b03f8SKarsten Keil {
3841b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
3851b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_REJEXC, &l2->flag);
3861b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
3871b2b03f8SKarsten Keil 	clear_peer_busy(l2);
3881b2b03f8SKarsten Keil }
3891b2b03f8SKarsten Keil 
3901b2b03f8SKarsten Keil static int
sethdraddr(struct layer2 * l2,u_char * header,int rsp)3911b2b03f8SKarsten Keil sethdraddr(struct layer2 *l2, u_char *header, int rsp)
3921b2b03f8SKarsten Keil {
3931b2b03f8SKarsten Keil 	u_char *ptr = header;
3941b2b03f8SKarsten Keil 	int crbit = rsp;
3951b2b03f8SKarsten Keil 
3961b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag)) {
3971b2b03f8SKarsten Keil 		if (test_bit(FLG_LAPD_NET, &l2->flag))
3981b2b03f8SKarsten Keil 			crbit = !crbit;
3991b2b03f8SKarsten Keil 		*ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0);
4001b2b03f8SKarsten Keil 		*ptr++ = (l2->tei << 1) | 1;
4011b2b03f8SKarsten Keil 		return 2;
4021b2b03f8SKarsten Keil 	} else {
4031b2b03f8SKarsten Keil 		if (test_bit(FLG_ORIG, &l2->flag))
4041b2b03f8SKarsten Keil 			crbit = !crbit;
4051b2b03f8SKarsten Keil 		if (crbit)
4061b2b03f8SKarsten Keil 			*ptr++ = l2->addr.B;
4071b2b03f8SKarsten Keil 		else
4081b2b03f8SKarsten Keil 			*ptr++ = l2->addr.A;
4091b2b03f8SKarsten Keil 		return 1;
4101b2b03f8SKarsten Keil 	}
4111b2b03f8SKarsten Keil }
4121b2b03f8SKarsten Keil 
4131b2b03f8SKarsten Keil static inline void
enqueue_super(struct layer2 * l2,struct sk_buff * skb)4141b2b03f8SKarsten Keil enqueue_super(struct layer2 *l2, struct sk_buff *skb)
4151b2b03f8SKarsten Keil {
4161b2b03f8SKarsten Keil 	if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
4171b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
4181b2b03f8SKarsten Keil }
4191b2b03f8SKarsten Keil 
4201b2b03f8SKarsten Keil static inline void
enqueue_ui(struct layer2 * l2,struct sk_buff * skb)4211b2b03f8SKarsten Keil enqueue_ui(struct layer2 *l2, struct sk_buff *skb)
4221b2b03f8SKarsten Keil {
4231b2b03f8SKarsten Keil 	if (l2->tm)
4241b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_UI_IND, 0);
4251b2b03f8SKarsten Keil 	if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
4261b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
4271b2b03f8SKarsten Keil }
4281b2b03f8SKarsten Keil 
4291b2b03f8SKarsten Keil inline int
IsUI(u_char * data)4301b2b03f8SKarsten Keil IsUI(u_char *data)
4311b2b03f8SKarsten Keil {
4321b2b03f8SKarsten Keil 	return (data[0] & 0xef) == UI;
4331b2b03f8SKarsten Keil }
4341b2b03f8SKarsten Keil 
4351b2b03f8SKarsten Keil inline int
IsUA(u_char * data)4361b2b03f8SKarsten Keil IsUA(u_char *data)
4371b2b03f8SKarsten Keil {
4381b2b03f8SKarsten Keil 	return (data[0] & 0xef) == UA;
4391b2b03f8SKarsten Keil }
4401b2b03f8SKarsten Keil 
4411b2b03f8SKarsten Keil inline int
IsDM(u_char * data)4421b2b03f8SKarsten Keil IsDM(u_char *data)
4431b2b03f8SKarsten Keil {
4441b2b03f8SKarsten Keil 	return (data[0] & 0xef) == DM;
4451b2b03f8SKarsten Keil }
4461b2b03f8SKarsten Keil 
4471b2b03f8SKarsten Keil inline int
IsDISC(u_char * data)4481b2b03f8SKarsten Keil IsDISC(u_char *data)
4491b2b03f8SKarsten Keil {
4501b2b03f8SKarsten Keil 	return (data[0] & 0xef) == DISC;
4511b2b03f8SKarsten Keil }
4521b2b03f8SKarsten Keil 
4531b2b03f8SKarsten Keil inline int
IsRR(u_char * data,struct layer2 * l2)4541b2b03f8SKarsten Keil IsRR(u_char *data, struct layer2 *l2)
4551b2b03f8SKarsten Keil {
4561b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag))
4571b2b03f8SKarsten Keil 		return data[0] == RR;
4581b2b03f8SKarsten Keil 	else
4591b2b03f8SKarsten Keil 		return (data[0] & 0xf) == 1;
4601b2b03f8SKarsten Keil }
4611b2b03f8SKarsten Keil 
4621b2b03f8SKarsten Keil inline int
IsSFrame(u_char * data,struct layer2 * l2)4631b2b03f8SKarsten Keil IsSFrame(u_char *data, struct layer2 *l2)
4641b2b03f8SKarsten Keil {
4651b2b03f8SKarsten Keil 	register u_char d = *data;
4661b2b03f8SKarsten Keil 
4671b2b03f8SKarsten Keil 	if (!test_bit(FLG_MOD128, &l2->flag))
4681b2b03f8SKarsten Keil 		d &= 0xf;
4691b2b03f8SKarsten Keil 	return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c);
4701b2b03f8SKarsten Keil }
4711b2b03f8SKarsten Keil 
4721b2b03f8SKarsten Keil inline int
IsSABME(u_char * data,struct layer2 * l2)4731b2b03f8SKarsten Keil IsSABME(u_char *data, struct layer2 *l2)
4741b2b03f8SKarsten Keil {
4751b2b03f8SKarsten Keil 	u_char d = data[0] & ~0x10;
4761b2b03f8SKarsten Keil 
4771b2b03f8SKarsten Keil 	return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM;
4781b2b03f8SKarsten Keil }
4791b2b03f8SKarsten Keil 
4801b2b03f8SKarsten Keil inline int
IsREJ(u_char * data,struct layer2 * l2)4811b2b03f8SKarsten Keil IsREJ(u_char *data, struct layer2 *l2)
4821b2b03f8SKarsten Keil {
4831b2b03f8SKarsten Keil 	return test_bit(FLG_MOD128, &l2->flag) ?
4841b2b03f8SKarsten Keil 		data[0] == REJ : (data[0] & 0xf) == REJ;
4851b2b03f8SKarsten Keil }
4861b2b03f8SKarsten Keil 
4871b2b03f8SKarsten Keil inline int
IsFRMR(u_char * data)4881b2b03f8SKarsten Keil IsFRMR(u_char *data)
4891b2b03f8SKarsten Keil {
4901b2b03f8SKarsten Keil 	return (data[0] & 0xef) == FRMR;
4911b2b03f8SKarsten Keil }
4921b2b03f8SKarsten Keil 
4931b2b03f8SKarsten Keil inline int
IsRNR(u_char * data,struct layer2 * l2)4941b2b03f8SKarsten Keil IsRNR(u_char *data, struct layer2 *l2)
4951b2b03f8SKarsten Keil {
4961b2b03f8SKarsten Keil 	return test_bit(FLG_MOD128, &l2->flag) ?
4971b2b03f8SKarsten Keil 		data[0] == RNR : (data[0] & 0xf) == RNR;
4981b2b03f8SKarsten Keil }
4991b2b03f8SKarsten Keil 
5005b834354SHannes Eder static int
iframe_error(struct layer2 * l2,struct sk_buff * skb)5011b2b03f8SKarsten Keil iframe_error(struct layer2 *l2, struct sk_buff *skb)
5021b2b03f8SKarsten Keil {
5031b2b03f8SKarsten Keil 	u_int	i;
5041b2b03f8SKarsten Keil 	int	rsp = *skb->data & 0x2;
5051b2b03f8SKarsten Keil 
5061b2b03f8SKarsten Keil 	i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1);
5071b2b03f8SKarsten Keil 	if (test_bit(FLG_ORIG, &l2->flag))
5081b2b03f8SKarsten Keil 		rsp = !rsp;
5091b2b03f8SKarsten Keil 	if (rsp)
5101b2b03f8SKarsten Keil 		return 'L';
5111b2b03f8SKarsten Keil 	if (skb->len < i)
5121b2b03f8SKarsten Keil 		return 'N';
5131b2b03f8SKarsten Keil 	if ((skb->len - i) > l2->maxlen)
5141b2b03f8SKarsten Keil 		return 'O';
5151b2b03f8SKarsten Keil 	return 0;
5161b2b03f8SKarsten Keil }
5171b2b03f8SKarsten Keil 
5185b834354SHannes Eder static int
super_error(struct layer2 * l2,struct sk_buff * skb)5191b2b03f8SKarsten Keil super_error(struct layer2 *l2, struct sk_buff *skb)
5201b2b03f8SKarsten Keil {
5211b2b03f8SKarsten Keil 	if (skb->len != l2addrsize(l2) +
5221b2b03f8SKarsten Keil 	    (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1))
5231b2b03f8SKarsten Keil 		return 'N';
5241b2b03f8SKarsten Keil 	return 0;
5251b2b03f8SKarsten Keil }
5261b2b03f8SKarsten Keil 
5275b834354SHannes Eder static int
unnum_error(struct layer2 * l2,struct sk_buff * skb,int wantrsp)5281b2b03f8SKarsten Keil unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp)
5291b2b03f8SKarsten Keil {
5301b2b03f8SKarsten Keil 	int rsp = (*skb->data & 0x2) >> 1;
5311b2b03f8SKarsten Keil 	if (test_bit(FLG_ORIG, &l2->flag))
5321b2b03f8SKarsten Keil 		rsp = !rsp;
5331b2b03f8SKarsten Keil 	if (rsp != wantrsp)
5341b2b03f8SKarsten Keil 		return 'L';
5351b2b03f8SKarsten Keil 	if (skb->len != l2addrsize(l2) + 1)
5361b2b03f8SKarsten Keil 		return 'N';
5371b2b03f8SKarsten Keil 	return 0;
5381b2b03f8SKarsten Keil }
5391b2b03f8SKarsten Keil 
5405b834354SHannes Eder static int
UI_error(struct layer2 * l2,struct sk_buff * skb)5411b2b03f8SKarsten Keil UI_error(struct layer2 *l2, struct sk_buff *skb)
5421b2b03f8SKarsten Keil {
5431b2b03f8SKarsten Keil 	int rsp = *skb->data & 0x2;
5441b2b03f8SKarsten Keil 	if (test_bit(FLG_ORIG, &l2->flag))
5451b2b03f8SKarsten Keil 		rsp = !rsp;
5461b2b03f8SKarsten Keil 	if (rsp)
5471b2b03f8SKarsten Keil 		return 'L';
5481b2b03f8SKarsten Keil 	if (skb->len > l2->maxlen + l2addrsize(l2) + 1)
5491b2b03f8SKarsten Keil 		return 'O';
5501b2b03f8SKarsten Keil 	return 0;
5511b2b03f8SKarsten Keil }
5521b2b03f8SKarsten Keil 
5535b834354SHannes Eder static int
FRMR_error(struct layer2 * l2,struct sk_buff * skb)5541b2b03f8SKarsten Keil FRMR_error(struct layer2 *l2, struct sk_buff *skb)
5551b2b03f8SKarsten Keil {
5561b2b03f8SKarsten Keil 	u_int	headers = l2addrsize(l2) + 1;
5571b2b03f8SKarsten Keil 	u_char	*datap = skb->data + headers;
5581b2b03f8SKarsten Keil 	int	rsp = *skb->data & 0x2;
5591b2b03f8SKarsten Keil 
5601b2b03f8SKarsten Keil 	if (test_bit(FLG_ORIG, &l2->flag))
5611b2b03f8SKarsten Keil 		rsp = !rsp;
5621b2b03f8SKarsten Keil 	if (!rsp)
5631b2b03f8SKarsten Keil 		return 'L';
5641b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
5651b2b03f8SKarsten Keil 		if (skb->len < headers + 5)
5661b2b03f8SKarsten Keil 			return 'N';
5671b2b03f8SKarsten Keil 		else if (*debug & DEBUG_L2)
5681b2b03f8SKarsten Keil 			l2m_debug(&l2->l2m,
5691b2b03f8SKarsten Keil 				  "FRMR information %2x %2x %2x %2x %2x",
5701b2b03f8SKarsten Keil 				  datap[0], datap[1], datap[2], datap[3], datap[4]);
5711b2b03f8SKarsten Keil 	} else {
5721b2b03f8SKarsten Keil 		if (skb->len < headers + 3)
5731b2b03f8SKarsten Keil 			return 'N';
5741b2b03f8SKarsten Keil 		else if (*debug & DEBUG_L2)
5751b2b03f8SKarsten Keil 			l2m_debug(&l2->l2m,
5761b2b03f8SKarsten Keil 				  "FRMR information %2x %2x %2x",
5771b2b03f8SKarsten Keil 				  datap[0], datap[1], datap[2]);
5781b2b03f8SKarsten Keil 	}
5791b2b03f8SKarsten Keil 	return 0;
5801b2b03f8SKarsten Keil }
5811b2b03f8SKarsten Keil 
5821b2b03f8SKarsten Keil static unsigned int
legalnr(struct layer2 * l2,unsigned int nr)5831b2b03f8SKarsten Keil legalnr(struct layer2 *l2, unsigned int nr)
5841b2b03f8SKarsten Keil {
5851b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag))
5861b2b03f8SKarsten Keil 		return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
5871b2b03f8SKarsten Keil 	else
5881b2b03f8SKarsten Keil 		return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
5891b2b03f8SKarsten Keil }
5901b2b03f8SKarsten Keil 
5911b2b03f8SKarsten Keil static void
setva(struct layer2 * l2,unsigned int nr)5921b2b03f8SKarsten Keil setva(struct layer2 *l2, unsigned int nr)
5931b2b03f8SKarsten Keil {
5941b2b03f8SKarsten Keil 	struct sk_buff	*skb;
5951b2b03f8SKarsten Keil 
5961b2b03f8SKarsten Keil 	while (l2->va != nr) {
5971b2b03f8SKarsten Keil 		l2->va++;
5981b2b03f8SKarsten Keil 		if (test_bit(FLG_MOD128, &l2->flag))
5991b2b03f8SKarsten Keil 			l2->va %= 128;
6001b2b03f8SKarsten Keil 		else
6011b2b03f8SKarsten Keil 			l2->va %= 8;
6021b2b03f8SKarsten Keil 		if (l2->windowar[l2->sow]) {
6031b2b03f8SKarsten Keil 			skb_trim(l2->windowar[l2->sow], 0);
6041b2b03f8SKarsten Keil 			skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]);
6051b2b03f8SKarsten Keil 			l2->windowar[l2->sow] = NULL;
6061b2b03f8SKarsten Keil 		}
6071b2b03f8SKarsten Keil 		l2->sow = (l2->sow + 1) % l2->window;
6081b2b03f8SKarsten Keil 	}
6091b2b03f8SKarsten Keil 	skb = skb_dequeue(&l2->tmp_queue);
6101b2b03f8SKarsten Keil 	while (skb) {
6111b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
6121b2b03f8SKarsten Keil 		skb = skb_dequeue(&l2->tmp_queue);
6131b2b03f8SKarsten Keil 	}
6141b2b03f8SKarsten Keil }
6151b2b03f8SKarsten Keil 
6161b2b03f8SKarsten Keil static void
send_uframe(struct layer2 * l2,struct sk_buff * skb,u_char cmd,u_char cr)6171b2b03f8SKarsten Keil send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr)
6181b2b03f8SKarsten Keil {
6191b2b03f8SKarsten Keil 	u_char tmp[MAX_L2HEADER_LEN];
6201b2b03f8SKarsten Keil 	int i;
6211b2b03f8SKarsten Keil 
6221b2b03f8SKarsten Keil 	i = sethdraddr(l2, tmp, cr);
6231b2b03f8SKarsten Keil 	tmp[i++] = cmd;
6241b2b03f8SKarsten Keil 	if (skb)
6251b2b03f8SKarsten Keil 		skb_trim(skb, 0);
6261b2b03f8SKarsten Keil 	else {
6271b2b03f8SKarsten Keil 		skb = mI_alloc_skb(i, GFP_ATOMIC);
6281b2b03f8SKarsten Keil 		if (!skb) {
629f45ebf3aSKarsten Keil 			printk(KERN_WARNING "%s: can't alloc skbuff in %s\n",
630f45ebf3aSKarsten Keil 			       mISDNDevName4ch(&l2->ch), __func__);
6311b2b03f8SKarsten Keil 			return;
6321b2b03f8SKarsten Keil 		}
6331b2b03f8SKarsten Keil 	}
63459ae1d12SJohannes Berg 	skb_put_data(skb, tmp, i);
6351b2b03f8SKarsten Keil 	enqueue_super(l2, skb);
6361b2b03f8SKarsten Keil }
6371b2b03f8SKarsten Keil 
6381b2b03f8SKarsten Keil 
6391b2b03f8SKarsten Keil inline u_char
get_PollFlag(struct layer2 * l2,struct sk_buff * skb)6401b2b03f8SKarsten Keil get_PollFlag(struct layer2 *l2, struct sk_buff *skb)
6411b2b03f8SKarsten Keil {
6421b2b03f8SKarsten Keil 	return skb->data[l2addrsize(l2)] & 0x10;
6431b2b03f8SKarsten Keil }
6441b2b03f8SKarsten Keil 
6451b2b03f8SKarsten Keil inline u_char
get_PollFlagFree(struct layer2 * l2,struct sk_buff * skb)6461b2b03f8SKarsten Keil get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb)
6471b2b03f8SKarsten Keil {
6481b2b03f8SKarsten Keil 	u_char PF;
6491b2b03f8SKarsten Keil 
6501b2b03f8SKarsten Keil 	PF = get_PollFlag(l2, skb);
6511b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
6521b2b03f8SKarsten Keil 	return PF;
6531b2b03f8SKarsten Keil }
6541b2b03f8SKarsten Keil 
6551b2b03f8SKarsten Keil inline void
start_t200(struct layer2 * l2,int i)6561b2b03f8SKarsten Keil start_t200(struct layer2 *l2, int i)
6571b2b03f8SKarsten Keil {
6581b2b03f8SKarsten Keil 	mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
6591b2b03f8SKarsten Keil 	test_and_set_bit(FLG_T200_RUN, &l2->flag);
6601b2b03f8SKarsten Keil }
6611b2b03f8SKarsten Keil 
6621b2b03f8SKarsten Keil inline void
restart_t200(struct layer2 * l2,int i)6631b2b03f8SKarsten Keil restart_t200(struct layer2 *l2, int i)
6641b2b03f8SKarsten Keil {
6651b2b03f8SKarsten Keil 	mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
6661b2b03f8SKarsten Keil 	test_and_set_bit(FLG_T200_RUN, &l2->flag);
6671b2b03f8SKarsten Keil }
6681b2b03f8SKarsten Keil 
6691b2b03f8SKarsten Keil inline void
stop_t200(struct layer2 * l2,int i)6701b2b03f8SKarsten Keil stop_t200(struct layer2 *l2, int i)
6711b2b03f8SKarsten Keil {
6721b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_T200_RUN, &l2->flag))
6731b2b03f8SKarsten Keil 		mISDN_FsmDelTimer(&l2->t200, i);
6741b2b03f8SKarsten Keil }
6751b2b03f8SKarsten Keil 
6761b2b03f8SKarsten Keil inline void
st5_dl_release_l2l3(struct layer2 * l2)6771b2b03f8SKarsten Keil st5_dl_release_l2l3(struct layer2 *l2)
6781b2b03f8SKarsten Keil {
6791b2b03f8SKarsten Keil 	int pr;
6801b2b03f8SKarsten Keil 
6811b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
6821b2b03f8SKarsten Keil 		pr = DL_RELEASE_CNF;
6831b2b03f8SKarsten Keil 	else
6841b2b03f8SKarsten Keil 		pr = DL_RELEASE_IND;
6851b2b03f8SKarsten Keil 	l2up_create(l2, pr, 0, NULL);
6861b2b03f8SKarsten Keil }
6871b2b03f8SKarsten Keil 
6881b2b03f8SKarsten Keil inline void
lapb_dl_release_l2l3(struct layer2 * l2,int f)6891b2b03f8SKarsten Keil lapb_dl_release_l2l3(struct layer2 *l2, int f)
6901b2b03f8SKarsten Keil {
6911b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPB, &l2->flag))
6921b2b03f8SKarsten Keil 		l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL);
6931b2b03f8SKarsten Keil 	l2up_create(l2, f, 0, NULL);
6941b2b03f8SKarsten Keil }
6951b2b03f8SKarsten Keil 
6961b2b03f8SKarsten Keil static void
establishlink(struct FsmInst * fi)6971b2b03f8SKarsten Keil establishlink(struct FsmInst *fi)
6981b2b03f8SKarsten Keil {
6991b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
7001b2b03f8SKarsten Keil 	u_char cmd;
7011b2b03f8SKarsten Keil 
7021b2b03f8SKarsten Keil 	clear_exception(l2);
7031b2b03f8SKarsten Keil 	l2->rc = 0;
7041b2b03f8SKarsten Keil 	cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10;
7051b2b03f8SKarsten Keil 	send_uframe(l2, NULL, cmd, CMD);
7061b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t203, 1);
7071b2b03f8SKarsten Keil 	restart_t200(l2, 1);
7081b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
7091b2b03f8SKarsten Keil 	freewin(l2);
7101b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_5);
7111b2b03f8SKarsten Keil }
7121b2b03f8SKarsten Keil 
7131b2b03f8SKarsten Keil static void
l2_mdl_error_ua(struct FsmInst * fi,int event,void * arg)7141b2b03f8SKarsten Keil l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
7151b2b03f8SKarsten Keil {
7161b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
7171b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
7181b2b03f8SKarsten Keil 
7191b2b03f8SKarsten Keil 	if (get_PollFlagFree(l2, skb))
7201b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'C');
7211b2b03f8SKarsten Keil 	else
7221b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'D');
7231b2b03f8SKarsten Keil 
7241b2b03f8SKarsten Keil }
7251b2b03f8SKarsten Keil 
7261b2b03f8SKarsten Keil static void
l2_mdl_error_dm(struct FsmInst * fi,int event,void * arg)7271b2b03f8SKarsten Keil l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
7281b2b03f8SKarsten Keil {
7291b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
7301b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
7311b2b03f8SKarsten Keil 
7321b2b03f8SKarsten Keil 	if (get_PollFlagFree(l2, skb))
7331b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
7341b2b03f8SKarsten Keil 	else {
7351b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
7361b2b03f8SKarsten Keil 		establishlink(fi);
7371b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
7381b2b03f8SKarsten Keil 	}
7391b2b03f8SKarsten Keil }
7401b2b03f8SKarsten Keil 
7411b2b03f8SKarsten Keil static void
l2_st8_mdl_error_dm(struct FsmInst * fi,int event,void * arg)7421b2b03f8SKarsten Keil l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
7431b2b03f8SKarsten Keil {
7441b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
7451b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
7461b2b03f8SKarsten Keil 
7471b2b03f8SKarsten Keil 	if (get_PollFlagFree(l2, skb))
7481b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
7491b2b03f8SKarsten Keil 	else
7501b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
7511b2b03f8SKarsten Keil 	establishlink(fi);
7521b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
7531b2b03f8SKarsten Keil }
7541b2b03f8SKarsten Keil 
7551b2b03f8SKarsten Keil static void
l2_go_st3(struct FsmInst * fi,int event,void * arg)7561b2b03f8SKarsten Keil l2_go_st3(struct FsmInst *fi, int event, void *arg)
7571b2b03f8SKarsten Keil {
7581b2b03f8SKarsten Keil 	dev_kfree_skb((struct sk_buff *)arg);
7591b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_3);
7601b2b03f8SKarsten Keil }
7611b2b03f8SKarsten Keil 
7621b2b03f8SKarsten Keil static void
l2_mdl_assign(struct FsmInst * fi,int event,void * arg)7631b2b03f8SKarsten Keil l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
7641b2b03f8SKarsten Keil {
7651b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
7661b2b03f8SKarsten Keil 
7671b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_3);
7681b2b03f8SKarsten Keil 	dev_kfree_skb((struct sk_buff *)arg);
7691b2b03f8SKarsten Keil 	l2_tei(l2, MDL_ASSIGN_IND, 0);
7701b2b03f8SKarsten Keil }
7711b2b03f8SKarsten Keil 
7721b2b03f8SKarsten Keil static void
l2_queue_ui_assign(struct FsmInst * fi,int event,void * arg)7731b2b03f8SKarsten Keil l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
7741b2b03f8SKarsten Keil {
7751b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
7761b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
7771b2b03f8SKarsten Keil 
7781b2b03f8SKarsten Keil 	skb_queue_tail(&l2->ui_queue, skb);
7791b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_2);
7801b2b03f8SKarsten Keil 	l2_tei(l2, MDL_ASSIGN_IND, 0);
7811b2b03f8SKarsten Keil }
7821b2b03f8SKarsten Keil 
7831b2b03f8SKarsten Keil static void
l2_queue_ui(struct FsmInst * fi,int event,void * arg)7841b2b03f8SKarsten Keil l2_queue_ui(struct FsmInst *fi, int event, void *arg)
7851b2b03f8SKarsten Keil {
7861b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
7871b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
7881b2b03f8SKarsten Keil 
7891b2b03f8SKarsten Keil 	skb_queue_tail(&l2->ui_queue, skb);
7901b2b03f8SKarsten Keil }
7911b2b03f8SKarsten Keil 
7921b2b03f8SKarsten Keil static void
tx_ui(struct layer2 * l2)7931b2b03f8SKarsten Keil tx_ui(struct layer2 *l2)
7941b2b03f8SKarsten Keil {
7951b2b03f8SKarsten Keil 	struct sk_buff *skb;
7961b2b03f8SKarsten Keil 	u_char header[MAX_L2HEADER_LEN];
7971b2b03f8SKarsten Keil 	int i;
7981b2b03f8SKarsten Keil 
7991b2b03f8SKarsten Keil 	i = sethdraddr(l2, header, CMD);
8001b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD_NET, &l2->flag))
8011b2b03f8SKarsten Keil 		header[1] = 0xff; /* tei 127 */
8021b2b03f8SKarsten Keil 	header[i++] = UI;
8031b2b03f8SKarsten Keil 	while ((skb = skb_dequeue(&l2->ui_queue))) {
8041b2b03f8SKarsten Keil 		memcpy(skb_push(skb, i), header, i);
8051b2b03f8SKarsten Keil 		enqueue_ui(l2, skb);
8061b2b03f8SKarsten Keil 	}
8071b2b03f8SKarsten Keil }
8081b2b03f8SKarsten Keil 
8091b2b03f8SKarsten Keil static void
l2_send_ui(struct FsmInst * fi,int event,void * arg)8101b2b03f8SKarsten Keil l2_send_ui(struct FsmInst *fi, int event, void *arg)
8111b2b03f8SKarsten Keil {
8121b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8131b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8141b2b03f8SKarsten Keil 
8151b2b03f8SKarsten Keil 	skb_queue_tail(&l2->ui_queue, skb);
8161b2b03f8SKarsten Keil 	tx_ui(l2);
8171b2b03f8SKarsten Keil }
8181b2b03f8SKarsten Keil 
8191b2b03f8SKarsten Keil static void
l2_got_ui(struct FsmInst * fi,int event,void * arg)8201b2b03f8SKarsten Keil l2_got_ui(struct FsmInst *fi, int event, void *arg)
8211b2b03f8SKarsten Keil {
8221b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8231b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8241b2b03f8SKarsten Keil 
8251b2b03f8SKarsten Keil 	skb_pull(skb, l2headersize(l2, 1));
8261b2b03f8SKarsten Keil /*
8271b2b03f8SKarsten Keil  *		in states 1-3 for broadcast
8281b2b03f8SKarsten Keil  */
8291b2b03f8SKarsten Keil 
8301b2b03f8SKarsten Keil 	if (l2->tm)
8311b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_UI_IND, 0);
8321b2b03f8SKarsten Keil 	l2up(l2, DL_UNITDATA_IND, skb);
8331b2b03f8SKarsten Keil }
8341b2b03f8SKarsten Keil 
8351b2b03f8SKarsten Keil static void
l2_establish(struct FsmInst * fi,int event,void * arg)8361b2b03f8SKarsten Keil l2_establish(struct FsmInst *fi, int event, void *arg)
8371b2b03f8SKarsten Keil {
8381b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8391b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8401b2b03f8SKarsten Keil 
8411b2b03f8SKarsten Keil 	establishlink(fi);
8421b2b03f8SKarsten Keil 	test_and_set_bit(FLG_L3_INIT, &l2->flag);
8431b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
8441b2b03f8SKarsten Keil }
8451b2b03f8SKarsten Keil 
8461b2b03f8SKarsten Keil static void
l2_discard_i_setl3(struct FsmInst * fi,int event,void * arg)8471b2b03f8SKarsten Keil l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
8481b2b03f8SKarsten Keil {
8491b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8501b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8511b2b03f8SKarsten Keil 
8521b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
8531b2b03f8SKarsten Keil 	test_and_set_bit(FLG_L3_INIT, &l2->flag);
8541b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
8551b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
8561b2b03f8SKarsten Keil }
8571b2b03f8SKarsten Keil 
8581b2b03f8SKarsten Keil static void
l2_l3_reestablish(struct FsmInst * fi,int event,void * arg)8591b2b03f8SKarsten Keil l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
8601b2b03f8SKarsten Keil {
8611b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8621b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8631b2b03f8SKarsten Keil 
8641b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
8651b2b03f8SKarsten Keil 	establishlink(fi);
8661b2b03f8SKarsten Keil 	test_and_set_bit(FLG_L3_INIT, &l2->flag);
8671b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
8681b2b03f8SKarsten Keil }
8691b2b03f8SKarsten Keil 
8701b2b03f8SKarsten Keil static void
l2_release(struct FsmInst * fi,int event,void * arg)8711b2b03f8SKarsten Keil l2_release(struct FsmInst *fi, int event, void *arg)
8721b2b03f8SKarsten Keil {
8731b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8741b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8751b2b03f8SKarsten Keil 
8761b2b03f8SKarsten Keil 	skb_trim(skb, 0);
8771b2b03f8SKarsten Keil 	l2up(l2, DL_RELEASE_CNF, skb);
8781b2b03f8SKarsten Keil }
8791b2b03f8SKarsten Keil 
8801b2b03f8SKarsten Keil static void
l2_pend_rel(struct FsmInst * fi,int event,void * arg)8811b2b03f8SKarsten Keil l2_pend_rel(struct FsmInst *fi, int event, void *arg)
8821b2b03f8SKarsten Keil {
8831b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8841b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8851b2b03f8SKarsten Keil 
8861b2b03f8SKarsten Keil 	test_and_set_bit(FLG_PEND_REL, &l2->flag);
8871b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
8881b2b03f8SKarsten Keil }
8891b2b03f8SKarsten Keil 
8901b2b03f8SKarsten Keil static void
l2_disconnect(struct FsmInst * fi,int event,void * arg)8911b2b03f8SKarsten Keil l2_disconnect(struct FsmInst *fi, int event, void *arg)
8921b2b03f8SKarsten Keil {
8931b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
8941b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
8951b2b03f8SKarsten Keil 
8961b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
8971b2b03f8SKarsten Keil 	freewin(l2);
8981b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_6);
8991b2b03f8SKarsten Keil 	l2->rc = 0;
9001b2b03f8SKarsten Keil 	send_uframe(l2, NULL, DISC | 0x10, CMD);
9011b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t203, 1);
9021b2b03f8SKarsten Keil 	restart_t200(l2, 2);
9031b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
9041b2b03f8SKarsten Keil }
9051b2b03f8SKarsten Keil 
9061b2b03f8SKarsten Keil static void
l2_start_multi(struct FsmInst * fi,int event,void * arg)9071b2b03f8SKarsten Keil l2_start_multi(struct FsmInst *fi, int event, void *arg)
9081b2b03f8SKarsten Keil {
9091b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
9101b2b03f8SKarsten Keil 	struct sk_buff	*skb = arg;
9111b2b03f8SKarsten Keil 
9121b2b03f8SKarsten Keil 	l2->vs = 0;
9131b2b03f8SKarsten Keil 	l2->va = 0;
9141b2b03f8SKarsten Keil 	l2->vr = 0;
9151b2b03f8SKarsten Keil 	l2->sow = 0;
9161b2b03f8SKarsten Keil 	clear_exception(l2);
9171b2b03f8SKarsten Keil 	send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP);
9181b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_7);
9191b2b03f8SKarsten Keil 	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
9201b2b03f8SKarsten Keil 	skb_trim(skb, 0);
9211b2b03f8SKarsten Keil 	l2up(l2, DL_ESTABLISH_IND, skb);
9221b2b03f8SKarsten Keil 	if (l2->tm)
9231b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_UP_IND, 0);
9241b2b03f8SKarsten Keil }
9251b2b03f8SKarsten Keil 
9261b2b03f8SKarsten Keil static void
l2_send_UA(struct FsmInst * fi,int event,void * arg)9271b2b03f8SKarsten Keil l2_send_UA(struct FsmInst *fi, int event, void *arg)
9281b2b03f8SKarsten Keil {
9291b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
9301b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
9311b2b03f8SKarsten Keil 
9321b2b03f8SKarsten Keil 	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
9331b2b03f8SKarsten Keil }
9341b2b03f8SKarsten Keil 
9351b2b03f8SKarsten Keil static void
l2_send_DM(struct FsmInst * fi,int event,void * arg)9361b2b03f8SKarsten Keil l2_send_DM(struct FsmInst *fi, int event, void *arg)
9371b2b03f8SKarsten Keil {
9381b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
9391b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
9401b2b03f8SKarsten Keil 
9411b2b03f8SKarsten Keil 	send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP);
9421b2b03f8SKarsten Keil }
9431b2b03f8SKarsten Keil 
9441b2b03f8SKarsten Keil static void
l2_restart_multi(struct FsmInst * fi,int event,void * arg)9451b2b03f8SKarsten Keil l2_restart_multi(struct FsmInst *fi, int event, void *arg)
9461b2b03f8SKarsten Keil {
9471b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
9481b2b03f8SKarsten Keil 	struct sk_buff	*skb = arg;
9491b2b03f8SKarsten Keil 	int		est = 0;
9501b2b03f8SKarsten Keil 
9511b2b03f8SKarsten Keil 	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
9521b2b03f8SKarsten Keil 
9531b2b03f8SKarsten Keil 	l2mgr(l2, MDL_ERROR_IND, (void *) 'F');
9541b2b03f8SKarsten Keil 
9551b2b03f8SKarsten Keil 	if (l2->vs != l2->va) {
9561b2b03f8SKarsten Keil 		skb_queue_purge(&l2->i_queue);
9571b2b03f8SKarsten Keil 		est = 1;
9581b2b03f8SKarsten Keil 	}
9591b2b03f8SKarsten Keil 
9601b2b03f8SKarsten Keil 	clear_exception(l2);
9611b2b03f8SKarsten Keil 	l2->vs = 0;
9621b2b03f8SKarsten Keil 	l2->va = 0;
9631b2b03f8SKarsten Keil 	l2->vr = 0;
9641b2b03f8SKarsten Keil 	l2->sow = 0;
9651b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_7);
9661b2b03f8SKarsten Keil 	stop_t200(l2, 3);
9671b2b03f8SKarsten Keil 	mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
9681b2b03f8SKarsten Keil 
9691b2b03f8SKarsten Keil 	if (est)
9701b2b03f8SKarsten Keil 		l2up_create(l2, DL_ESTABLISH_IND, 0, NULL);
9711b2b03f8SKarsten Keil /*		mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
9721b2b03f8SKarsten Keil  *		    MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
9731b2b03f8SKarsten Keil  *		    0, NULL, 0);
9741b2b03f8SKarsten Keil  */
9751b2b03f8SKarsten Keil 	if (skb_queue_len(&l2->i_queue) && cansend(l2))
9761b2b03f8SKarsten Keil 		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
9771b2b03f8SKarsten Keil }
9781b2b03f8SKarsten Keil 
9791b2b03f8SKarsten Keil static void
l2_stop_multi(struct FsmInst * fi,int event,void * arg)9801b2b03f8SKarsten Keil l2_stop_multi(struct FsmInst *fi, int event, void *arg)
9811b2b03f8SKarsten Keil {
9821b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
9831b2b03f8SKarsten Keil 	struct sk_buff	*skb = arg;
9841b2b03f8SKarsten Keil 
9851b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_4);
9861b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t203, 3);
9871b2b03f8SKarsten Keil 	stop_t200(l2, 4);
9881b2b03f8SKarsten Keil 
9891b2b03f8SKarsten Keil 	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
9901b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
9911b2b03f8SKarsten Keil 	freewin(l2);
9921b2b03f8SKarsten Keil 	lapb_dl_release_l2l3(l2, DL_RELEASE_IND);
9931b2b03f8SKarsten Keil 	if (l2->tm)
9941b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
9951b2b03f8SKarsten Keil }
9961b2b03f8SKarsten Keil 
9971b2b03f8SKarsten Keil static void
l2_connected(struct FsmInst * fi,int event,void * arg)9981b2b03f8SKarsten Keil l2_connected(struct FsmInst *fi, int event, void *arg)
9991b2b03f8SKarsten Keil {
10001b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
10011b2b03f8SKarsten Keil 	struct sk_buff	*skb = arg;
10021b2b03f8SKarsten Keil 	int pr = -1;
10031b2b03f8SKarsten Keil 
10041b2b03f8SKarsten Keil 	if (!get_PollFlag(l2, skb)) {
10051b2b03f8SKarsten Keil 		l2_mdl_error_ua(fi, event, arg);
10061b2b03f8SKarsten Keil 		return;
10071b2b03f8SKarsten Keil 	}
10081b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
10091b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
10101b2b03f8SKarsten Keil 		l2_disconnect(fi, event, NULL);
10111b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) {
10121b2b03f8SKarsten Keil 		pr = DL_ESTABLISH_CNF;
10131b2b03f8SKarsten Keil 	} else if (l2->vs != l2->va) {
10141b2b03f8SKarsten Keil 		skb_queue_purge(&l2->i_queue);
10151b2b03f8SKarsten Keil 		pr = DL_ESTABLISH_IND;
10161b2b03f8SKarsten Keil 	}
10171b2b03f8SKarsten Keil 	stop_t200(l2, 5);
10181b2b03f8SKarsten Keil 	l2->vr = 0;
10191b2b03f8SKarsten Keil 	l2->vs = 0;
10201b2b03f8SKarsten Keil 	l2->va = 0;
10211b2b03f8SKarsten Keil 	l2->sow = 0;
10221b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_7);
10231b2b03f8SKarsten Keil 	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
10241b2b03f8SKarsten Keil 	if (pr != -1)
10251b2b03f8SKarsten Keil 		l2up_create(l2, pr, 0, NULL);
10261b2b03f8SKarsten Keil 
10271b2b03f8SKarsten Keil 	if (skb_queue_len(&l2->i_queue) && cansend(l2))
10281b2b03f8SKarsten Keil 		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
10291b2b03f8SKarsten Keil 
10301b2b03f8SKarsten Keil 	if (l2->tm)
10311b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_UP_IND, 0);
10321b2b03f8SKarsten Keil }
10331b2b03f8SKarsten Keil 
10341b2b03f8SKarsten Keil static void
l2_released(struct FsmInst * fi,int event,void * arg)10351b2b03f8SKarsten Keil l2_released(struct FsmInst *fi, int event, void *arg)
10361b2b03f8SKarsten Keil {
10371b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
10381b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
10391b2b03f8SKarsten Keil 
10401b2b03f8SKarsten Keil 	if (!get_PollFlag(l2, skb)) {
10411b2b03f8SKarsten Keil 		l2_mdl_error_ua(fi, event, arg);
10421b2b03f8SKarsten Keil 		return;
10431b2b03f8SKarsten Keil 	}
10441b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
10451b2b03f8SKarsten Keil 	stop_t200(l2, 6);
10461b2b03f8SKarsten Keil 	lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
10471b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_4);
10481b2b03f8SKarsten Keil 	if (l2->tm)
10491b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
10501b2b03f8SKarsten Keil }
10511b2b03f8SKarsten Keil 
10521b2b03f8SKarsten Keil static void
l2_reestablish(struct FsmInst * fi,int event,void * arg)10531b2b03f8SKarsten Keil l2_reestablish(struct FsmInst *fi, int event, void *arg)
10541b2b03f8SKarsten Keil {
10551b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
10561b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
10571b2b03f8SKarsten Keil 
10581b2b03f8SKarsten Keil 	if (!get_PollFlagFree(l2, skb)) {
10591b2b03f8SKarsten Keil 		establishlink(fi);
10601b2b03f8SKarsten Keil 		test_and_set_bit(FLG_L3_INIT, &l2->flag);
10611b2b03f8SKarsten Keil 	}
10621b2b03f8SKarsten Keil }
10631b2b03f8SKarsten Keil 
10641b2b03f8SKarsten Keil static void
l2_st5_dm_release(struct FsmInst * fi,int event,void * arg)10651b2b03f8SKarsten Keil l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
10661b2b03f8SKarsten Keil {
10671b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
10681b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
10691b2b03f8SKarsten Keil 
10701b2b03f8SKarsten Keil 	if (get_PollFlagFree(l2, skb)) {
10711b2b03f8SKarsten Keil 		stop_t200(l2, 7);
10721b2b03f8SKarsten Keil 		if (!test_bit(FLG_L3_INIT, &l2->flag))
10731b2b03f8SKarsten Keil 			skb_queue_purge(&l2->i_queue);
10741b2b03f8SKarsten Keil 		if (test_bit(FLG_LAPB, &l2->flag))
10751b2b03f8SKarsten Keil 			l2down_create(l2, PH_DEACTIVATE_REQ,
10761b2b03f8SKarsten Keil 				      l2_newid(l2), 0, NULL);
10771b2b03f8SKarsten Keil 		st5_dl_release_l2l3(l2);
10781b2b03f8SKarsten Keil 		mISDN_FsmChangeState(fi, ST_L2_4);
10791b2b03f8SKarsten Keil 		if (l2->tm)
10801b2b03f8SKarsten Keil 			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
10811b2b03f8SKarsten Keil 	}
10821b2b03f8SKarsten Keil }
10831b2b03f8SKarsten Keil 
10841b2b03f8SKarsten Keil static void
l2_st6_dm_release(struct FsmInst * fi,int event,void * arg)10851b2b03f8SKarsten Keil l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
10861b2b03f8SKarsten Keil {
10871b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
10881b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
10891b2b03f8SKarsten Keil 
10901b2b03f8SKarsten Keil 	if (get_PollFlagFree(l2, skb)) {
10911b2b03f8SKarsten Keil 		stop_t200(l2, 8);
10921b2b03f8SKarsten Keil 		lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
10931b2b03f8SKarsten Keil 		mISDN_FsmChangeState(fi, ST_L2_4);
10941b2b03f8SKarsten Keil 		if (l2->tm)
10951b2b03f8SKarsten Keil 			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
10961b2b03f8SKarsten Keil 	}
10971b2b03f8SKarsten Keil }
10981b2b03f8SKarsten Keil 
10995b834354SHannes Eder static void
enquiry_cr(struct layer2 * l2,u_char typ,u_char cr,u_char pf)11001b2b03f8SKarsten Keil enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
11011b2b03f8SKarsten Keil {
11021b2b03f8SKarsten Keil 	struct sk_buff *skb;
11031b2b03f8SKarsten Keil 	u_char tmp[MAX_L2HEADER_LEN];
11041b2b03f8SKarsten Keil 	int i;
11051b2b03f8SKarsten Keil 
11061b2b03f8SKarsten Keil 	i = sethdraddr(l2, tmp, cr);
11071b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
11081b2b03f8SKarsten Keil 		tmp[i++] = typ;
11091b2b03f8SKarsten Keil 		tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
11101b2b03f8SKarsten Keil 	} else
11111b2b03f8SKarsten Keil 		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
11121b2b03f8SKarsten Keil 	skb = mI_alloc_skb(i, GFP_ATOMIC);
11131b2b03f8SKarsten Keil 	if (!skb) {
1114f45ebf3aSKarsten Keil 		printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n",
1115f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), __func__);
11161b2b03f8SKarsten Keil 		return;
11171b2b03f8SKarsten Keil 	}
111859ae1d12SJohannes Berg 	skb_put_data(skb, tmp, i);
11191b2b03f8SKarsten Keil 	enqueue_super(l2, skb);
11201b2b03f8SKarsten Keil }
11211b2b03f8SKarsten Keil 
11221b2b03f8SKarsten Keil inline void
enquiry_response(struct layer2 * l2)11231b2b03f8SKarsten Keil enquiry_response(struct layer2 *l2)
11241b2b03f8SKarsten Keil {
11251b2b03f8SKarsten Keil 	if (test_bit(FLG_OWN_BUSY, &l2->flag))
11261b2b03f8SKarsten Keil 		enquiry_cr(l2, RNR, RSP, 1);
11271b2b03f8SKarsten Keil 	else
11281b2b03f8SKarsten Keil 		enquiry_cr(l2, RR, RSP, 1);
11291b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
11301b2b03f8SKarsten Keil }
11311b2b03f8SKarsten Keil 
11321b2b03f8SKarsten Keil inline void
transmit_enquiry(struct layer2 * l2)11331b2b03f8SKarsten Keil transmit_enquiry(struct layer2 *l2)
11341b2b03f8SKarsten Keil {
11351b2b03f8SKarsten Keil 	if (test_bit(FLG_OWN_BUSY, &l2->flag))
11361b2b03f8SKarsten Keil 		enquiry_cr(l2, RNR, CMD, 1);
11371b2b03f8SKarsten Keil 	else
11381b2b03f8SKarsten Keil 		enquiry_cr(l2, RR, CMD, 1);
11391b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
11401b2b03f8SKarsten Keil 	start_t200(l2, 9);
11411b2b03f8SKarsten Keil }
11421b2b03f8SKarsten Keil 
11431b2b03f8SKarsten Keil 
11441b2b03f8SKarsten Keil static void
nrerrorrecovery(struct FsmInst * fi)11451b2b03f8SKarsten Keil nrerrorrecovery(struct FsmInst *fi)
11461b2b03f8SKarsten Keil {
11471b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
11481b2b03f8SKarsten Keil 
11491b2b03f8SKarsten Keil 	l2mgr(l2, MDL_ERROR_IND, (void *) 'J');
11501b2b03f8SKarsten Keil 	establishlink(fi);
11511b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
11521b2b03f8SKarsten Keil }
11531b2b03f8SKarsten Keil 
11541b2b03f8SKarsten Keil static void
invoke_retransmission(struct layer2 * l2,unsigned int nr)11551b2b03f8SKarsten Keil invoke_retransmission(struct layer2 *l2, unsigned int nr)
11561b2b03f8SKarsten Keil {
11571b2b03f8SKarsten Keil 	u_int	p1;
11581b2b03f8SKarsten Keil 
11591b2b03f8SKarsten Keil 	if (l2->vs != nr) {
11601b2b03f8SKarsten Keil 		while (l2->vs != nr) {
11611b2b03f8SKarsten Keil 			(l2->vs)--;
11621b2b03f8SKarsten Keil 			if (test_bit(FLG_MOD128, &l2->flag)) {
11631b2b03f8SKarsten Keil 				l2->vs %= 128;
11641b2b03f8SKarsten Keil 				p1 = (l2->vs - l2->va) % 128;
11651b2b03f8SKarsten Keil 			} else {
11661b2b03f8SKarsten Keil 				l2->vs %= 8;
11671b2b03f8SKarsten Keil 				p1 = (l2->vs - l2->va) % 8;
11681b2b03f8SKarsten Keil 			}
11691b2b03f8SKarsten Keil 			p1 = (p1 + l2->sow) % l2->window;
11701b2b03f8SKarsten Keil 			if (l2->windowar[p1])
11711b2b03f8SKarsten Keil 				skb_queue_head(&l2->i_queue, l2->windowar[p1]);
11721b2b03f8SKarsten Keil 			else
11731b2b03f8SKarsten Keil 				printk(KERN_WARNING
11741b2b03f8SKarsten Keil 				       "%s: windowar[%d] is NULL\n",
1175f45ebf3aSKarsten Keil 				       mISDNDevName4ch(&l2->ch), p1);
11761b2b03f8SKarsten Keil 			l2->windowar[p1] = NULL;
11771b2b03f8SKarsten Keil 		}
11781b2b03f8SKarsten Keil 		mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
11791b2b03f8SKarsten Keil 	}
11801b2b03f8SKarsten Keil }
11811b2b03f8SKarsten Keil 
11821b2b03f8SKarsten Keil static void
l2_st7_got_super(struct FsmInst * fi,int event,void * arg)11831b2b03f8SKarsten Keil l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
11841b2b03f8SKarsten Keil {
11851b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
11861b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
11871b2b03f8SKarsten Keil 	int PollFlag, rsp, typ = RR;
11881b2b03f8SKarsten Keil 	unsigned int nr;
11891b2b03f8SKarsten Keil 
11901b2b03f8SKarsten Keil 	rsp = *skb->data & 0x2;
11911b2b03f8SKarsten Keil 	if (test_bit(FLG_ORIG, &l2->flag))
11921b2b03f8SKarsten Keil 		rsp = !rsp;
11931b2b03f8SKarsten Keil 
11941b2b03f8SKarsten Keil 	skb_pull(skb, l2addrsize(l2));
11951b2b03f8SKarsten Keil 	if (IsRNR(skb->data, l2)) {
11961b2b03f8SKarsten Keil 		set_peer_busy(l2);
11971b2b03f8SKarsten Keil 		typ = RNR;
11981b2b03f8SKarsten Keil 	} else
11991b2b03f8SKarsten Keil 		clear_peer_busy(l2);
12001b2b03f8SKarsten Keil 	if (IsREJ(skb->data, l2))
12011b2b03f8SKarsten Keil 		typ = REJ;
12021b2b03f8SKarsten Keil 
12031b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
12041b2b03f8SKarsten Keil 		PollFlag = (skb->data[1] & 0x1) == 0x1;
12051b2b03f8SKarsten Keil 		nr = skb->data[1] >> 1;
12061b2b03f8SKarsten Keil 	} else {
12071b2b03f8SKarsten Keil 		PollFlag = (skb->data[0] & 0x10);
12081b2b03f8SKarsten Keil 		nr = (skb->data[0] >> 5) & 0x7;
12091b2b03f8SKarsten Keil 	}
12101b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
12111b2b03f8SKarsten Keil 
12121b2b03f8SKarsten Keil 	if (PollFlag) {
12131b2b03f8SKarsten Keil 		if (rsp)
12141b2b03f8SKarsten Keil 			l2mgr(l2, MDL_ERROR_IND, (void *) 'A');
12151b2b03f8SKarsten Keil 		else
12161b2b03f8SKarsten Keil 			enquiry_response(l2);
12171b2b03f8SKarsten Keil 	}
12181b2b03f8SKarsten Keil 	if (legalnr(l2, nr)) {
12191b2b03f8SKarsten Keil 		if (typ == REJ) {
12201b2b03f8SKarsten Keil 			setva(l2, nr);
12211b2b03f8SKarsten Keil 			invoke_retransmission(l2, nr);
12221b2b03f8SKarsten Keil 			stop_t200(l2, 10);
12231b2b03f8SKarsten Keil 			if (mISDN_FsmAddTimer(&l2->t203, l2->T203,
12241b2b03f8SKarsten Keil 					      EV_L2_T203, NULL, 6))
12251b2b03f8SKarsten Keil 				l2m_debug(&l2->l2m, "Restart T203 ST7 REJ");
12261b2b03f8SKarsten Keil 		} else if ((nr == l2->vs) && (typ == RR)) {
12271b2b03f8SKarsten Keil 			setva(l2, nr);
12281b2b03f8SKarsten Keil 			stop_t200(l2, 11);
12291b2b03f8SKarsten Keil 			mISDN_FsmRestartTimer(&l2->t203, l2->T203,
12301b2b03f8SKarsten Keil 					      EV_L2_T203, NULL, 7);
12311b2b03f8SKarsten Keil 		} else if ((l2->va != nr) || (typ == RNR)) {
12321b2b03f8SKarsten Keil 			setva(l2, nr);
12331b2b03f8SKarsten Keil 			if (typ != RR)
12341b2b03f8SKarsten Keil 				mISDN_FsmDelTimer(&l2->t203, 9);
12351b2b03f8SKarsten Keil 			restart_t200(l2, 12);
12361b2b03f8SKarsten Keil 		}
12371b2b03f8SKarsten Keil 		if (skb_queue_len(&l2->i_queue) && (typ == RR))
12381b2b03f8SKarsten Keil 			mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
12391b2b03f8SKarsten Keil 	} else
12401b2b03f8SKarsten Keil 		nrerrorrecovery(fi);
12411b2b03f8SKarsten Keil }
12421b2b03f8SKarsten Keil 
12431b2b03f8SKarsten Keil static void
l2_feed_i_if_reest(struct FsmInst * fi,int event,void * arg)12441b2b03f8SKarsten Keil l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
12451b2b03f8SKarsten Keil {
12461b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
12471b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
12481b2b03f8SKarsten Keil 
12491b2b03f8SKarsten Keil 	if (!test_bit(FLG_L3_INIT, &l2->flag))
12501b2b03f8SKarsten Keil 		skb_queue_tail(&l2->i_queue, skb);
12511b2b03f8SKarsten Keil 	else
12521b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
12531b2b03f8SKarsten Keil }
12541b2b03f8SKarsten Keil 
12551b2b03f8SKarsten Keil static void
l2_feed_i_pull(struct FsmInst * fi,int event,void * arg)12561b2b03f8SKarsten Keil l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
12571b2b03f8SKarsten Keil {
12581b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
12591b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
12601b2b03f8SKarsten Keil 
12611b2b03f8SKarsten Keil 	skb_queue_tail(&l2->i_queue, skb);
12621b2b03f8SKarsten Keil 	mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
12631b2b03f8SKarsten Keil }
12641b2b03f8SKarsten Keil 
12651b2b03f8SKarsten Keil static void
l2_feed_iqueue(struct FsmInst * fi,int event,void * arg)12661b2b03f8SKarsten Keil l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
12671b2b03f8SKarsten Keil {
12681b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
12691b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
12701b2b03f8SKarsten Keil 
12711b2b03f8SKarsten Keil 	skb_queue_tail(&l2->i_queue, skb);
12721b2b03f8SKarsten Keil }
12731b2b03f8SKarsten Keil 
12741b2b03f8SKarsten Keil static void
l2_got_iframe(struct FsmInst * fi,int event,void * arg)12751b2b03f8SKarsten Keil l2_got_iframe(struct FsmInst *fi, int event, void *arg)
12761b2b03f8SKarsten Keil {
12771b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
12781b2b03f8SKarsten Keil 	struct sk_buff	*skb = arg;
12791b2b03f8SKarsten Keil 	int		PollFlag, i;
12801b2b03f8SKarsten Keil 	u_int		ns, nr;
12811b2b03f8SKarsten Keil 
12821b2b03f8SKarsten Keil 	i = l2addrsize(l2);
12831b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
12841b2b03f8SKarsten Keil 		PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
12851b2b03f8SKarsten Keil 		ns = skb->data[i] >> 1;
12861b2b03f8SKarsten Keil 		nr = (skb->data[i + 1] >> 1) & 0x7f;
12871b2b03f8SKarsten Keil 	} else {
12881b2b03f8SKarsten Keil 		PollFlag = (skb->data[i] & 0x10);
12891b2b03f8SKarsten Keil 		ns = (skb->data[i] >> 1) & 0x7;
12901b2b03f8SKarsten Keil 		nr = (skb->data[i] >> 5) & 0x7;
12911b2b03f8SKarsten Keil 	}
12921b2b03f8SKarsten Keil 	if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
12931b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
12941b2b03f8SKarsten Keil 		if (PollFlag)
12951b2b03f8SKarsten Keil 			enquiry_response(l2);
12961b2b03f8SKarsten Keil 	} else {
12971b2b03f8SKarsten Keil 		if (l2->vr == ns) {
12981b2b03f8SKarsten Keil 			l2->vr++;
12991b2b03f8SKarsten Keil 			if (test_bit(FLG_MOD128, &l2->flag))
13001b2b03f8SKarsten Keil 				l2->vr %= 128;
13011b2b03f8SKarsten Keil 			else
13021b2b03f8SKarsten Keil 				l2->vr %= 8;
13031b2b03f8SKarsten Keil 			test_and_clear_bit(FLG_REJEXC, &l2->flag);
13041b2b03f8SKarsten Keil 			if (PollFlag)
13051b2b03f8SKarsten Keil 				enquiry_response(l2);
13061b2b03f8SKarsten Keil 			else
13071b2b03f8SKarsten Keil 				test_and_set_bit(FLG_ACK_PEND, &l2->flag);
13081b2b03f8SKarsten Keil 			skb_pull(skb, l2headersize(l2, 0));
13091b2b03f8SKarsten Keil 			l2up(l2, DL_DATA_IND, skb);
13101b2b03f8SKarsten Keil 		} else {
13111b2b03f8SKarsten Keil 			/* n(s)!=v(r) */
13121b2b03f8SKarsten Keil 			dev_kfree_skb(skb);
13131b2b03f8SKarsten Keil 			if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
13141b2b03f8SKarsten Keil 				if (PollFlag)
13151b2b03f8SKarsten Keil 					enquiry_response(l2);
13161b2b03f8SKarsten Keil 			} else {
13171b2b03f8SKarsten Keil 				enquiry_cr(l2, REJ, RSP, PollFlag);
13181b2b03f8SKarsten Keil 				test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
13191b2b03f8SKarsten Keil 			}
13201b2b03f8SKarsten Keil 		}
13211b2b03f8SKarsten Keil 	}
13221b2b03f8SKarsten Keil 	if (legalnr(l2, nr)) {
13231b2b03f8SKarsten Keil 		if (!test_bit(FLG_PEER_BUSY, &l2->flag) &&
13241b2b03f8SKarsten Keil 		    (fi->state == ST_L2_7)) {
13251b2b03f8SKarsten Keil 			if (nr == l2->vs) {
13261b2b03f8SKarsten Keil 				stop_t200(l2, 13);
13271b2b03f8SKarsten Keil 				mISDN_FsmRestartTimer(&l2->t203, l2->T203,
13281b2b03f8SKarsten Keil 						      EV_L2_T203, NULL, 7);
13291b2b03f8SKarsten Keil 			} else if (nr != l2->va)
13301b2b03f8SKarsten Keil 				restart_t200(l2, 14);
13311b2b03f8SKarsten Keil 		}
13321b2b03f8SKarsten Keil 		setva(l2, nr);
13331b2b03f8SKarsten Keil 	} else {
13341b2b03f8SKarsten Keil 		nrerrorrecovery(fi);
13351b2b03f8SKarsten Keil 		return;
13361b2b03f8SKarsten Keil 	}
13371b2b03f8SKarsten Keil 	if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7))
13381b2b03f8SKarsten Keil 		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
13391b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag))
13401b2b03f8SKarsten Keil 		enquiry_cr(l2, RR, RSP, 0);
13411b2b03f8SKarsten Keil }
13421b2b03f8SKarsten Keil 
13431b2b03f8SKarsten Keil static void
l2_got_tei(struct FsmInst * fi,int event,void * arg)13441b2b03f8SKarsten Keil l2_got_tei(struct FsmInst *fi, int event, void *arg)
13451b2b03f8SKarsten Keil {
13461b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
13471b2b03f8SKarsten Keil 	u_int		info;
13481b2b03f8SKarsten Keil 
13491b2b03f8SKarsten Keil 	l2->tei = (signed char)(long)arg;
13501b2b03f8SKarsten Keil 	set_channel_address(&l2->ch, l2->sapi, l2->tei);
13511b2b03f8SKarsten Keil 	info = DL_INFO_L2_CONNECT;
13521b2b03f8SKarsten Keil 	l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info);
13531b2b03f8SKarsten Keil 	if (fi->state == ST_L2_3) {
13541b2b03f8SKarsten Keil 		establishlink(fi);
13551b2b03f8SKarsten Keil 		test_and_set_bit(FLG_L3_INIT, &l2->flag);
13561b2b03f8SKarsten Keil 	} else
13571b2b03f8SKarsten Keil 		mISDN_FsmChangeState(fi, ST_L2_4);
13581b2b03f8SKarsten Keil 	if (skb_queue_len(&l2->ui_queue))
13591b2b03f8SKarsten Keil 		tx_ui(l2);
13601b2b03f8SKarsten Keil }
13611b2b03f8SKarsten Keil 
13621b2b03f8SKarsten Keil static void
l2_st5_tout_200(struct FsmInst * fi,int event,void * arg)13631b2b03f8SKarsten Keil l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
13641b2b03f8SKarsten Keil {
13651b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
13661b2b03f8SKarsten Keil 
13671b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag) &&
13681b2b03f8SKarsten Keil 	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
13691b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
13701b2b03f8SKarsten Keil 	} else if (l2->rc == l2->N200) {
13711b2b03f8SKarsten Keil 		mISDN_FsmChangeState(fi, ST_L2_4);
13721b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
13731b2b03f8SKarsten Keil 		skb_queue_purge(&l2->i_queue);
13741b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'G');
13751b2b03f8SKarsten Keil 		if (test_bit(FLG_LAPB, &l2->flag))
13761b2b03f8SKarsten Keil 			l2down_create(l2, PH_DEACTIVATE_REQ,
13771b2b03f8SKarsten Keil 				      l2_newid(l2), 0, NULL);
13781b2b03f8SKarsten Keil 		st5_dl_release_l2l3(l2);
13791b2b03f8SKarsten Keil 		if (l2->tm)
13801b2b03f8SKarsten Keil 			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
13811b2b03f8SKarsten Keil 	} else {
13821b2b03f8SKarsten Keil 		l2->rc++;
13831b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
13841b2b03f8SKarsten Keil 		send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ?
13851b2b03f8SKarsten Keil 				       SABME : SABM) | 0x10, CMD);
13861b2b03f8SKarsten Keil 	}
13871b2b03f8SKarsten Keil }
13881b2b03f8SKarsten Keil 
13891b2b03f8SKarsten Keil static void
l2_st6_tout_200(struct FsmInst * fi,int event,void * arg)13901b2b03f8SKarsten Keil l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
13911b2b03f8SKarsten Keil {
13921b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
13931b2b03f8SKarsten Keil 
13941b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag) &&
13951b2b03f8SKarsten Keil 	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
13961b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
13971b2b03f8SKarsten Keil 	} else if (l2->rc == l2->N200) {
13981b2b03f8SKarsten Keil 		mISDN_FsmChangeState(fi, ST_L2_4);
13991b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
14001b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'H');
14011b2b03f8SKarsten Keil 		lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
14021b2b03f8SKarsten Keil 		if (l2->tm)
14031b2b03f8SKarsten Keil 			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
14041b2b03f8SKarsten Keil 	} else {
14051b2b03f8SKarsten Keil 		l2->rc++;
14061b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200,
14071b2b03f8SKarsten Keil 				  NULL, 9);
14081b2b03f8SKarsten Keil 		send_uframe(l2, NULL, DISC | 0x10, CMD);
14091b2b03f8SKarsten Keil 	}
14101b2b03f8SKarsten Keil }
14111b2b03f8SKarsten Keil 
14121b2b03f8SKarsten Keil static void
l2_st7_tout_200(struct FsmInst * fi,int event,void * arg)14131b2b03f8SKarsten Keil l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
14141b2b03f8SKarsten Keil {
14151b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
14161b2b03f8SKarsten Keil 
14171b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag) &&
14181b2b03f8SKarsten Keil 	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
14191b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
14201b2b03f8SKarsten Keil 		return;
14211b2b03f8SKarsten Keil 	}
14221b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
14231b2b03f8SKarsten Keil 	l2->rc = 0;
14241b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_8);
14251b2b03f8SKarsten Keil 	transmit_enquiry(l2);
14261b2b03f8SKarsten Keil 	l2->rc++;
14271b2b03f8SKarsten Keil }
14281b2b03f8SKarsten Keil 
14291b2b03f8SKarsten Keil static void
l2_st8_tout_200(struct FsmInst * fi,int event,void * arg)14301b2b03f8SKarsten Keil l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
14311b2b03f8SKarsten Keil {
14321b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
14331b2b03f8SKarsten Keil 
14341b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag) &&
14351b2b03f8SKarsten Keil 	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
14361b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
14371b2b03f8SKarsten Keil 		return;
14381b2b03f8SKarsten Keil 	}
14391b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
14401b2b03f8SKarsten Keil 	if (l2->rc == l2->N200) {
14411b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'I');
14421b2b03f8SKarsten Keil 		establishlink(fi);
14431b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
14441b2b03f8SKarsten Keil 	} else {
14451b2b03f8SKarsten Keil 		transmit_enquiry(l2);
14461b2b03f8SKarsten Keil 		l2->rc++;
14471b2b03f8SKarsten Keil 	}
14481b2b03f8SKarsten Keil }
14491b2b03f8SKarsten Keil 
14501b2b03f8SKarsten Keil static void
l2_st7_tout_203(struct FsmInst * fi,int event,void * arg)14511b2b03f8SKarsten Keil l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
14521b2b03f8SKarsten Keil {
14531b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
14541b2b03f8SKarsten Keil 
14551b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag) &&
14561b2b03f8SKarsten Keil 	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
14571b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9);
14581b2b03f8SKarsten Keil 		return;
14591b2b03f8SKarsten Keil 	}
14601b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_8);
14611b2b03f8SKarsten Keil 	transmit_enquiry(l2);
14621b2b03f8SKarsten Keil 	l2->rc = 0;
14631b2b03f8SKarsten Keil }
14641b2b03f8SKarsten Keil 
14651b2b03f8SKarsten Keil static void
l2_pull_iqueue(struct FsmInst * fi,int event,void * arg)14661b2b03f8SKarsten Keil l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
14671b2b03f8SKarsten Keil {
14681b2b03f8SKarsten Keil 	struct layer2	*l2 = fi->userdata;
1469c96356a9SKarsten Keil 	struct sk_buff	*skb, *nskb;
14701b2b03f8SKarsten Keil 	u_char		header[MAX_L2HEADER_LEN];
14711b2b03f8SKarsten Keil 	u_int		i, p1;
14721b2b03f8SKarsten Keil 
14731b2b03f8SKarsten Keil 	if (!cansend(l2))
14741b2b03f8SKarsten Keil 		return;
14751b2b03f8SKarsten Keil 
14761b2b03f8SKarsten Keil 	skb = skb_dequeue(&l2->i_queue);
14771b2b03f8SKarsten Keil 	if (!skb)
14781b2b03f8SKarsten Keil 		return;
1479c96356a9SKarsten Keil 	i = sethdraddr(l2, header, CMD);
1480c96356a9SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
1481c96356a9SKarsten Keil 		header[i++] = l2->vs << 1;
1482c96356a9SKarsten Keil 		header[i++] = l2->vr << 1;
1483c96356a9SKarsten Keil 	} else
1484c96356a9SKarsten Keil 		header[i++] = (l2->vr << 5) | (l2->vs << 1);
1485c96356a9SKarsten Keil 	nskb = skb_realloc_headroom(skb, i);
1486c96356a9SKarsten Keil 	if (!nskb) {
1487c96356a9SKarsten Keil 		printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
1488c96356a9SKarsten Keil 		       mISDNDevName4ch(&l2->ch), i);
1489c96356a9SKarsten Keil 		skb_queue_head(&l2->i_queue, skb);
1490c96356a9SKarsten Keil 		return;
1491c96356a9SKarsten Keil 	}
1492c96356a9SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
14931b2b03f8SKarsten Keil 		p1 = (l2->vs - l2->va) % 128;
1494c96356a9SKarsten Keil 		l2->vs = (l2->vs + 1) % 128;
1495c96356a9SKarsten Keil 	} else {
14961b2b03f8SKarsten Keil 		p1 = (l2->vs - l2->va) % 8;
1497c96356a9SKarsten Keil 		l2->vs = (l2->vs + 1) % 8;
1498c96356a9SKarsten Keil 	}
14991b2b03f8SKarsten Keil 	p1 = (p1 + l2->sow) % l2->window;
15001b2b03f8SKarsten Keil 	if (l2->windowar[p1]) {
1501f45ebf3aSKarsten Keil 		printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
1502f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), p1);
15031b2b03f8SKarsten Keil 		dev_kfree_skb(l2->windowar[p1]);
15041b2b03f8SKarsten Keil 	}
15051b2b03f8SKarsten Keil 	l2->windowar[p1] = skb;
15061b2b03f8SKarsten Keil 	memcpy(skb_push(nskb, i), header, i);
15071b2b03f8SKarsten Keil 	l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
15081b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
15091b2b03f8SKarsten Keil 	if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {
15101b2b03f8SKarsten Keil 		mISDN_FsmDelTimer(&l2->t203, 13);
15111b2b03f8SKarsten Keil 		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11);
15121b2b03f8SKarsten Keil 	}
15131b2b03f8SKarsten Keil }
15141b2b03f8SKarsten Keil 
15151b2b03f8SKarsten Keil static void
l2_st8_got_super(struct FsmInst * fi,int event,void * arg)15161b2b03f8SKarsten Keil l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
15171b2b03f8SKarsten Keil {
15181b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
15191b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
15201b2b03f8SKarsten Keil 	int PollFlag, rsp, rnr = 0;
15211b2b03f8SKarsten Keil 	unsigned int nr;
15221b2b03f8SKarsten Keil 
15231b2b03f8SKarsten Keil 	rsp = *skb->data & 0x2;
15241b2b03f8SKarsten Keil 	if (test_bit(FLG_ORIG, &l2->flag))
15251b2b03f8SKarsten Keil 		rsp = !rsp;
15261b2b03f8SKarsten Keil 
15271b2b03f8SKarsten Keil 	skb_pull(skb, l2addrsize(l2));
15281b2b03f8SKarsten Keil 
15291b2b03f8SKarsten Keil 	if (IsRNR(skb->data, l2)) {
15301b2b03f8SKarsten Keil 		set_peer_busy(l2);
15311b2b03f8SKarsten Keil 		rnr = 1;
15321b2b03f8SKarsten Keil 	} else
15331b2b03f8SKarsten Keil 		clear_peer_busy(l2);
15341b2b03f8SKarsten Keil 
15351b2b03f8SKarsten Keil 	if (test_bit(FLG_MOD128, &l2->flag)) {
15361b2b03f8SKarsten Keil 		PollFlag = (skb->data[1] & 0x1) == 0x1;
15371b2b03f8SKarsten Keil 		nr = skb->data[1] >> 1;
15381b2b03f8SKarsten Keil 	} else {
15391b2b03f8SKarsten Keil 		PollFlag = (skb->data[0] & 0x10);
15401b2b03f8SKarsten Keil 		nr = (skb->data[0] >> 5) & 0x7;
15411b2b03f8SKarsten Keil 	}
15421b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
15431b2b03f8SKarsten Keil 	if (rsp && PollFlag) {
15441b2b03f8SKarsten Keil 		if (legalnr(l2, nr)) {
15451b2b03f8SKarsten Keil 			if (rnr) {
15461b2b03f8SKarsten Keil 				restart_t200(l2, 15);
15471b2b03f8SKarsten Keil 			} else {
15481b2b03f8SKarsten Keil 				stop_t200(l2, 16);
15491b2b03f8SKarsten Keil 				mISDN_FsmAddTimer(&l2->t203, l2->T203,
15501b2b03f8SKarsten Keil 						  EV_L2_T203, NULL, 5);
15511b2b03f8SKarsten Keil 				setva(l2, nr);
15521b2b03f8SKarsten Keil 			}
15531b2b03f8SKarsten Keil 			invoke_retransmission(l2, nr);
15541b2b03f8SKarsten Keil 			mISDN_FsmChangeState(fi, ST_L2_7);
15551b2b03f8SKarsten Keil 			if (skb_queue_len(&l2->i_queue) && cansend(l2))
15561b2b03f8SKarsten Keil 				mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
15571b2b03f8SKarsten Keil 		} else
15581b2b03f8SKarsten Keil 			nrerrorrecovery(fi);
15591b2b03f8SKarsten Keil 	} else {
15601b2b03f8SKarsten Keil 		if (!rsp && PollFlag)
15611b2b03f8SKarsten Keil 			enquiry_response(l2);
15621b2b03f8SKarsten Keil 		if (legalnr(l2, nr))
15631b2b03f8SKarsten Keil 			setva(l2, nr);
15641b2b03f8SKarsten Keil 		else
15651b2b03f8SKarsten Keil 			nrerrorrecovery(fi);
15661b2b03f8SKarsten Keil 	}
15671b2b03f8SKarsten Keil }
15681b2b03f8SKarsten Keil 
15691b2b03f8SKarsten Keil static void
l2_got_FRMR(struct FsmInst * fi,int event,void * arg)15701b2b03f8SKarsten Keil l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
15711b2b03f8SKarsten Keil {
15721b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
15731b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
15741b2b03f8SKarsten Keil 
15751b2b03f8SKarsten Keil 	skb_pull(skb, l2addrsize(l2) + 1);
15761b2b03f8SKarsten Keil 
15771b2b03f8SKarsten Keil 	if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
15781b2b03f8SKarsten Keil 	    (IsUA(skb->data) && (fi->state == ST_L2_7))) {
15791b2b03f8SKarsten Keil 		l2mgr(l2, MDL_ERROR_IND, (void *) 'K');
15801b2b03f8SKarsten Keil 		establishlink(fi);
15811b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
15821b2b03f8SKarsten Keil 	}
15831b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
15841b2b03f8SKarsten Keil }
15851b2b03f8SKarsten Keil 
15861b2b03f8SKarsten Keil static void
l2_st24_tei_remove(struct FsmInst * fi,int event,void * arg)15871b2b03f8SKarsten Keil l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
15881b2b03f8SKarsten Keil {
15891b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
15901b2b03f8SKarsten Keil 
15911b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
15921b2b03f8SKarsten Keil 	l2->tei = GROUP_TEI;
15931b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_1);
15941b2b03f8SKarsten Keil }
15951b2b03f8SKarsten Keil 
15961b2b03f8SKarsten Keil static void
l2_st3_tei_remove(struct FsmInst * fi,int event,void * arg)15971b2b03f8SKarsten Keil l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
15981b2b03f8SKarsten Keil {
15991b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16001b2b03f8SKarsten Keil 
16011b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16021b2b03f8SKarsten Keil 	l2->tei = GROUP_TEI;
16031b2b03f8SKarsten Keil 	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
16041b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_1);
16051b2b03f8SKarsten Keil }
16061b2b03f8SKarsten Keil 
16071b2b03f8SKarsten Keil static void
l2_st5_tei_remove(struct FsmInst * fi,int event,void * arg)16081b2b03f8SKarsten Keil l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
16091b2b03f8SKarsten Keil {
16101b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16111b2b03f8SKarsten Keil 
16121b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
16131b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16141b2b03f8SKarsten Keil 	freewin(l2);
16151b2b03f8SKarsten Keil 	l2->tei = GROUP_TEI;
16161b2b03f8SKarsten Keil 	stop_t200(l2, 17);
16171b2b03f8SKarsten Keil 	st5_dl_release_l2l3(l2);
16181b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_1);
16191b2b03f8SKarsten Keil }
16201b2b03f8SKarsten Keil 
16211b2b03f8SKarsten Keil static void
l2_st6_tei_remove(struct FsmInst * fi,int event,void * arg)16221b2b03f8SKarsten Keil l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
16231b2b03f8SKarsten Keil {
16241b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16251b2b03f8SKarsten Keil 
16261b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16271b2b03f8SKarsten Keil 	l2->tei = GROUP_TEI;
16281b2b03f8SKarsten Keil 	stop_t200(l2, 18);
16291b2b03f8SKarsten Keil 	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
16301b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_1);
16311b2b03f8SKarsten Keil }
16321b2b03f8SKarsten Keil 
16331b2b03f8SKarsten Keil static void
l2_tei_remove(struct FsmInst * fi,int event,void * arg)16341b2b03f8SKarsten Keil l2_tei_remove(struct FsmInst *fi, int event, void *arg)
16351b2b03f8SKarsten Keil {
16361b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16371b2b03f8SKarsten Keil 
16381b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
16391b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16401b2b03f8SKarsten Keil 	freewin(l2);
16411b2b03f8SKarsten Keil 	l2->tei = GROUP_TEI;
16421b2b03f8SKarsten Keil 	stop_t200(l2, 17);
16431b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t203, 19);
16441b2b03f8SKarsten Keil 	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
16451b2b03f8SKarsten Keil /*	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
16461b2b03f8SKarsten Keil  *		MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED,
16471b2b03f8SKarsten Keil  *		0, NULL, 0);
16481b2b03f8SKarsten Keil  */
16491b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_1);
16501b2b03f8SKarsten Keil }
16511b2b03f8SKarsten Keil 
16521b2b03f8SKarsten Keil static void
l2_st14_persistent_da(struct FsmInst * fi,int event,void * arg)165395b8fbadSJan Engelhardt l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
16541b2b03f8SKarsten Keil {
16551b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16561b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
16571b2b03f8SKarsten Keil 
16581b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
16591b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16601b2b03f8SKarsten Keil 	if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
16611b2b03f8SKarsten Keil 		l2up(l2, DL_RELEASE_IND, skb);
16621b2b03f8SKarsten Keil 	else
16631b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
16641b2b03f8SKarsten Keil }
16651b2b03f8SKarsten Keil 
16661b2b03f8SKarsten Keil static void
l2_st5_persistent_da(struct FsmInst * fi,int event,void * arg)166795b8fbadSJan Engelhardt l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
16681b2b03f8SKarsten Keil {
16691b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16701b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
16711b2b03f8SKarsten Keil 
16721b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
16731b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16741b2b03f8SKarsten Keil 	freewin(l2);
16751b2b03f8SKarsten Keil 	stop_t200(l2, 19);
16761b2b03f8SKarsten Keil 	st5_dl_release_l2l3(l2);
16771b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_4);
16781b2b03f8SKarsten Keil 	if (l2->tm)
16791b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
16801b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
16811b2b03f8SKarsten Keil }
16821b2b03f8SKarsten Keil 
16831b2b03f8SKarsten Keil static void
l2_st6_persistent_da(struct FsmInst * fi,int event,void * arg)168495b8fbadSJan Engelhardt l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
16851b2b03f8SKarsten Keil {
16861b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
16871b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
16881b2b03f8SKarsten Keil 
16891b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
16901b2b03f8SKarsten Keil 	stop_t200(l2, 20);
16911b2b03f8SKarsten Keil 	l2up(l2, DL_RELEASE_CNF, skb);
16921b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_4);
16931b2b03f8SKarsten Keil 	if (l2->tm)
16941b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
16951b2b03f8SKarsten Keil }
16961b2b03f8SKarsten Keil 
16971b2b03f8SKarsten Keil static void
l2_persistent_da(struct FsmInst * fi,int event,void * arg)169895b8fbadSJan Engelhardt l2_persistent_da(struct FsmInst *fi, int event, void *arg)
16991b2b03f8SKarsten Keil {
17001b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
17011b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
17021b2b03f8SKarsten Keil 
17031b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
17041b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
17051b2b03f8SKarsten Keil 	freewin(l2);
17061b2b03f8SKarsten Keil 	stop_t200(l2, 19);
17071b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t203, 19);
17081b2b03f8SKarsten Keil 	l2up(l2, DL_RELEASE_IND, skb);
17091b2b03f8SKarsten Keil 	mISDN_FsmChangeState(fi, ST_L2_4);
17101b2b03f8SKarsten Keil 	if (l2->tm)
17111b2b03f8SKarsten Keil 		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
17121b2b03f8SKarsten Keil }
17131b2b03f8SKarsten Keil 
17141b2b03f8SKarsten Keil static void
l2_set_own_busy(struct FsmInst * fi,int event,void * arg)17151b2b03f8SKarsten Keil l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
17161b2b03f8SKarsten Keil {
17171b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
17181b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
17191b2b03f8SKarsten Keil 
17201b2b03f8SKarsten Keil 	if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) {
17211b2b03f8SKarsten Keil 		enquiry_cr(l2, RNR, RSP, 0);
17221b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
17231b2b03f8SKarsten Keil 	}
17241b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
17251b2b03f8SKarsten Keil }
17261b2b03f8SKarsten Keil 
17271b2b03f8SKarsten Keil static void
l2_clear_own_busy(struct FsmInst * fi,int event,void * arg)17281b2b03f8SKarsten Keil l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
17291b2b03f8SKarsten Keil {
17301b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
17311b2b03f8SKarsten Keil 	struct sk_buff *skb = arg;
17321b2b03f8SKarsten Keil 
17331b2b03f8SKarsten Keil 	if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) {
17341b2b03f8SKarsten Keil 		enquiry_cr(l2, RR, RSP, 0);
17351b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
17361b2b03f8SKarsten Keil 	}
17371b2b03f8SKarsten Keil 	dev_kfree_skb(skb);
17381b2b03f8SKarsten Keil }
17391b2b03f8SKarsten Keil 
17401b2b03f8SKarsten Keil static void
l2_frame_error(struct FsmInst * fi,int event,void * arg)17411b2b03f8SKarsten Keil l2_frame_error(struct FsmInst *fi, int event, void *arg)
17421b2b03f8SKarsten Keil {
17431b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
17441b2b03f8SKarsten Keil 
17451b2b03f8SKarsten Keil 	l2mgr(l2, MDL_ERROR_IND, arg);
17461b2b03f8SKarsten Keil }
17471b2b03f8SKarsten Keil 
17481b2b03f8SKarsten Keil static void
l2_frame_error_reest(struct FsmInst * fi,int event,void * arg)17491b2b03f8SKarsten Keil l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
17501b2b03f8SKarsten Keil {
17511b2b03f8SKarsten Keil 	struct layer2 *l2 = fi->userdata;
17521b2b03f8SKarsten Keil 
17531b2b03f8SKarsten Keil 	l2mgr(l2, MDL_ERROR_IND, arg);
17541b2b03f8SKarsten Keil 	establishlink(fi);
17551b2b03f8SKarsten Keil 	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
17561b2b03f8SKarsten Keil }
17571b2b03f8SKarsten Keil 
17581b2b03f8SKarsten Keil static struct FsmNode L2FnList[] =
17591b2b03f8SKarsten Keil {
17601b2b03f8SKarsten Keil 	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
17611b2b03f8SKarsten Keil 	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
17621b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
17631b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
17641b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
17651b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
17661b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
17671b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
17681b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
17691b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
17701b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
17711b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
17721b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
17731b2b03f8SKarsten Keil 	{ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign},
17741b2b03f8SKarsten Keil 	{ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui},
17751b2b03f8SKarsten Keil 	{ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui},
17761b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui},
17771b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui},
17781b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui},
17791b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui},
17801b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui},
17811b2b03f8SKarsten Keil 	{ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
17821b2b03f8SKarsten Keil 	{ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
17831b2b03f8SKarsten Keil 	{ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
17841b2b03f8SKarsten Keil 	{ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
17851b2b03f8SKarsten Keil 	{ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
17861b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
17871b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
17881b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
17891b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
17901b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
17911b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_SABME, l2_start_multi},
17921b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_SABME, l2_send_UA},
17931b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_SABME, l2_send_DM},
17941b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_SABME, l2_restart_multi},
17951b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_SABME, l2_restart_multi},
17961b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_DISC, l2_send_DM},
17971b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_DISC, l2_send_DM},
17981b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_DISC, l2_send_UA},
17991b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_DISC, l2_stop_multi},
18001b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_DISC, l2_stop_multi},
18011b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
18021b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_UA, l2_connected},
18031b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_UA, l2_released},
18041b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
18051b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
18061b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_DM, l2_reestablish},
18071b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_DM, l2_st5_dm_release},
18081b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_DM, l2_st6_dm_release},
18091b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
18101b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
18111b2b03f8SKarsten Keil 	{ST_L2_1, EV_L2_UI, l2_got_ui},
18121b2b03f8SKarsten Keil 	{ST_L2_2, EV_L2_UI, l2_got_ui},
18131b2b03f8SKarsten Keil 	{ST_L2_3, EV_L2_UI, l2_got_ui},
18141b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_UI, l2_got_ui},
18151b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_UI, l2_got_ui},
18161b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_UI, l2_got_ui},
18171b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_UI, l2_got_ui},
18181b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_UI, l2_got_ui},
18191b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
18201b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
18211b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
18221b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
18231b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_I, l2_got_iframe},
18241b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_I, l2_got_iframe},
18258423e6b2SKarsten Keil 	{ST_L2_5, EV_L2_T200, l2_timeout},
18268423e6b2SKarsten Keil 	{ST_L2_6, EV_L2_T200, l2_timeout},
18278423e6b2SKarsten Keil 	{ST_L2_7, EV_L2_T200, l2_timeout},
18288423e6b2SKarsten Keil 	{ST_L2_8, EV_L2_T200, l2_timeout},
18298423e6b2SKarsten Keil 	{ST_L2_7, EV_L2_T203, l2_timeout},
18308423e6b2SKarsten Keil 	{ST_L2_5, EV_L2_T200I, l2_st5_tout_200},
18318423e6b2SKarsten Keil 	{ST_L2_6, EV_L2_T200I, l2_st6_tout_200},
18328423e6b2SKarsten Keil 	{ST_L2_7, EV_L2_T200I, l2_st7_tout_200},
18338423e6b2SKarsten Keil 	{ST_L2_8, EV_L2_T200I, l2_st8_tout_200},
18348423e6b2SKarsten Keil 	{ST_L2_7, EV_L2_T203I, l2_st7_tout_203},
18351b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
18361b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
18371b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
18381b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
18391b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
18401b2b03f8SKarsten Keil 	{ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
18411b2b03f8SKarsten Keil 	{ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
18421b2b03f8SKarsten Keil 	{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
18431b2b03f8SKarsten Keil 	{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
18441b2b03f8SKarsten Keil 	{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
184595b8fbadSJan Engelhardt 	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
18461b2b03f8SKarsten Keil 	{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
18471b2b03f8SKarsten Keil 	{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
184895b8fbadSJan Engelhardt 	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
184995b8fbadSJan Engelhardt 	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
185095b8fbadSJan Engelhardt 	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
185195b8fbadSJan Engelhardt 	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
185295b8fbadSJan Engelhardt 	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
18531b2b03f8SKarsten Keil };
18541b2b03f8SKarsten Keil 
18551b2b03f8SKarsten Keil static int
ph_data_indication(struct layer2 * l2,struct mISDNhead * hh,struct sk_buff * skb)18561b2b03f8SKarsten Keil ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
18571b2b03f8SKarsten Keil {
18581b2b03f8SKarsten Keil 	u_char	*datap = skb->data;
18591b2b03f8SKarsten Keil 	int	ret = -EINVAL;
18601b2b03f8SKarsten Keil 	int	psapi, ptei;
18611b2b03f8SKarsten Keil 	u_int	l;
18621b2b03f8SKarsten Keil 	int	c = 0;
18631b2b03f8SKarsten Keil 
18641b2b03f8SKarsten Keil 	l = l2addrsize(l2);
18651b2b03f8SKarsten Keil 	if (skb->len <= l) {
18661b2b03f8SKarsten Keil 		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N');
18671b2b03f8SKarsten Keil 		return ret;
18681b2b03f8SKarsten Keil 	}
18691b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */
18701b2b03f8SKarsten Keil 		psapi = *datap++;
18711b2b03f8SKarsten Keil 		ptei = *datap++;
18721b2b03f8SKarsten Keil 		if ((psapi & 1) || !(ptei & 1)) {
18731b2b03f8SKarsten Keil 			printk(KERN_WARNING
1874f45ebf3aSKarsten Keil 			       "%s l2 D-channel frame wrong EA0/EA1\n",
1875f45ebf3aSKarsten Keil 			       mISDNDevName4ch(&l2->ch));
18761b2b03f8SKarsten Keil 			return ret;
18771b2b03f8SKarsten Keil 		}
18781b2b03f8SKarsten Keil 		psapi >>= 2;
18791b2b03f8SKarsten Keil 		ptei >>= 1;
18801b2b03f8SKarsten Keil 		if (psapi != l2->sapi) {
188125985edcSLucas De Marchi 			/* not our business */
1882d796509aSAndreas Eversberg 			if (*debug & DEBUG_L2)
1883d796509aSAndreas Eversberg 				printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
1884f45ebf3aSKarsten Keil 				       mISDNDevName4ch(&l2->ch), psapi,
1885f45ebf3aSKarsten Keil 				       l2->sapi);
18861b2b03f8SKarsten Keil 			dev_kfree_skb(skb);
18871b2b03f8SKarsten Keil 			return 0;
18881b2b03f8SKarsten Keil 		}
18891b2b03f8SKarsten Keil 		if ((ptei != l2->tei) && (ptei != GROUP_TEI)) {
189025985edcSLucas De Marchi 			/* not our business */
1891d796509aSAndreas Eversberg 			if (*debug & DEBUG_L2)
1892d796509aSAndreas Eversberg 				printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
1893f45ebf3aSKarsten Keil 				       mISDNDevName4ch(&l2->ch), ptei, l2->tei);
18941b2b03f8SKarsten Keil 			dev_kfree_skb(skb);
18951b2b03f8SKarsten Keil 			return 0;
18961b2b03f8SKarsten Keil 		}
18971b2b03f8SKarsten Keil 	} else
18981b2b03f8SKarsten Keil 		datap += l;
18991b2b03f8SKarsten Keil 	if (!(*datap & 1)) {	/* I-Frame */
19001b2b03f8SKarsten Keil 		c = iframe_error(l2, skb);
19011b2b03f8SKarsten Keil 		if (!c)
19021b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb);
19031b2b03f8SKarsten Keil 	} else if (IsSFrame(datap, l2)) {	/* S-Frame */
19041b2b03f8SKarsten Keil 		c = super_error(l2, skb);
19051b2b03f8SKarsten Keil 		if (!c)
19061b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb);
19071b2b03f8SKarsten Keil 	} else if (IsUI(datap)) {
19081b2b03f8SKarsten Keil 		c = UI_error(l2, skb);
19091b2b03f8SKarsten Keil 		if (!c)
19101b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb);
19111b2b03f8SKarsten Keil 	} else if (IsSABME(datap, l2)) {
19121b2b03f8SKarsten Keil 		c = unnum_error(l2, skb, CMD);
19131b2b03f8SKarsten Keil 		if (!c)
19141b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb);
19151b2b03f8SKarsten Keil 	} else if (IsUA(datap)) {
19161b2b03f8SKarsten Keil 		c = unnum_error(l2, skb, RSP);
19171b2b03f8SKarsten Keil 		if (!c)
19181b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb);
19191b2b03f8SKarsten Keil 	} else if (IsDISC(datap)) {
19201b2b03f8SKarsten Keil 		c = unnum_error(l2, skb, CMD);
19211b2b03f8SKarsten Keil 		if (!c)
19221b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb);
19231b2b03f8SKarsten Keil 	} else if (IsDM(datap)) {
19241b2b03f8SKarsten Keil 		c = unnum_error(l2, skb, RSP);
19251b2b03f8SKarsten Keil 		if (!c)
19261b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb);
19271b2b03f8SKarsten Keil 	} else if (IsFRMR(datap)) {
19281b2b03f8SKarsten Keil 		c = FRMR_error(l2, skb);
19291b2b03f8SKarsten Keil 		if (!c)
19301b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb);
19311b2b03f8SKarsten Keil 	} else
19321b2b03f8SKarsten Keil 		c = 'L';
19331b2b03f8SKarsten Keil 	if (c) {
1934f45ebf3aSKarsten Keil 		printk(KERN_WARNING "%s:l2 D-channel frame error %c\n",
1935f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), c);
19361b2b03f8SKarsten Keil 		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
19371b2b03f8SKarsten Keil 	}
19381b2b03f8SKarsten Keil 	return ret;
19391b2b03f8SKarsten Keil }
19401b2b03f8SKarsten Keil 
19411b2b03f8SKarsten Keil static int
l2_send(struct mISDNchannel * ch,struct sk_buff * skb)19421b2b03f8SKarsten Keil l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
19431b2b03f8SKarsten Keil {
19441b2b03f8SKarsten Keil 	struct layer2		*l2 = container_of(ch, struct layer2, ch);
19451b2b03f8SKarsten Keil 	struct mISDNhead	*hh =  mISDN_HEAD_P(skb);
19461b2b03f8SKarsten Keil 	int			ret = -EINVAL;
19471b2b03f8SKarsten Keil 
19481b2b03f8SKarsten Keil 	if (*debug & DEBUG_L2_RECV)
1949f45ebf3aSKarsten Keil 		printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n",
1950f45ebf3aSKarsten Keil 		       __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id,
1951f45ebf3aSKarsten Keil 		       l2->sapi, l2->tei);
19528423e6b2SKarsten Keil 	if (hh->prim == DL_INTERN_MSG) {
19538423e6b2SKarsten Keil 		struct mISDNhead *chh = hh + 1; /* saved copy */
19548423e6b2SKarsten Keil 
19558423e6b2SKarsten Keil 		*hh = *chh;
19568423e6b2SKarsten Keil 		if (*debug & DEBUG_L2_RECV)
19578423e6b2SKarsten Keil 			printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
1958f45ebf3aSKarsten Keil 				mISDNDevName4ch(&l2->ch), hh->prim, hh->id);
19598423e6b2SKarsten Keil 	}
19601b2b03f8SKarsten Keil 	switch (hh->prim) {
19611b2b03f8SKarsten Keil 	case PH_DATA_IND:
19621b2b03f8SKarsten Keil 		ret = ph_data_indication(l2, hh, skb);
19631b2b03f8SKarsten Keil 		break;
19641b2b03f8SKarsten Keil 	case PH_DATA_CNF:
19651b2b03f8SKarsten Keil 		ret = ph_data_confirm(l2, hh, skb);
19661b2b03f8SKarsten Keil 		break;
19671b2b03f8SKarsten Keil 	case PH_ACTIVATE_IND:
19681b2b03f8SKarsten Keil 		test_and_set_bit(FLG_L1_ACTIV, &l2->flag);
19691b2b03f8SKarsten Keil 		l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL);
19701b2b03f8SKarsten Keil 		if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
19711b2b03f8SKarsten Keil 			ret = mISDN_FsmEvent(&l2->l2m,
19721b2b03f8SKarsten Keil 					     EV_L2_DL_ESTABLISH_REQ, skb);
19731b2b03f8SKarsten Keil 		break;
19741b2b03f8SKarsten Keil 	case PH_DEACTIVATE_IND:
19751b2b03f8SKarsten Keil 		test_and_clear_bit(FLG_L1_ACTIV, &l2->flag);
19761b2b03f8SKarsten Keil 		l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL);
19771b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb);
19781b2b03f8SKarsten Keil 		break;
19791b2b03f8SKarsten Keil 	case MPH_INFORMATION_IND:
19801b2b03f8SKarsten Keil 		if (!l2->up)
19811b2b03f8SKarsten Keil 			break;
19821b2b03f8SKarsten Keil 		ret = l2->up->send(l2->up, skb);
19831b2b03f8SKarsten Keil 		break;
19841b2b03f8SKarsten Keil 	case DL_DATA_REQ:
19851b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb);
19861b2b03f8SKarsten Keil 		break;
19871b2b03f8SKarsten Keil 	case DL_UNITDATA_REQ:
19881b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb);
19891b2b03f8SKarsten Keil 		break;
19901b2b03f8SKarsten Keil 	case DL_ESTABLISH_REQ:
19911b2b03f8SKarsten Keil 		if (test_bit(FLG_LAPB, &l2->flag))
19921b2b03f8SKarsten Keil 			test_and_set_bit(FLG_ORIG, &l2->flag);
19931b2b03f8SKarsten Keil 		if (test_bit(FLG_L1_ACTIV, &l2->flag)) {
19941b2b03f8SKarsten Keil 			if (test_bit(FLG_LAPD, &l2->flag) ||
19951b2b03f8SKarsten Keil 			    test_bit(FLG_ORIG, &l2->flag))
19961b2b03f8SKarsten Keil 				ret = mISDN_FsmEvent(&l2->l2m,
19971b2b03f8SKarsten Keil 						     EV_L2_DL_ESTABLISH_REQ, skb);
19981b2b03f8SKarsten Keil 		} else {
19991b2b03f8SKarsten Keil 			if (test_bit(FLG_LAPD, &l2->flag) ||
20001b2b03f8SKarsten Keil 			    test_bit(FLG_ORIG, &l2->flag)) {
20011b2b03f8SKarsten Keil 				test_and_set_bit(FLG_ESTAB_PEND,
20021b2b03f8SKarsten Keil 						 &l2->flag);
20031b2b03f8SKarsten Keil 			}
20041b2b03f8SKarsten Keil 			ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2),
20051b2b03f8SKarsten Keil 				     skb);
20061b2b03f8SKarsten Keil 		}
20071b2b03f8SKarsten Keil 		break;
20081b2b03f8SKarsten Keil 	case DL_RELEASE_REQ:
20091b2b03f8SKarsten Keil 		if (test_bit(FLG_LAPB, &l2->flag))
20101b2b03f8SKarsten Keil 			l2down_create(l2, PH_DEACTIVATE_REQ,
20111b2b03f8SKarsten Keil 				      l2_newid(l2), 0, NULL);
20121b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ,
20131b2b03f8SKarsten Keil 				     skb);
20141b2b03f8SKarsten Keil 		break;
20158423e6b2SKarsten Keil 	case DL_TIMER200_IND:
20168423e6b2SKarsten Keil 		mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL);
20178423e6b2SKarsten Keil 		break;
20188423e6b2SKarsten Keil 	case DL_TIMER203_IND:
20198423e6b2SKarsten Keil 		mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL);
20208423e6b2SKarsten Keil 		break;
20211b2b03f8SKarsten Keil 	default:
20221b2b03f8SKarsten Keil 		if (*debug & DEBUG_L2)
20231b2b03f8SKarsten Keil 			l2m_debug(&l2->l2m, "l2 unknown pr %04x",
20241b2b03f8SKarsten Keil 				  hh->prim);
20251b2b03f8SKarsten Keil 	}
20261b2b03f8SKarsten Keil 	if (ret) {
20271b2b03f8SKarsten Keil 		dev_kfree_skb(skb);
20281b2b03f8SKarsten Keil 		ret = 0;
20291b2b03f8SKarsten Keil 	}
20301b2b03f8SKarsten Keil 	return ret;
20311b2b03f8SKarsten Keil }
20321b2b03f8SKarsten Keil 
20331b2b03f8SKarsten Keil int
tei_l2(struct layer2 * l2,u_int cmd,u_long arg)20341b2b03f8SKarsten Keil tei_l2(struct layer2 *l2, u_int cmd, u_long arg)
20351b2b03f8SKarsten Keil {
20361b2b03f8SKarsten Keil 	int		ret = -EINVAL;
20371b2b03f8SKarsten Keil 
20381b2b03f8SKarsten Keil 	if (*debug & DEBUG_L2_TEI)
2039f45ebf3aSKarsten Keil 		printk(KERN_DEBUG "%s: cmd(%x) in %s\n",
2040f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch), cmd, __func__);
20411b2b03f8SKarsten Keil 	switch (cmd) {
20421b2b03f8SKarsten Keil 	case (MDL_ASSIGN_REQ):
20431b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg);
20441b2b03f8SKarsten Keil 		break;
20451b2b03f8SKarsten Keil 	case (MDL_REMOVE_REQ):
20461b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL);
20471b2b03f8SKarsten Keil 		break;
20481b2b03f8SKarsten Keil 	case (MDL_ERROR_IND):
20491b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
20501b2b03f8SKarsten Keil 		break;
20511b2b03f8SKarsten Keil 	case (MDL_ERROR_RSP):
20521b2b03f8SKarsten Keil 		/* ETS 300-125 5.3.2.1 Test: TC13010 */
2053f45ebf3aSKarsten Keil 		printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n",
2054f45ebf3aSKarsten Keil 		       mISDNDevName4ch(&l2->ch));
20551b2b03f8SKarsten Keil 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
20561b2b03f8SKarsten Keil 		break;
20571b2b03f8SKarsten Keil 	}
20581b2b03f8SKarsten Keil 	return ret;
20591b2b03f8SKarsten Keil }
20601b2b03f8SKarsten Keil 
20611b2b03f8SKarsten Keil static void
release_l2(struct layer2 * l2)20621b2b03f8SKarsten Keil release_l2(struct layer2 *l2)
20631b2b03f8SKarsten Keil {
20641b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t200, 21);
20651b2b03f8SKarsten Keil 	mISDN_FsmDelTimer(&l2->t203, 16);
20661b2b03f8SKarsten Keil 	skb_queue_purge(&l2->i_queue);
20671b2b03f8SKarsten Keil 	skb_queue_purge(&l2->ui_queue);
20681b2b03f8SKarsten Keil 	skb_queue_purge(&l2->down_queue);
20691b2b03f8SKarsten Keil 	ReleaseWin(l2);
20701b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPD, &l2->flag)) {
2071c5b61d59SKarsten Keil 		TEIrelease(l2);
20721b2b03f8SKarsten Keil 		if (l2->ch.st)
20731b2b03f8SKarsten Keil 			l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
20741b2b03f8SKarsten Keil 					       CLOSE_CHANNEL, NULL);
20751b2b03f8SKarsten Keil 	}
20761b2b03f8SKarsten Keil 	kfree(l2);
20771b2b03f8SKarsten Keil }
20781b2b03f8SKarsten Keil 
20791b2b03f8SKarsten Keil static int
l2_ctrl(struct mISDNchannel * ch,u_int cmd,void * arg)20801b2b03f8SKarsten Keil l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
20811b2b03f8SKarsten Keil {
20821b2b03f8SKarsten Keil 	struct layer2		*l2 = container_of(ch, struct layer2, ch);
20831b2b03f8SKarsten Keil 	u_int			info;
20841b2b03f8SKarsten Keil 
20851b2b03f8SKarsten Keil 	if (*debug & DEBUG_L2_CTRL)
2086f45ebf3aSKarsten Keil 		printk(KERN_DEBUG "%s: %s cmd(%x)\n",
2087f45ebf3aSKarsten Keil 		       mISDNDevName4ch(ch), __func__, cmd);
20881b2b03f8SKarsten Keil 
20891b2b03f8SKarsten Keil 	switch (cmd) {
20901b2b03f8SKarsten Keil 	case OPEN_CHANNEL:
20911b2b03f8SKarsten Keil 		if (test_bit(FLG_LAPD, &l2->flag)) {
20921b2b03f8SKarsten Keil 			set_channel_address(&l2->ch, l2->sapi, l2->tei);
20931b2b03f8SKarsten Keil 			info = DL_INFO_L2_CONNECT;
20941b2b03f8SKarsten Keil 			l2up_create(l2, DL_INFORMATION_IND,
20951b2b03f8SKarsten Keil 				    sizeof(info), &info);
20961b2b03f8SKarsten Keil 		}
20971b2b03f8SKarsten Keil 		break;
20981b2b03f8SKarsten Keil 	case CLOSE_CHANNEL:
20991b2b03f8SKarsten Keil 		if (l2->ch.peer)
21001b2b03f8SKarsten Keil 			l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL);
21011b2b03f8SKarsten Keil 		release_l2(l2);
21021b2b03f8SKarsten Keil 		break;
21031b2b03f8SKarsten Keil 	}
21041b2b03f8SKarsten Keil 	return 0;
21051b2b03f8SKarsten Keil }
21061b2b03f8SKarsten Keil 
21071b2b03f8SKarsten Keil struct layer2 *
create_l2(struct mISDNchannel * ch,u_int protocol,u_long options,int tei,int sapi)21085b277b86SAndreas Eversberg create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
21095b277b86SAndreas Eversberg 	  int sapi)
21101b2b03f8SKarsten Keil {
21111b2b03f8SKarsten Keil 	struct layer2		*l2;
21121b2b03f8SKarsten Keil 	struct channel_req	rq;
21131b2b03f8SKarsten Keil 
21141b2b03f8SKarsten Keil 	l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL);
21151b2b03f8SKarsten Keil 	if (!l2) {
21161b2b03f8SKarsten Keil 		printk(KERN_ERR "kzalloc layer2 failed\n");
21171b2b03f8SKarsten Keil 		return NULL;
21181b2b03f8SKarsten Keil 	}
21191b2b03f8SKarsten Keil 	l2->next_id = 1;
21201b2b03f8SKarsten Keil 	l2->down_id = MISDN_ID_NONE;
21211b2b03f8SKarsten Keil 	l2->up = ch;
21221b2b03f8SKarsten Keil 	l2->ch.st = ch->st;
21231b2b03f8SKarsten Keil 	l2->ch.send = l2_send;
21241b2b03f8SKarsten Keil 	l2->ch.ctrl = l2_ctrl;
21251b2b03f8SKarsten Keil 	switch (protocol) {
21261b2b03f8SKarsten Keil 	case ISDN_P_LAPD_NT:
21271b2b03f8SKarsten Keil 		test_and_set_bit(FLG_LAPD, &l2->flag);
21281b2b03f8SKarsten Keil 		test_and_set_bit(FLG_LAPD_NET, &l2->flag);
21291b2b03f8SKarsten Keil 		test_and_set_bit(FLG_MOD128, &l2->flag);
21305b277b86SAndreas Eversberg 		l2->sapi = sapi;
21311b2b03f8SKarsten Keil 		l2->maxlen = MAX_DFRAME_LEN;
21321b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_PMX, &options))
21331b2b03f8SKarsten Keil 			l2->window = 7;
21341b2b03f8SKarsten Keil 		else
21351b2b03f8SKarsten Keil 			l2->window = 1;
21361b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_PTP, &options))
21371b2b03f8SKarsten Keil 			test_and_set_bit(FLG_PTP, &l2->flag);
21381b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_FIXEDTEI, &options))
21391b2b03f8SKarsten Keil 			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
21405b277b86SAndreas Eversberg 		l2->tei = tei;
21411b2b03f8SKarsten Keil 		l2->T200 = 1000;
21421b2b03f8SKarsten Keil 		l2->N200 = 3;
21431b2b03f8SKarsten Keil 		l2->T203 = 10000;
21441b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_PMX, &options))
21451b2b03f8SKarsten Keil 			rq.protocol = ISDN_P_NT_E1;
21461b2b03f8SKarsten Keil 		else
21471b2b03f8SKarsten Keil 			rq.protocol = ISDN_P_NT_S0;
21481b2b03f8SKarsten Keil 		rq.adr.channel = 0;
21491b2b03f8SKarsten Keil 		l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
21501b2b03f8SKarsten Keil 		break;
21511b2b03f8SKarsten Keil 	case ISDN_P_LAPD_TE:
21521b2b03f8SKarsten Keil 		test_and_set_bit(FLG_LAPD, &l2->flag);
21531b2b03f8SKarsten Keil 		test_and_set_bit(FLG_MOD128, &l2->flag);
21541b2b03f8SKarsten Keil 		test_and_set_bit(FLG_ORIG, &l2->flag);
21555b277b86SAndreas Eversberg 		l2->sapi = sapi;
21561b2b03f8SKarsten Keil 		l2->maxlen = MAX_DFRAME_LEN;
21571b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_PMX, &options))
21581b2b03f8SKarsten Keil 			l2->window = 7;
21591b2b03f8SKarsten Keil 		else
21601b2b03f8SKarsten Keil 			l2->window = 1;
21611b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_PTP, &options))
21621b2b03f8SKarsten Keil 			test_and_set_bit(FLG_PTP, &l2->flag);
21631b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_FIXEDTEI, &options))
21641b2b03f8SKarsten Keil 			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
21655b277b86SAndreas Eversberg 		l2->tei = tei;
21661b2b03f8SKarsten Keil 		l2->T200 = 1000;
21671b2b03f8SKarsten Keil 		l2->N200 = 3;
21681b2b03f8SKarsten Keil 		l2->T203 = 10000;
21691b2b03f8SKarsten Keil 		if (test_bit(OPTION_L2_PMX, &options))
21701b2b03f8SKarsten Keil 			rq.protocol = ISDN_P_TE_E1;
21711b2b03f8SKarsten Keil 		else
21721b2b03f8SKarsten Keil 			rq.protocol = ISDN_P_TE_S0;
21731b2b03f8SKarsten Keil 		rq.adr.channel = 0;
21741b2b03f8SKarsten Keil 		l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
21751b2b03f8SKarsten Keil 		break;
21761b2b03f8SKarsten Keil 	case ISDN_P_B_X75SLP:
21771b2b03f8SKarsten Keil 		test_and_set_bit(FLG_LAPB, &l2->flag);
21781b2b03f8SKarsten Keil 		l2->window = 7;
21791b2b03f8SKarsten Keil 		l2->maxlen = MAX_DATA_SIZE;
21801b2b03f8SKarsten Keil 		l2->T200 = 1000;
21811b2b03f8SKarsten Keil 		l2->N200 = 4;
21821b2b03f8SKarsten Keil 		l2->T203 = 5000;
21831b2b03f8SKarsten Keil 		l2->addr.A = 3;
21841b2b03f8SKarsten Keil 		l2->addr.B = 1;
21851b2b03f8SKarsten Keil 		break;
21861b2b03f8SKarsten Keil 	default:
21871b2b03f8SKarsten Keil 		printk(KERN_ERR "layer2 create failed prt %x\n",
21881b2b03f8SKarsten Keil 		       protocol);
21891b2b03f8SKarsten Keil 		kfree(l2);
21901b2b03f8SKarsten Keil 		return NULL;
21911b2b03f8SKarsten Keil 	}
21921b2b03f8SKarsten Keil 	skb_queue_head_init(&l2->i_queue);
21931b2b03f8SKarsten Keil 	skb_queue_head_init(&l2->ui_queue);
21941b2b03f8SKarsten Keil 	skb_queue_head_init(&l2->down_queue);
21951b2b03f8SKarsten Keil 	skb_queue_head_init(&l2->tmp_queue);
21961b2b03f8SKarsten Keil 	InitWin(l2);
21971b2b03f8SKarsten Keil 	l2->l2m.fsm = &l2fsm;
21981b2b03f8SKarsten Keil 	if (test_bit(FLG_LAPB, &l2->flag) ||
219925099335SKarsten Keil 	    test_bit(FLG_FIXED_TEI, &l2->flag) ||
22001b2b03f8SKarsten Keil 	    test_bit(FLG_LAPD_NET, &l2->flag))
22011b2b03f8SKarsten Keil 		l2->l2m.state = ST_L2_4;
22021b2b03f8SKarsten Keil 	else
22031b2b03f8SKarsten Keil 		l2->l2m.state = ST_L2_1;
22041b2b03f8SKarsten Keil 	l2->l2m.debug = *debug;
22051b2b03f8SKarsten Keil 	l2->l2m.userdata = l2;
22061b2b03f8SKarsten Keil 	l2->l2m.userint = 0;
22071b2b03f8SKarsten Keil 	l2->l2m.printdebug = l2m_debug;
22081b2b03f8SKarsten Keil 
22091b2b03f8SKarsten Keil 	mISDN_FsmInitTimer(&l2->l2m, &l2->t200);
22101b2b03f8SKarsten Keil 	mISDN_FsmInitTimer(&l2->l2m, &l2->t203);
22111b2b03f8SKarsten Keil 	return l2;
22121b2b03f8SKarsten Keil }
22131b2b03f8SKarsten Keil 
22141b2b03f8SKarsten Keil static int
x75create(struct channel_req * crq)22151b2b03f8SKarsten Keil x75create(struct channel_req *crq)
22161b2b03f8SKarsten Keil {
22171b2b03f8SKarsten Keil 	struct layer2	*l2;
22181b2b03f8SKarsten Keil 
22191b2b03f8SKarsten Keil 	if (crq->protocol != ISDN_P_B_X75SLP)
22201b2b03f8SKarsten Keil 		return -EPROTONOSUPPORT;
22215b277b86SAndreas Eversberg 	l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0);
22221b2b03f8SKarsten Keil 	if (!l2)
22231b2b03f8SKarsten Keil 		return -ENOMEM;
22241b2b03f8SKarsten Keil 	crq->ch = &l2->ch;
22251b2b03f8SKarsten Keil 	crq->protocol = ISDN_P_B_HDLC;
22261b2b03f8SKarsten Keil 	return 0;
22271b2b03f8SKarsten Keil }
22281b2b03f8SKarsten Keil 
22291b2b03f8SKarsten Keil static struct Bprotocol X75SLP = {
22301b2b03f8SKarsten Keil 	.Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)),
22311b2b03f8SKarsten Keil 	.name = "X75SLP",
22321b2b03f8SKarsten Keil 	.create = x75create
22331b2b03f8SKarsten Keil };
22341b2b03f8SKarsten Keil 
22351b2b03f8SKarsten Keil int
Isdnl2_Init(u_int * deb)22361b2b03f8SKarsten Keil Isdnl2_Init(u_int *deb)
22371b2b03f8SKarsten Keil {
223854a6a043SAnton Vasilyev 	int res;
22391b2b03f8SKarsten Keil 	debug = deb;
22401b2b03f8SKarsten Keil 	mISDN_register_Bprotocol(&X75SLP);
22411b2b03f8SKarsten Keil 	l2fsm.state_count = L2_STATE_COUNT;
22421b2b03f8SKarsten Keil 	l2fsm.event_count = L2_EVENT_COUNT;
22431b2b03f8SKarsten Keil 	l2fsm.strEvent = strL2Event;
22441b2b03f8SKarsten Keil 	l2fsm.strState = strL2State;
224554a6a043SAnton Vasilyev 	res = mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
224654a6a043SAnton Vasilyev 	if (res)
224754a6a043SAnton Vasilyev 		goto error;
224854a6a043SAnton Vasilyev 	res = TEIInit(deb);
224954a6a043SAnton Vasilyev 	if (res)
225054a6a043SAnton Vasilyev 		goto error_fsm;
22511b2b03f8SKarsten Keil 	return 0;
225254a6a043SAnton Vasilyev 
225354a6a043SAnton Vasilyev error_fsm:
225454a6a043SAnton Vasilyev 	mISDN_FsmFree(&l2fsm);
225554a6a043SAnton Vasilyev error:
225654a6a043SAnton Vasilyev 	mISDN_unregister_Bprotocol(&X75SLP);
225754a6a043SAnton Vasilyev 	return res;
22581b2b03f8SKarsten Keil }
22591b2b03f8SKarsten Keil 
22601b2b03f8SKarsten Keil void
Isdnl2_cleanup(void)22611b2b03f8SKarsten Keil Isdnl2_cleanup(void)
22621b2b03f8SKarsten Keil {
22631b2b03f8SKarsten Keil 	mISDN_unregister_Bprotocol(&X75SLP);
22641b2b03f8SKarsten Keil 	TEIFree();
22651b2b03f8SKarsten Keil 	mISDN_FsmFree(&l2fsm);
22661b2b03f8SKarsten Keil }
2267