18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Author	Karsten Keil <kkeil@novell.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2008  by Karsten Keil <kkeil@novell.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/mISDNif.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include "core.h"
128c2ecf20Sopenharmony_ci#include "fsm.h"
138c2ecf20Sopenharmony_ci#include "layer2.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic u_int *debug;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic
188c2ecf20Sopenharmony_cistruct Fsm l2fsm = {NULL, 0, 0, NULL, NULL};
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic char *strL2State[] =
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	"ST_L2_1",
238c2ecf20Sopenharmony_ci	"ST_L2_2",
248c2ecf20Sopenharmony_ci	"ST_L2_3",
258c2ecf20Sopenharmony_ci	"ST_L2_4",
268c2ecf20Sopenharmony_ci	"ST_L2_5",
278c2ecf20Sopenharmony_ci	"ST_L2_6",
288c2ecf20Sopenharmony_ci	"ST_L2_7",
298c2ecf20Sopenharmony_ci	"ST_L2_8",
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cienum {
338c2ecf20Sopenharmony_ci	EV_L2_UI,
348c2ecf20Sopenharmony_ci	EV_L2_SABME,
358c2ecf20Sopenharmony_ci	EV_L2_DISC,
368c2ecf20Sopenharmony_ci	EV_L2_DM,
378c2ecf20Sopenharmony_ci	EV_L2_UA,
388c2ecf20Sopenharmony_ci	EV_L2_FRMR,
398c2ecf20Sopenharmony_ci	EV_L2_SUPER,
408c2ecf20Sopenharmony_ci	EV_L2_I,
418c2ecf20Sopenharmony_ci	EV_L2_DL_DATA,
428c2ecf20Sopenharmony_ci	EV_L2_ACK_PULL,
438c2ecf20Sopenharmony_ci	EV_L2_DL_UNITDATA,
448c2ecf20Sopenharmony_ci	EV_L2_DL_ESTABLISH_REQ,
458c2ecf20Sopenharmony_ci	EV_L2_DL_RELEASE_REQ,
468c2ecf20Sopenharmony_ci	EV_L2_MDL_ASSIGN,
478c2ecf20Sopenharmony_ci	EV_L2_MDL_REMOVE,
488c2ecf20Sopenharmony_ci	EV_L2_MDL_ERROR,
498c2ecf20Sopenharmony_ci	EV_L1_DEACTIVATE,
508c2ecf20Sopenharmony_ci	EV_L2_T200,
518c2ecf20Sopenharmony_ci	EV_L2_T203,
528c2ecf20Sopenharmony_ci	EV_L2_T200I,
538c2ecf20Sopenharmony_ci	EV_L2_T203I,
548c2ecf20Sopenharmony_ci	EV_L2_SET_OWN_BUSY,
558c2ecf20Sopenharmony_ci	EV_L2_CLEAR_OWN_BUSY,
568c2ecf20Sopenharmony_ci	EV_L2_FRAME_ERROR,
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic char *strL2Event[] =
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	"EV_L2_UI",
648c2ecf20Sopenharmony_ci	"EV_L2_SABME",
658c2ecf20Sopenharmony_ci	"EV_L2_DISC",
668c2ecf20Sopenharmony_ci	"EV_L2_DM",
678c2ecf20Sopenharmony_ci	"EV_L2_UA",
688c2ecf20Sopenharmony_ci	"EV_L2_FRMR",
698c2ecf20Sopenharmony_ci	"EV_L2_SUPER",
708c2ecf20Sopenharmony_ci	"EV_L2_I",
718c2ecf20Sopenharmony_ci	"EV_L2_DL_DATA",
728c2ecf20Sopenharmony_ci	"EV_L2_ACK_PULL",
738c2ecf20Sopenharmony_ci	"EV_L2_DL_UNITDATA",
748c2ecf20Sopenharmony_ci	"EV_L2_DL_ESTABLISH_REQ",
758c2ecf20Sopenharmony_ci	"EV_L2_DL_RELEASE_REQ",
768c2ecf20Sopenharmony_ci	"EV_L2_MDL_ASSIGN",
778c2ecf20Sopenharmony_ci	"EV_L2_MDL_REMOVE",
788c2ecf20Sopenharmony_ci	"EV_L2_MDL_ERROR",
798c2ecf20Sopenharmony_ci	"EV_L1_DEACTIVATE",
808c2ecf20Sopenharmony_ci	"EV_L2_T200",
818c2ecf20Sopenharmony_ci	"EV_L2_T203",
828c2ecf20Sopenharmony_ci	"EV_L2_T200I",
838c2ecf20Sopenharmony_ci	"EV_L2_T203I",
848c2ecf20Sopenharmony_ci	"EV_L2_SET_OWN_BUSY",
858c2ecf20Sopenharmony_ci	"EV_L2_CLEAR_OWN_BUSY",
868c2ecf20Sopenharmony_ci	"EV_L2_FRAME_ERROR",
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic void
908c2ecf20Sopenharmony_cil2m_debug(struct FsmInst *fi, char *fmt, ...)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
938c2ecf20Sopenharmony_ci	struct va_format vaf;
948c2ecf20Sopenharmony_ci	va_list va;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (!(*debug & DEBUG_L2_FSM))
978c2ecf20Sopenharmony_ci		return;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	va_start(va, fmt);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	vaf.fmt = fmt;
1028c2ecf20Sopenharmony_ci	vaf.va = &va;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n",
1058c2ecf20Sopenharmony_ci	       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	va_end(va);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciinline u_int
1118c2ecf20Sopenharmony_cil2headersize(struct layer2 *l2, int ui)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
1148c2ecf20Sopenharmony_ci		(test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciinline u_int
1188c2ecf20Sopenharmony_cil2addrsize(struct layer2 *l2)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic u_int
1248c2ecf20Sopenharmony_cil2_newid(struct layer2 *l2)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	u_int	id;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	id = l2->next_id++;
1298c2ecf20Sopenharmony_ci	if (id == 0x7fff)
1308c2ecf20Sopenharmony_ci		l2->next_id = 1;
1318c2ecf20Sopenharmony_ci	id <<= 16;
1328c2ecf20Sopenharmony_ci	id |= l2->tei << 8;
1338c2ecf20Sopenharmony_ci	id |= l2->sapi;
1348c2ecf20Sopenharmony_ci	return id;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void
1388c2ecf20Sopenharmony_cil2up(struct layer2 *l2, u_int prim, struct sk_buff *skb)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	int	err;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (!l2->up)
1438c2ecf20Sopenharmony_ci		return;
1448c2ecf20Sopenharmony_ci	mISDN_HEAD_PRIM(skb) = prim;
1458c2ecf20Sopenharmony_ci	mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr;
1468c2ecf20Sopenharmony_ci	err = l2->up->send(l2->up, skb);
1478c2ecf20Sopenharmony_ci	if (err) {
1488c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
1498c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), err);
1508c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic void
1558c2ecf20Sopenharmony_cil2up_create(struct layer2 *l2, u_int prim, int len, void *arg)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct sk_buff	*skb;
1588c2ecf20Sopenharmony_ci	struct mISDNhead *hh;
1598c2ecf20Sopenharmony_ci	int		err;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (!l2->up)
1628c2ecf20Sopenharmony_ci		return;
1638c2ecf20Sopenharmony_ci	skb = mI_alloc_skb(len, GFP_ATOMIC);
1648c2ecf20Sopenharmony_ci	if (!skb)
1658c2ecf20Sopenharmony_ci		return;
1668c2ecf20Sopenharmony_ci	hh = mISDN_HEAD_P(skb);
1678c2ecf20Sopenharmony_ci	hh->prim = prim;
1688c2ecf20Sopenharmony_ci	hh->id = (l2->ch.nr << 16) | l2->ch.addr;
1698c2ecf20Sopenharmony_ci	if (len)
1708c2ecf20Sopenharmony_ci		skb_put_data(skb, arg, len);
1718c2ecf20Sopenharmony_ci	err = l2->up->send(l2->up, skb);
1728c2ecf20Sopenharmony_ci	if (err) {
1738c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
1748c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), err);
1758c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int
1808c2ecf20Sopenharmony_cil2down_skb(struct layer2 *l2, struct sk_buff *skb) {
1818c2ecf20Sopenharmony_ci	int ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	ret = l2->ch.recv(l2->ch.peer, skb);
1848c2ecf20Sopenharmony_ci	if (ret && (*debug & DEBUG_L2_RECV))
1858c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n",
1868c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), ret);
1878c2ecf20Sopenharmony_ci	return ret;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int
1918c2ecf20Sopenharmony_cil2down_raw(struct layer2 *l2, struct sk_buff *skb)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct mISDNhead *hh = mISDN_HEAD_P(skb);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (hh->prim == PH_DATA_REQ) {
1968c2ecf20Sopenharmony_ci		if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
1978c2ecf20Sopenharmony_ci			skb_queue_tail(&l2->down_queue, skb);
1988c2ecf20Sopenharmony_ci			return 0;
1998c2ecf20Sopenharmony_ci		}
2008c2ecf20Sopenharmony_ci		l2->down_id = mISDN_HEAD_ID(skb);
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	return l2down_skb(l2, skb);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int
2068c2ecf20Sopenharmony_cil2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct mISDNhead *hh = mISDN_HEAD_P(skb);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	hh->prim = prim;
2118c2ecf20Sopenharmony_ci	hh->id = id;
2128c2ecf20Sopenharmony_ci	return l2down_raw(l2, skb);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic int
2168c2ecf20Sopenharmony_cil2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct sk_buff	*skb;
2198c2ecf20Sopenharmony_ci	int		err;
2208c2ecf20Sopenharmony_ci	struct mISDNhead *hh;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	skb = mI_alloc_skb(len, GFP_ATOMIC);
2238c2ecf20Sopenharmony_ci	if (!skb)
2248c2ecf20Sopenharmony_ci		return -ENOMEM;
2258c2ecf20Sopenharmony_ci	hh = mISDN_HEAD_P(skb);
2268c2ecf20Sopenharmony_ci	hh->prim = prim;
2278c2ecf20Sopenharmony_ci	hh->id = id;
2288c2ecf20Sopenharmony_ci	if (len)
2298c2ecf20Sopenharmony_ci		skb_put_data(skb, arg, len);
2308c2ecf20Sopenharmony_ci	err = l2down_raw(l2, skb);
2318c2ecf20Sopenharmony_ci	if (err)
2328c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
2338c2ecf20Sopenharmony_ci	return err;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int
2378c2ecf20Sopenharmony_ciph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) {
2388c2ecf20Sopenharmony_ci	struct sk_buff *nskb = skb;
2398c2ecf20Sopenharmony_ci	int ret = -EAGAIN;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (test_bit(FLG_L1_NOTREADY, &l2->flag)) {
2428c2ecf20Sopenharmony_ci		if (hh->id == l2->down_id) {
2438c2ecf20Sopenharmony_ci			nskb = skb_dequeue(&l2->down_queue);
2448c2ecf20Sopenharmony_ci			if (nskb) {
2458c2ecf20Sopenharmony_ci				l2->down_id = mISDN_HEAD_ID(nskb);
2468c2ecf20Sopenharmony_ci				if (l2down_skb(l2, nskb)) {
2478c2ecf20Sopenharmony_ci					dev_kfree_skb(nskb);
2488c2ecf20Sopenharmony_ci					l2->down_id = MISDN_ID_NONE;
2498c2ecf20Sopenharmony_ci				}
2508c2ecf20Sopenharmony_ci			} else
2518c2ecf20Sopenharmony_ci				l2->down_id = MISDN_ID_NONE;
2528c2ecf20Sopenharmony_ci			if (ret) {
2538c2ecf20Sopenharmony_ci				dev_kfree_skb(skb);
2548c2ecf20Sopenharmony_ci				ret = 0;
2558c2ecf20Sopenharmony_ci			}
2568c2ecf20Sopenharmony_ci			if (l2->down_id == MISDN_ID_NONE) {
2578c2ecf20Sopenharmony_ci				test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
2588c2ecf20Sopenharmony_ci				mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
2598c2ecf20Sopenharmony_ci			}
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci	if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
2638c2ecf20Sopenharmony_ci		nskb = skb_dequeue(&l2->down_queue);
2648c2ecf20Sopenharmony_ci		if (nskb) {
2658c2ecf20Sopenharmony_ci			l2->down_id = mISDN_HEAD_ID(nskb);
2668c2ecf20Sopenharmony_ci			if (l2down_skb(l2, nskb)) {
2678c2ecf20Sopenharmony_ci				dev_kfree_skb(nskb);
2688c2ecf20Sopenharmony_ci				l2->down_id = MISDN_ID_NONE;
2698c2ecf20Sopenharmony_ci				test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
2708c2ecf20Sopenharmony_ci			}
2718c2ecf20Sopenharmony_ci		} else
2728c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	return ret;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic void
2788c2ecf20Sopenharmony_cil2_timeout(struct FsmInst *fi, int event, void *arg)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
2818c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2828c2ecf20Sopenharmony_ci	struct mISDNhead *hh;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	skb = mI_alloc_skb(0, GFP_ATOMIC);
2858c2ecf20Sopenharmony_ci	if (!skb) {
2868c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n",
2878c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
2888c2ecf20Sopenharmony_ci		       l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
2898c2ecf20Sopenharmony_ci		return;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci	hh = mISDN_HEAD_P(skb);
2928c2ecf20Sopenharmony_ci	hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
2938c2ecf20Sopenharmony_ci	hh->id = l2->ch.nr;
2948c2ecf20Sopenharmony_ci	if (*debug & DEBUG_TIMER)
2958c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n",
2968c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
2978c2ecf20Sopenharmony_ci		       l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
2988c2ecf20Sopenharmony_ci	if (l2->ch.st)
2998c2ecf20Sopenharmony_ci		l2->ch.st->own.recv(&l2->ch.st->own, skb);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int
3038c2ecf20Sopenharmony_cil2mgr(struct layer2 *l2, u_int prim, void *arg) {
3048c2ecf20Sopenharmony_ci	long c = (long)arg;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n",
3078c2ecf20Sopenharmony_ci	       mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c);
3088c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
3098c2ecf20Sopenharmony_ci	    !test_bit(FLG_FIXED_TEI, &l2->flag)) {
3108c2ecf20Sopenharmony_ci		switch (c) {
3118c2ecf20Sopenharmony_ci		case 'C':
3128c2ecf20Sopenharmony_ci		case 'D':
3138c2ecf20Sopenharmony_ci		case 'G':
3148c2ecf20Sopenharmony_ci		case 'H':
3158c2ecf20Sopenharmony_ci			l2_tei(l2, prim, (u_long)arg);
3168c2ecf20Sopenharmony_ci			break;
3178c2ecf20Sopenharmony_ci		}
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic void
3238c2ecf20Sopenharmony_ciset_peer_busy(struct layer2 *l2) {
3248c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
3258c2ecf20Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
3268c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_L2BLOCK, &l2->flag);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic void
3308c2ecf20Sopenharmony_ciclear_peer_busy(struct layer2 *l2) {
3318c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
3328c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void
3368c2ecf20Sopenharmony_ciInitWin(struct layer2 *l2)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	int i;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_WINDOW; i++)
3418c2ecf20Sopenharmony_ci		l2->windowar[i] = NULL;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int
3458c2ecf20Sopenharmony_cifreewin(struct layer2 *l2)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	int i, cnt = 0;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_WINDOW; i++) {
3508c2ecf20Sopenharmony_ci		if (l2->windowar[i]) {
3518c2ecf20Sopenharmony_ci			cnt++;
3528c2ecf20Sopenharmony_ci			dev_kfree_skb(l2->windowar[i]);
3538c2ecf20Sopenharmony_ci			l2->windowar[i] = NULL;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	return cnt;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic void
3608c2ecf20Sopenharmony_ciReleaseWin(struct layer2 *l2)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	int cnt = freewin(l2);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (cnt)
3658c2ecf20Sopenharmony_ci		printk(KERN_WARNING
3668c2ecf20Sopenharmony_ci		       "isdnl2 freed %d skbuffs in release\n", cnt);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ciinline unsigned int
3708c2ecf20Sopenharmony_cicansend(struct layer2 *l2)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	unsigned int p1;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag))
3758c2ecf20Sopenharmony_ci		p1 = (l2->vs - l2->va) % 128;
3768c2ecf20Sopenharmony_ci	else
3778c2ecf20Sopenharmony_ci		p1 = (l2->vs - l2->va) % 8;
3788c2ecf20Sopenharmony_ci	return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ciinline void
3828c2ecf20Sopenharmony_ciclear_exception(struct layer2 *l2)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
3858c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_REJEXC, &l2->flag);
3868c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
3878c2ecf20Sopenharmony_ci	clear_peer_busy(l2);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int
3918c2ecf20Sopenharmony_cisethdraddr(struct layer2 *l2, u_char *header, int rsp)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	u_char *ptr = header;
3948c2ecf20Sopenharmony_ci	int crbit = rsp;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag)) {
3978c2ecf20Sopenharmony_ci		if (test_bit(FLG_LAPD_NET, &l2->flag))
3988c2ecf20Sopenharmony_ci			crbit = !crbit;
3998c2ecf20Sopenharmony_ci		*ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0);
4008c2ecf20Sopenharmony_ci		*ptr++ = (l2->tei << 1) | 1;
4018c2ecf20Sopenharmony_ci		return 2;
4028c2ecf20Sopenharmony_ci	} else {
4038c2ecf20Sopenharmony_ci		if (test_bit(FLG_ORIG, &l2->flag))
4048c2ecf20Sopenharmony_ci			crbit = !crbit;
4058c2ecf20Sopenharmony_ci		if (crbit)
4068c2ecf20Sopenharmony_ci			*ptr++ = l2->addr.B;
4078c2ecf20Sopenharmony_ci		else
4088c2ecf20Sopenharmony_ci			*ptr++ = l2->addr.A;
4098c2ecf20Sopenharmony_ci		return 1;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic inline void
4148c2ecf20Sopenharmony_cienqueue_super(struct layer2 *l2, struct sk_buff *skb)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
4178c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic inline void
4218c2ecf20Sopenharmony_cienqueue_ui(struct layer2 *l2, struct sk_buff *skb)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	if (l2->tm)
4248c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UI_IND, 0);
4258c2ecf20Sopenharmony_ci	if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
4268c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ciinline int
4308c2ecf20Sopenharmony_ciIsUI(u_char *data)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	return (data[0] & 0xef) == UI;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ciinline int
4368c2ecf20Sopenharmony_ciIsUA(u_char *data)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	return (data[0] & 0xef) == UA;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ciinline int
4428c2ecf20Sopenharmony_ciIsDM(u_char *data)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	return (data[0] & 0xef) == DM;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ciinline int
4488c2ecf20Sopenharmony_ciIsDISC(u_char *data)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	return (data[0] & 0xef) == DISC;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ciinline int
4548c2ecf20Sopenharmony_ciIsRR(u_char *data, struct layer2 *l2)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag))
4578c2ecf20Sopenharmony_ci		return data[0] == RR;
4588c2ecf20Sopenharmony_ci	else
4598c2ecf20Sopenharmony_ci		return (data[0] & 0xf) == 1;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ciinline int
4638c2ecf20Sopenharmony_ciIsSFrame(u_char *data, struct layer2 *l2)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	register u_char d = *data;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	if (!test_bit(FLG_MOD128, &l2->flag))
4688c2ecf20Sopenharmony_ci		d &= 0xf;
4698c2ecf20Sopenharmony_ci	return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c);
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ciinline int
4738c2ecf20Sopenharmony_ciIsSABME(u_char *data, struct layer2 *l2)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	u_char d = data[0] & ~0x10;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ciinline int
4818c2ecf20Sopenharmony_ciIsREJ(u_char *data, struct layer2 *l2)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	return test_bit(FLG_MOD128, &l2->flag) ?
4848c2ecf20Sopenharmony_ci		data[0] == REJ : (data[0] & 0xf) == REJ;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ciinline int
4888c2ecf20Sopenharmony_ciIsFRMR(u_char *data)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	return (data[0] & 0xef) == FRMR;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ciinline int
4948c2ecf20Sopenharmony_ciIsRNR(u_char *data, struct layer2 *l2)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	return test_bit(FLG_MOD128, &l2->flag) ?
4978c2ecf20Sopenharmony_ci		data[0] == RNR : (data[0] & 0xf) == RNR;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic int
5018c2ecf20Sopenharmony_ciiframe_error(struct layer2 *l2, struct sk_buff *skb)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	u_int	i;
5048c2ecf20Sopenharmony_ci	int	rsp = *skb->data & 0x2;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1);
5078c2ecf20Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
5088c2ecf20Sopenharmony_ci		rsp = !rsp;
5098c2ecf20Sopenharmony_ci	if (rsp)
5108c2ecf20Sopenharmony_ci		return 'L';
5118c2ecf20Sopenharmony_ci	if (skb->len < i)
5128c2ecf20Sopenharmony_ci		return 'N';
5138c2ecf20Sopenharmony_ci	if ((skb->len - i) > l2->maxlen)
5148c2ecf20Sopenharmony_ci		return 'O';
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic int
5198c2ecf20Sopenharmony_cisuper_error(struct layer2 *l2, struct sk_buff *skb)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	if (skb->len != l2addrsize(l2) +
5228c2ecf20Sopenharmony_ci	    (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1))
5238c2ecf20Sopenharmony_ci		return 'N';
5248c2ecf20Sopenharmony_ci	return 0;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int
5288c2ecf20Sopenharmony_ciunnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	int rsp = (*skb->data & 0x2) >> 1;
5318c2ecf20Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
5328c2ecf20Sopenharmony_ci		rsp = !rsp;
5338c2ecf20Sopenharmony_ci	if (rsp != wantrsp)
5348c2ecf20Sopenharmony_ci		return 'L';
5358c2ecf20Sopenharmony_ci	if (skb->len != l2addrsize(l2) + 1)
5368c2ecf20Sopenharmony_ci		return 'N';
5378c2ecf20Sopenharmony_ci	return 0;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic int
5418c2ecf20Sopenharmony_ciUI_error(struct layer2 *l2, struct sk_buff *skb)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	int rsp = *skb->data & 0x2;
5448c2ecf20Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
5458c2ecf20Sopenharmony_ci		rsp = !rsp;
5468c2ecf20Sopenharmony_ci	if (rsp)
5478c2ecf20Sopenharmony_ci		return 'L';
5488c2ecf20Sopenharmony_ci	if (skb->len > l2->maxlen + l2addrsize(l2) + 1)
5498c2ecf20Sopenharmony_ci		return 'O';
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic int
5548c2ecf20Sopenharmony_ciFRMR_error(struct layer2 *l2, struct sk_buff *skb)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	u_int	headers = l2addrsize(l2) + 1;
5578c2ecf20Sopenharmony_ci	u_char	*datap = skb->data + headers;
5588c2ecf20Sopenharmony_ci	int	rsp = *skb->data & 0x2;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
5618c2ecf20Sopenharmony_ci		rsp = !rsp;
5628c2ecf20Sopenharmony_ci	if (!rsp)
5638c2ecf20Sopenharmony_ci		return 'L';
5648c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
5658c2ecf20Sopenharmony_ci		if (skb->len < headers + 5)
5668c2ecf20Sopenharmony_ci			return 'N';
5678c2ecf20Sopenharmony_ci		else if (*debug & DEBUG_L2)
5688c2ecf20Sopenharmony_ci			l2m_debug(&l2->l2m,
5698c2ecf20Sopenharmony_ci				  "FRMR information %2x %2x %2x %2x %2x",
5708c2ecf20Sopenharmony_ci				  datap[0], datap[1], datap[2], datap[3], datap[4]);
5718c2ecf20Sopenharmony_ci	} else {
5728c2ecf20Sopenharmony_ci		if (skb->len < headers + 3)
5738c2ecf20Sopenharmony_ci			return 'N';
5748c2ecf20Sopenharmony_ci		else if (*debug & DEBUG_L2)
5758c2ecf20Sopenharmony_ci			l2m_debug(&l2->l2m,
5768c2ecf20Sopenharmony_ci				  "FRMR information %2x %2x %2x",
5778c2ecf20Sopenharmony_ci				  datap[0], datap[1], datap[2]);
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci	return 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic unsigned int
5838c2ecf20Sopenharmony_cilegalnr(struct layer2 *l2, unsigned int nr)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag))
5868c2ecf20Sopenharmony_ci		return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
5878c2ecf20Sopenharmony_ci	else
5888c2ecf20Sopenharmony_ci		return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic void
5928c2ecf20Sopenharmony_cisetva(struct layer2 *l2, unsigned int nr)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct sk_buff	*skb;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	while (l2->va != nr) {
5978c2ecf20Sopenharmony_ci		l2->va++;
5988c2ecf20Sopenharmony_ci		if (test_bit(FLG_MOD128, &l2->flag))
5998c2ecf20Sopenharmony_ci			l2->va %= 128;
6008c2ecf20Sopenharmony_ci		else
6018c2ecf20Sopenharmony_ci			l2->va %= 8;
6028c2ecf20Sopenharmony_ci		if (l2->windowar[l2->sow]) {
6038c2ecf20Sopenharmony_ci			skb_trim(l2->windowar[l2->sow], 0);
6048c2ecf20Sopenharmony_ci			skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]);
6058c2ecf20Sopenharmony_ci			l2->windowar[l2->sow] = NULL;
6068c2ecf20Sopenharmony_ci		}
6078c2ecf20Sopenharmony_ci		l2->sow = (l2->sow + 1) % l2->window;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	skb = skb_dequeue(&l2->tmp_queue);
6108c2ecf20Sopenharmony_ci	while (skb) {
6118c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
6128c2ecf20Sopenharmony_ci		skb = skb_dequeue(&l2->tmp_queue);
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic void
6178c2ecf20Sopenharmony_cisend_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	u_char tmp[MAX_L2HEADER_LEN];
6208c2ecf20Sopenharmony_ci	int i;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	i = sethdraddr(l2, tmp, cr);
6238c2ecf20Sopenharmony_ci	tmp[i++] = cmd;
6248c2ecf20Sopenharmony_ci	if (skb)
6258c2ecf20Sopenharmony_ci		skb_trim(skb, 0);
6268c2ecf20Sopenharmony_ci	else {
6278c2ecf20Sopenharmony_ci		skb = mI_alloc_skb(i, GFP_ATOMIC);
6288c2ecf20Sopenharmony_ci		if (!skb) {
6298c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: can't alloc skbuff in %s\n",
6308c2ecf20Sopenharmony_ci			       mISDNDevName4ch(&l2->ch), __func__);
6318c2ecf20Sopenharmony_ci			return;
6328c2ecf20Sopenharmony_ci		}
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci	skb_put_data(skb, tmp, i);
6358c2ecf20Sopenharmony_ci	enqueue_super(l2, skb);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ciinline u_char
6408c2ecf20Sopenharmony_ciget_PollFlag(struct layer2 *l2, struct sk_buff *skb)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	return skb->data[l2addrsize(l2)] & 0x10;
6438c2ecf20Sopenharmony_ci}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ciinline u_char
6468c2ecf20Sopenharmony_ciget_PollFlagFree(struct layer2 *l2, struct sk_buff *skb)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	u_char PF;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	PF = get_PollFlag(l2, skb);
6518c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
6528c2ecf20Sopenharmony_ci	return PF;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ciinline void
6568c2ecf20Sopenharmony_cistart_t200(struct layer2 *l2, int i)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
6598c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_T200_RUN, &l2->flag);
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ciinline void
6638c2ecf20Sopenharmony_cirestart_t200(struct layer2 *l2, int i)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
6668c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_T200_RUN, &l2->flag);
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ciinline void
6708c2ecf20Sopenharmony_cistop_t200(struct layer2 *l2, int i)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_T200_RUN, &l2->flag))
6738c2ecf20Sopenharmony_ci		mISDN_FsmDelTimer(&l2->t200, i);
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ciinline void
6778c2ecf20Sopenharmony_cist5_dl_release_l2l3(struct layer2 *l2)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	int pr;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
6828c2ecf20Sopenharmony_ci		pr = DL_RELEASE_CNF;
6838c2ecf20Sopenharmony_ci	else
6848c2ecf20Sopenharmony_ci		pr = DL_RELEASE_IND;
6858c2ecf20Sopenharmony_ci	l2up_create(l2, pr, 0, NULL);
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ciinline void
6898c2ecf20Sopenharmony_cilapb_dl_release_l2l3(struct layer2 *l2, int f)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPB, &l2->flag))
6928c2ecf20Sopenharmony_ci		l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL);
6938c2ecf20Sopenharmony_ci	l2up_create(l2, f, 0, NULL);
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic void
6978c2ecf20Sopenharmony_ciestablishlink(struct FsmInst *fi)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
7008c2ecf20Sopenharmony_ci	u_char cmd;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	clear_exception(l2);
7038c2ecf20Sopenharmony_ci	l2->rc = 0;
7048c2ecf20Sopenharmony_ci	cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10;
7058c2ecf20Sopenharmony_ci	send_uframe(l2, NULL, cmd, CMD);
7068c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 1);
7078c2ecf20Sopenharmony_ci	restart_t200(l2, 1);
7088c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
7098c2ecf20Sopenharmony_ci	freewin(l2);
7108c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_5);
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic void
7148c2ecf20Sopenharmony_cil2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
7178c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	if (get_PollFlagFree(l2, skb))
7208c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'C');
7218c2ecf20Sopenharmony_ci	else
7228c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'D');
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic void
7278c2ecf20Sopenharmony_cil2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
7308c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	if (get_PollFlagFree(l2, skb))
7338c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
7348c2ecf20Sopenharmony_ci	else {
7358c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
7368c2ecf20Sopenharmony_ci		establishlink(fi);
7378c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistatic void
7428c2ecf20Sopenharmony_cil2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
7458c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	if (get_PollFlagFree(l2, skb))
7488c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
7498c2ecf20Sopenharmony_ci	else
7508c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
7518c2ecf20Sopenharmony_ci	establishlink(fi);
7528c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic void
7568c2ecf20Sopenharmony_cil2_go_st3(struct FsmInst *fi, int event, void *arg)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	dev_kfree_skb((struct sk_buff *)arg);
7598c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_3);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_cistatic void
7638c2ecf20Sopenharmony_cil2_mdl_assign(struct FsmInst *fi, int event, void *arg)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_3);
7688c2ecf20Sopenharmony_ci	dev_kfree_skb((struct sk_buff *)arg);
7698c2ecf20Sopenharmony_ci	l2_tei(l2, MDL_ASSIGN_IND, 0);
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic void
7738c2ecf20Sopenharmony_cil2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
7768c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	skb_queue_tail(&l2->ui_queue, skb);
7798c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_2);
7808c2ecf20Sopenharmony_ci	l2_tei(l2, MDL_ASSIGN_IND, 0);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic void
7848c2ecf20Sopenharmony_cil2_queue_ui(struct FsmInst *fi, int event, void *arg)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
7878c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	skb_queue_tail(&l2->ui_queue, skb);
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic void
7938c2ecf20Sopenharmony_citx_ui(struct layer2 *l2)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7968c2ecf20Sopenharmony_ci	u_char header[MAX_L2HEADER_LEN];
7978c2ecf20Sopenharmony_ci	int i;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	i = sethdraddr(l2, header, CMD);
8008c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD_NET, &l2->flag))
8018c2ecf20Sopenharmony_ci		header[1] = 0xff; /* tei 127 */
8028c2ecf20Sopenharmony_ci	header[i++] = UI;
8038c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&l2->ui_queue))) {
8048c2ecf20Sopenharmony_ci		memcpy(skb_push(skb, i), header, i);
8058c2ecf20Sopenharmony_ci		enqueue_ui(l2, skb);
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic void
8108c2ecf20Sopenharmony_cil2_send_ui(struct FsmInst *fi, int event, void *arg)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8138c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	skb_queue_tail(&l2->ui_queue, skb);
8168c2ecf20Sopenharmony_ci	tx_ui(l2);
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic void
8208c2ecf20Sopenharmony_cil2_got_ui(struct FsmInst *fi, int event, void *arg)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8238c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	skb_pull(skb, l2headersize(l2, 1));
8268c2ecf20Sopenharmony_ci/*
8278c2ecf20Sopenharmony_ci *		in states 1-3 for broadcast
8288c2ecf20Sopenharmony_ci */
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (l2->tm)
8318c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UI_IND, 0);
8328c2ecf20Sopenharmony_ci	l2up(l2, DL_UNITDATA_IND, skb);
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_cistatic void
8368c2ecf20Sopenharmony_cil2_establish(struct FsmInst *fi, int event, void *arg)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8398c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	establishlink(fi);
8428c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_L3_INIT, &l2->flag);
8438c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic void
8478c2ecf20Sopenharmony_cil2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8508c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
8538c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_L3_INIT, &l2->flag);
8548c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
8558c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic void
8598c2ecf20Sopenharmony_cil2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8628c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
8658c2ecf20Sopenharmony_ci	establishlink(fi);
8668c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_L3_INIT, &l2->flag);
8678c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_cistatic void
8718c2ecf20Sopenharmony_cil2_release(struct FsmInst *fi, int event, void *arg)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8748c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	skb_trim(skb, 0);
8778c2ecf20Sopenharmony_ci	l2up(l2, DL_RELEASE_CNF, skb);
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic void
8818c2ecf20Sopenharmony_cil2_pend_rel(struct FsmInst *fi, int event, void *arg)
8828c2ecf20Sopenharmony_ci{
8838c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8848c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_PEND_REL, &l2->flag);
8878c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic void
8918c2ecf20Sopenharmony_cil2_disconnect(struct FsmInst *fi, int event, void *arg)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
8948c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
8978c2ecf20Sopenharmony_ci	freewin(l2);
8988c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_6);
8998c2ecf20Sopenharmony_ci	l2->rc = 0;
9008c2ecf20Sopenharmony_ci	send_uframe(l2, NULL, DISC | 0x10, CMD);
9018c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 1);
9028c2ecf20Sopenharmony_ci	restart_t200(l2, 2);
9038c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic void
9078c2ecf20Sopenharmony_cil2_start_multi(struct FsmInst *fi, int event, void *arg)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
9108c2ecf20Sopenharmony_ci	struct sk_buff	*skb = arg;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	l2->vs = 0;
9138c2ecf20Sopenharmony_ci	l2->va = 0;
9148c2ecf20Sopenharmony_ci	l2->vr = 0;
9158c2ecf20Sopenharmony_ci	l2->sow = 0;
9168c2ecf20Sopenharmony_ci	clear_exception(l2);
9178c2ecf20Sopenharmony_ci	send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP);
9188c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_7);
9198c2ecf20Sopenharmony_ci	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
9208c2ecf20Sopenharmony_ci	skb_trim(skb, 0);
9218c2ecf20Sopenharmony_ci	l2up(l2, DL_ESTABLISH_IND, skb);
9228c2ecf20Sopenharmony_ci	if (l2->tm)
9238c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UP_IND, 0);
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_cistatic void
9278c2ecf20Sopenharmony_cil2_send_UA(struct FsmInst *fi, int event, void *arg)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
9308c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic void
9368c2ecf20Sopenharmony_cil2_send_DM(struct FsmInst *fi, int event, void *arg)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
9398c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP);
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cistatic void
9458c2ecf20Sopenharmony_cil2_restart_multi(struct FsmInst *fi, int event, void *arg)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
9488c2ecf20Sopenharmony_ci	struct sk_buff	*skb = arg;
9498c2ecf20Sopenharmony_ci	int		est = 0;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, (void *) 'F');
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (l2->vs != l2->va) {
9568c2ecf20Sopenharmony_ci		skb_queue_purge(&l2->i_queue);
9578c2ecf20Sopenharmony_ci		est = 1;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	clear_exception(l2);
9618c2ecf20Sopenharmony_ci	l2->vs = 0;
9628c2ecf20Sopenharmony_ci	l2->va = 0;
9638c2ecf20Sopenharmony_ci	l2->vr = 0;
9648c2ecf20Sopenharmony_ci	l2->sow = 0;
9658c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_7);
9668c2ecf20Sopenharmony_ci	stop_t200(l2, 3);
9678c2ecf20Sopenharmony_ci	mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	if (est)
9708c2ecf20Sopenharmony_ci		l2up_create(l2, DL_ESTABLISH_IND, 0, NULL);
9718c2ecf20Sopenharmony_ci/*		mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
9728c2ecf20Sopenharmony_ci *		    MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
9738c2ecf20Sopenharmony_ci *		    0, NULL, 0);
9748c2ecf20Sopenharmony_ci */
9758c2ecf20Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) && cansend(l2))
9768c2ecf20Sopenharmony_ci		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic void
9808c2ecf20Sopenharmony_cil2_stop_multi(struct FsmInst *fi, int event, void *arg)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
9838c2ecf20Sopenharmony_ci	struct sk_buff	*skb = arg;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
9868c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 3);
9878c2ecf20Sopenharmony_ci	stop_t200(l2, 4);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
9908c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
9918c2ecf20Sopenharmony_ci	freewin(l2);
9928c2ecf20Sopenharmony_ci	lapb_dl_release_l2l3(l2, DL_RELEASE_IND);
9938c2ecf20Sopenharmony_ci	if (l2->tm)
9948c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic void
9988c2ecf20Sopenharmony_cil2_connected(struct FsmInst *fi, int event, void *arg)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
10018c2ecf20Sopenharmony_ci	struct sk_buff	*skb = arg;
10028c2ecf20Sopenharmony_ci	int pr = -1;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	if (!get_PollFlag(l2, skb)) {
10058c2ecf20Sopenharmony_ci		l2_mdl_error_ua(fi, event, arg);
10068c2ecf20Sopenharmony_ci		return;
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
10098c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
10108c2ecf20Sopenharmony_ci		l2_disconnect(fi, event, NULL);
10118c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) {
10128c2ecf20Sopenharmony_ci		pr = DL_ESTABLISH_CNF;
10138c2ecf20Sopenharmony_ci	} else if (l2->vs != l2->va) {
10148c2ecf20Sopenharmony_ci		skb_queue_purge(&l2->i_queue);
10158c2ecf20Sopenharmony_ci		pr = DL_ESTABLISH_IND;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci	stop_t200(l2, 5);
10188c2ecf20Sopenharmony_ci	l2->vr = 0;
10198c2ecf20Sopenharmony_ci	l2->vs = 0;
10208c2ecf20Sopenharmony_ci	l2->va = 0;
10218c2ecf20Sopenharmony_ci	l2->sow = 0;
10228c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_7);
10238c2ecf20Sopenharmony_ci	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
10248c2ecf20Sopenharmony_ci	if (pr != -1)
10258c2ecf20Sopenharmony_ci		l2up_create(l2, pr, 0, NULL);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) && cansend(l2))
10288c2ecf20Sopenharmony_ci		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (l2->tm)
10318c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UP_IND, 0);
10328c2ecf20Sopenharmony_ci}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_cistatic void
10358c2ecf20Sopenharmony_cil2_released(struct FsmInst *fi, int event, void *arg)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
10388c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if (!get_PollFlag(l2, skb)) {
10418c2ecf20Sopenharmony_ci		l2_mdl_error_ua(fi, event, arg);
10428c2ecf20Sopenharmony_ci		return;
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
10458c2ecf20Sopenharmony_ci	stop_t200(l2, 6);
10468c2ecf20Sopenharmony_ci	lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
10478c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
10488c2ecf20Sopenharmony_ci	if (l2->tm)
10498c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_cistatic void
10538c2ecf20Sopenharmony_cil2_reestablish(struct FsmInst *fi, int event, void *arg)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
10568c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	if (!get_PollFlagFree(l2, skb)) {
10598c2ecf20Sopenharmony_ci		establishlink(fi);
10608c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_L3_INIT, &l2->flag);
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic void
10658c2ecf20Sopenharmony_cil2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
10688c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (get_PollFlagFree(l2, skb)) {
10718c2ecf20Sopenharmony_ci		stop_t200(l2, 7);
10728c2ecf20Sopenharmony_ci		if (!test_bit(FLG_L3_INIT, &l2->flag))
10738c2ecf20Sopenharmony_ci			skb_queue_purge(&l2->i_queue);
10748c2ecf20Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
10758c2ecf20Sopenharmony_ci			l2down_create(l2, PH_DEACTIVATE_REQ,
10768c2ecf20Sopenharmony_ci				      l2_newid(l2), 0, NULL);
10778c2ecf20Sopenharmony_ci		st5_dl_release_l2l3(l2);
10788c2ecf20Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
10798c2ecf20Sopenharmony_ci		if (l2->tm)
10808c2ecf20Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_cistatic void
10858c2ecf20Sopenharmony_cil2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
10888c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (get_PollFlagFree(l2, skb)) {
10918c2ecf20Sopenharmony_ci		stop_t200(l2, 8);
10928c2ecf20Sopenharmony_ci		lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
10938c2ecf20Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
10948c2ecf20Sopenharmony_ci		if (l2->tm)
10958c2ecf20Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic void
11008c2ecf20Sopenharmony_cienquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
11018c2ecf20Sopenharmony_ci{
11028c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11038c2ecf20Sopenharmony_ci	u_char tmp[MAX_L2HEADER_LEN];
11048c2ecf20Sopenharmony_ci	int i;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	i = sethdraddr(l2, tmp, cr);
11078c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
11088c2ecf20Sopenharmony_ci		tmp[i++] = typ;
11098c2ecf20Sopenharmony_ci		tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
11108c2ecf20Sopenharmony_ci	} else
11118c2ecf20Sopenharmony_ci		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
11128c2ecf20Sopenharmony_ci	skb = mI_alloc_skb(i, GFP_ATOMIC);
11138c2ecf20Sopenharmony_ci	if (!skb) {
11148c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n",
11158c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), __func__);
11168c2ecf20Sopenharmony_ci		return;
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci	skb_put_data(skb, tmp, i);
11198c2ecf20Sopenharmony_ci	enqueue_super(l2, skb);
11208c2ecf20Sopenharmony_ci}
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ciinline void
11238c2ecf20Sopenharmony_cienquiry_response(struct layer2 *l2)
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	if (test_bit(FLG_OWN_BUSY, &l2->flag))
11268c2ecf20Sopenharmony_ci		enquiry_cr(l2, RNR, RSP, 1);
11278c2ecf20Sopenharmony_ci	else
11288c2ecf20Sopenharmony_ci		enquiry_cr(l2, RR, RSP, 1);
11298c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ciinline void
11338c2ecf20Sopenharmony_citransmit_enquiry(struct layer2 *l2)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	if (test_bit(FLG_OWN_BUSY, &l2->flag))
11368c2ecf20Sopenharmony_ci		enquiry_cr(l2, RNR, CMD, 1);
11378c2ecf20Sopenharmony_ci	else
11388c2ecf20Sopenharmony_ci		enquiry_cr(l2, RR, CMD, 1);
11398c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
11408c2ecf20Sopenharmony_ci	start_t200(l2, 9);
11418c2ecf20Sopenharmony_ci}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_cistatic void
11458c2ecf20Sopenharmony_cinrerrorrecovery(struct FsmInst *fi)
11468c2ecf20Sopenharmony_ci{
11478c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, (void *) 'J');
11508c2ecf20Sopenharmony_ci	establishlink(fi);
11518c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_cistatic void
11558c2ecf20Sopenharmony_ciinvoke_retransmission(struct layer2 *l2, unsigned int nr)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	u_int	p1;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	if (l2->vs != nr) {
11608c2ecf20Sopenharmony_ci		while (l2->vs != nr) {
11618c2ecf20Sopenharmony_ci			(l2->vs)--;
11628c2ecf20Sopenharmony_ci			if (test_bit(FLG_MOD128, &l2->flag)) {
11638c2ecf20Sopenharmony_ci				l2->vs %= 128;
11648c2ecf20Sopenharmony_ci				p1 = (l2->vs - l2->va) % 128;
11658c2ecf20Sopenharmony_ci			} else {
11668c2ecf20Sopenharmony_ci				l2->vs %= 8;
11678c2ecf20Sopenharmony_ci				p1 = (l2->vs - l2->va) % 8;
11688c2ecf20Sopenharmony_ci			}
11698c2ecf20Sopenharmony_ci			p1 = (p1 + l2->sow) % l2->window;
11708c2ecf20Sopenharmony_ci			if (l2->windowar[p1])
11718c2ecf20Sopenharmony_ci				skb_queue_head(&l2->i_queue, l2->windowar[p1]);
11728c2ecf20Sopenharmony_ci			else
11738c2ecf20Sopenharmony_ci				printk(KERN_WARNING
11748c2ecf20Sopenharmony_ci				       "%s: windowar[%d] is NULL\n",
11758c2ecf20Sopenharmony_ci				       mISDNDevName4ch(&l2->ch), p1);
11768c2ecf20Sopenharmony_ci			l2->windowar[p1] = NULL;
11778c2ecf20Sopenharmony_ci		}
11788c2ecf20Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_cistatic void
11838c2ecf20Sopenharmony_cil2_st7_got_super(struct FsmInst *fi, int event, void *arg)
11848c2ecf20Sopenharmony_ci{
11858c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
11868c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
11878c2ecf20Sopenharmony_ci	int PollFlag, rsp, typ = RR;
11888c2ecf20Sopenharmony_ci	unsigned int nr;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	rsp = *skb->data & 0x2;
11918c2ecf20Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
11928c2ecf20Sopenharmony_ci		rsp = !rsp;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	skb_pull(skb, l2addrsize(l2));
11958c2ecf20Sopenharmony_ci	if (IsRNR(skb->data, l2)) {
11968c2ecf20Sopenharmony_ci		set_peer_busy(l2);
11978c2ecf20Sopenharmony_ci		typ = RNR;
11988c2ecf20Sopenharmony_ci	} else
11998c2ecf20Sopenharmony_ci		clear_peer_busy(l2);
12008c2ecf20Sopenharmony_ci	if (IsREJ(skb->data, l2))
12018c2ecf20Sopenharmony_ci		typ = REJ;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
12048c2ecf20Sopenharmony_ci		PollFlag = (skb->data[1] & 0x1) == 0x1;
12058c2ecf20Sopenharmony_ci		nr = skb->data[1] >> 1;
12068c2ecf20Sopenharmony_ci	} else {
12078c2ecf20Sopenharmony_ci		PollFlag = (skb->data[0] & 0x10);
12088c2ecf20Sopenharmony_ci		nr = (skb->data[0] >> 5) & 0x7;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	if (PollFlag) {
12138c2ecf20Sopenharmony_ci		if (rsp)
12148c2ecf20Sopenharmony_ci			l2mgr(l2, MDL_ERROR_IND, (void *) 'A');
12158c2ecf20Sopenharmony_ci		else
12168c2ecf20Sopenharmony_ci			enquiry_response(l2);
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci	if (legalnr(l2, nr)) {
12198c2ecf20Sopenharmony_ci		if (typ == REJ) {
12208c2ecf20Sopenharmony_ci			setva(l2, nr);
12218c2ecf20Sopenharmony_ci			invoke_retransmission(l2, nr);
12228c2ecf20Sopenharmony_ci			stop_t200(l2, 10);
12238c2ecf20Sopenharmony_ci			if (mISDN_FsmAddTimer(&l2->t203, l2->T203,
12248c2ecf20Sopenharmony_ci					      EV_L2_T203, NULL, 6))
12258c2ecf20Sopenharmony_ci				l2m_debug(&l2->l2m, "Restart T203 ST7 REJ");
12268c2ecf20Sopenharmony_ci		} else if ((nr == l2->vs) && (typ == RR)) {
12278c2ecf20Sopenharmony_ci			setva(l2, nr);
12288c2ecf20Sopenharmony_ci			stop_t200(l2, 11);
12298c2ecf20Sopenharmony_ci			mISDN_FsmRestartTimer(&l2->t203, l2->T203,
12308c2ecf20Sopenharmony_ci					      EV_L2_T203, NULL, 7);
12318c2ecf20Sopenharmony_ci		} else if ((l2->va != nr) || (typ == RNR)) {
12328c2ecf20Sopenharmony_ci			setva(l2, nr);
12338c2ecf20Sopenharmony_ci			if (typ != RR)
12348c2ecf20Sopenharmony_ci				mISDN_FsmDelTimer(&l2->t203, 9);
12358c2ecf20Sopenharmony_ci			restart_t200(l2, 12);
12368c2ecf20Sopenharmony_ci		}
12378c2ecf20Sopenharmony_ci		if (skb_queue_len(&l2->i_queue) && (typ == RR))
12388c2ecf20Sopenharmony_ci			mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
12398c2ecf20Sopenharmony_ci	} else
12408c2ecf20Sopenharmony_ci		nrerrorrecovery(fi);
12418c2ecf20Sopenharmony_ci}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_cistatic void
12448c2ecf20Sopenharmony_cil2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
12458c2ecf20Sopenharmony_ci{
12468c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
12478c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	if (!test_bit(FLG_L3_INIT, &l2->flag))
12508c2ecf20Sopenharmony_ci		skb_queue_tail(&l2->i_queue, skb);
12518c2ecf20Sopenharmony_ci	else
12528c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_cistatic void
12568c2ecf20Sopenharmony_cil2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
12578c2ecf20Sopenharmony_ci{
12588c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
12598c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	skb_queue_tail(&l2->i_queue, skb);
12628c2ecf20Sopenharmony_ci	mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_cistatic void
12668c2ecf20Sopenharmony_cil2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
12678c2ecf20Sopenharmony_ci{
12688c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
12698c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	skb_queue_tail(&l2->i_queue, skb);
12728c2ecf20Sopenharmony_ci}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_cistatic void
12758c2ecf20Sopenharmony_cil2_got_iframe(struct FsmInst *fi, int event, void *arg)
12768c2ecf20Sopenharmony_ci{
12778c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
12788c2ecf20Sopenharmony_ci	struct sk_buff	*skb = arg;
12798c2ecf20Sopenharmony_ci	int		PollFlag, i;
12808c2ecf20Sopenharmony_ci	u_int		ns, nr;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	i = l2addrsize(l2);
12838c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
12848c2ecf20Sopenharmony_ci		PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
12858c2ecf20Sopenharmony_ci		ns = skb->data[i] >> 1;
12868c2ecf20Sopenharmony_ci		nr = (skb->data[i + 1] >> 1) & 0x7f;
12878c2ecf20Sopenharmony_ci	} else {
12888c2ecf20Sopenharmony_ci		PollFlag = (skb->data[i] & 0x10);
12898c2ecf20Sopenharmony_ci		ns = (skb->data[i] >> 1) & 0x7;
12908c2ecf20Sopenharmony_ci		nr = (skb->data[i] >> 5) & 0x7;
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci	if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
12938c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
12948c2ecf20Sopenharmony_ci		if (PollFlag)
12958c2ecf20Sopenharmony_ci			enquiry_response(l2);
12968c2ecf20Sopenharmony_ci	} else {
12978c2ecf20Sopenharmony_ci		if (l2->vr == ns) {
12988c2ecf20Sopenharmony_ci			l2->vr++;
12998c2ecf20Sopenharmony_ci			if (test_bit(FLG_MOD128, &l2->flag))
13008c2ecf20Sopenharmony_ci				l2->vr %= 128;
13018c2ecf20Sopenharmony_ci			else
13028c2ecf20Sopenharmony_ci				l2->vr %= 8;
13038c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_REJEXC, &l2->flag);
13048c2ecf20Sopenharmony_ci			if (PollFlag)
13058c2ecf20Sopenharmony_ci				enquiry_response(l2);
13068c2ecf20Sopenharmony_ci			else
13078c2ecf20Sopenharmony_ci				test_and_set_bit(FLG_ACK_PEND, &l2->flag);
13088c2ecf20Sopenharmony_ci			skb_pull(skb, l2headersize(l2, 0));
13098c2ecf20Sopenharmony_ci			l2up(l2, DL_DATA_IND, skb);
13108c2ecf20Sopenharmony_ci		} else {
13118c2ecf20Sopenharmony_ci			/* n(s)!=v(r) */
13128c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
13138c2ecf20Sopenharmony_ci			if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
13148c2ecf20Sopenharmony_ci				if (PollFlag)
13158c2ecf20Sopenharmony_ci					enquiry_response(l2);
13168c2ecf20Sopenharmony_ci			} else {
13178c2ecf20Sopenharmony_ci				enquiry_cr(l2, REJ, RSP, PollFlag);
13188c2ecf20Sopenharmony_ci				test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
13198c2ecf20Sopenharmony_ci			}
13208c2ecf20Sopenharmony_ci		}
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci	if (legalnr(l2, nr)) {
13238c2ecf20Sopenharmony_ci		if (!test_bit(FLG_PEER_BUSY, &l2->flag) &&
13248c2ecf20Sopenharmony_ci		    (fi->state == ST_L2_7)) {
13258c2ecf20Sopenharmony_ci			if (nr == l2->vs) {
13268c2ecf20Sopenharmony_ci				stop_t200(l2, 13);
13278c2ecf20Sopenharmony_ci				mISDN_FsmRestartTimer(&l2->t203, l2->T203,
13288c2ecf20Sopenharmony_ci						      EV_L2_T203, NULL, 7);
13298c2ecf20Sopenharmony_ci			} else if (nr != l2->va)
13308c2ecf20Sopenharmony_ci				restart_t200(l2, 14);
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci		setva(l2, nr);
13338c2ecf20Sopenharmony_ci	} else {
13348c2ecf20Sopenharmony_ci		nrerrorrecovery(fi);
13358c2ecf20Sopenharmony_ci		return;
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7))
13388c2ecf20Sopenharmony_ci		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
13398c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag))
13408c2ecf20Sopenharmony_ci		enquiry_cr(l2, RR, RSP, 0);
13418c2ecf20Sopenharmony_ci}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_cistatic void
13448c2ecf20Sopenharmony_cil2_got_tei(struct FsmInst *fi, int event, void *arg)
13458c2ecf20Sopenharmony_ci{
13468c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
13478c2ecf20Sopenharmony_ci	u_int		info;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	l2->tei = (signed char)(long)arg;
13508c2ecf20Sopenharmony_ci	set_channel_address(&l2->ch, l2->sapi, l2->tei);
13518c2ecf20Sopenharmony_ci	info = DL_INFO_L2_CONNECT;
13528c2ecf20Sopenharmony_ci	l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info);
13538c2ecf20Sopenharmony_ci	if (fi->state == ST_L2_3) {
13548c2ecf20Sopenharmony_ci		establishlink(fi);
13558c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_L3_INIT, &l2->flag);
13568c2ecf20Sopenharmony_ci	} else
13578c2ecf20Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
13588c2ecf20Sopenharmony_ci	if (skb_queue_len(&l2->ui_queue))
13598c2ecf20Sopenharmony_ci		tx_ui(l2);
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_cistatic void
13638c2ecf20Sopenharmony_cil2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
13688c2ecf20Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
13698c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
13708c2ecf20Sopenharmony_ci	} else if (l2->rc == l2->N200) {
13718c2ecf20Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
13728c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
13738c2ecf20Sopenharmony_ci		skb_queue_purge(&l2->i_queue);
13748c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'G');
13758c2ecf20Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
13768c2ecf20Sopenharmony_ci			l2down_create(l2, PH_DEACTIVATE_REQ,
13778c2ecf20Sopenharmony_ci				      l2_newid(l2), 0, NULL);
13788c2ecf20Sopenharmony_ci		st5_dl_release_l2l3(l2);
13798c2ecf20Sopenharmony_ci		if (l2->tm)
13808c2ecf20Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
13818c2ecf20Sopenharmony_ci	} else {
13828c2ecf20Sopenharmony_ci		l2->rc++;
13838c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
13848c2ecf20Sopenharmony_ci		send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ?
13858c2ecf20Sopenharmony_ci				       SABME : SABM) | 0x10, CMD);
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistatic void
13908c2ecf20Sopenharmony_cil2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
13958c2ecf20Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
13968c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
13978c2ecf20Sopenharmony_ci	} else if (l2->rc == l2->N200) {
13988c2ecf20Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
13998c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
14008c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'H');
14018c2ecf20Sopenharmony_ci		lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
14028c2ecf20Sopenharmony_ci		if (l2->tm)
14038c2ecf20Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
14048c2ecf20Sopenharmony_ci	} else {
14058c2ecf20Sopenharmony_ci		l2->rc++;
14068c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200,
14078c2ecf20Sopenharmony_ci				  NULL, 9);
14088c2ecf20Sopenharmony_ci		send_uframe(l2, NULL, DISC | 0x10, CMD);
14098c2ecf20Sopenharmony_ci	}
14108c2ecf20Sopenharmony_ci}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_cistatic void
14138c2ecf20Sopenharmony_cil2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
14148c2ecf20Sopenharmony_ci{
14158c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
14188c2ecf20Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
14198c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
14208c2ecf20Sopenharmony_ci		return;
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
14238c2ecf20Sopenharmony_ci	l2->rc = 0;
14248c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_8);
14258c2ecf20Sopenharmony_ci	transmit_enquiry(l2);
14268c2ecf20Sopenharmony_ci	l2->rc++;
14278c2ecf20Sopenharmony_ci}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_cistatic void
14308c2ecf20Sopenharmony_cil2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
14358c2ecf20Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
14368c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
14378c2ecf20Sopenharmony_ci		return;
14388c2ecf20Sopenharmony_ci	}
14398c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
14408c2ecf20Sopenharmony_ci	if (l2->rc == l2->N200) {
14418c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'I');
14428c2ecf20Sopenharmony_ci		establishlink(fi);
14438c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
14448c2ecf20Sopenharmony_ci	} else {
14458c2ecf20Sopenharmony_ci		transmit_enquiry(l2);
14468c2ecf20Sopenharmony_ci		l2->rc++;
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic void
14518c2ecf20Sopenharmony_cil2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
14568c2ecf20Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
14578c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9);
14588c2ecf20Sopenharmony_ci		return;
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_8);
14618c2ecf20Sopenharmony_ci	transmit_enquiry(l2);
14628c2ecf20Sopenharmony_ci	l2->rc = 0;
14638c2ecf20Sopenharmony_ci}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_cistatic void
14668c2ecf20Sopenharmony_cil2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
14678c2ecf20Sopenharmony_ci{
14688c2ecf20Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
14698c2ecf20Sopenharmony_ci	struct sk_buff	*skb, *nskb;
14708c2ecf20Sopenharmony_ci	u_char		header[MAX_L2HEADER_LEN];
14718c2ecf20Sopenharmony_ci	u_int		i, p1;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (!cansend(l2))
14748c2ecf20Sopenharmony_ci		return;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	skb = skb_dequeue(&l2->i_queue);
14778c2ecf20Sopenharmony_ci	if (!skb)
14788c2ecf20Sopenharmony_ci		return;
14798c2ecf20Sopenharmony_ci	i = sethdraddr(l2, header, CMD);
14808c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
14818c2ecf20Sopenharmony_ci		header[i++] = l2->vs << 1;
14828c2ecf20Sopenharmony_ci		header[i++] = l2->vr << 1;
14838c2ecf20Sopenharmony_ci	} else
14848c2ecf20Sopenharmony_ci		header[i++] = (l2->vr << 5) | (l2->vs << 1);
14858c2ecf20Sopenharmony_ci	nskb = skb_realloc_headroom(skb, i);
14868c2ecf20Sopenharmony_ci	if (!nskb) {
14878c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
14888c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), i);
14898c2ecf20Sopenharmony_ci		skb_queue_head(&l2->i_queue, skb);
14908c2ecf20Sopenharmony_ci		return;
14918c2ecf20Sopenharmony_ci	}
14928c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
14938c2ecf20Sopenharmony_ci		p1 = (l2->vs - l2->va) % 128;
14948c2ecf20Sopenharmony_ci		l2->vs = (l2->vs + 1) % 128;
14958c2ecf20Sopenharmony_ci	} else {
14968c2ecf20Sopenharmony_ci		p1 = (l2->vs - l2->va) % 8;
14978c2ecf20Sopenharmony_ci		l2->vs = (l2->vs + 1) % 8;
14988c2ecf20Sopenharmony_ci	}
14998c2ecf20Sopenharmony_ci	p1 = (p1 + l2->sow) % l2->window;
15008c2ecf20Sopenharmony_ci	if (l2->windowar[p1]) {
15018c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
15028c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), p1);
15038c2ecf20Sopenharmony_ci		dev_kfree_skb(l2->windowar[p1]);
15048c2ecf20Sopenharmony_ci	}
15058c2ecf20Sopenharmony_ci	l2->windowar[p1] = skb;
15068c2ecf20Sopenharmony_ci	memcpy(skb_push(nskb, i), header, i);
15078c2ecf20Sopenharmony_ci	l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
15088c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
15098c2ecf20Sopenharmony_ci	if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {
15108c2ecf20Sopenharmony_ci		mISDN_FsmDelTimer(&l2->t203, 13);
15118c2ecf20Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11);
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_cistatic void
15168c2ecf20Sopenharmony_cil2_st8_got_super(struct FsmInst *fi, int event, void *arg)
15178c2ecf20Sopenharmony_ci{
15188c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
15198c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
15208c2ecf20Sopenharmony_ci	int PollFlag, rsp, rnr = 0;
15218c2ecf20Sopenharmony_ci	unsigned int nr;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	rsp = *skb->data & 0x2;
15248c2ecf20Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
15258c2ecf20Sopenharmony_ci		rsp = !rsp;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	skb_pull(skb, l2addrsize(l2));
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	if (IsRNR(skb->data, l2)) {
15308c2ecf20Sopenharmony_ci		set_peer_busy(l2);
15318c2ecf20Sopenharmony_ci		rnr = 1;
15328c2ecf20Sopenharmony_ci	} else
15338c2ecf20Sopenharmony_ci		clear_peer_busy(l2);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
15368c2ecf20Sopenharmony_ci		PollFlag = (skb->data[1] & 0x1) == 0x1;
15378c2ecf20Sopenharmony_ci		nr = skb->data[1] >> 1;
15388c2ecf20Sopenharmony_ci	} else {
15398c2ecf20Sopenharmony_ci		PollFlag = (skb->data[0] & 0x10);
15408c2ecf20Sopenharmony_ci		nr = (skb->data[0] >> 5) & 0x7;
15418c2ecf20Sopenharmony_ci	}
15428c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
15438c2ecf20Sopenharmony_ci	if (rsp && PollFlag) {
15448c2ecf20Sopenharmony_ci		if (legalnr(l2, nr)) {
15458c2ecf20Sopenharmony_ci			if (rnr) {
15468c2ecf20Sopenharmony_ci				restart_t200(l2, 15);
15478c2ecf20Sopenharmony_ci			} else {
15488c2ecf20Sopenharmony_ci				stop_t200(l2, 16);
15498c2ecf20Sopenharmony_ci				mISDN_FsmAddTimer(&l2->t203, l2->T203,
15508c2ecf20Sopenharmony_ci						  EV_L2_T203, NULL, 5);
15518c2ecf20Sopenharmony_ci				setva(l2, nr);
15528c2ecf20Sopenharmony_ci			}
15538c2ecf20Sopenharmony_ci			invoke_retransmission(l2, nr);
15548c2ecf20Sopenharmony_ci			mISDN_FsmChangeState(fi, ST_L2_7);
15558c2ecf20Sopenharmony_ci			if (skb_queue_len(&l2->i_queue) && cansend(l2))
15568c2ecf20Sopenharmony_ci				mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
15578c2ecf20Sopenharmony_ci		} else
15588c2ecf20Sopenharmony_ci			nrerrorrecovery(fi);
15598c2ecf20Sopenharmony_ci	} else {
15608c2ecf20Sopenharmony_ci		if (!rsp && PollFlag)
15618c2ecf20Sopenharmony_ci			enquiry_response(l2);
15628c2ecf20Sopenharmony_ci		if (legalnr(l2, nr))
15638c2ecf20Sopenharmony_ci			setva(l2, nr);
15648c2ecf20Sopenharmony_ci		else
15658c2ecf20Sopenharmony_ci			nrerrorrecovery(fi);
15668c2ecf20Sopenharmony_ci	}
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic void
15708c2ecf20Sopenharmony_cil2_got_FRMR(struct FsmInst *fi, int event, void *arg)
15718c2ecf20Sopenharmony_ci{
15728c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
15738c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	skb_pull(skb, l2addrsize(l2) + 1);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
15788c2ecf20Sopenharmony_ci	    (IsUA(skb->data) && (fi->state == ST_L2_7))) {
15798c2ecf20Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'K');
15808c2ecf20Sopenharmony_ci		establishlink(fi);
15818c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
15828c2ecf20Sopenharmony_ci	}
15838c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
15848c2ecf20Sopenharmony_ci}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic void
15878c2ecf20Sopenharmony_cil2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
15928c2ecf20Sopenharmony_ci	l2->tei = GROUP_TEI;
15938c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
15948c2ecf20Sopenharmony_ci}
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_cistatic void
15978c2ecf20Sopenharmony_cil2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
15988c2ecf20Sopenharmony_ci{
15998c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16028c2ecf20Sopenharmony_ci	l2->tei = GROUP_TEI;
16038c2ecf20Sopenharmony_ci	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
16048c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_cistatic void
16088c2ecf20Sopenharmony_cil2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
16098c2ecf20Sopenharmony_ci{
16108c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
16138c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16148c2ecf20Sopenharmony_ci	freewin(l2);
16158c2ecf20Sopenharmony_ci	l2->tei = GROUP_TEI;
16168c2ecf20Sopenharmony_ci	stop_t200(l2, 17);
16178c2ecf20Sopenharmony_ci	st5_dl_release_l2l3(l2);
16188c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_cistatic void
16228c2ecf20Sopenharmony_cil2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
16238c2ecf20Sopenharmony_ci{
16248c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16278c2ecf20Sopenharmony_ci	l2->tei = GROUP_TEI;
16288c2ecf20Sopenharmony_ci	stop_t200(l2, 18);
16298c2ecf20Sopenharmony_ci	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
16308c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
16318c2ecf20Sopenharmony_ci}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_cistatic void
16348c2ecf20Sopenharmony_cil2_tei_remove(struct FsmInst *fi, int event, void *arg)
16358c2ecf20Sopenharmony_ci{
16368c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
16398c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16408c2ecf20Sopenharmony_ci	freewin(l2);
16418c2ecf20Sopenharmony_ci	l2->tei = GROUP_TEI;
16428c2ecf20Sopenharmony_ci	stop_t200(l2, 17);
16438c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 19);
16448c2ecf20Sopenharmony_ci	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
16458c2ecf20Sopenharmony_ci/*	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
16468c2ecf20Sopenharmony_ci *		MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED,
16478c2ecf20Sopenharmony_ci *		0, NULL, 0);
16488c2ecf20Sopenharmony_ci */
16498c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
16508c2ecf20Sopenharmony_ci}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_cistatic void
16538c2ecf20Sopenharmony_cil2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16568c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
16598c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16608c2ecf20Sopenharmony_ci	if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
16618c2ecf20Sopenharmony_ci		l2up(l2, DL_RELEASE_IND, skb);
16628c2ecf20Sopenharmony_ci	else
16638c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_cistatic void
16678c2ecf20Sopenharmony_cil2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16708c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
16738c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16748c2ecf20Sopenharmony_ci	freewin(l2);
16758c2ecf20Sopenharmony_ci	stop_t200(l2, 19);
16768c2ecf20Sopenharmony_ci	st5_dl_release_l2l3(l2);
16778c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
16788c2ecf20Sopenharmony_ci	if (l2->tm)
16798c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
16808c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cistatic void
16848c2ecf20Sopenharmony_cil2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
16858c2ecf20Sopenharmony_ci{
16868c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
16878c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
16908c2ecf20Sopenharmony_ci	stop_t200(l2, 20);
16918c2ecf20Sopenharmony_ci	l2up(l2, DL_RELEASE_CNF, skb);
16928c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
16938c2ecf20Sopenharmony_ci	if (l2->tm)
16948c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_cistatic void
16988c2ecf20Sopenharmony_cil2_persistent_da(struct FsmInst *fi, int event, void *arg)
16998c2ecf20Sopenharmony_ci{
17008c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
17018c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
17048c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
17058c2ecf20Sopenharmony_ci	freewin(l2);
17068c2ecf20Sopenharmony_ci	stop_t200(l2, 19);
17078c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 19);
17088c2ecf20Sopenharmony_ci	l2up(l2, DL_RELEASE_IND, skb);
17098c2ecf20Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
17108c2ecf20Sopenharmony_ci	if (l2->tm)
17118c2ecf20Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
17128c2ecf20Sopenharmony_ci}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_cistatic void
17158c2ecf20Sopenharmony_cil2_set_own_busy(struct FsmInst *fi, int event, void *arg)
17168c2ecf20Sopenharmony_ci{
17178c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
17188c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) {
17218c2ecf20Sopenharmony_ci		enquiry_cr(l2, RNR, RSP, 0);
17228c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
17238c2ecf20Sopenharmony_ci	}
17248c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
17258c2ecf20Sopenharmony_ci}
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic void
17288c2ecf20Sopenharmony_cil2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
17318c2ecf20Sopenharmony_ci	struct sk_buff *skb = arg;
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) {
17348c2ecf20Sopenharmony_ci		enquiry_cr(l2, RR, RSP, 0);
17358c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
17368c2ecf20Sopenharmony_ci	}
17378c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
17388c2ecf20Sopenharmony_ci}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_cistatic void
17418c2ecf20Sopenharmony_cil2_frame_error(struct FsmInst *fi, int event, void *arg)
17428c2ecf20Sopenharmony_ci{
17438c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, arg);
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_cistatic void
17498c2ecf20Sopenharmony_cil2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
17508c2ecf20Sopenharmony_ci{
17518c2ecf20Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, arg);
17548c2ecf20Sopenharmony_ci	establishlink(fi);
17558c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
17568c2ecf20Sopenharmony_ci}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_cistatic struct FsmNode L2FnList[] =
17598c2ecf20Sopenharmony_ci{
17608c2ecf20Sopenharmony_ci	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
17618c2ecf20Sopenharmony_ci	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
17628c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
17638c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
17648c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
17658c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
17668c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
17678c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
17688c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
17698c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
17708c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
17718c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
17728c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
17738c2ecf20Sopenharmony_ci	{ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign},
17748c2ecf20Sopenharmony_ci	{ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui},
17758c2ecf20Sopenharmony_ci	{ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui},
17768c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui},
17778c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui},
17788c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui},
17798c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui},
17808c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui},
17818c2ecf20Sopenharmony_ci	{ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
17828c2ecf20Sopenharmony_ci	{ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
17838c2ecf20Sopenharmony_ci	{ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
17848c2ecf20Sopenharmony_ci	{ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
17858c2ecf20Sopenharmony_ci	{ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
17868c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
17878c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
17888c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
17898c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
17908c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
17918c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_SABME, l2_start_multi},
17928c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_SABME, l2_send_UA},
17938c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_SABME, l2_send_DM},
17948c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_SABME, l2_restart_multi},
17958c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_SABME, l2_restart_multi},
17968c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_DISC, l2_send_DM},
17978c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_DISC, l2_send_DM},
17988c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_DISC, l2_send_UA},
17998c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_DISC, l2_stop_multi},
18008c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_DISC, l2_stop_multi},
18018c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
18028c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_UA, l2_connected},
18038c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_UA, l2_released},
18048c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
18058c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
18068c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_DM, l2_reestablish},
18078c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_DM, l2_st5_dm_release},
18088c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_DM, l2_st6_dm_release},
18098c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
18108c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
18118c2ecf20Sopenharmony_ci	{ST_L2_1, EV_L2_UI, l2_got_ui},
18128c2ecf20Sopenharmony_ci	{ST_L2_2, EV_L2_UI, l2_got_ui},
18138c2ecf20Sopenharmony_ci	{ST_L2_3, EV_L2_UI, l2_got_ui},
18148c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_UI, l2_got_ui},
18158c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_UI, l2_got_ui},
18168c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_UI, l2_got_ui},
18178c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_UI, l2_got_ui},
18188c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_UI, l2_got_ui},
18198c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
18208c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
18218c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
18228c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
18238c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_I, l2_got_iframe},
18248c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_I, l2_got_iframe},
18258c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_T200, l2_timeout},
18268c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_T200, l2_timeout},
18278c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_T200, l2_timeout},
18288c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_T200, l2_timeout},
18298c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_T203, l2_timeout},
18308c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_T200I, l2_st5_tout_200},
18318c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_T200I, l2_st6_tout_200},
18328c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_T200I, l2_st7_tout_200},
18338c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_T200I, l2_st8_tout_200},
18348c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_T203I, l2_st7_tout_203},
18358c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
18368c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
18378c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
18388c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
18398c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
18408c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
18418c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
18428c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
18438c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
18448c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
18458c2ecf20Sopenharmony_ci	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
18468c2ecf20Sopenharmony_ci	{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
18478c2ecf20Sopenharmony_ci	{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
18488c2ecf20Sopenharmony_ci	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
18498c2ecf20Sopenharmony_ci	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
18508c2ecf20Sopenharmony_ci	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
18518c2ecf20Sopenharmony_ci	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
18528c2ecf20Sopenharmony_ci	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
18538c2ecf20Sopenharmony_ci};
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_cistatic int
18568c2ecf20Sopenharmony_ciph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
18578c2ecf20Sopenharmony_ci{
18588c2ecf20Sopenharmony_ci	u_char	*datap = skb->data;
18598c2ecf20Sopenharmony_ci	int	ret = -EINVAL;
18608c2ecf20Sopenharmony_ci	int	psapi, ptei;
18618c2ecf20Sopenharmony_ci	u_int	l;
18628c2ecf20Sopenharmony_ci	int	c = 0;
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	l = l2addrsize(l2);
18658c2ecf20Sopenharmony_ci	if (skb->len <= l) {
18668c2ecf20Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N');
18678c2ecf20Sopenharmony_ci		return ret;
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */
18708c2ecf20Sopenharmony_ci		psapi = *datap++;
18718c2ecf20Sopenharmony_ci		ptei = *datap++;
18728c2ecf20Sopenharmony_ci		if ((psapi & 1) || !(ptei & 1)) {
18738c2ecf20Sopenharmony_ci			printk(KERN_WARNING
18748c2ecf20Sopenharmony_ci			       "%s l2 D-channel frame wrong EA0/EA1\n",
18758c2ecf20Sopenharmony_ci			       mISDNDevName4ch(&l2->ch));
18768c2ecf20Sopenharmony_ci			return ret;
18778c2ecf20Sopenharmony_ci		}
18788c2ecf20Sopenharmony_ci		psapi >>= 2;
18798c2ecf20Sopenharmony_ci		ptei >>= 1;
18808c2ecf20Sopenharmony_ci		if (psapi != l2->sapi) {
18818c2ecf20Sopenharmony_ci			/* not our business */
18828c2ecf20Sopenharmony_ci			if (*debug & DEBUG_L2)
18838c2ecf20Sopenharmony_ci				printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
18848c2ecf20Sopenharmony_ci				       mISDNDevName4ch(&l2->ch), psapi,
18858c2ecf20Sopenharmony_ci				       l2->sapi);
18868c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
18878c2ecf20Sopenharmony_ci			return 0;
18888c2ecf20Sopenharmony_ci		}
18898c2ecf20Sopenharmony_ci		if ((ptei != l2->tei) && (ptei != GROUP_TEI)) {
18908c2ecf20Sopenharmony_ci			/* not our business */
18918c2ecf20Sopenharmony_ci			if (*debug & DEBUG_L2)
18928c2ecf20Sopenharmony_ci				printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
18938c2ecf20Sopenharmony_ci				       mISDNDevName4ch(&l2->ch), ptei, l2->tei);
18948c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
18958c2ecf20Sopenharmony_ci			return 0;
18968c2ecf20Sopenharmony_ci		}
18978c2ecf20Sopenharmony_ci	} else
18988c2ecf20Sopenharmony_ci		datap += l;
18998c2ecf20Sopenharmony_ci	if (!(*datap & 1)) {	/* I-Frame */
19008c2ecf20Sopenharmony_ci		c = iframe_error(l2, skb);
19018c2ecf20Sopenharmony_ci		if (!c)
19028c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb);
19038c2ecf20Sopenharmony_ci	} else if (IsSFrame(datap, l2)) {	/* S-Frame */
19048c2ecf20Sopenharmony_ci		c = super_error(l2, skb);
19058c2ecf20Sopenharmony_ci		if (!c)
19068c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb);
19078c2ecf20Sopenharmony_ci	} else if (IsUI(datap)) {
19088c2ecf20Sopenharmony_ci		c = UI_error(l2, skb);
19098c2ecf20Sopenharmony_ci		if (!c)
19108c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb);
19118c2ecf20Sopenharmony_ci	} else if (IsSABME(datap, l2)) {
19128c2ecf20Sopenharmony_ci		c = unnum_error(l2, skb, CMD);
19138c2ecf20Sopenharmony_ci		if (!c)
19148c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb);
19158c2ecf20Sopenharmony_ci	} else if (IsUA(datap)) {
19168c2ecf20Sopenharmony_ci		c = unnum_error(l2, skb, RSP);
19178c2ecf20Sopenharmony_ci		if (!c)
19188c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb);
19198c2ecf20Sopenharmony_ci	} else if (IsDISC(datap)) {
19208c2ecf20Sopenharmony_ci		c = unnum_error(l2, skb, CMD);
19218c2ecf20Sopenharmony_ci		if (!c)
19228c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb);
19238c2ecf20Sopenharmony_ci	} else if (IsDM(datap)) {
19248c2ecf20Sopenharmony_ci		c = unnum_error(l2, skb, RSP);
19258c2ecf20Sopenharmony_ci		if (!c)
19268c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb);
19278c2ecf20Sopenharmony_ci	} else if (IsFRMR(datap)) {
19288c2ecf20Sopenharmony_ci		c = FRMR_error(l2, skb);
19298c2ecf20Sopenharmony_ci		if (!c)
19308c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb);
19318c2ecf20Sopenharmony_ci	} else
19328c2ecf20Sopenharmony_ci		c = 'L';
19338c2ecf20Sopenharmony_ci	if (c) {
19348c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s:l2 D-channel frame error %c\n",
19358c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), c);
19368c2ecf20Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
19378c2ecf20Sopenharmony_ci	}
19388c2ecf20Sopenharmony_ci	return ret;
19398c2ecf20Sopenharmony_ci}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_cistatic int
19428c2ecf20Sopenharmony_cil2_send(struct mISDNchannel *ch, struct sk_buff *skb)
19438c2ecf20Sopenharmony_ci{
19448c2ecf20Sopenharmony_ci	struct layer2		*l2 = container_of(ch, struct layer2, ch);
19458c2ecf20Sopenharmony_ci	struct mISDNhead	*hh =  mISDN_HEAD_P(skb);
19468c2ecf20Sopenharmony_ci	int			ret = -EINVAL;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (*debug & DEBUG_L2_RECV)
19498c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n",
19508c2ecf20Sopenharmony_ci		       __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id,
19518c2ecf20Sopenharmony_ci		       l2->sapi, l2->tei);
19528c2ecf20Sopenharmony_ci	if (hh->prim == DL_INTERN_MSG) {
19538c2ecf20Sopenharmony_ci		struct mISDNhead *chh = hh + 1; /* saved copy */
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci		*hh = *chh;
19568c2ecf20Sopenharmony_ci		if (*debug & DEBUG_L2_RECV)
19578c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
19588c2ecf20Sopenharmony_ci				mISDNDevName4ch(&l2->ch), hh->prim, hh->id);
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci	switch (hh->prim) {
19618c2ecf20Sopenharmony_ci	case PH_DATA_IND:
19628c2ecf20Sopenharmony_ci		ret = ph_data_indication(l2, hh, skb);
19638c2ecf20Sopenharmony_ci		break;
19648c2ecf20Sopenharmony_ci	case PH_DATA_CNF:
19658c2ecf20Sopenharmony_ci		ret = ph_data_confirm(l2, hh, skb);
19668c2ecf20Sopenharmony_ci		break;
19678c2ecf20Sopenharmony_ci	case PH_ACTIVATE_IND:
19688c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_L1_ACTIV, &l2->flag);
19698c2ecf20Sopenharmony_ci		l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL);
19708c2ecf20Sopenharmony_ci		if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
19718c2ecf20Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m,
19728c2ecf20Sopenharmony_ci					     EV_L2_DL_ESTABLISH_REQ, skb);
19738c2ecf20Sopenharmony_ci		break;
19748c2ecf20Sopenharmony_ci	case PH_DEACTIVATE_IND:
19758c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L1_ACTIV, &l2->flag);
19768c2ecf20Sopenharmony_ci		l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL);
19778c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb);
19788c2ecf20Sopenharmony_ci		break;
19798c2ecf20Sopenharmony_ci	case MPH_INFORMATION_IND:
19808c2ecf20Sopenharmony_ci		if (!l2->up)
19818c2ecf20Sopenharmony_ci			break;
19828c2ecf20Sopenharmony_ci		ret = l2->up->send(l2->up, skb);
19838c2ecf20Sopenharmony_ci		break;
19848c2ecf20Sopenharmony_ci	case DL_DATA_REQ:
19858c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb);
19868c2ecf20Sopenharmony_ci		break;
19878c2ecf20Sopenharmony_ci	case DL_UNITDATA_REQ:
19888c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb);
19898c2ecf20Sopenharmony_ci		break;
19908c2ecf20Sopenharmony_ci	case DL_ESTABLISH_REQ:
19918c2ecf20Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
19928c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_ORIG, &l2->flag);
19938c2ecf20Sopenharmony_ci		if (test_bit(FLG_L1_ACTIV, &l2->flag)) {
19948c2ecf20Sopenharmony_ci			if (test_bit(FLG_LAPD, &l2->flag) ||
19958c2ecf20Sopenharmony_ci			    test_bit(FLG_ORIG, &l2->flag))
19968c2ecf20Sopenharmony_ci				ret = mISDN_FsmEvent(&l2->l2m,
19978c2ecf20Sopenharmony_ci						     EV_L2_DL_ESTABLISH_REQ, skb);
19988c2ecf20Sopenharmony_ci		} else {
19998c2ecf20Sopenharmony_ci			if (test_bit(FLG_LAPD, &l2->flag) ||
20008c2ecf20Sopenharmony_ci			    test_bit(FLG_ORIG, &l2->flag)) {
20018c2ecf20Sopenharmony_ci				test_and_set_bit(FLG_ESTAB_PEND,
20028c2ecf20Sopenharmony_ci						 &l2->flag);
20038c2ecf20Sopenharmony_ci			}
20048c2ecf20Sopenharmony_ci			ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2),
20058c2ecf20Sopenharmony_ci				     skb);
20068c2ecf20Sopenharmony_ci		}
20078c2ecf20Sopenharmony_ci		break;
20088c2ecf20Sopenharmony_ci	case DL_RELEASE_REQ:
20098c2ecf20Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
20108c2ecf20Sopenharmony_ci			l2down_create(l2, PH_DEACTIVATE_REQ,
20118c2ecf20Sopenharmony_ci				      l2_newid(l2), 0, NULL);
20128c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ,
20138c2ecf20Sopenharmony_ci				     skb);
20148c2ecf20Sopenharmony_ci		break;
20158c2ecf20Sopenharmony_ci	case DL_TIMER200_IND:
20168c2ecf20Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL);
20178c2ecf20Sopenharmony_ci		break;
20188c2ecf20Sopenharmony_ci	case DL_TIMER203_IND:
20198c2ecf20Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL);
20208c2ecf20Sopenharmony_ci		break;
20218c2ecf20Sopenharmony_ci	default:
20228c2ecf20Sopenharmony_ci		if (*debug & DEBUG_L2)
20238c2ecf20Sopenharmony_ci			l2m_debug(&l2->l2m, "l2 unknown pr %04x",
20248c2ecf20Sopenharmony_ci				  hh->prim);
20258c2ecf20Sopenharmony_ci	}
20268c2ecf20Sopenharmony_ci	if (ret) {
20278c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
20288c2ecf20Sopenharmony_ci		ret = 0;
20298c2ecf20Sopenharmony_ci	}
20308c2ecf20Sopenharmony_ci	return ret;
20318c2ecf20Sopenharmony_ci}
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ciint
20348c2ecf20Sopenharmony_citei_l2(struct layer2 *l2, u_int cmd, u_long arg)
20358c2ecf20Sopenharmony_ci{
20368c2ecf20Sopenharmony_ci	int		ret = -EINVAL;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	if (*debug & DEBUG_L2_TEI)
20398c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd(%x) in %s\n",
20408c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), cmd, __func__);
20418c2ecf20Sopenharmony_ci	switch (cmd) {
20428c2ecf20Sopenharmony_ci	case (MDL_ASSIGN_REQ):
20438c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg);
20448c2ecf20Sopenharmony_ci		break;
20458c2ecf20Sopenharmony_ci	case (MDL_REMOVE_REQ):
20468c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL);
20478c2ecf20Sopenharmony_ci		break;
20488c2ecf20Sopenharmony_ci	case (MDL_ERROR_IND):
20498c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
20508c2ecf20Sopenharmony_ci		break;
20518c2ecf20Sopenharmony_ci	case (MDL_ERROR_RSP):
20528c2ecf20Sopenharmony_ci		/* ETS 300-125 5.3.2.1 Test: TC13010 */
20538c2ecf20Sopenharmony_ci		printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n",
20548c2ecf20Sopenharmony_ci		       mISDNDevName4ch(&l2->ch));
20558c2ecf20Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
20568c2ecf20Sopenharmony_ci		break;
20578c2ecf20Sopenharmony_ci	}
20588c2ecf20Sopenharmony_ci	return ret;
20598c2ecf20Sopenharmony_ci}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_cistatic void
20628c2ecf20Sopenharmony_cirelease_l2(struct layer2 *l2)
20638c2ecf20Sopenharmony_ci{
20648c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t200, 21);
20658c2ecf20Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 16);
20668c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
20678c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
20688c2ecf20Sopenharmony_ci	skb_queue_purge(&l2->down_queue);
20698c2ecf20Sopenharmony_ci	ReleaseWin(l2);
20708c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag)) {
20718c2ecf20Sopenharmony_ci		TEIrelease(l2);
20728c2ecf20Sopenharmony_ci		if (l2->ch.st)
20738c2ecf20Sopenharmony_ci			l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
20748c2ecf20Sopenharmony_ci					       CLOSE_CHANNEL, NULL);
20758c2ecf20Sopenharmony_ci	}
20768c2ecf20Sopenharmony_ci	kfree(l2);
20778c2ecf20Sopenharmony_ci}
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_cistatic int
20808c2ecf20Sopenharmony_cil2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
20818c2ecf20Sopenharmony_ci{
20828c2ecf20Sopenharmony_ci	struct layer2		*l2 = container_of(ch, struct layer2, ch);
20838c2ecf20Sopenharmony_ci	u_int			info;
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	if (*debug & DEBUG_L2_CTRL)
20868c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: %s cmd(%x)\n",
20878c2ecf20Sopenharmony_ci		       mISDNDevName4ch(ch), __func__, cmd);
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	switch (cmd) {
20908c2ecf20Sopenharmony_ci	case OPEN_CHANNEL:
20918c2ecf20Sopenharmony_ci		if (test_bit(FLG_LAPD, &l2->flag)) {
20928c2ecf20Sopenharmony_ci			set_channel_address(&l2->ch, l2->sapi, l2->tei);
20938c2ecf20Sopenharmony_ci			info = DL_INFO_L2_CONNECT;
20948c2ecf20Sopenharmony_ci			l2up_create(l2, DL_INFORMATION_IND,
20958c2ecf20Sopenharmony_ci				    sizeof(info), &info);
20968c2ecf20Sopenharmony_ci		}
20978c2ecf20Sopenharmony_ci		break;
20988c2ecf20Sopenharmony_ci	case CLOSE_CHANNEL:
20998c2ecf20Sopenharmony_ci		if (l2->ch.peer)
21008c2ecf20Sopenharmony_ci			l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL);
21018c2ecf20Sopenharmony_ci		release_l2(l2);
21028c2ecf20Sopenharmony_ci		break;
21038c2ecf20Sopenharmony_ci	}
21048c2ecf20Sopenharmony_ci	return 0;
21058c2ecf20Sopenharmony_ci}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_cistruct layer2 *
21088c2ecf20Sopenharmony_cicreate_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
21098c2ecf20Sopenharmony_ci	  int sapi)
21108c2ecf20Sopenharmony_ci{
21118c2ecf20Sopenharmony_ci	struct layer2		*l2;
21128c2ecf20Sopenharmony_ci	struct channel_req	rq;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL);
21158c2ecf20Sopenharmony_ci	if (!l2) {
21168c2ecf20Sopenharmony_ci		printk(KERN_ERR "kzalloc layer2 failed\n");
21178c2ecf20Sopenharmony_ci		return NULL;
21188c2ecf20Sopenharmony_ci	}
21198c2ecf20Sopenharmony_ci	l2->next_id = 1;
21208c2ecf20Sopenharmony_ci	l2->down_id = MISDN_ID_NONE;
21218c2ecf20Sopenharmony_ci	l2->up = ch;
21228c2ecf20Sopenharmony_ci	l2->ch.st = ch->st;
21238c2ecf20Sopenharmony_ci	l2->ch.send = l2_send;
21248c2ecf20Sopenharmony_ci	l2->ch.ctrl = l2_ctrl;
21258c2ecf20Sopenharmony_ci	switch (protocol) {
21268c2ecf20Sopenharmony_ci	case ISDN_P_LAPD_NT:
21278c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_LAPD, &l2->flag);
21288c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_LAPD_NET, &l2->flag);
21298c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_MOD128, &l2->flag);
21308c2ecf20Sopenharmony_ci		l2->sapi = sapi;
21318c2ecf20Sopenharmony_ci		l2->maxlen = MAX_DFRAME_LEN;
21328c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
21338c2ecf20Sopenharmony_ci			l2->window = 7;
21348c2ecf20Sopenharmony_ci		else
21358c2ecf20Sopenharmony_ci			l2->window = 1;
21368c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_PTP, &options))
21378c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_PTP, &l2->flag);
21388c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_FIXEDTEI, &options))
21398c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
21408c2ecf20Sopenharmony_ci		l2->tei = tei;
21418c2ecf20Sopenharmony_ci		l2->T200 = 1000;
21428c2ecf20Sopenharmony_ci		l2->N200 = 3;
21438c2ecf20Sopenharmony_ci		l2->T203 = 10000;
21448c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
21458c2ecf20Sopenharmony_ci			rq.protocol = ISDN_P_NT_E1;
21468c2ecf20Sopenharmony_ci		else
21478c2ecf20Sopenharmony_ci			rq.protocol = ISDN_P_NT_S0;
21488c2ecf20Sopenharmony_ci		rq.adr.channel = 0;
21498c2ecf20Sopenharmony_ci		l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
21508c2ecf20Sopenharmony_ci		break;
21518c2ecf20Sopenharmony_ci	case ISDN_P_LAPD_TE:
21528c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_LAPD, &l2->flag);
21538c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_MOD128, &l2->flag);
21548c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_ORIG, &l2->flag);
21558c2ecf20Sopenharmony_ci		l2->sapi = sapi;
21568c2ecf20Sopenharmony_ci		l2->maxlen = MAX_DFRAME_LEN;
21578c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
21588c2ecf20Sopenharmony_ci			l2->window = 7;
21598c2ecf20Sopenharmony_ci		else
21608c2ecf20Sopenharmony_ci			l2->window = 1;
21618c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_PTP, &options))
21628c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_PTP, &l2->flag);
21638c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_FIXEDTEI, &options))
21648c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
21658c2ecf20Sopenharmony_ci		l2->tei = tei;
21668c2ecf20Sopenharmony_ci		l2->T200 = 1000;
21678c2ecf20Sopenharmony_ci		l2->N200 = 3;
21688c2ecf20Sopenharmony_ci		l2->T203 = 10000;
21698c2ecf20Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
21708c2ecf20Sopenharmony_ci			rq.protocol = ISDN_P_TE_E1;
21718c2ecf20Sopenharmony_ci		else
21728c2ecf20Sopenharmony_ci			rq.protocol = ISDN_P_TE_S0;
21738c2ecf20Sopenharmony_ci		rq.adr.channel = 0;
21748c2ecf20Sopenharmony_ci		l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
21758c2ecf20Sopenharmony_ci		break;
21768c2ecf20Sopenharmony_ci	case ISDN_P_B_X75SLP:
21778c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_LAPB, &l2->flag);
21788c2ecf20Sopenharmony_ci		l2->window = 7;
21798c2ecf20Sopenharmony_ci		l2->maxlen = MAX_DATA_SIZE;
21808c2ecf20Sopenharmony_ci		l2->T200 = 1000;
21818c2ecf20Sopenharmony_ci		l2->N200 = 4;
21828c2ecf20Sopenharmony_ci		l2->T203 = 5000;
21838c2ecf20Sopenharmony_ci		l2->addr.A = 3;
21848c2ecf20Sopenharmony_ci		l2->addr.B = 1;
21858c2ecf20Sopenharmony_ci		break;
21868c2ecf20Sopenharmony_ci	default:
21878c2ecf20Sopenharmony_ci		printk(KERN_ERR "layer2 create failed prt %x\n",
21888c2ecf20Sopenharmony_ci		       protocol);
21898c2ecf20Sopenharmony_ci		kfree(l2);
21908c2ecf20Sopenharmony_ci		return NULL;
21918c2ecf20Sopenharmony_ci	}
21928c2ecf20Sopenharmony_ci	skb_queue_head_init(&l2->i_queue);
21938c2ecf20Sopenharmony_ci	skb_queue_head_init(&l2->ui_queue);
21948c2ecf20Sopenharmony_ci	skb_queue_head_init(&l2->down_queue);
21958c2ecf20Sopenharmony_ci	skb_queue_head_init(&l2->tmp_queue);
21968c2ecf20Sopenharmony_ci	InitWin(l2);
21978c2ecf20Sopenharmony_ci	l2->l2m.fsm = &l2fsm;
21988c2ecf20Sopenharmony_ci	if (test_bit(FLG_LAPB, &l2->flag) ||
21998c2ecf20Sopenharmony_ci	    test_bit(FLG_FIXED_TEI, &l2->flag) ||
22008c2ecf20Sopenharmony_ci	    test_bit(FLG_LAPD_NET, &l2->flag))
22018c2ecf20Sopenharmony_ci		l2->l2m.state = ST_L2_4;
22028c2ecf20Sopenharmony_ci	else
22038c2ecf20Sopenharmony_ci		l2->l2m.state = ST_L2_1;
22048c2ecf20Sopenharmony_ci	l2->l2m.debug = *debug;
22058c2ecf20Sopenharmony_ci	l2->l2m.userdata = l2;
22068c2ecf20Sopenharmony_ci	l2->l2m.userint = 0;
22078c2ecf20Sopenharmony_ci	l2->l2m.printdebug = l2m_debug;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	mISDN_FsmInitTimer(&l2->l2m, &l2->t200);
22108c2ecf20Sopenharmony_ci	mISDN_FsmInitTimer(&l2->l2m, &l2->t203);
22118c2ecf20Sopenharmony_ci	return l2;
22128c2ecf20Sopenharmony_ci}
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_cistatic int
22158c2ecf20Sopenharmony_cix75create(struct channel_req *crq)
22168c2ecf20Sopenharmony_ci{
22178c2ecf20Sopenharmony_ci	struct layer2	*l2;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	if (crq->protocol != ISDN_P_B_X75SLP)
22208c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
22218c2ecf20Sopenharmony_ci	l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0);
22228c2ecf20Sopenharmony_ci	if (!l2)
22238c2ecf20Sopenharmony_ci		return -ENOMEM;
22248c2ecf20Sopenharmony_ci	crq->ch = &l2->ch;
22258c2ecf20Sopenharmony_ci	crq->protocol = ISDN_P_B_HDLC;
22268c2ecf20Sopenharmony_ci	return 0;
22278c2ecf20Sopenharmony_ci}
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_cistatic struct Bprotocol X75SLP = {
22308c2ecf20Sopenharmony_ci	.Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)),
22318c2ecf20Sopenharmony_ci	.name = "X75SLP",
22328c2ecf20Sopenharmony_ci	.create = x75create
22338c2ecf20Sopenharmony_ci};
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ciint
22368c2ecf20Sopenharmony_ciIsdnl2_Init(u_int *deb)
22378c2ecf20Sopenharmony_ci{
22388c2ecf20Sopenharmony_ci	int res;
22398c2ecf20Sopenharmony_ci	debug = deb;
22408c2ecf20Sopenharmony_ci	mISDN_register_Bprotocol(&X75SLP);
22418c2ecf20Sopenharmony_ci	l2fsm.state_count = L2_STATE_COUNT;
22428c2ecf20Sopenharmony_ci	l2fsm.event_count = L2_EVENT_COUNT;
22438c2ecf20Sopenharmony_ci	l2fsm.strEvent = strL2Event;
22448c2ecf20Sopenharmony_ci	l2fsm.strState = strL2State;
22458c2ecf20Sopenharmony_ci	res = mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
22468c2ecf20Sopenharmony_ci	if (res)
22478c2ecf20Sopenharmony_ci		goto error;
22488c2ecf20Sopenharmony_ci	res = TEIInit(deb);
22498c2ecf20Sopenharmony_ci	if (res)
22508c2ecf20Sopenharmony_ci		goto error_fsm;
22518c2ecf20Sopenharmony_ci	return 0;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_cierror_fsm:
22548c2ecf20Sopenharmony_ci	mISDN_FsmFree(&l2fsm);
22558c2ecf20Sopenharmony_cierror:
22568c2ecf20Sopenharmony_ci	mISDN_unregister_Bprotocol(&X75SLP);
22578c2ecf20Sopenharmony_ci	return res;
22588c2ecf20Sopenharmony_ci}
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_civoid
22618c2ecf20Sopenharmony_ciIsdnl2_cleanup(void)
22628c2ecf20Sopenharmony_ci{
22638c2ecf20Sopenharmony_ci	mISDN_unregister_Bprotocol(&X75SLP);
22648c2ecf20Sopenharmony_ci	TEIFree();
22658c2ecf20Sopenharmony_ci	mISDN_FsmFree(&l2fsm);
22668c2ecf20Sopenharmony_ci}
2267