162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Author	Karsten Keil <kkeil@novell.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2008  by Karsten Keil <kkeil@novell.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/mISDNif.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include "core.h"
1262306a36Sopenharmony_ci#include "fsm.h"
1362306a36Sopenharmony_ci#include "layer2.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic u_int *debug;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic
1862306a36Sopenharmony_cistruct Fsm l2fsm = {NULL, 0, 0, NULL, NULL};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic char *strL2State[] =
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	"ST_L2_1",
2362306a36Sopenharmony_ci	"ST_L2_2",
2462306a36Sopenharmony_ci	"ST_L2_3",
2562306a36Sopenharmony_ci	"ST_L2_4",
2662306a36Sopenharmony_ci	"ST_L2_5",
2762306a36Sopenharmony_ci	"ST_L2_6",
2862306a36Sopenharmony_ci	"ST_L2_7",
2962306a36Sopenharmony_ci	"ST_L2_8",
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cienum {
3362306a36Sopenharmony_ci	EV_L2_UI,
3462306a36Sopenharmony_ci	EV_L2_SABME,
3562306a36Sopenharmony_ci	EV_L2_DISC,
3662306a36Sopenharmony_ci	EV_L2_DM,
3762306a36Sopenharmony_ci	EV_L2_UA,
3862306a36Sopenharmony_ci	EV_L2_FRMR,
3962306a36Sopenharmony_ci	EV_L2_SUPER,
4062306a36Sopenharmony_ci	EV_L2_I,
4162306a36Sopenharmony_ci	EV_L2_DL_DATA,
4262306a36Sopenharmony_ci	EV_L2_ACK_PULL,
4362306a36Sopenharmony_ci	EV_L2_DL_UNITDATA,
4462306a36Sopenharmony_ci	EV_L2_DL_ESTABLISH_REQ,
4562306a36Sopenharmony_ci	EV_L2_DL_RELEASE_REQ,
4662306a36Sopenharmony_ci	EV_L2_MDL_ASSIGN,
4762306a36Sopenharmony_ci	EV_L2_MDL_REMOVE,
4862306a36Sopenharmony_ci	EV_L2_MDL_ERROR,
4962306a36Sopenharmony_ci	EV_L1_DEACTIVATE,
5062306a36Sopenharmony_ci	EV_L2_T200,
5162306a36Sopenharmony_ci	EV_L2_T203,
5262306a36Sopenharmony_ci	EV_L2_T200I,
5362306a36Sopenharmony_ci	EV_L2_T203I,
5462306a36Sopenharmony_ci	EV_L2_SET_OWN_BUSY,
5562306a36Sopenharmony_ci	EV_L2_CLEAR_OWN_BUSY,
5662306a36Sopenharmony_ci	EV_L2_FRAME_ERROR,
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic char *strL2Event[] =
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	"EV_L2_UI",
6462306a36Sopenharmony_ci	"EV_L2_SABME",
6562306a36Sopenharmony_ci	"EV_L2_DISC",
6662306a36Sopenharmony_ci	"EV_L2_DM",
6762306a36Sopenharmony_ci	"EV_L2_UA",
6862306a36Sopenharmony_ci	"EV_L2_FRMR",
6962306a36Sopenharmony_ci	"EV_L2_SUPER",
7062306a36Sopenharmony_ci	"EV_L2_I",
7162306a36Sopenharmony_ci	"EV_L2_DL_DATA",
7262306a36Sopenharmony_ci	"EV_L2_ACK_PULL",
7362306a36Sopenharmony_ci	"EV_L2_DL_UNITDATA",
7462306a36Sopenharmony_ci	"EV_L2_DL_ESTABLISH_REQ",
7562306a36Sopenharmony_ci	"EV_L2_DL_RELEASE_REQ",
7662306a36Sopenharmony_ci	"EV_L2_MDL_ASSIGN",
7762306a36Sopenharmony_ci	"EV_L2_MDL_REMOVE",
7862306a36Sopenharmony_ci	"EV_L2_MDL_ERROR",
7962306a36Sopenharmony_ci	"EV_L1_DEACTIVATE",
8062306a36Sopenharmony_ci	"EV_L2_T200",
8162306a36Sopenharmony_ci	"EV_L2_T203",
8262306a36Sopenharmony_ci	"EV_L2_T200I",
8362306a36Sopenharmony_ci	"EV_L2_T203I",
8462306a36Sopenharmony_ci	"EV_L2_SET_OWN_BUSY",
8562306a36Sopenharmony_ci	"EV_L2_CLEAR_OWN_BUSY",
8662306a36Sopenharmony_ci	"EV_L2_FRAME_ERROR",
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void
9062306a36Sopenharmony_cil2m_debug(struct FsmInst *fi, char *fmt, ...)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
9362306a36Sopenharmony_ci	struct va_format vaf;
9462306a36Sopenharmony_ci	va_list va;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (!(*debug & DEBUG_L2_FSM))
9762306a36Sopenharmony_ci		return;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	va_start(va, fmt);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	vaf.fmt = fmt;
10262306a36Sopenharmony_ci	vaf.va = &va;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n",
10562306a36Sopenharmony_ci	       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	va_end(va);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciinline u_int
11162306a36Sopenharmony_cil2headersize(struct layer2 *l2, int ui)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
11462306a36Sopenharmony_ci		(test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ciinline u_int
11862306a36Sopenharmony_cil2addrsize(struct layer2 *l2)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic u_int
12462306a36Sopenharmony_cil2_newid(struct layer2 *l2)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	u_int	id;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	id = l2->next_id++;
12962306a36Sopenharmony_ci	if (id == 0x7fff)
13062306a36Sopenharmony_ci		l2->next_id = 1;
13162306a36Sopenharmony_ci	id <<= 16;
13262306a36Sopenharmony_ci	id |= l2->tei << 8;
13362306a36Sopenharmony_ci	id |= l2->sapi;
13462306a36Sopenharmony_ci	return id;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void
13862306a36Sopenharmony_cil2up(struct layer2 *l2, u_int prim, struct sk_buff *skb)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	int	err;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (!l2->up)
14362306a36Sopenharmony_ci		return;
14462306a36Sopenharmony_ci	mISDN_HEAD_PRIM(skb) = prim;
14562306a36Sopenharmony_ci	mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr;
14662306a36Sopenharmony_ci	err = l2->up->send(l2->up, skb);
14762306a36Sopenharmony_ci	if (err) {
14862306a36Sopenharmony_ci		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
14962306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), err);
15062306a36Sopenharmony_ci		dev_kfree_skb(skb);
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void
15562306a36Sopenharmony_cil2up_create(struct layer2 *l2, u_int prim, int len, void *arg)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct sk_buff	*skb;
15862306a36Sopenharmony_ci	struct mISDNhead *hh;
15962306a36Sopenharmony_ci	int		err;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!l2->up)
16262306a36Sopenharmony_ci		return;
16362306a36Sopenharmony_ci	skb = mI_alloc_skb(len, GFP_ATOMIC);
16462306a36Sopenharmony_ci	if (!skb)
16562306a36Sopenharmony_ci		return;
16662306a36Sopenharmony_ci	hh = mISDN_HEAD_P(skb);
16762306a36Sopenharmony_ci	hh->prim = prim;
16862306a36Sopenharmony_ci	hh->id = (l2->ch.nr << 16) | l2->ch.addr;
16962306a36Sopenharmony_ci	if (len)
17062306a36Sopenharmony_ci		skb_put_data(skb, arg, len);
17162306a36Sopenharmony_ci	err = l2->up->send(l2->up, skb);
17262306a36Sopenharmony_ci	if (err) {
17362306a36Sopenharmony_ci		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
17462306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), err);
17562306a36Sopenharmony_ci		dev_kfree_skb(skb);
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int
18062306a36Sopenharmony_cil2down_skb(struct layer2 *l2, struct sk_buff *skb) {
18162306a36Sopenharmony_ci	int ret;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	ret = l2->ch.recv(l2->ch.peer, skb);
18462306a36Sopenharmony_ci	if (ret && (*debug & DEBUG_L2_RECV))
18562306a36Sopenharmony_ci		printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n",
18662306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), ret);
18762306a36Sopenharmony_ci	return ret;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int
19162306a36Sopenharmony_cil2down_raw(struct layer2 *l2, struct sk_buff *skb)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct mISDNhead *hh = mISDN_HEAD_P(skb);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (hh->prim == PH_DATA_REQ) {
19662306a36Sopenharmony_ci		if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
19762306a36Sopenharmony_ci			skb_queue_tail(&l2->down_queue, skb);
19862306a36Sopenharmony_ci			return 0;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci		l2->down_id = mISDN_HEAD_ID(skb);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci	return l2down_skb(l2, skb);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int
20662306a36Sopenharmony_cil2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct mISDNhead *hh = mISDN_HEAD_P(skb);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	hh->prim = prim;
21162306a36Sopenharmony_ci	hh->id = id;
21262306a36Sopenharmony_ci	return l2down_raw(l2, skb);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic int
21662306a36Sopenharmony_cil2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct sk_buff	*skb;
21962306a36Sopenharmony_ci	int		err;
22062306a36Sopenharmony_ci	struct mISDNhead *hh;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	skb = mI_alloc_skb(len, GFP_ATOMIC);
22362306a36Sopenharmony_ci	if (!skb)
22462306a36Sopenharmony_ci		return -ENOMEM;
22562306a36Sopenharmony_ci	hh = mISDN_HEAD_P(skb);
22662306a36Sopenharmony_ci	hh->prim = prim;
22762306a36Sopenharmony_ci	hh->id = id;
22862306a36Sopenharmony_ci	if (len)
22962306a36Sopenharmony_ci		skb_put_data(skb, arg, len);
23062306a36Sopenharmony_ci	err = l2down_raw(l2, skb);
23162306a36Sopenharmony_ci	if (err)
23262306a36Sopenharmony_ci		dev_kfree_skb(skb);
23362306a36Sopenharmony_ci	return err;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic int
23762306a36Sopenharmony_ciph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) {
23862306a36Sopenharmony_ci	struct sk_buff *nskb = skb;
23962306a36Sopenharmony_ci	int ret = -EAGAIN;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (test_bit(FLG_L1_NOTREADY, &l2->flag)) {
24262306a36Sopenharmony_ci		if (hh->id == l2->down_id) {
24362306a36Sopenharmony_ci			nskb = skb_dequeue(&l2->down_queue);
24462306a36Sopenharmony_ci			if (nskb) {
24562306a36Sopenharmony_ci				l2->down_id = mISDN_HEAD_ID(nskb);
24662306a36Sopenharmony_ci				if (l2down_skb(l2, nskb)) {
24762306a36Sopenharmony_ci					dev_kfree_skb(nskb);
24862306a36Sopenharmony_ci					l2->down_id = MISDN_ID_NONE;
24962306a36Sopenharmony_ci				}
25062306a36Sopenharmony_ci			} else
25162306a36Sopenharmony_ci				l2->down_id = MISDN_ID_NONE;
25262306a36Sopenharmony_ci			if (ret) {
25362306a36Sopenharmony_ci				dev_kfree_skb(skb);
25462306a36Sopenharmony_ci				ret = 0;
25562306a36Sopenharmony_ci			}
25662306a36Sopenharmony_ci			if (l2->down_id == MISDN_ID_NONE) {
25762306a36Sopenharmony_ci				test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
25862306a36Sopenharmony_ci				mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
25962306a36Sopenharmony_ci			}
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
26362306a36Sopenharmony_ci		nskb = skb_dequeue(&l2->down_queue);
26462306a36Sopenharmony_ci		if (nskb) {
26562306a36Sopenharmony_ci			l2->down_id = mISDN_HEAD_ID(nskb);
26662306a36Sopenharmony_ci			if (l2down_skb(l2, nskb)) {
26762306a36Sopenharmony_ci				dev_kfree_skb(nskb);
26862306a36Sopenharmony_ci				l2->down_id = MISDN_ID_NONE;
26962306a36Sopenharmony_ci				test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
27062306a36Sopenharmony_ci			}
27162306a36Sopenharmony_ci		} else
27262306a36Sopenharmony_ci			test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	return ret;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void
27862306a36Sopenharmony_cil2_timeout(struct FsmInst *fi, int event, void *arg)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
28162306a36Sopenharmony_ci	struct sk_buff *skb;
28262306a36Sopenharmony_ci	struct mISDNhead *hh;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	skb = mI_alloc_skb(0, GFP_ATOMIC);
28562306a36Sopenharmony_ci	if (!skb) {
28662306a36Sopenharmony_ci		printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n",
28762306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
28862306a36Sopenharmony_ci		       l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
28962306a36Sopenharmony_ci		return;
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci	hh = mISDN_HEAD_P(skb);
29262306a36Sopenharmony_ci	hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
29362306a36Sopenharmony_ci	hh->id = l2->ch.nr;
29462306a36Sopenharmony_ci	if (*debug & DEBUG_TIMER)
29562306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n",
29662306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
29762306a36Sopenharmony_ci		       l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
29862306a36Sopenharmony_ci	if (l2->ch.st)
29962306a36Sopenharmony_ci		l2->ch.st->own.recv(&l2->ch.st->own, skb);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int
30362306a36Sopenharmony_cil2mgr(struct layer2 *l2, u_int prim, void *arg) {
30462306a36Sopenharmony_ci	long c = (long)arg;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n",
30762306a36Sopenharmony_ci	       mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c);
30862306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
30962306a36Sopenharmony_ci	    !test_bit(FLG_FIXED_TEI, &l2->flag)) {
31062306a36Sopenharmony_ci		switch (c) {
31162306a36Sopenharmony_ci		case 'C':
31262306a36Sopenharmony_ci		case 'D':
31362306a36Sopenharmony_ci		case 'G':
31462306a36Sopenharmony_ci		case 'H':
31562306a36Sopenharmony_ci			l2_tei(l2, prim, (u_long)arg);
31662306a36Sopenharmony_ci			break;
31762306a36Sopenharmony_ci		}
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic void
32362306a36Sopenharmony_ciset_peer_busy(struct layer2 *l2) {
32462306a36Sopenharmony_ci	test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
32562306a36Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
32662306a36Sopenharmony_ci		test_and_set_bit(FLG_L2BLOCK, &l2->flag);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic void
33062306a36Sopenharmony_ciclear_peer_busy(struct layer2 *l2) {
33162306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
33262306a36Sopenharmony_ci		test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void
33662306a36Sopenharmony_ciInitWin(struct layer2 *l2)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int i;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	for (i = 0; i < MAX_WINDOW; i++)
34162306a36Sopenharmony_ci		l2->windowar[i] = NULL;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int
34562306a36Sopenharmony_cifreewin(struct layer2 *l2)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int i, cnt = 0;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	for (i = 0; i < MAX_WINDOW; i++) {
35062306a36Sopenharmony_ci		if (l2->windowar[i]) {
35162306a36Sopenharmony_ci			cnt++;
35262306a36Sopenharmony_ci			dev_kfree_skb(l2->windowar[i]);
35362306a36Sopenharmony_ci			l2->windowar[i] = NULL;
35462306a36Sopenharmony_ci		}
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci	return cnt;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void
36062306a36Sopenharmony_ciReleaseWin(struct layer2 *l2)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	int cnt = freewin(l2);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (cnt)
36562306a36Sopenharmony_ci		printk(KERN_WARNING
36662306a36Sopenharmony_ci		       "isdnl2 freed %d skbuffs in release\n", cnt);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciinline unsigned int
37062306a36Sopenharmony_cicansend(struct layer2 *l2)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	unsigned int p1;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag))
37562306a36Sopenharmony_ci		p1 = (l2->vs - l2->va) % 128;
37662306a36Sopenharmony_ci	else
37762306a36Sopenharmony_ci		p1 = (l2->vs - l2->va) % 8;
37862306a36Sopenharmony_ci	return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ciinline void
38262306a36Sopenharmony_ciclear_exception(struct layer2 *l2)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
38562306a36Sopenharmony_ci	test_and_clear_bit(FLG_REJEXC, &l2->flag);
38662306a36Sopenharmony_ci	test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
38762306a36Sopenharmony_ci	clear_peer_busy(l2);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int
39162306a36Sopenharmony_cisethdraddr(struct layer2 *l2, u_char *header, int rsp)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	u_char *ptr = header;
39462306a36Sopenharmony_ci	int crbit = rsp;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag)) {
39762306a36Sopenharmony_ci		if (test_bit(FLG_LAPD_NET, &l2->flag))
39862306a36Sopenharmony_ci			crbit = !crbit;
39962306a36Sopenharmony_ci		*ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0);
40062306a36Sopenharmony_ci		*ptr++ = (l2->tei << 1) | 1;
40162306a36Sopenharmony_ci		return 2;
40262306a36Sopenharmony_ci	} else {
40362306a36Sopenharmony_ci		if (test_bit(FLG_ORIG, &l2->flag))
40462306a36Sopenharmony_ci			crbit = !crbit;
40562306a36Sopenharmony_ci		if (crbit)
40662306a36Sopenharmony_ci			*ptr++ = l2->addr.B;
40762306a36Sopenharmony_ci		else
40862306a36Sopenharmony_ci			*ptr++ = l2->addr.A;
40962306a36Sopenharmony_ci		return 1;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic inline void
41462306a36Sopenharmony_cienqueue_super(struct layer2 *l2, struct sk_buff *skb)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
41762306a36Sopenharmony_ci		dev_kfree_skb(skb);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic inline void
42162306a36Sopenharmony_cienqueue_ui(struct layer2 *l2, struct sk_buff *skb)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	if (l2->tm)
42462306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UI_IND, 0);
42562306a36Sopenharmony_ci	if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
42662306a36Sopenharmony_ci		dev_kfree_skb(skb);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ciinline int
43062306a36Sopenharmony_ciIsUI(u_char *data)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	return (data[0] & 0xef) == UI;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ciinline int
43662306a36Sopenharmony_ciIsUA(u_char *data)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	return (data[0] & 0xef) == UA;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ciinline int
44262306a36Sopenharmony_ciIsDM(u_char *data)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	return (data[0] & 0xef) == DM;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ciinline int
44862306a36Sopenharmony_ciIsDISC(u_char *data)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	return (data[0] & 0xef) == DISC;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ciinline int
45462306a36Sopenharmony_ciIsRR(u_char *data, struct layer2 *l2)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag))
45762306a36Sopenharmony_ci		return data[0] == RR;
45862306a36Sopenharmony_ci	else
45962306a36Sopenharmony_ci		return (data[0] & 0xf) == 1;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ciinline int
46362306a36Sopenharmony_ciIsSFrame(u_char *data, struct layer2 *l2)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	register u_char d = *data;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (!test_bit(FLG_MOD128, &l2->flag))
46862306a36Sopenharmony_ci		d &= 0xf;
46962306a36Sopenharmony_ci	return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c);
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ciinline int
47362306a36Sopenharmony_ciIsSABME(u_char *data, struct layer2 *l2)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	u_char d = data[0] & ~0x10;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ciinline int
48162306a36Sopenharmony_ciIsREJ(u_char *data, struct layer2 *l2)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	return test_bit(FLG_MOD128, &l2->flag) ?
48462306a36Sopenharmony_ci		data[0] == REJ : (data[0] & 0xf) == REJ;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ciinline int
48862306a36Sopenharmony_ciIsFRMR(u_char *data)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	return (data[0] & 0xef) == FRMR;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ciinline int
49462306a36Sopenharmony_ciIsRNR(u_char *data, struct layer2 *l2)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	return test_bit(FLG_MOD128, &l2->flag) ?
49762306a36Sopenharmony_ci		data[0] == RNR : (data[0] & 0xf) == RNR;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int
50162306a36Sopenharmony_ciiframe_error(struct layer2 *l2, struct sk_buff *skb)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	u_int	i;
50462306a36Sopenharmony_ci	int	rsp = *skb->data & 0x2;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1);
50762306a36Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
50862306a36Sopenharmony_ci		rsp = !rsp;
50962306a36Sopenharmony_ci	if (rsp)
51062306a36Sopenharmony_ci		return 'L';
51162306a36Sopenharmony_ci	if (skb->len < i)
51262306a36Sopenharmony_ci		return 'N';
51362306a36Sopenharmony_ci	if ((skb->len - i) > l2->maxlen)
51462306a36Sopenharmony_ci		return 'O';
51562306a36Sopenharmony_ci	return 0;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic int
51962306a36Sopenharmony_cisuper_error(struct layer2 *l2, struct sk_buff *skb)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	if (skb->len != l2addrsize(l2) +
52262306a36Sopenharmony_ci	    (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1))
52362306a36Sopenharmony_ci		return 'N';
52462306a36Sopenharmony_ci	return 0;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic int
52862306a36Sopenharmony_ciunnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int rsp = (*skb->data & 0x2) >> 1;
53162306a36Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
53262306a36Sopenharmony_ci		rsp = !rsp;
53362306a36Sopenharmony_ci	if (rsp != wantrsp)
53462306a36Sopenharmony_ci		return 'L';
53562306a36Sopenharmony_ci	if (skb->len != l2addrsize(l2) + 1)
53662306a36Sopenharmony_ci		return 'N';
53762306a36Sopenharmony_ci	return 0;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic int
54162306a36Sopenharmony_ciUI_error(struct layer2 *l2, struct sk_buff *skb)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	int rsp = *skb->data & 0x2;
54462306a36Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
54562306a36Sopenharmony_ci		rsp = !rsp;
54662306a36Sopenharmony_ci	if (rsp)
54762306a36Sopenharmony_ci		return 'L';
54862306a36Sopenharmony_ci	if (skb->len > l2->maxlen + l2addrsize(l2) + 1)
54962306a36Sopenharmony_ci		return 'O';
55062306a36Sopenharmony_ci	return 0;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int
55462306a36Sopenharmony_ciFRMR_error(struct layer2 *l2, struct sk_buff *skb)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	u_int	headers = l2addrsize(l2) + 1;
55762306a36Sopenharmony_ci	u_char	*datap = skb->data + headers;
55862306a36Sopenharmony_ci	int	rsp = *skb->data & 0x2;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
56162306a36Sopenharmony_ci		rsp = !rsp;
56262306a36Sopenharmony_ci	if (!rsp)
56362306a36Sopenharmony_ci		return 'L';
56462306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
56562306a36Sopenharmony_ci		if (skb->len < headers + 5)
56662306a36Sopenharmony_ci			return 'N';
56762306a36Sopenharmony_ci		else if (*debug & DEBUG_L2)
56862306a36Sopenharmony_ci			l2m_debug(&l2->l2m,
56962306a36Sopenharmony_ci				  "FRMR information %2x %2x %2x %2x %2x",
57062306a36Sopenharmony_ci				  datap[0], datap[1], datap[2], datap[3], datap[4]);
57162306a36Sopenharmony_ci	} else {
57262306a36Sopenharmony_ci		if (skb->len < headers + 3)
57362306a36Sopenharmony_ci			return 'N';
57462306a36Sopenharmony_ci		else if (*debug & DEBUG_L2)
57562306a36Sopenharmony_ci			l2m_debug(&l2->l2m,
57662306a36Sopenharmony_ci				  "FRMR information %2x %2x %2x",
57762306a36Sopenharmony_ci				  datap[0], datap[1], datap[2]);
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci	return 0;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic unsigned int
58362306a36Sopenharmony_cilegalnr(struct layer2 *l2, unsigned int nr)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag))
58662306a36Sopenharmony_ci		return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
58762306a36Sopenharmony_ci	else
58862306a36Sopenharmony_ci		return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void
59262306a36Sopenharmony_cisetva(struct layer2 *l2, unsigned int nr)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct sk_buff	*skb;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	while (l2->va != nr) {
59762306a36Sopenharmony_ci		l2->va++;
59862306a36Sopenharmony_ci		if (test_bit(FLG_MOD128, &l2->flag))
59962306a36Sopenharmony_ci			l2->va %= 128;
60062306a36Sopenharmony_ci		else
60162306a36Sopenharmony_ci			l2->va %= 8;
60262306a36Sopenharmony_ci		if (l2->windowar[l2->sow]) {
60362306a36Sopenharmony_ci			skb_trim(l2->windowar[l2->sow], 0);
60462306a36Sopenharmony_ci			skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]);
60562306a36Sopenharmony_ci			l2->windowar[l2->sow] = NULL;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci		l2->sow = (l2->sow + 1) % l2->window;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci	skb = skb_dequeue(&l2->tmp_queue);
61062306a36Sopenharmony_ci	while (skb) {
61162306a36Sopenharmony_ci		dev_kfree_skb(skb);
61262306a36Sopenharmony_ci		skb = skb_dequeue(&l2->tmp_queue);
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic void
61762306a36Sopenharmony_cisend_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	u_char tmp[MAX_L2HEADER_LEN];
62062306a36Sopenharmony_ci	int i;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	i = sethdraddr(l2, tmp, cr);
62362306a36Sopenharmony_ci	tmp[i++] = cmd;
62462306a36Sopenharmony_ci	if (skb)
62562306a36Sopenharmony_ci		skb_trim(skb, 0);
62662306a36Sopenharmony_ci	else {
62762306a36Sopenharmony_ci		skb = mI_alloc_skb(i, GFP_ATOMIC);
62862306a36Sopenharmony_ci		if (!skb) {
62962306a36Sopenharmony_ci			printk(KERN_WARNING "%s: can't alloc skbuff in %s\n",
63062306a36Sopenharmony_ci			       mISDNDevName4ch(&l2->ch), __func__);
63162306a36Sopenharmony_ci			return;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci	skb_put_data(skb, tmp, i);
63562306a36Sopenharmony_ci	enqueue_super(l2, skb);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ciinline u_char
64062306a36Sopenharmony_ciget_PollFlag(struct layer2 *l2, struct sk_buff *skb)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	return skb->data[l2addrsize(l2)] & 0x10;
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ciinline u_char
64662306a36Sopenharmony_ciget_PollFlagFree(struct layer2 *l2, struct sk_buff *skb)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	u_char PF;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	PF = get_PollFlag(l2, skb);
65162306a36Sopenharmony_ci	dev_kfree_skb(skb);
65262306a36Sopenharmony_ci	return PF;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ciinline void
65662306a36Sopenharmony_cistart_t200(struct layer2 *l2, int i)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
65962306a36Sopenharmony_ci	test_and_set_bit(FLG_T200_RUN, &l2->flag);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciinline void
66362306a36Sopenharmony_cirestart_t200(struct layer2 *l2, int i)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
66662306a36Sopenharmony_ci	test_and_set_bit(FLG_T200_RUN, &l2->flag);
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ciinline void
67062306a36Sopenharmony_cistop_t200(struct layer2 *l2, int i)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_T200_RUN, &l2->flag))
67362306a36Sopenharmony_ci		mISDN_FsmDelTimer(&l2->t200, i);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciinline void
67762306a36Sopenharmony_cist5_dl_release_l2l3(struct layer2 *l2)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	int pr;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
68262306a36Sopenharmony_ci		pr = DL_RELEASE_CNF;
68362306a36Sopenharmony_ci	else
68462306a36Sopenharmony_ci		pr = DL_RELEASE_IND;
68562306a36Sopenharmony_ci	l2up_create(l2, pr, 0, NULL);
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciinline void
68962306a36Sopenharmony_cilapb_dl_release_l2l3(struct layer2 *l2, int f)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	if (test_bit(FLG_LAPB, &l2->flag))
69262306a36Sopenharmony_ci		l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL);
69362306a36Sopenharmony_ci	l2up_create(l2, f, 0, NULL);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic void
69762306a36Sopenharmony_ciestablishlink(struct FsmInst *fi)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
70062306a36Sopenharmony_ci	u_char cmd;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	clear_exception(l2);
70362306a36Sopenharmony_ci	l2->rc = 0;
70462306a36Sopenharmony_ci	cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10;
70562306a36Sopenharmony_ci	send_uframe(l2, NULL, cmd, CMD);
70662306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 1);
70762306a36Sopenharmony_ci	restart_t200(l2, 1);
70862306a36Sopenharmony_ci	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
70962306a36Sopenharmony_ci	freewin(l2);
71062306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_5);
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic void
71462306a36Sopenharmony_cil2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	struct sk_buff *skb = arg;
71762306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (get_PollFlagFree(l2, skb))
72062306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'C');
72162306a36Sopenharmony_ci	else
72262306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'D');
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic void
72762306a36Sopenharmony_cil2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct sk_buff *skb = arg;
73062306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (get_PollFlagFree(l2, skb))
73362306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
73462306a36Sopenharmony_ci	else {
73562306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
73662306a36Sopenharmony_ci		establishlink(fi);
73762306a36Sopenharmony_ci		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic void
74262306a36Sopenharmony_cil2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct sk_buff *skb = arg;
74562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (get_PollFlagFree(l2, skb))
74862306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
74962306a36Sopenharmony_ci	else
75062306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
75162306a36Sopenharmony_ci	establishlink(fi);
75262306a36Sopenharmony_ci	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void
75662306a36Sopenharmony_cil2_go_st3(struct FsmInst *fi, int event, void *arg)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	dev_kfree_skb((struct sk_buff *)arg);
75962306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_3);
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic void
76362306a36Sopenharmony_cil2_mdl_assign(struct FsmInst *fi, int event, void *arg)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_3);
76862306a36Sopenharmony_ci	dev_kfree_skb((struct sk_buff *)arg);
76962306a36Sopenharmony_ci	l2_tei(l2, MDL_ASSIGN_IND, 0);
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic void
77362306a36Sopenharmony_cil2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
77662306a36Sopenharmony_ci	struct sk_buff *skb = arg;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	skb_queue_tail(&l2->ui_queue, skb);
77962306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_2);
78062306a36Sopenharmony_ci	l2_tei(l2, MDL_ASSIGN_IND, 0);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic void
78462306a36Sopenharmony_cil2_queue_ui(struct FsmInst *fi, int event, void *arg)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
78762306a36Sopenharmony_ci	struct sk_buff *skb = arg;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	skb_queue_tail(&l2->ui_queue, skb);
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic void
79362306a36Sopenharmony_citx_ui(struct layer2 *l2)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct sk_buff *skb;
79662306a36Sopenharmony_ci	u_char header[MAX_L2HEADER_LEN];
79762306a36Sopenharmony_ci	int i;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	i = sethdraddr(l2, header, CMD);
80062306a36Sopenharmony_ci	if (test_bit(FLG_LAPD_NET, &l2->flag))
80162306a36Sopenharmony_ci		header[1] = 0xff; /* tei 127 */
80262306a36Sopenharmony_ci	header[i++] = UI;
80362306a36Sopenharmony_ci	while ((skb = skb_dequeue(&l2->ui_queue))) {
80462306a36Sopenharmony_ci		memcpy(skb_push(skb, i), header, i);
80562306a36Sopenharmony_ci		enqueue_ui(l2, skb);
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic void
81062306a36Sopenharmony_cil2_send_ui(struct FsmInst *fi, int event, void *arg)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
81362306a36Sopenharmony_ci	struct sk_buff *skb = arg;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	skb_queue_tail(&l2->ui_queue, skb);
81662306a36Sopenharmony_ci	tx_ui(l2);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic void
82062306a36Sopenharmony_cil2_got_ui(struct FsmInst *fi, int event, void *arg)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
82362306a36Sopenharmony_ci	struct sk_buff *skb = arg;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	skb_pull(skb, l2headersize(l2, 1));
82662306a36Sopenharmony_ci/*
82762306a36Sopenharmony_ci *		in states 1-3 for broadcast
82862306a36Sopenharmony_ci */
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (l2->tm)
83162306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UI_IND, 0);
83262306a36Sopenharmony_ci	l2up(l2, DL_UNITDATA_IND, skb);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic void
83662306a36Sopenharmony_cil2_establish(struct FsmInst *fi, int event, void *arg)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	struct sk_buff *skb = arg;
83962306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	establishlink(fi);
84262306a36Sopenharmony_ci	test_and_set_bit(FLG_L3_INIT, &l2->flag);
84362306a36Sopenharmony_ci	dev_kfree_skb(skb);
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic void
84762306a36Sopenharmony_cil2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct sk_buff *skb = arg;
85062306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
85362306a36Sopenharmony_ci	test_and_set_bit(FLG_L3_INIT, &l2->flag);
85462306a36Sopenharmony_ci	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
85562306a36Sopenharmony_ci	dev_kfree_skb(skb);
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void
85962306a36Sopenharmony_cil2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	struct sk_buff *skb = arg;
86262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
86562306a36Sopenharmony_ci	establishlink(fi);
86662306a36Sopenharmony_ci	test_and_set_bit(FLG_L3_INIT, &l2->flag);
86762306a36Sopenharmony_ci	dev_kfree_skb(skb);
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic void
87162306a36Sopenharmony_cil2_release(struct FsmInst *fi, int event, void *arg)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
87462306a36Sopenharmony_ci	struct sk_buff *skb = arg;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	skb_trim(skb, 0);
87762306a36Sopenharmony_ci	l2up(l2, DL_RELEASE_CNF, skb);
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void
88162306a36Sopenharmony_cil2_pend_rel(struct FsmInst *fi, int event, void *arg)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	struct sk_buff *skb = arg;
88462306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	test_and_set_bit(FLG_PEND_REL, &l2->flag);
88762306a36Sopenharmony_ci	dev_kfree_skb(skb);
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic void
89162306a36Sopenharmony_cil2_disconnect(struct FsmInst *fi, int event, void *arg)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
89462306a36Sopenharmony_ci	struct sk_buff *skb = arg;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
89762306a36Sopenharmony_ci	freewin(l2);
89862306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_6);
89962306a36Sopenharmony_ci	l2->rc = 0;
90062306a36Sopenharmony_ci	send_uframe(l2, NULL, DISC | 0x10, CMD);
90162306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 1);
90262306a36Sopenharmony_ci	restart_t200(l2, 2);
90362306a36Sopenharmony_ci	dev_kfree_skb(skb);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic void
90762306a36Sopenharmony_cil2_start_multi(struct FsmInst *fi, int event, void *arg)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
91062306a36Sopenharmony_ci	struct sk_buff	*skb = arg;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	l2->vs = 0;
91362306a36Sopenharmony_ci	l2->va = 0;
91462306a36Sopenharmony_ci	l2->vr = 0;
91562306a36Sopenharmony_ci	l2->sow = 0;
91662306a36Sopenharmony_ci	clear_exception(l2);
91762306a36Sopenharmony_ci	send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP);
91862306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_7);
91962306a36Sopenharmony_ci	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
92062306a36Sopenharmony_ci	skb_trim(skb, 0);
92162306a36Sopenharmony_ci	l2up(l2, DL_ESTABLISH_IND, skb);
92262306a36Sopenharmony_ci	if (l2->tm)
92362306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UP_IND, 0);
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic void
92762306a36Sopenharmony_cil2_send_UA(struct FsmInst *fi, int event, void *arg)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
93062306a36Sopenharmony_ci	struct sk_buff *skb = arg;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic void
93662306a36Sopenharmony_cil2_send_DM(struct FsmInst *fi, int event, void *arg)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
93962306a36Sopenharmony_ci	struct sk_buff *skb = arg;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic void
94562306a36Sopenharmony_cil2_restart_multi(struct FsmInst *fi, int event, void *arg)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
94862306a36Sopenharmony_ci	struct sk_buff	*skb = arg;
94962306a36Sopenharmony_ci	int		est = 0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, (void *) 'F');
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (l2->vs != l2->va) {
95662306a36Sopenharmony_ci		skb_queue_purge(&l2->i_queue);
95762306a36Sopenharmony_ci		est = 1;
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	clear_exception(l2);
96162306a36Sopenharmony_ci	l2->vs = 0;
96262306a36Sopenharmony_ci	l2->va = 0;
96362306a36Sopenharmony_ci	l2->vr = 0;
96462306a36Sopenharmony_ci	l2->sow = 0;
96562306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_7);
96662306a36Sopenharmony_ci	stop_t200(l2, 3);
96762306a36Sopenharmony_ci	mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (est)
97062306a36Sopenharmony_ci		l2up_create(l2, DL_ESTABLISH_IND, 0, NULL);
97162306a36Sopenharmony_ci/*		mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
97262306a36Sopenharmony_ci *		    MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
97362306a36Sopenharmony_ci *		    0, NULL, 0);
97462306a36Sopenharmony_ci */
97562306a36Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) && cansend(l2))
97662306a36Sopenharmony_ci		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic void
98062306a36Sopenharmony_cil2_stop_multi(struct FsmInst *fi, int event, void *arg)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
98362306a36Sopenharmony_ci	struct sk_buff	*skb = arg;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
98662306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 3);
98762306a36Sopenharmony_ci	stop_t200(l2, 4);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
99062306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
99162306a36Sopenharmony_ci	freewin(l2);
99262306a36Sopenharmony_ci	lapb_dl_release_l2l3(l2, DL_RELEASE_IND);
99362306a36Sopenharmony_ci	if (l2->tm)
99462306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic void
99862306a36Sopenharmony_cil2_connected(struct FsmInst *fi, int event, void *arg)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
100162306a36Sopenharmony_ci	struct sk_buff	*skb = arg;
100262306a36Sopenharmony_ci	int pr = -1;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (!get_PollFlag(l2, skb)) {
100562306a36Sopenharmony_ci		l2_mdl_error_ua(fi, event, arg);
100662306a36Sopenharmony_ci		return;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci	dev_kfree_skb(skb);
100962306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
101062306a36Sopenharmony_ci		l2_disconnect(fi, event, NULL);
101162306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) {
101262306a36Sopenharmony_ci		pr = DL_ESTABLISH_CNF;
101362306a36Sopenharmony_ci	} else if (l2->vs != l2->va) {
101462306a36Sopenharmony_ci		skb_queue_purge(&l2->i_queue);
101562306a36Sopenharmony_ci		pr = DL_ESTABLISH_IND;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci	stop_t200(l2, 5);
101862306a36Sopenharmony_ci	l2->vr = 0;
101962306a36Sopenharmony_ci	l2->vs = 0;
102062306a36Sopenharmony_ci	l2->va = 0;
102162306a36Sopenharmony_ci	l2->sow = 0;
102262306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_7);
102362306a36Sopenharmony_ci	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
102462306a36Sopenharmony_ci	if (pr != -1)
102562306a36Sopenharmony_ci		l2up_create(l2, pr, 0, NULL);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) && cansend(l2))
102862306a36Sopenharmony_ci		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (l2->tm)
103162306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_UP_IND, 0);
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic void
103562306a36Sopenharmony_cil2_released(struct FsmInst *fi, int event, void *arg)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
103862306a36Sopenharmony_ci	struct sk_buff *skb = arg;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (!get_PollFlag(l2, skb)) {
104162306a36Sopenharmony_ci		l2_mdl_error_ua(fi, event, arg);
104262306a36Sopenharmony_ci		return;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci	dev_kfree_skb(skb);
104562306a36Sopenharmony_ci	stop_t200(l2, 6);
104662306a36Sopenharmony_ci	lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
104762306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
104862306a36Sopenharmony_ci	if (l2->tm)
104962306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic void
105362306a36Sopenharmony_cil2_reestablish(struct FsmInst *fi, int event, void *arg)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
105662306a36Sopenharmony_ci	struct sk_buff *skb = arg;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	if (!get_PollFlagFree(l2, skb)) {
105962306a36Sopenharmony_ci		establishlink(fi);
106062306a36Sopenharmony_ci		test_and_set_bit(FLG_L3_INIT, &l2->flag);
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic void
106562306a36Sopenharmony_cil2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
106862306a36Sopenharmony_ci	struct sk_buff *skb = arg;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (get_PollFlagFree(l2, skb)) {
107162306a36Sopenharmony_ci		stop_t200(l2, 7);
107262306a36Sopenharmony_ci		if (!test_bit(FLG_L3_INIT, &l2->flag))
107362306a36Sopenharmony_ci			skb_queue_purge(&l2->i_queue);
107462306a36Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
107562306a36Sopenharmony_ci			l2down_create(l2, PH_DEACTIVATE_REQ,
107662306a36Sopenharmony_ci				      l2_newid(l2), 0, NULL);
107762306a36Sopenharmony_ci		st5_dl_release_l2l3(l2);
107862306a36Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
107962306a36Sopenharmony_ci		if (l2->tm)
108062306a36Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic void
108562306a36Sopenharmony_cil2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
108862306a36Sopenharmony_ci	struct sk_buff *skb = arg;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (get_PollFlagFree(l2, skb)) {
109162306a36Sopenharmony_ci		stop_t200(l2, 8);
109262306a36Sopenharmony_ci		lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
109362306a36Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
109462306a36Sopenharmony_ci		if (l2->tm)
109562306a36Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic void
110062306a36Sopenharmony_cienquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	struct sk_buff *skb;
110362306a36Sopenharmony_ci	u_char tmp[MAX_L2HEADER_LEN];
110462306a36Sopenharmony_ci	int i;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	i = sethdraddr(l2, tmp, cr);
110762306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
110862306a36Sopenharmony_ci		tmp[i++] = typ;
110962306a36Sopenharmony_ci		tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
111062306a36Sopenharmony_ci	} else
111162306a36Sopenharmony_ci		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
111262306a36Sopenharmony_ci	skb = mI_alloc_skb(i, GFP_ATOMIC);
111362306a36Sopenharmony_ci	if (!skb) {
111462306a36Sopenharmony_ci		printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n",
111562306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), __func__);
111662306a36Sopenharmony_ci		return;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci	skb_put_data(skb, tmp, i);
111962306a36Sopenharmony_ci	enqueue_super(l2, skb);
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ciinline void
112362306a36Sopenharmony_cienquiry_response(struct layer2 *l2)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	if (test_bit(FLG_OWN_BUSY, &l2->flag))
112662306a36Sopenharmony_ci		enquiry_cr(l2, RNR, RSP, 1);
112762306a36Sopenharmony_ci	else
112862306a36Sopenharmony_ci		enquiry_cr(l2, RR, RSP, 1);
112962306a36Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ciinline void
113362306a36Sopenharmony_citransmit_enquiry(struct layer2 *l2)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	if (test_bit(FLG_OWN_BUSY, &l2->flag))
113662306a36Sopenharmony_ci		enquiry_cr(l2, RNR, CMD, 1);
113762306a36Sopenharmony_ci	else
113862306a36Sopenharmony_ci		enquiry_cr(l2, RR, CMD, 1);
113962306a36Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
114062306a36Sopenharmony_ci	start_t200(l2, 9);
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic void
114562306a36Sopenharmony_cinrerrorrecovery(struct FsmInst *fi)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, (void *) 'J');
115062306a36Sopenharmony_ci	establishlink(fi);
115162306a36Sopenharmony_ci	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic void
115562306a36Sopenharmony_ciinvoke_retransmission(struct layer2 *l2, unsigned int nr)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	u_int	p1;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	if (l2->vs != nr) {
116062306a36Sopenharmony_ci		while (l2->vs != nr) {
116162306a36Sopenharmony_ci			(l2->vs)--;
116262306a36Sopenharmony_ci			if (test_bit(FLG_MOD128, &l2->flag)) {
116362306a36Sopenharmony_ci				l2->vs %= 128;
116462306a36Sopenharmony_ci				p1 = (l2->vs - l2->va) % 128;
116562306a36Sopenharmony_ci			} else {
116662306a36Sopenharmony_ci				l2->vs %= 8;
116762306a36Sopenharmony_ci				p1 = (l2->vs - l2->va) % 8;
116862306a36Sopenharmony_ci			}
116962306a36Sopenharmony_ci			p1 = (p1 + l2->sow) % l2->window;
117062306a36Sopenharmony_ci			if (l2->windowar[p1])
117162306a36Sopenharmony_ci				skb_queue_head(&l2->i_queue, l2->windowar[p1]);
117262306a36Sopenharmony_ci			else
117362306a36Sopenharmony_ci				printk(KERN_WARNING
117462306a36Sopenharmony_ci				       "%s: windowar[%d] is NULL\n",
117562306a36Sopenharmony_ci				       mISDNDevName4ch(&l2->ch), p1);
117662306a36Sopenharmony_ci			l2->windowar[p1] = NULL;
117762306a36Sopenharmony_ci		}
117862306a36Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic void
118362306a36Sopenharmony_cil2_st7_got_super(struct FsmInst *fi, int event, void *arg)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
118662306a36Sopenharmony_ci	struct sk_buff *skb = arg;
118762306a36Sopenharmony_ci	int PollFlag, rsp, typ = RR;
118862306a36Sopenharmony_ci	unsigned int nr;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	rsp = *skb->data & 0x2;
119162306a36Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
119262306a36Sopenharmony_ci		rsp = !rsp;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	skb_pull(skb, l2addrsize(l2));
119562306a36Sopenharmony_ci	if (IsRNR(skb->data, l2)) {
119662306a36Sopenharmony_ci		set_peer_busy(l2);
119762306a36Sopenharmony_ci		typ = RNR;
119862306a36Sopenharmony_ci	} else
119962306a36Sopenharmony_ci		clear_peer_busy(l2);
120062306a36Sopenharmony_ci	if (IsREJ(skb->data, l2))
120162306a36Sopenharmony_ci		typ = REJ;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
120462306a36Sopenharmony_ci		PollFlag = (skb->data[1] & 0x1) == 0x1;
120562306a36Sopenharmony_ci		nr = skb->data[1] >> 1;
120662306a36Sopenharmony_ci	} else {
120762306a36Sopenharmony_ci		PollFlag = (skb->data[0] & 0x10);
120862306a36Sopenharmony_ci		nr = (skb->data[0] >> 5) & 0x7;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci	dev_kfree_skb(skb);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (PollFlag) {
121362306a36Sopenharmony_ci		if (rsp)
121462306a36Sopenharmony_ci			l2mgr(l2, MDL_ERROR_IND, (void *) 'A');
121562306a36Sopenharmony_ci		else
121662306a36Sopenharmony_ci			enquiry_response(l2);
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci	if (legalnr(l2, nr)) {
121962306a36Sopenharmony_ci		if (typ == REJ) {
122062306a36Sopenharmony_ci			setva(l2, nr);
122162306a36Sopenharmony_ci			invoke_retransmission(l2, nr);
122262306a36Sopenharmony_ci			stop_t200(l2, 10);
122362306a36Sopenharmony_ci			if (mISDN_FsmAddTimer(&l2->t203, l2->T203,
122462306a36Sopenharmony_ci					      EV_L2_T203, NULL, 6))
122562306a36Sopenharmony_ci				l2m_debug(&l2->l2m, "Restart T203 ST7 REJ");
122662306a36Sopenharmony_ci		} else if ((nr == l2->vs) && (typ == RR)) {
122762306a36Sopenharmony_ci			setva(l2, nr);
122862306a36Sopenharmony_ci			stop_t200(l2, 11);
122962306a36Sopenharmony_ci			mISDN_FsmRestartTimer(&l2->t203, l2->T203,
123062306a36Sopenharmony_ci					      EV_L2_T203, NULL, 7);
123162306a36Sopenharmony_ci		} else if ((l2->va != nr) || (typ == RNR)) {
123262306a36Sopenharmony_ci			setva(l2, nr);
123362306a36Sopenharmony_ci			if (typ != RR)
123462306a36Sopenharmony_ci				mISDN_FsmDelTimer(&l2->t203, 9);
123562306a36Sopenharmony_ci			restart_t200(l2, 12);
123662306a36Sopenharmony_ci		}
123762306a36Sopenharmony_ci		if (skb_queue_len(&l2->i_queue) && (typ == RR))
123862306a36Sopenharmony_ci			mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
123962306a36Sopenharmony_ci	} else
124062306a36Sopenharmony_ci		nrerrorrecovery(fi);
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic void
124462306a36Sopenharmony_cil2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
124762306a36Sopenharmony_ci	struct sk_buff *skb = arg;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if (!test_bit(FLG_L3_INIT, &l2->flag))
125062306a36Sopenharmony_ci		skb_queue_tail(&l2->i_queue, skb);
125162306a36Sopenharmony_ci	else
125262306a36Sopenharmony_ci		dev_kfree_skb(skb);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic void
125662306a36Sopenharmony_cil2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
125962306a36Sopenharmony_ci	struct sk_buff *skb = arg;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	skb_queue_tail(&l2->i_queue, skb);
126262306a36Sopenharmony_ci	mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic void
126662306a36Sopenharmony_cil2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
126962306a36Sopenharmony_ci	struct sk_buff *skb = arg;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	skb_queue_tail(&l2->i_queue, skb);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic void
127562306a36Sopenharmony_cil2_got_iframe(struct FsmInst *fi, int event, void *arg)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
127862306a36Sopenharmony_ci	struct sk_buff	*skb = arg;
127962306a36Sopenharmony_ci	int		PollFlag, i;
128062306a36Sopenharmony_ci	u_int		ns, nr;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	i = l2addrsize(l2);
128362306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
128462306a36Sopenharmony_ci		PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
128562306a36Sopenharmony_ci		ns = skb->data[i] >> 1;
128662306a36Sopenharmony_ci		nr = (skb->data[i + 1] >> 1) & 0x7f;
128762306a36Sopenharmony_ci	} else {
128862306a36Sopenharmony_ci		PollFlag = (skb->data[i] & 0x10);
128962306a36Sopenharmony_ci		ns = (skb->data[i] >> 1) & 0x7;
129062306a36Sopenharmony_ci		nr = (skb->data[i] >> 5) & 0x7;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci	if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
129362306a36Sopenharmony_ci		dev_kfree_skb(skb);
129462306a36Sopenharmony_ci		if (PollFlag)
129562306a36Sopenharmony_ci			enquiry_response(l2);
129662306a36Sopenharmony_ci	} else {
129762306a36Sopenharmony_ci		if (l2->vr == ns) {
129862306a36Sopenharmony_ci			l2->vr++;
129962306a36Sopenharmony_ci			if (test_bit(FLG_MOD128, &l2->flag))
130062306a36Sopenharmony_ci				l2->vr %= 128;
130162306a36Sopenharmony_ci			else
130262306a36Sopenharmony_ci				l2->vr %= 8;
130362306a36Sopenharmony_ci			test_and_clear_bit(FLG_REJEXC, &l2->flag);
130462306a36Sopenharmony_ci			if (PollFlag)
130562306a36Sopenharmony_ci				enquiry_response(l2);
130662306a36Sopenharmony_ci			else
130762306a36Sopenharmony_ci				test_and_set_bit(FLG_ACK_PEND, &l2->flag);
130862306a36Sopenharmony_ci			skb_pull(skb, l2headersize(l2, 0));
130962306a36Sopenharmony_ci			l2up(l2, DL_DATA_IND, skb);
131062306a36Sopenharmony_ci		} else {
131162306a36Sopenharmony_ci			/* n(s)!=v(r) */
131262306a36Sopenharmony_ci			dev_kfree_skb(skb);
131362306a36Sopenharmony_ci			if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
131462306a36Sopenharmony_ci				if (PollFlag)
131562306a36Sopenharmony_ci					enquiry_response(l2);
131662306a36Sopenharmony_ci			} else {
131762306a36Sopenharmony_ci				enquiry_cr(l2, REJ, RSP, PollFlag);
131862306a36Sopenharmony_ci				test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
131962306a36Sopenharmony_ci			}
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci	if (legalnr(l2, nr)) {
132362306a36Sopenharmony_ci		if (!test_bit(FLG_PEER_BUSY, &l2->flag) &&
132462306a36Sopenharmony_ci		    (fi->state == ST_L2_7)) {
132562306a36Sopenharmony_ci			if (nr == l2->vs) {
132662306a36Sopenharmony_ci				stop_t200(l2, 13);
132762306a36Sopenharmony_ci				mISDN_FsmRestartTimer(&l2->t203, l2->T203,
132862306a36Sopenharmony_ci						      EV_L2_T203, NULL, 7);
132962306a36Sopenharmony_ci			} else if (nr != l2->va)
133062306a36Sopenharmony_ci				restart_t200(l2, 14);
133162306a36Sopenharmony_ci		}
133262306a36Sopenharmony_ci		setva(l2, nr);
133362306a36Sopenharmony_ci	} else {
133462306a36Sopenharmony_ci		nrerrorrecovery(fi);
133562306a36Sopenharmony_ci		return;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7))
133862306a36Sopenharmony_ci		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
133962306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag))
134062306a36Sopenharmony_ci		enquiry_cr(l2, RR, RSP, 0);
134162306a36Sopenharmony_ci}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_cistatic void
134462306a36Sopenharmony_cil2_got_tei(struct FsmInst *fi, int event, void *arg)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
134762306a36Sopenharmony_ci	u_int		info;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	l2->tei = (signed char)(long)arg;
135062306a36Sopenharmony_ci	set_channel_address(&l2->ch, l2->sapi, l2->tei);
135162306a36Sopenharmony_ci	info = DL_INFO_L2_CONNECT;
135262306a36Sopenharmony_ci	l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info);
135362306a36Sopenharmony_ci	if (fi->state == ST_L2_3) {
135462306a36Sopenharmony_ci		establishlink(fi);
135562306a36Sopenharmony_ci		test_and_set_bit(FLG_L3_INIT, &l2->flag);
135662306a36Sopenharmony_ci	} else
135762306a36Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
135862306a36Sopenharmony_ci	if (skb_queue_len(&l2->ui_queue))
135962306a36Sopenharmony_ci		tx_ui(l2);
136062306a36Sopenharmony_ci}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cistatic void
136362306a36Sopenharmony_cil2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
136862306a36Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
136962306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
137062306a36Sopenharmony_ci	} else if (l2->rc == l2->N200) {
137162306a36Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
137262306a36Sopenharmony_ci		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
137362306a36Sopenharmony_ci		skb_queue_purge(&l2->i_queue);
137462306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'G');
137562306a36Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
137662306a36Sopenharmony_ci			l2down_create(l2, PH_DEACTIVATE_REQ,
137762306a36Sopenharmony_ci				      l2_newid(l2), 0, NULL);
137862306a36Sopenharmony_ci		st5_dl_release_l2l3(l2);
137962306a36Sopenharmony_ci		if (l2->tm)
138062306a36Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
138162306a36Sopenharmony_ci	} else {
138262306a36Sopenharmony_ci		l2->rc++;
138362306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
138462306a36Sopenharmony_ci		send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ?
138562306a36Sopenharmony_ci				       SABME : SABM) | 0x10, CMD);
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic void
139062306a36Sopenharmony_cil2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
139562306a36Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
139662306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
139762306a36Sopenharmony_ci	} else if (l2->rc == l2->N200) {
139862306a36Sopenharmony_ci		mISDN_FsmChangeState(fi, ST_L2_4);
139962306a36Sopenharmony_ci		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
140062306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'H');
140162306a36Sopenharmony_ci		lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
140262306a36Sopenharmony_ci		if (l2->tm)
140362306a36Sopenharmony_ci			l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
140462306a36Sopenharmony_ci	} else {
140562306a36Sopenharmony_ci		l2->rc++;
140662306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200,
140762306a36Sopenharmony_ci				  NULL, 9);
140862306a36Sopenharmony_ci		send_uframe(l2, NULL, DISC | 0x10, CMD);
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void
141362306a36Sopenharmony_cil2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
141862306a36Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
141962306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
142062306a36Sopenharmony_ci		return;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
142362306a36Sopenharmony_ci	l2->rc = 0;
142462306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_8);
142562306a36Sopenharmony_ci	transmit_enquiry(l2);
142662306a36Sopenharmony_ci	l2->rc++;
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic void
143062306a36Sopenharmony_cil2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
143562306a36Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
143662306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
143762306a36Sopenharmony_ci		return;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
144062306a36Sopenharmony_ci	if (l2->rc == l2->N200) {
144162306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'I');
144262306a36Sopenharmony_ci		establishlink(fi);
144362306a36Sopenharmony_ci		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
144462306a36Sopenharmony_ci	} else {
144562306a36Sopenharmony_ci		transmit_enquiry(l2);
144662306a36Sopenharmony_ci		l2->rc++;
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_cistatic void
145162306a36Sopenharmony_cil2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag) &&
145662306a36Sopenharmony_ci	    test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
145762306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9);
145862306a36Sopenharmony_ci		return;
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_8);
146162306a36Sopenharmony_ci	transmit_enquiry(l2);
146262306a36Sopenharmony_ci	l2->rc = 0;
146362306a36Sopenharmony_ci}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cistatic void
146662306a36Sopenharmony_cil2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	struct layer2	*l2 = fi->userdata;
146962306a36Sopenharmony_ci	struct sk_buff	*skb, *nskb;
147062306a36Sopenharmony_ci	u_char		header[MAX_L2HEADER_LEN];
147162306a36Sopenharmony_ci	u_int		i, p1;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	if (!cansend(l2))
147462306a36Sopenharmony_ci		return;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	skb = skb_dequeue(&l2->i_queue);
147762306a36Sopenharmony_ci	if (!skb)
147862306a36Sopenharmony_ci		return;
147962306a36Sopenharmony_ci	i = sethdraddr(l2, header, CMD);
148062306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
148162306a36Sopenharmony_ci		header[i++] = l2->vs << 1;
148262306a36Sopenharmony_ci		header[i++] = l2->vr << 1;
148362306a36Sopenharmony_ci	} else
148462306a36Sopenharmony_ci		header[i++] = (l2->vr << 5) | (l2->vs << 1);
148562306a36Sopenharmony_ci	nskb = skb_realloc_headroom(skb, i);
148662306a36Sopenharmony_ci	if (!nskb) {
148762306a36Sopenharmony_ci		printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
148862306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), i);
148962306a36Sopenharmony_ci		skb_queue_head(&l2->i_queue, skb);
149062306a36Sopenharmony_ci		return;
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
149362306a36Sopenharmony_ci		p1 = (l2->vs - l2->va) % 128;
149462306a36Sopenharmony_ci		l2->vs = (l2->vs + 1) % 128;
149562306a36Sopenharmony_ci	} else {
149662306a36Sopenharmony_ci		p1 = (l2->vs - l2->va) % 8;
149762306a36Sopenharmony_ci		l2->vs = (l2->vs + 1) % 8;
149862306a36Sopenharmony_ci	}
149962306a36Sopenharmony_ci	p1 = (p1 + l2->sow) % l2->window;
150062306a36Sopenharmony_ci	if (l2->windowar[p1]) {
150162306a36Sopenharmony_ci		printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
150262306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), p1);
150362306a36Sopenharmony_ci		dev_kfree_skb(l2->windowar[p1]);
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci	l2->windowar[p1] = skb;
150662306a36Sopenharmony_ci	memcpy(skb_push(nskb, i), header, i);
150762306a36Sopenharmony_ci	l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
150862306a36Sopenharmony_ci	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
150962306a36Sopenharmony_ci	if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {
151062306a36Sopenharmony_ci		mISDN_FsmDelTimer(&l2->t203, 13);
151162306a36Sopenharmony_ci		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11);
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic void
151662306a36Sopenharmony_cil2_st8_got_super(struct FsmInst *fi, int event, void *arg)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
151962306a36Sopenharmony_ci	struct sk_buff *skb = arg;
152062306a36Sopenharmony_ci	int PollFlag, rsp, rnr = 0;
152162306a36Sopenharmony_ci	unsigned int nr;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	rsp = *skb->data & 0x2;
152462306a36Sopenharmony_ci	if (test_bit(FLG_ORIG, &l2->flag))
152562306a36Sopenharmony_ci		rsp = !rsp;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	skb_pull(skb, l2addrsize(l2));
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (IsRNR(skb->data, l2)) {
153062306a36Sopenharmony_ci		set_peer_busy(l2);
153162306a36Sopenharmony_ci		rnr = 1;
153262306a36Sopenharmony_ci	} else
153362306a36Sopenharmony_ci		clear_peer_busy(l2);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (test_bit(FLG_MOD128, &l2->flag)) {
153662306a36Sopenharmony_ci		PollFlag = (skb->data[1] & 0x1) == 0x1;
153762306a36Sopenharmony_ci		nr = skb->data[1] >> 1;
153862306a36Sopenharmony_ci	} else {
153962306a36Sopenharmony_ci		PollFlag = (skb->data[0] & 0x10);
154062306a36Sopenharmony_ci		nr = (skb->data[0] >> 5) & 0x7;
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci	dev_kfree_skb(skb);
154362306a36Sopenharmony_ci	if (rsp && PollFlag) {
154462306a36Sopenharmony_ci		if (legalnr(l2, nr)) {
154562306a36Sopenharmony_ci			if (rnr) {
154662306a36Sopenharmony_ci				restart_t200(l2, 15);
154762306a36Sopenharmony_ci			} else {
154862306a36Sopenharmony_ci				stop_t200(l2, 16);
154962306a36Sopenharmony_ci				mISDN_FsmAddTimer(&l2->t203, l2->T203,
155062306a36Sopenharmony_ci						  EV_L2_T203, NULL, 5);
155162306a36Sopenharmony_ci				setva(l2, nr);
155262306a36Sopenharmony_ci			}
155362306a36Sopenharmony_ci			invoke_retransmission(l2, nr);
155462306a36Sopenharmony_ci			mISDN_FsmChangeState(fi, ST_L2_7);
155562306a36Sopenharmony_ci			if (skb_queue_len(&l2->i_queue) && cansend(l2))
155662306a36Sopenharmony_ci				mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
155762306a36Sopenharmony_ci		} else
155862306a36Sopenharmony_ci			nrerrorrecovery(fi);
155962306a36Sopenharmony_ci	} else {
156062306a36Sopenharmony_ci		if (!rsp && PollFlag)
156162306a36Sopenharmony_ci			enquiry_response(l2);
156262306a36Sopenharmony_ci		if (legalnr(l2, nr))
156362306a36Sopenharmony_ci			setva(l2, nr);
156462306a36Sopenharmony_ci		else
156562306a36Sopenharmony_ci			nrerrorrecovery(fi);
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic void
157062306a36Sopenharmony_cil2_got_FRMR(struct FsmInst *fi, int event, void *arg)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
157362306a36Sopenharmony_ci	struct sk_buff *skb = arg;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	skb_pull(skb, l2addrsize(l2) + 1);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
157862306a36Sopenharmony_ci	    (IsUA(skb->data) && (fi->state == ST_L2_7))) {
157962306a36Sopenharmony_ci		l2mgr(l2, MDL_ERROR_IND, (void *) 'K');
158062306a36Sopenharmony_ci		establishlink(fi);
158162306a36Sopenharmony_ci		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci	dev_kfree_skb(skb);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_cistatic void
158762306a36Sopenharmony_cil2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
159262306a36Sopenharmony_ci	l2->tei = GROUP_TEI;
159362306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic void
159762306a36Sopenharmony_cil2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
159862306a36Sopenharmony_ci{
159962306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
160262306a36Sopenharmony_ci	l2->tei = GROUP_TEI;
160362306a36Sopenharmony_ci	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
160462306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic void
160862306a36Sopenharmony_cil2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
161362306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
161462306a36Sopenharmony_ci	freewin(l2);
161562306a36Sopenharmony_ci	l2->tei = GROUP_TEI;
161662306a36Sopenharmony_ci	stop_t200(l2, 17);
161762306a36Sopenharmony_ci	st5_dl_release_l2l3(l2);
161862306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic void
162262306a36Sopenharmony_cil2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
162362306a36Sopenharmony_ci{
162462306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
162762306a36Sopenharmony_ci	l2->tei = GROUP_TEI;
162862306a36Sopenharmony_ci	stop_t200(l2, 18);
162962306a36Sopenharmony_ci	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
163062306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic void
163462306a36Sopenharmony_cil2_tei_remove(struct FsmInst *fi, int event, void *arg)
163562306a36Sopenharmony_ci{
163662306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
163962306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
164062306a36Sopenharmony_ci	freewin(l2);
164162306a36Sopenharmony_ci	l2->tei = GROUP_TEI;
164262306a36Sopenharmony_ci	stop_t200(l2, 17);
164362306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 19);
164462306a36Sopenharmony_ci	l2up_create(l2, DL_RELEASE_IND, 0, NULL);
164562306a36Sopenharmony_ci/*	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
164662306a36Sopenharmony_ci *		MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED,
164762306a36Sopenharmony_ci *		0, NULL, 0);
164862306a36Sopenharmony_ci */
164962306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_1);
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_cistatic void
165362306a36Sopenharmony_cil2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
165662306a36Sopenharmony_ci	struct sk_buff *skb = arg;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
165962306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
166062306a36Sopenharmony_ci	if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
166162306a36Sopenharmony_ci		l2up(l2, DL_RELEASE_IND, skb);
166262306a36Sopenharmony_ci	else
166362306a36Sopenharmony_ci		dev_kfree_skb(skb);
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cistatic void
166762306a36Sopenharmony_cil2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
167062306a36Sopenharmony_ci	struct sk_buff *skb = arg;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
167362306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
167462306a36Sopenharmony_ci	freewin(l2);
167562306a36Sopenharmony_ci	stop_t200(l2, 19);
167662306a36Sopenharmony_ci	st5_dl_release_l2l3(l2);
167762306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
167862306a36Sopenharmony_ci	if (l2->tm)
167962306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
168062306a36Sopenharmony_ci	dev_kfree_skb(skb);
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistatic void
168462306a36Sopenharmony_cil2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
168762306a36Sopenharmony_ci	struct sk_buff *skb = arg;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
169062306a36Sopenharmony_ci	stop_t200(l2, 20);
169162306a36Sopenharmony_ci	l2up(l2, DL_RELEASE_CNF, skb);
169262306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
169362306a36Sopenharmony_ci	if (l2->tm)
169462306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistatic void
169862306a36Sopenharmony_cil2_persistent_da(struct FsmInst *fi, int event, void *arg)
169962306a36Sopenharmony_ci{
170062306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
170162306a36Sopenharmony_ci	struct sk_buff *skb = arg;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
170462306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
170562306a36Sopenharmony_ci	freewin(l2);
170662306a36Sopenharmony_ci	stop_t200(l2, 19);
170762306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 19);
170862306a36Sopenharmony_ci	l2up(l2, DL_RELEASE_IND, skb);
170962306a36Sopenharmony_ci	mISDN_FsmChangeState(fi, ST_L2_4);
171062306a36Sopenharmony_ci	if (l2->tm)
171162306a36Sopenharmony_ci		l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic void
171562306a36Sopenharmony_cil2_set_own_busy(struct FsmInst *fi, int event, void *arg)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
171862306a36Sopenharmony_ci	struct sk_buff *skb = arg;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) {
172162306a36Sopenharmony_ci		enquiry_cr(l2, RNR, RSP, 0);
172262306a36Sopenharmony_ci		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
172362306a36Sopenharmony_ci	}
172462306a36Sopenharmony_ci	dev_kfree_skb(skb);
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic void
172862306a36Sopenharmony_cil2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
173162306a36Sopenharmony_ci	struct sk_buff *skb = arg;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) {
173462306a36Sopenharmony_ci		enquiry_cr(l2, RR, RSP, 0);
173562306a36Sopenharmony_ci		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci	dev_kfree_skb(skb);
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic void
174162306a36Sopenharmony_cil2_frame_error(struct FsmInst *fi, int event, void *arg)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, arg);
174662306a36Sopenharmony_ci}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_cistatic void
174962306a36Sopenharmony_cil2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	struct layer2 *l2 = fi->userdata;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	l2mgr(l2, MDL_ERROR_IND, arg);
175462306a36Sopenharmony_ci	establishlink(fi);
175562306a36Sopenharmony_ci	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
175662306a36Sopenharmony_ci}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_cistatic struct FsmNode L2FnList[] =
175962306a36Sopenharmony_ci{
176062306a36Sopenharmony_ci	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
176162306a36Sopenharmony_ci	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
176262306a36Sopenharmony_ci	{ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
176362306a36Sopenharmony_ci	{ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
176462306a36Sopenharmony_ci	{ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
176562306a36Sopenharmony_ci	{ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
176662306a36Sopenharmony_ci	{ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
176762306a36Sopenharmony_ci	{ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
176862306a36Sopenharmony_ci	{ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
176962306a36Sopenharmony_ci	{ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
177062306a36Sopenharmony_ci	{ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
177162306a36Sopenharmony_ci	{ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
177262306a36Sopenharmony_ci	{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
177362306a36Sopenharmony_ci	{ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign},
177462306a36Sopenharmony_ci	{ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui},
177562306a36Sopenharmony_ci	{ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui},
177662306a36Sopenharmony_ci	{ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui},
177762306a36Sopenharmony_ci	{ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui},
177862306a36Sopenharmony_ci	{ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui},
177962306a36Sopenharmony_ci	{ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui},
178062306a36Sopenharmony_ci	{ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui},
178162306a36Sopenharmony_ci	{ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
178262306a36Sopenharmony_ci	{ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
178362306a36Sopenharmony_ci	{ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
178462306a36Sopenharmony_ci	{ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
178562306a36Sopenharmony_ci	{ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
178662306a36Sopenharmony_ci	{ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
178762306a36Sopenharmony_ci	{ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
178862306a36Sopenharmony_ci	{ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
178962306a36Sopenharmony_ci	{ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
179062306a36Sopenharmony_ci	{ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
179162306a36Sopenharmony_ci	{ST_L2_4, EV_L2_SABME, l2_start_multi},
179262306a36Sopenharmony_ci	{ST_L2_5, EV_L2_SABME, l2_send_UA},
179362306a36Sopenharmony_ci	{ST_L2_6, EV_L2_SABME, l2_send_DM},
179462306a36Sopenharmony_ci	{ST_L2_7, EV_L2_SABME, l2_restart_multi},
179562306a36Sopenharmony_ci	{ST_L2_8, EV_L2_SABME, l2_restart_multi},
179662306a36Sopenharmony_ci	{ST_L2_4, EV_L2_DISC, l2_send_DM},
179762306a36Sopenharmony_ci	{ST_L2_5, EV_L2_DISC, l2_send_DM},
179862306a36Sopenharmony_ci	{ST_L2_6, EV_L2_DISC, l2_send_UA},
179962306a36Sopenharmony_ci	{ST_L2_7, EV_L2_DISC, l2_stop_multi},
180062306a36Sopenharmony_ci	{ST_L2_8, EV_L2_DISC, l2_stop_multi},
180162306a36Sopenharmony_ci	{ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
180262306a36Sopenharmony_ci	{ST_L2_5, EV_L2_UA, l2_connected},
180362306a36Sopenharmony_ci	{ST_L2_6, EV_L2_UA, l2_released},
180462306a36Sopenharmony_ci	{ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
180562306a36Sopenharmony_ci	{ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
180662306a36Sopenharmony_ci	{ST_L2_4, EV_L2_DM, l2_reestablish},
180762306a36Sopenharmony_ci	{ST_L2_5, EV_L2_DM, l2_st5_dm_release},
180862306a36Sopenharmony_ci	{ST_L2_6, EV_L2_DM, l2_st6_dm_release},
180962306a36Sopenharmony_ci	{ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
181062306a36Sopenharmony_ci	{ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
181162306a36Sopenharmony_ci	{ST_L2_1, EV_L2_UI, l2_got_ui},
181262306a36Sopenharmony_ci	{ST_L2_2, EV_L2_UI, l2_got_ui},
181362306a36Sopenharmony_ci	{ST_L2_3, EV_L2_UI, l2_got_ui},
181462306a36Sopenharmony_ci	{ST_L2_4, EV_L2_UI, l2_got_ui},
181562306a36Sopenharmony_ci	{ST_L2_5, EV_L2_UI, l2_got_ui},
181662306a36Sopenharmony_ci	{ST_L2_6, EV_L2_UI, l2_got_ui},
181762306a36Sopenharmony_ci	{ST_L2_7, EV_L2_UI, l2_got_ui},
181862306a36Sopenharmony_ci	{ST_L2_8, EV_L2_UI, l2_got_ui},
181962306a36Sopenharmony_ci	{ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
182062306a36Sopenharmony_ci	{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
182162306a36Sopenharmony_ci	{ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
182262306a36Sopenharmony_ci	{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
182362306a36Sopenharmony_ci	{ST_L2_7, EV_L2_I, l2_got_iframe},
182462306a36Sopenharmony_ci	{ST_L2_8, EV_L2_I, l2_got_iframe},
182562306a36Sopenharmony_ci	{ST_L2_5, EV_L2_T200, l2_timeout},
182662306a36Sopenharmony_ci	{ST_L2_6, EV_L2_T200, l2_timeout},
182762306a36Sopenharmony_ci	{ST_L2_7, EV_L2_T200, l2_timeout},
182862306a36Sopenharmony_ci	{ST_L2_8, EV_L2_T200, l2_timeout},
182962306a36Sopenharmony_ci	{ST_L2_7, EV_L2_T203, l2_timeout},
183062306a36Sopenharmony_ci	{ST_L2_5, EV_L2_T200I, l2_st5_tout_200},
183162306a36Sopenharmony_ci	{ST_L2_6, EV_L2_T200I, l2_st6_tout_200},
183262306a36Sopenharmony_ci	{ST_L2_7, EV_L2_T200I, l2_st7_tout_200},
183362306a36Sopenharmony_ci	{ST_L2_8, EV_L2_T200I, l2_st8_tout_200},
183462306a36Sopenharmony_ci	{ST_L2_7, EV_L2_T203I, l2_st7_tout_203},
183562306a36Sopenharmony_ci	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
183662306a36Sopenharmony_ci	{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
183762306a36Sopenharmony_ci	{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
183862306a36Sopenharmony_ci	{ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
183962306a36Sopenharmony_ci	{ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
184062306a36Sopenharmony_ci	{ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
184162306a36Sopenharmony_ci	{ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
184262306a36Sopenharmony_ci	{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
184362306a36Sopenharmony_ci	{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
184462306a36Sopenharmony_ci	{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
184562306a36Sopenharmony_ci	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
184662306a36Sopenharmony_ci	{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
184762306a36Sopenharmony_ci	{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
184862306a36Sopenharmony_ci	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
184962306a36Sopenharmony_ci	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
185062306a36Sopenharmony_ci	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
185162306a36Sopenharmony_ci	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
185262306a36Sopenharmony_ci	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
185362306a36Sopenharmony_ci};
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_cistatic int
185662306a36Sopenharmony_ciph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	u_char	*datap = skb->data;
185962306a36Sopenharmony_ci	int	ret = -EINVAL;
186062306a36Sopenharmony_ci	int	psapi, ptei;
186162306a36Sopenharmony_ci	u_int	l;
186262306a36Sopenharmony_ci	int	c = 0;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	l = l2addrsize(l2);
186562306a36Sopenharmony_ci	if (skb->len <= l) {
186662306a36Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N');
186762306a36Sopenharmony_ci		return ret;
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */
187062306a36Sopenharmony_ci		psapi = *datap++;
187162306a36Sopenharmony_ci		ptei = *datap++;
187262306a36Sopenharmony_ci		if ((psapi & 1) || !(ptei & 1)) {
187362306a36Sopenharmony_ci			printk(KERN_WARNING
187462306a36Sopenharmony_ci			       "%s l2 D-channel frame wrong EA0/EA1\n",
187562306a36Sopenharmony_ci			       mISDNDevName4ch(&l2->ch));
187662306a36Sopenharmony_ci			return ret;
187762306a36Sopenharmony_ci		}
187862306a36Sopenharmony_ci		psapi >>= 2;
187962306a36Sopenharmony_ci		ptei >>= 1;
188062306a36Sopenharmony_ci		if (psapi != l2->sapi) {
188162306a36Sopenharmony_ci			/* not our business */
188262306a36Sopenharmony_ci			if (*debug & DEBUG_L2)
188362306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
188462306a36Sopenharmony_ci				       mISDNDevName4ch(&l2->ch), psapi,
188562306a36Sopenharmony_ci				       l2->sapi);
188662306a36Sopenharmony_ci			dev_kfree_skb(skb);
188762306a36Sopenharmony_ci			return 0;
188862306a36Sopenharmony_ci		}
188962306a36Sopenharmony_ci		if ((ptei != l2->tei) && (ptei != GROUP_TEI)) {
189062306a36Sopenharmony_ci			/* not our business */
189162306a36Sopenharmony_ci			if (*debug & DEBUG_L2)
189262306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
189362306a36Sopenharmony_ci				       mISDNDevName4ch(&l2->ch), ptei, l2->tei);
189462306a36Sopenharmony_ci			dev_kfree_skb(skb);
189562306a36Sopenharmony_ci			return 0;
189662306a36Sopenharmony_ci		}
189762306a36Sopenharmony_ci	} else
189862306a36Sopenharmony_ci		datap += l;
189962306a36Sopenharmony_ci	if (!(*datap & 1)) {	/* I-Frame */
190062306a36Sopenharmony_ci		c = iframe_error(l2, skb);
190162306a36Sopenharmony_ci		if (!c)
190262306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb);
190362306a36Sopenharmony_ci	} else if (IsSFrame(datap, l2)) {	/* S-Frame */
190462306a36Sopenharmony_ci		c = super_error(l2, skb);
190562306a36Sopenharmony_ci		if (!c)
190662306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb);
190762306a36Sopenharmony_ci	} else if (IsUI(datap)) {
190862306a36Sopenharmony_ci		c = UI_error(l2, skb);
190962306a36Sopenharmony_ci		if (!c)
191062306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb);
191162306a36Sopenharmony_ci	} else if (IsSABME(datap, l2)) {
191262306a36Sopenharmony_ci		c = unnum_error(l2, skb, CMD);
191362306a36Sopenharmony_ci		if (!c)
191462306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb);
191562306a36Sopenharmony_ci	} else if (IsUA(datap)) {
191662306a36Sopenharmony_ci		c = unnum_error(l2, skb, RSP);
191762306a36Sopenharmony_ci		if (!c)
191862306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb);
191962306a36Sopenharmony_ci	} else if (IsDISC(datap)) {
192062306a36Sopenharmony_ci		c = unnum_error(l2, skb, CMD);
192162306a36Sopenharmony_ci		if (!c)
192262306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb);
192362306a36Sopenharmony_ci	} else if (IsDM(datap)) {
192462306a36Sopenharmony_ci		c = unnum_error(l2, skb, RSP);
192562306a36Sopenharmony_ci		if (!c)
192662306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb);
192762306a36Sopenharmony_ci	} else if (IsFRMR(datap)) {
192862306a36Sopenharmony_ci		c = FRMR_error(l2, skb);
192962306a36Sopenharmony_ci		if (!c)
193062306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb);
193162306a36Sopenharmony_ci	} else
193262306a36Sopenharmony_ci		c = 'L';
193362306a36Sopenharmony_ci	if (c) {
193462306a36Sopenharmony_ci		printk(KERN_WARNING "%s:l2 D-channel frame error %c\n",
193562306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), c);
193662306a36Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci	return ret;
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_cistatic int
194262306a36Sopenharmony_cil2_send(struct mISDNchannel *ch, struct sk_buff *skb)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	struct layer2		*l2 = container_of(ch, struct layer2, ch);
194562306a36Sopenharmony_ci	struct mISDNhead	*hh =  mISDN_HEAD_P(skb);
194662306a36Sopenharmony_ci	int			ret = -EINVAL;
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	if (*debug & DEBUG_L2_RECV)
194962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n",
195062306a36Sopenharmony_ci		       __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id,
195162306a36Sopenharmony_ci		       l2->sapi, l2->tei);
195262306a36Sopenharmony_ci	if (hh->prim == DL_INTERN_MSG) {
195362306a36Sopenharmony_ci		struct mISDNhead *chh = hh + 1; /* saved copy */
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		*hh = *chh;
195662306a36Sopenharmony_ci		if (*debug & DEBUG_L2_RECV)
195762306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
195862306a36Sopenharmony_ci				mISDNDevName4ch(&l2->ch), hh->prim, hh->id);
195962306a36Sopenharmony_ci	}
196062306a36Sopenharmony_ci	switch (hh->prim) {
196162306a36Sopenharmony_ci	case PH_DATA_IND:
196262306a36Sopenharmony_ci		ret = ph_data_indication(l2, hh, skb);
196362306a36Sopenharmony_ci		break;
196462306a36Sopenharmony_ci	case PH_DATA_CNF:
196562306a36Sopenharmony_ci		ret = ph_data_confirm(l2, hh, skb);
196662306a36Sopenharmony_ci		break;
196762306a36Sopenharmony_ci	case PH_ACTIVATE_IND:
196862306a36Sopenharmony_ci		test_and_set_bit(FLG_L1_ACTIV, &l2->flag);
196962306a36Sopenharmony_ci		l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL);
197062306a36Sopenharmony_ci		if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
197162306a36Sopenharmony_ci			ret = mISDN_FsmEvent(&l2->l2m,
197262306a36Sopenharmony_ci					     EV_L2_DL_ESTABLISH_REQ, skb);
197362306a36Sopenharmony_ci		break;
197462306a36Sopenharmony_ci	case PH_DEACTIVATE_IND:
197562306a36Sopenharmony_ci		test_and_clear_bit(FLG_L1_ACTIV, &l2->flag);
197662306a36Sopenharmony_ci		l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL);
197762306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb);
197862306a36Sopenharmony_ci		break;
197962306a36Sopenharmony_ci	case MPH_INFORMATION_IND:
198062306a36Sopenharmony_ci		if (!l2->up)
198162306a36Sopenharmony_ci			break;
198262306a36Sopenharmony_ci		ret = l2->up->send(l2->up, skb);
198362306a36Sopenharmony_ci		break;
198462306a36Sopenharmony_ci	case DL_DATA_REQ:
198562306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb);
198662306a36Sopenharmony_ci		break;
198762306a36Sopenharmony_ci	case DL_UNITDATA_REQ:
198862306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb);
198962306a36Sopenharmony_ci		break;
199062306a36Sopenharmony_ci	case DL_ESTABLISH_REQ:
199162306a36Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
199262306a36Sopenharmony_ci			test_and_set_bit(FLG_ORIG, &l2->flag);
199362306a36Sopenharmony_ci		if (test_bit(FLG_L1_ACTIV, &l2->flag)) {
199462306a36Sopenharmony_ci			if (test_bit(FLG_LAPD, &l2->flag) ||
199562306a36Sopenharmony_ci			    test_bit(FLG_ORIG, &l2->flag))
199662306a36Sopenharmony_ci				ret = mISDN_FsmEvent(&l2->l2m,
199762306a36Sopenharmony_ci						     EV_L2_DL_ESTABLISH_REQ, skb);
199862306a36Sopenharmony_ci		} else {
199962306a36Sopenharmony_ci			if (test_bit(FLG_LAPD, &l2->flag) ||
200062306a36Sopenharmony_ci			    test_bit(FLG_ORIG, &l2->flag)) {
200162306a36Sopenharmony_ci				test_and_set_bit(FLG_ESTAB_PEND,
200262306a36Sopenharmony_ci						 &l2->flag);
200362306a36Sopenharmony_ci			}
200462306a36Sopenharmony_ci			ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2),
200562306a36Sopenharmony_ci				     skb);
200662306a36Sopenharmony_ci		}
200762306a36Sopenharmony_ci		break;
200862306a36Sopenharmony_ci	case DL_RELEASE_REQ:
200962306a36Sopenharmony_ci		if (test_bit(FLG_LAPB, &l2->flag))
201062306a36Sopenharmony_ci			l2down_create(l2, PH_DEACTIVATE_REQ,
201162306a36Sopenharmony_ci				      l2_newid(l2), 0, NULL);
201262306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ,
201362306a36Sopenharmony_ci				     skb);
201462306a36Sopenharmony_ci		break;
201562306a36Sopenharmony_ci	case DL_TIMER200_IND:
201662306a36Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL);
201762306a36Sopenharmony_ci		break;
201862306a36Sopenharmony_ci	case DL_TIMER203_IND:
201962306a36Sopenharmony_ci		mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL);
202062306a36Sopenharmony_ci		break;
202162306a36Sopenharmony_ci	default:
202262306a36Sopenharmony_ci		if (*debug & DEBUG_L2)
202362306a36Sopenharmony_ci			l2m_debug(&l2->l2m, "l2 unknown pr %04x",
202462306a36Sopenharmony_ci				  hh->prim);
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci	if (ret) {
202762306a36Sopenharmony_ci		dev_kfree_skb(skb);
202862306a36Sopenharmony_ci		ret = 0;
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci	return ret;
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ciint
203462306a36Sopenharmony_citei_l2(struct layer2 *l2, u_int cmd, u_long arg)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	int		ret = -EINVAL;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	if (*debug & DEBUG_L2_TEI)
203962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd(%x) in %s\n",
204062306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch), cmd, __func__);
204162306a36Sopenharmony_ci	switch (cmd) {
204262306a36Sopenharmony_ci	case (MDL_ASSIGN_REQ):
204362306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg);
204462306a36Sopenharmony_ci		break;
204562306a36Sopenharmony_ci	case (MDL_REMOVE_REQ):
204662306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL);
204762306a36Sopenharmony_ci		break;
204862306a36Sopenharmony_ci	case (MDL_ERROR_IND):
204962306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
205062306a36Sopenharmony_ci		break;
205162306a36Sopenharmony_ci	case (MDL_ERROR_RSP):
205262306a36Sopenharmony_ci		/* ETS 300-125 5.3.2.1 Test: TC13010 */
205362306a36Sopenharmony_ci		printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n",
205462306a36Sopenharmony_ci		       mISDNDevName4ch(&l2->ch));
205562306a36Sopenharmony_ci		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
205662306a36Sopenharmony_ci		break;
205762306a36Sopenharmony_ci	}
205862306a36Sopenharmony_ci	return ret;
205962306a36Sopenharmony_ci}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cistatic void
206262306a36Sopenharmony_cirelease_l2(struct layer2 *l2)
206362306a36Sopenharmony_ci{
206462306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t200, 21);
206562306a36Sopenharmony_ci	mISDN_FsmDelTimer(&l2->t203, 16);
206662306a36Sopenharmony_ci	skb_queue_purge(&l2->i_queue);
206762306a36Sopenharmony_ci	skb_queue_purge(&l2->ui_queue);
206862306a36Sopenharmony_ci	skb_queue_purge(&l2->down_queue);
206962306a36Sopenharmony_ci	ReleaseWin(l2);
207062306a36Sopenharmony_ci	if (test_bit(FLG_LAPD, &l2->flag)) {
207162306a36Sopenharmony_ci		TEIrelease(l2);
207262306a36Sopenharmony_ci		if (l2->ch.st)
207362306a36Sopenharmony_ci			l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
207462306a36Sopenharmony_ci					       CLOSE_CHANNEL, NULL);
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci	kfree(l2);
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_cistatic int
208062306a36Sopenharmony_cil2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	struct layer2		*l2 = container_of(ch, struct layer2, ch);
208362306a36Sopenharmony_ci	u_int			info;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	if (*debug & DEBUG_L2_CTRL)
208662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: %s cmd(%x)\n",
208762306a36Sopenharmony_ci		       mISDNDevName4ch(ch), __func__, cmd);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	switch (cmd) {
209062306a36Sopenharmony_ci	case OPEN_CHANNEL:
209162306a36Sopenharmony_ci		if (test_bit(FLG_LAPD, &l2->flag)) {
209262306a36Sopenharmony_ci			set_channel_address(&l2->ch, l2->sapi, l2->tei);
209362306a36Sopenharmony_ci			info = DL_INFO_L2_CONNECT;
209462306a36Sopenharmony_ci			l2up_create(l2, DL_INFORMATION_IND,
209562306a36Sopenharmony_ci				    sizeof(info), &info);
209662306a36Sopenharmony_ci		}
209762306a36Sopenharmony_ci		break;
209862306a36Sopenharmony_ci	case CLOSE_CHANNEL:
209962306a36Sopenharmony_ci		if (l2->ch.peer)
210062306a36Sopenharmony_ci			l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL);
210162306a36Sopenharmony_ci		release_l2(l2);
210262306a36Sopenharmony_ci		break;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci	return 0;
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_cistruct layer2 *
210862306a36Sopenharmony_cicreate_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
210962306a36Sopenharmony_ci	  int sapi)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	struct layer2		*l2;
211262306a36Sopenharmony_ci	struct channel_req	rq;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL);
211562306a36Sopenharmony_ci	if (!l2) {
211662306a36Sopenharmony_ci		printk(KERN_ERR "kzalloc layer2 failed\n");
211762306a36Sopenharmony_ci		return NULL;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci	l2->next_id = 1;
212062306a36Sopenharmony_ci	l2->down_id = MISDN_ID_NONE;
212162306a36Sopenharmony_ci	l2->up = ch;
212262306a36Sopenharmony_ci	l2->ch.st = ch->st;
212362306a36Sopenharmony_ci	l2->ch.send = l2_send;
212462306a36Sopenharmony_ci	l2->ch.ctrl = l2_ctrl;
212562306a36Sopenharmony_ci	switch (protocol) {
212662306a36Sopenharmony_ci	case ISDN_P_LAPD_NT:
212762306a36Sopenharmony_ci		test_and_set_bit(FLG_LAPD, &l2->flag);
212862306a36Sopenharmony_ci		test_and_set_bit(FLG_LAPD_NET, &l2->flag);
212962306a36Sopenharmony_ci		test_and_set_bit(FLG_MOD128, &l2->flag);
213062306a36Sopenharmony_ci		l2->sapi = sapi;
213162306a36Sopenharmony_ci		l2->maxlen = MAX_DFRAME_LEN;
213262306a36Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
213362306a36Sopenharmony_ci			l2->window = 7;
213462306a36Sopenharmony_ci		else
213562306a36Sopenharmony_ci			l2->window = 1;
213662306a36Sopenharmony_ci		if (test_bit(OPTION_L2_PTP, &options))
213762306a36Sopenharmony_ci			test_and_set_bit(FLG_PTP, &l2->flag);
213862306a36Sopenharmony_ci		if (test_bit(OPTION_L2_FIXEDTEI, &options))
213962306a36Sopenharmony_ci			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
214062306a36Sopenharmony_ci		l2->tei = tei;
214162306a36Sopenharmony_ci		l2->T200 = 1000;
214262306a36Sopenharmony_ci		l2->N200 = 3;
214362306a36Sopenharmony_ci		l2->T203 = 10000;
214462306a36Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
214562306a36Sopenharmony_ci			rq.protocol = ISDN_P_NT_E1;
214662306a36Sopenharmony_ci		else
214762306a36Sopenharmony_ci			rq.protocol = ISDN_P_NT_S0;
214862306a36Sopenharmony_ci		rq.adr.channel = 0;
214962306a36Sopenharmony_ci		l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
215062306a36Sopenharmony_ci		break;
215162306a36Sopenharmony_ci	case ISDN_P_LAPD_TE:
215262306a36Sopenharmony_ci		test_and_set_bit(FLG_LAPD, &l2->flag);
215362306a36Sopenharmony_ci		test_and_set_bit(FLG_MOD128, &l2->flag);
215462306a36Sopenharmony_ci		test_and_set_bit(FLG_ORIG, &l2->flag);
215562306a36Sopenharmony_ci		l2->sapi = sapi;
215662306a36Sopenharmony_ci		l2->maxlen = MAX_DFRAME_LEN;
215762306a36Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
215862306a36Sopenharmony_ci			l2->window = 7;
215962306a36Sopenharmony_ci		else
216062306a36Sopenharmony_ci			l2->window = 1;
216162306a36Sopenharmony_ci		if (test_bit(OPTION_L2_PTP, &options))
216262306a36Sopenharmony_ci			test_and_set_bit(FLG_PTP, &l2->flag);
216362306a36Sopenharmony_ci		if (test_bit(OPTION_L2_FIXEDTEI, &options))
216462306a36Sopenharmony_ci			test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
216562306a36Sopenharmony_ci		l2->tei = tei;
216662306a36Sopenharmony_ci		l2->T200 = 1000;
216762306a36Sopenharmony_ci		l2->N200 = 3;
216862306a36Sopenharmony_ci		l2->T203 = 10000;
216962306a36Sopenharmony_ci		if (test_bit(OPTION_L2_PMX, &options))
217062306a36Sopenharmony_ci			rq.protocol = ISDN_P_TE_E1;
217162306a36Sopenharmony_ci		else
217262306a36Sopenharmony_ci			rq.protocol = ISDN_P_TE_S0;
217362306a36Sopenharmony_ci		rq.adr.channel = 0;
217462306a36Sopenharmony_ci		l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
217562306a36Sopenharmony_ci		break;
217662306a36Sopenharmony_ci	case ISDN_P_B_X75SLP:
217762306a36Sopenharmony_ci		test_and_set_bit(FLG_LAPB, &l2->flag);
217862306a36Sopenharmony_ci		l2->window = 7;
217962306a36Sopenharmony_ci		l2->maxlen = MAX_DATA_SIZE;
218062306a36Sopenharmony_ci		l2->T200 = 1000;
218162306a36Sopenharmony_ci		l2->N200 = 4;
218262306a36Sopenharmony_ci		l2->T203 = 5000;
218362306a36Sopenharmony_ci		l2->addr.A = 3;
218462306a36Sopenharmony_ci		l2->addr.B = 1;
218562306a36Sopenharmony_ci		break;
218662306a36Sopenharmony_ci	default:
218762306a36Sopenharmony_ci		printk(KERN_ERR "layer2 create failed prt %x\n",
218862306a36Sopenharmony_ci		       protocol);
218962306a36Sopenharmony_ci		kfree(l2);
219062306a36Sopenharmony_ci		return NULL;
219162306a36Sopenharmony_ci	}
219262306a36Sopenharmony_ci	skb_queue_head_init(&l2->i_queue);
219362306a36Sopenharmony_ci	skb_queue_head_init(&l2->ui_queue);
219462306a36Sopenharmony_ci	skb_queue_head_init(&l2->down_queue);
219562306a36Sopenharmony_ci	skb_queue_head_init(&l2->tmp_queue);
219662306a36Sopenharmony_ci	InitWin(l2);
219762306a36Sopenharmony_ci	l2->l2m.fsm = &l2fsm;
219862306a36Sopenharmony_ci	if (test_bit(FLG_LAPB, &l2->flag) ||
219962306a36Sopenharmony_ci	    test_bit(FLG_FIXED_TEI, &l2->flag) ||
220062306a36Sopenharmony_ci	    test_bit(FLG_LAPD_NET, &l2->flag))
220162306a36Sopenharmony_ci		l2->l2m.state = ST_L2_4;
220262306a36Sopenharmony_ci	else
220362306a36Sopenharmony_ci		l2->l2m.state = ST_L2_1;
220462306a36Sopenharmony_ci	l2->l2m.debug = *debug;
220562306a36Sopenharmony_ci	l2->l2m.userdata = l2;
220662306a36Sopenharmony_ci	l2->l2m.userint = 0;
220762306a36Sopenharmony_ci	l2->l2m.printdebug = l2m_debug;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	mISDN_FsmInitTimer(&l2->l2m, &l2->t200);
221062306a36Sopenharmony_ci	mISDN_FsmInitTimer(&l2->l2m, &l2->t203);
221162306a36Sopenharmony_ci	return l2;
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic int
221562306a36Sopenharmony_cix75create(struct channel_req *crq)
221662306a36Sopenharmony_ci{
221762306a36Sopenharmony_ci	struct layer2	*l2;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (crq->protocol != ISDN_P_B_X75SLP)
222062306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
222162306a36Sopenharmony_ci	l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0);
222262306a36Sopenharmony_ci	if (!l2)
222362306a36Sopenharmony_ci		return -ENOMEM;
222462306a36Sopenharmony_ci	crq->ch = &l2->ch;
222562306a36Sopenharmony_ci	crq->protocol = ISDN_P_B_HDLC;
222662306a36Sopenharmony_ci	return 0;
222762306a36Sopenharmony_ci}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_cistatic struct Bprotocol X75SLP = {
223062306a36Sopenharmony_ci	.Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)),
223162306a36Sopenharmony_ci	.name = "X75SLP",
223262306a36Sopenharmony_ci	.create = x75create
223362306a36Sopenharmony_ci};
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ciint
223662306a36Sopenharmony_ciIsdnl2_Init(u_int *deb)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	int res;
223962306a36Sopenharmony_ci	debug = deb;
224062306a36Sopenharmony_ci	mISDN_register_Bprotocol(&X75SLP);
224162306a36Sopenharmony_ci	l2fsm.state_count = L2_STATE_COUNT;
224262306a36Sopenharmony_ci	l2fsm.event_count = L2_EVENT_COUNT;
224362306a36Sopenharmony_ci	l2fsm.strEvent = strL2Event;
224462306a36Sopenharmony_ci	l2fsm.strState = strL2State;
224562306a36Sopenharmony_ci	res = mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
224662306a36Sopenharmony_ci	if (res)
224762306a36Sopenharmony_ci		goto error;
224862306a36Sopenharmony_ci	res = TEIInit(deb);
224962306a36Sopenharmony_ci	if (res)
225062306a36Sopenharmony_ci		goto error_fsm;
225162306a36Sopenharmony_ci	return 0;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_cierror_fsm:
225462306a36Sopenharmony_ci	mISDN_FsmFree(&l2fsm);
225562306a36Sopenharmony_cierror:
225662306a36Sopenharmony_ci	mISDN_unregister_Bprotocol(&X75SLP);
225762306a36Sopenharmony_ci	return res;
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_civoid
226162306a36Sopenharmony_ciIsdnl2_cleanup(void)
226262306a36Sopenharmony_ci{
226362306a36Sopenharmony_ci	mISDN_unregister_Bprotocol(&X75SLP);
226462306a36Sopenharmony_ci	TEIFree();
226562306a36Sopenharmony_ci	mISDN_FsmFree(&l2fsm);
226662306a36Sopenharmony_ci}
2267