11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author       Karsten Keil
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              based on the teles driver from Jan den Ouden
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright    by Karsten Keil      <keil@isdn4linux.de>
6475be4d85a274d0961593db41cf85689db1d583cJoe Perches *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For changes and modifications please read
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Documentation/isdn/HiSax.cert
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thanks to    Jan den Ouden
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              Fritz Elfert
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hisax.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "isdnl3.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconst char *l3_revision = "$Revision: 2.22.2.3 $";
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Fsm l3fsm;
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_REL,
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_ESTAB_WAIT,
30475be4d85a274d0961593db41cf85689db1d583cJoe Perches	ST_L3_LC_REL_DELAY,
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_REL_WAIT,
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_ESTAB,
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35475be4d85a274d0961593db41cf85689db1d583cJoe Perches#define L3_STATE_COUNT (ST_L3_LC_ESTAB + 1)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *strL3State[] =
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_REL",
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_ESTAB_WAIT",
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_REL_DELAY",
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_REL_WAIT",
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_ESTAB",
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_ESTABLISH_REQ,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_ESTABLISH_IND,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_ESTABLISH_CNF,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_RELEASE_REQ,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_RELEASE_CNF,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_RELEASE_IND,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_TIMEOUT,
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56475be4d85a274d0961593db41cf85689db1d583cJoe Perches#define L3_EVENT_COUNT (EV_TIMEOUT + 1)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *strL3Event[] =
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_ESTABLISH_REQ",
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_ESTABLISH_IND",
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_ESTABLISH_CNF",
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_RELEASE_REQ",
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_RELEASE_CNF",
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_RELEASE_IND",
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_TIMEOUT",
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69b9075fa968a0a4347aef35e235e2995c0e57ddddJoe Perchesstatic __printf(2, 3) void
70475be4d85a274d0961593db41cf85689db1d583cJoe Perches	l3m_debug(struct FsmInst *fi, char *fmt, ...)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_list args;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_start(args, fmt);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_end(args);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu_char *
81475be4d85a274d0961593db41cf85689db1d583cJoe Perchesfindie(u_char *p, int size, u_char ie, int wanted_set)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int l, codeset, maincodeset;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *pend = p + size;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* skip protocol discriminator, callref and message type */
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p++;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l = (*p++) & 0xf;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p += l;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p++;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	codeset = 0;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maincodeset = 0;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* while there are bytes left... */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (p < pend) {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((*p & 0xf0) == 0x90) {
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			codeset = *p & 0x07;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(*p & 0x08))
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maincodeset = codeset;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*p & 0x80)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p++;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (codeset == wanted_set) {
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (*p == ie)
105475be4d85a274d0961593db41cf85689db1d583cJoe Perches				{ /* improved length check (Werner Cornelius) */
106475be4d85a274d0961593db41cf85689db1d583cJoe Perches					if ((pend - p) < 2)
107475be4d85a274d0961593db41cf85689db1d583cJoe Perches						return (NULL);
108475be4d85a274d0961593db41cf85689db1d583cJoe Perches					if (*(p + 1) > (pend - (p + 2)))
109475be4d85a274d0961593db41cf85689db1d583cJoe Perches						return (NULL);
110475be4d85a274d0961593db41cf85689db1d583cJoe Perches					return (p);
111475be4d85a274d0961593db41cf85689db1d583cJoe Perches				}
112475be4d85a274d0961593db41cf85689db1d583cJoe Perches
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (*p > ie)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return (NULL);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p++;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l = *p++;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p += l;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			codeset = maincodeset;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (NULL);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
126475be4d85a274d0961593db41cf85689db1d583cJoe Perchesgetcallref(u_char *p)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int l, cr = 0;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p++;			/* prot discr */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*p & 0xfe)		/* wrong callref BRI only 1 octet*/
132475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (-2);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l = 0xf & *p++;		/* callref length */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!l)			/* dummy CallRef */
135475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (-1);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cr = *p++;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (cr);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int OrigCallRef = 0;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnewcallref(void)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (OrigCallRef == 127)
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		OrigCallRef = 1;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		OrigCallRef++;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (OrigCallRef);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnewl3state(struct l3_process *pc, int state)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pc->debug & L3_DEB_STATE)
156475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l3_debug(pc->st, "newstate cr %d %d --> %d",
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 pc->callref & 0x7F,
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 pc->state, state);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pc->state = state;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3ExpireTimer(struct L3Timer *t)
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3InitTimer(struct l3_process *pc, struct L3Timer *t)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->pc = pc;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->tl.function = (void *) L3ExpireTimer;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->tl.data = (long) t;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&t->tl);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3DelTimer(struct L3Timer *t)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&t->tl);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3AddTimer(struct L3Timer *t,
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   int millisec, int event)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timer_pending(&t->tl)) {
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "L3AddTimer: timer already active!\n");
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&t->tl);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->event = event;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->tl.expires = jiffies + (millisec * HZ) / 1000;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&t->tl);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsStopAllL3Timer(struct l3_process *pc)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	L3DelTimer(&pc->timer);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sk_buff *
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3_alloc_skb(int len)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "HiSax: No skb for D-channel\n");
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_reserve(skb, MAX_HEADER_LEN);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (skb);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_l3_proto(struct PStack *st, int pr, void *arg)
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb) {
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb(skb);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
231475be4d85a274d0961593db41cf85689db1d583cJoe Perches	printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n", ic->arg & 0xFF);
232475be4d85a274d0961593db41cf85689db1d583cJoe Perches	return (-1);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct l3_process
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*getl3proc(struct PStack *st, int cr)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *p = st->l3.proc;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (p)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (p->callref == cr)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (p);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = p->next;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (NULL);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct l3_process
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*new_l3_process(struct PStack *st, int cr)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *p, *np;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!st->l3.proc)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.proc = p;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np = st->l3.proc;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (np->next)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			np = np->next;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np->next = p;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->next = NULL;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->debug = st->l3.debug;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->callref = cr;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->state = 0;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->chan = NULL;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->st = st;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->N303 = st->l3.N303;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	L3InitTimer(p, &p->timer);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (p);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrelease_l3_process(struct l3_process *p)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *np, *pp = NULL;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p)
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	np = p->st->l3.proc;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (np) {
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (np == p) {
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			StopAllL3Timer(p);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pp)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pp->next = np->next;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (!(p->st->l3.proc = np->next) &&
290475be4d85a274d0961593db41cf85689db1d583cJoe Perches				 !test_bit(FLG_PTP, &p->st->l2.flag)) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (p->debug)
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					l3_debug(p->st, "release_l3_process: last process");
293b03efcfb2180289718991bb984044ce6c5b7d1b0David S. Miller				if (skb_queue_empty(&p->st->l3.squeue)) {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (p->debug)
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						l3_debug(p->st, "release_l3_process: release link");
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (p->st->protocol != ISDN_PTYPE_NI1)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					else
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (p->debug)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						l3_debug(p->st, "release_l3_process: not release link");
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
304475be4d85a274d0961593db41cf85689db1d583cJoe Perches			}
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(p);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pp = np;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np = np->next;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3ml3p(struct PStack *st, int pr)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *p = st->l3.proc;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *np;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (p) {
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* p might be kfreed under us, so we need to save where we want to go on */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np = p->next;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3ml3(st, pr, p);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = np;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetstack_l3dc(struct PStack *st, struct Channel *chanp)
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tmp[64];
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.proc   = NULL;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.global = NULL;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_head_init(&st->l3.squeue);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.fsm = &l3fsm;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.state = ST_L3_LC_REL;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.debug = 1;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userdata = st;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userint = 0;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.printdebug = l3m_debug;
343475be4d85a274d0961593db41cf85689db1d583cJoe Perches	FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(st->l3.debug_id, "L3DC ");
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->lli.l4l3_proto = no_l3_proto_spec;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
347475be4d85a274d0961593db41cf85689db1d583cJoe Perches#ifdef CONFIG_HISAX_EURO
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->protocol == ISDN_PTYPE_EURO) {
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		setstack_dss1(st);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
352475be4d85a274d0961593db41cf85689db1d583cJoe Perches#ifdef CONFIG_HISAX_NI1
353475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (st->protocol == ISDN_PTYPE_NI1) {
354475be4d85a274d0961593db41cf85689db1d583cJoe Perches			setstack_ni1(st);
355475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
357475be4d85a274d0961593db41cf85689db1d583cJoe Perches#ifdef CONFIG_HISAX_1TR6
358475be4d85a274d0961593db41cf85689db1d583cJoe Perches			if (st->protocol == ISDN_PTYPE_1TR6) {
359475be4d85a274d0961593db41cf85689db1d583cJoe Perches				setstack_1tr6(st);
360475be4d85a274d0961593db41cf85689db1d583cJoe Perches			} else
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
362475be4d85a274d0961593db41cf85689db1d583cJoe Perches				if (st->protocol == ISDN_PTYPE_LEASED) {
363475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->lli.l4l3 = no_l3_proto;
364475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->l2.l2l3 = no_l3_proto;
365475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->l3.l3ml3 = no_l3_proto;
366475be4d85a274d0961593db41cf85689db1d583cJoe Perches					printk(KERN_INFO "HiSax: Leased line mode\n");
367475be4d85a274d0961593db41cf85689db1d583cJoe Perches				} else {
368475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->lli.l4l3 = no_l3_proto;
369475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->l2.l2l3 = no_l3_proto;
370475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->l3.l3ml3 = no_l3_proto;
371475be4d85a274d0961593db41cf85689db1d583cJoe Perches					sprintf(tmp, "protocol %s not supported",
372475be4d85a274d0961593db41cf85689db1d583cJoe Perches						(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
373475be4d85a274d0961593db41cf85689db1d583cJoe Perches						(st->protocol == ISDN_PTYPE_EURO) ? "euro" :
374475be4d85a274d0961593db41cf85689db1d583cJoe Perches						(st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
375475be4d85a274d0961593db41cf85689db1d583cJoe Perches						"unknown");
376475be4d85a274d0961593db41cf85689db1d583cJoe Perches					printk(KERN_WARNING "HiSax: %s\n", tmp);
377475be4d85a274d0961593db41cf85689db1d583cJoe Perches					st->protocol = -1;
378475be4d85a274d0961593db41cf85689db1d583cJoe Perches				}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381672c3fd9069e5a138f9d4afc9aeb5aa34aacce32Adrian Bunkstatic void
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisdnl3_trans(struct PStack *st, int pr, void *arg) {
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3l2(st, pr, arg);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreleasestack_isdnl3(struct PStack *st)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (st->l3.proc)
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_l3_process(st->l3.proc);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->l3.global) {
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		StopAllL3Timer(st->l3.global);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(st->l3.global);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.global = NULL;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmDelTimer(&st->l3.l3m_timer, 54);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&st->l3.squeue);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetstack_l3bc(struct PStack *st, struct Channel *chanp)
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.proc   = NULL;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.global = NULL;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_head_init(&st->l3.squeue);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.fsm = &l3fsm;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.state = ST_L3_LC_REL;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.debug = 1;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userdata = st;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userint = 0;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.printdebug = l3m_debug;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(st->l3.debug_id, "L3BC ");
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->lli.l4l3 = isdnl3_trans;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DREL_TIMER_VALUE 40000
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_activate(struct FsmInst *fi, int event, void *arg)
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_connect(struct FsmInst *fi, int event, void *arg)
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dequeued = 0;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_ESTAB);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((skb = skb_dequeue(&st->l3.squeue))) {
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dequeued++;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!st->l3.proc) &&  dequeued) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st->l3.debug)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l3_debug(st, "lc_connect: release link");
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		l3ml3p(st, DL_ESTABLISH | INDICATION);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_connected(struct FsmInst *fi, int event, void *arg)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dequeued = 0;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmDelTimer(&st->l3.l3m_timer, 51);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_ESTAB);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((skb = skb_dequeue(&st->l3.squeue))) {
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dequeued++;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!st->l3.proc) &&  dequeued) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st->l3.debug)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l3_debug(st, "lc_connected: release link");
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		l3ml3p(st, DL_ESTABLISH | CONFIRM);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_start_delay(struct FsmInst *fi, int event, void *arg)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
472475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct PStack *st = fi->userdata;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
474475be4d85a274d0961593db41cf85689db1d583cJoe Perches	FsmChangeState(fi, ST_L3_LC_REL_DELAY);
475475be4d85a274d0961593db41cf85689db1d583cJoe Perches	FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_start_delay_check(struct FsmInst *fi, int event, void *arg)
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
482475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct PStack *st = fi->userdata;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
484475be4d85a274d0961593db41cf85689db1d583cJoe Perches	FsmChangeState(fi, ST_L3_LC_REL_DELAY);
485475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* 19/09/00 - GE timer not user for NI-1 */
486475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (st->protocol != ISDN_PTYPE_NI1)
487475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_release_req(struct FsmInst *fi, int event, void *arg)
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st->l3.debug)
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l3_debug(st, "lc_release_req: l2 blocked");
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* restart release timer */
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmChangeState(fi, ST_L3_LC_REL_WAIT);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_release_ind(struct FsmInst *fi, int event, void *arg)
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmDelTimer(&st->l3.l3m_timer, 52);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_REL);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&st->l3.squeue);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3ml3p(st, DL_RELEASE | INDICATION);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_release_cnf(struct FsmInst *fi, int event, void *arg)
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_REL);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&st->l3.squeue);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3ml3p(st, DL_RELEASE | CONFIRM);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* *INDENT-OFF* */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct FsmNode L3FnList[] __initdata =
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL,		EV_ESTABLISH_REQ,	lc_activate},
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL,		EV_ESTABLISH_IND,	lc_connect},
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL,		EV_ESTABLISH_CNF,	lc_connect},
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB_WAIT,	EV_ESTABLISH_CNF,	lc_connected},
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_REQ,		lc_start_delay},
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_IND,		lc_release_ind},
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB,	EV_RELEASE_IND,		lc_release_ind},
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB,	EV_RELEASE_REQ,		lc_start_delay_check},
539475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_L3_LC_REL_DELAY,    EV_RELEASE_IND,         lc_release_ind},
540475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_L3_LC_REL_DELAY,    EV_ESTABLISH_REQ,       lc_connected},
541475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_L3_LC_REL_DELAY,    EV_TIMEOUT,             lc_release_req},
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL_WAIT,	EV_RELEASE_CNF,		lc_release_cnf},
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL_WAIT,	EV_ESTABLISH_REQ,	lc_activate},
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* *INDENT-ON* */
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3_msg(struct PStack *st, int pr, void *arg)
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (pr) {
551475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_DATA | REQUEST):
552475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
553475be4d85a274d0961593db41cf85689db1d583cJoe Perches			st->l3.l3l2(st, pr, arg);
554475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else {
555475be4d85a274d0961593db41cf85689db1d583cJoe Perches			struct sk_buff *skb = arg;
556475be4d85a274d0961593db41cf85689db1d583cJoe Perches
557475be4d85a274d0961593db41cf85689db1d583cJoe Perches			skb_queue_tail(&st->l3.squeue, skb);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
559475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
560475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
561475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_ESTABLISH | REQUEST):
562475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
563475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
564475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_ESTABLISH | CONFIRM):
565475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
566475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
567475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_ESTABLISH | INDICATION):
568475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
569475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
570475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_RELEASE | INDICATION):
571475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
572475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
573475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_RELEASE | CONFIRM):
574475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
575475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
576475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (DL_RELEASE | REQUEST):
577475be4d85a274d0961593db41cf85689db1d583cJoe Perches		FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
578475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIsdnl3New(void)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.state_count = L3_STATE_COUNT;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.event_count = L3_EVENT_COUNT;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.strEvent = strL3Event;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.strState = strL3State;
589ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil	return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList));
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIsdnl3Free(void)
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmFree(&l3fsm);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
597