isdnl3.c revision ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469
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>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
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>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hisax.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "isdnl3.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconst char *l3_revision = "$Revision: 2.22.2.3 $";
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Fsm l3fsm;
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_REL,
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_ESTAB_WAIT,
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_REL_DELAY,
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_REL_WAIT,
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ST_L3_LC_ESTAB,
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *strL3State[] =
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_REL",
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_ESTAB_WAIT",
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_REL_DELAY",
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_REL_WAIT",
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ST_L3_LC_ESTAB",
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_ESTABLISH_REQ,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_ESTABLISH_IND,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_ESTABLISH_CNF,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_RELEASE_REQ,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_RELEASE_CNF,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_RELEASE_IND,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EV_TIMEOUT,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define L3_EVENT_COUNT (EV_TIMEOUT+1)
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *strL3Event[] =
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_ESTABLISH_REQ",
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_ESTABLISH_IND",
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_ESTABLISH_CNF",
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_RELEASE_REQ",
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_RELEASE_CNF",
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_RELEASE_IND",
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EV_TIMEOUT",
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3m_debug(struct FsmInst *fi, char *fmt, ...)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_list args;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_start(args, fmt);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_end(args);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu_char *
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfindie(u_char * p, int size, u_char ie, int wanted_set)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int l, codeset, maincodeset;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *pend = p + size;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* skip protocol discriminator, callref and message type */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p++;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l = (*p++) & 0xf;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p += l;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p++;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	codeset = 0;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maincodeset = 0;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* while there are bytes left... */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (p < pend) {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((*p & 0xf0) == 0x90) {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			codeset = *p & 0x07;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(*p & 0x08))
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maincodeset = codeset;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*p & 0x80)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p++;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (codeset == wanted_set) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (*p == ie)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                  { /* improved length check (Werner Cornelius) */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    if ((pend - p) < 2)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                      return(NULL);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    if (*(p+1) > (pend - (p+2)))
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                      return(NULL);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                    return (p);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                  }
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (*p > ie)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return (NULL);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p++;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l = *p++;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p += l;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			codeset = maincodeset;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (NULL);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgetcallref(u_char * p)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int l, cr = 0;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p++;			/* prot discr */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*p & 0xfe)		/* wrong callref BRI only 1 octet*/
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(-2);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l = 0xf & *p++;		/* callref length */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!l)			/* dummy CallRef */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(-1);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cr = *p++;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (cr);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int OrigCallRef = 0;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnewcallref(void)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (OrigCallRef == 127)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		OrigCallRef = 1;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		OrigCallRef++;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (OrigCallRef);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnewl3state(struct l3_process *pc, int state)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pc->debug & L3_DEB_STATE)
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		l3_debug(pc->st, "newstate cr %d %d --> %d",
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 pc->callref & 0x7F,
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 pc->state, state);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pc->state = state;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3ExpireTimer(struct L3Timer *t)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3InitTimer(struct l3_process *pc, struct L3Timer *t)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->pc = pc;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->tl.function = (void *) L3ExpireTimer;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->tl.data = (long) t;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&t->tl);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3DelTimer(struct L3Timer *t)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&t->tl);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsL3AddTimer(struct L3Timer *t,
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   int millisec, int event)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timer_pending(&t->tl)) {
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "L3AddTimer: timer already active!\n");
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&t->tl);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->event = event;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t->tl.expires = jiffies + (millisec * HZ) / 1000;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&t->tl);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsStopAllL3Timer(struct l3_process *pc)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	L3DelTimer(&pc->timer);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sk_buff *
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3_alloc_skb(int len)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "HiSax: No skb for D-channel\n");
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_reserve(skb, MAX_HEADER_LEN);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (skb);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_l3_proto(struct PStack *st, int pr, void *arg)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb) {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb(skb);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n",ic->arg & 0xFF);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(-1);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct l3_process
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*getl3proc(struct PStack *st, int cr)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *p = st->l3.proc;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (p)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (p->callref == cr)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (p);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = p->next;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (NULL);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct l3_process
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*new_l3_process(struct PStack *st, int cr)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *p, *np;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (NULL);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!st->l3.proc)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.proc = p;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np = st->l3.proc;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (np->next)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			np = np->next;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np->next = p;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->next = NULL;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->debug = st->l3.debug;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->callref = cr;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->state = 0;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->chan = NULL;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->st = st;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->N303 = st->l3.N303;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	L3InitTimer(p, &p->timer);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (p);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrelease_l3_process(struct l3_process *p)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *np, *pp = NULL;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	np = p->st->l3.proc;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (np) {
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (np == p) {
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			StopAllL3Timer(p);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pp)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pp->next = np->next;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (!(p->st->l3.proc = np->next) &&
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				!test_bit(FLG_PTP, &p->st->l2.flag)) {
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (p->debug)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					l3_debug(p->st, "release_l3_process: last process");
292b03efcfb2180289718991bb984044ce6c5b7d1b0David S. Miller				if (skb_queue_empty(&p->st->l3.squeue)) {
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (p->debug)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						l3_debug(p->st, "release_l3_process: release link");
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (p->st->protocol != ISDN_PTYPE_NI1)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					else
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (p->debug)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						l3_debug(p->st, "release_l3_process: not release link");
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(p);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pp = np;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np = np->next;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3ml3p(struct PStack *st, int pr)
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *p = st->l3.proc;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct l3_process *np;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (p) {
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* p might be kfreed under us, so we need to save where we want to go on */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		np = p->next;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3ml3(st, pr, p);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = np;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetstack_l3dc(struct PStack *st, struct Channel *chanp)
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tmp[64];
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.proc   = NULL;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.global = NULL;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_head_init(&st->l3.squeue);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.fsm = &l3fsm;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.state = ST_L3_LC_REL;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.debug = 1;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userdata = st;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userint = 0;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.printdebug = l3m_debug;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(st->l3.debug_id, "L3DC ");
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->lli.l4l3_proto = no_l3_proto_spec;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef	CONFIG_HISAX_EURO
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->protocol == ISDN_PTYPE_EURO) {
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		setstack_dss1(st);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef  CONFIG_HISAX_NI1
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->protocol == ISDN_PTYPE_NI1) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		setstack_ni1(st);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef	CONFIG_HISAX_1TR6
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->protocol == ISDN_PTYPE_1TR6) {
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		setstack_1tr6(st);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->protocol == ISDN_PTYPE_LEASED) {
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->lli.l4l3 = no_l3_proto;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l2.l2l3 = no_l3_proto;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                st->l3.l3ml3 = no_l3_proto;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "HiSax: Leased line mode\n");
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->lli.l4l3 = no_l3_proto;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l2.l2l3 = no_l3_proto;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                st->l3.l3ml3 = no_l3_proto;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(tmp, "protocol %s not supported",
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(st->protocol == ISDN_PTYPE_EURO) ? "euro" :
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"unknown");
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "HiSax: %s\n", tmp);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->protocol = -1;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
380672c3fd9069e5a138f9d4afc9aeb5aa34aacce32Adrian Bunkstatic void
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisdnl3_trans(struct PStack *st, int pr, void *arg) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3l2(st, pr, arg);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreleasestack_isdnl3(struct PStack *st)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (st->l3.proc)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_l3_process(st->l3.proc);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (st->l3.global) {
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		StopAllL3Timer(st->l3.global);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(st->l3.global);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.global = NULL;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmDelTimer(&st->l3.l3m_timer, 54);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&st->l3.squeue);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetstack_l3bc(struct PStack *st, struct Channel *chanp)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.proc   = NULL;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.global = NULL;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_head_init(&st->l3.squeue);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.fsm = &l3fsm;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.state = ST_L3_LC_REL;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.debug = 1;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userdata = st;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.userint = 0;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3m.printdebug = l3m_debug;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(st->l3.debug_id, "L3BC ");
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->lli.l4l3 = isdnl3_trans;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DREL_TIMER_VALUE 40000
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_activate(struct FsmInst *fi, int event, void *arg)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_connect(struct FsmInst *fi, int event, void *arg)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dequeued = 0;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_ESTAB);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((skb = skb_dequeue(&st->l3.squeue))) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dequeued++;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!st->l3.proc) &&  dequeued) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st->l3.debug)
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l3_debug(st, "lc_connect: release link");
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		l3ml3p(st, DL_ESTABLISH | INDICATION);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_connected(struct FsmInst *fi, int event, void *arg)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dequeued = 0;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmDelTimer(&st->l3.l3m_timer, 51);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_ESTAB);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((skb = skb_dequeue(&st->l3.squeue))) {
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dequeued++;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!st->l3.proc) &&  dequeued) {
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st->l3.debug)
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l3_debug(st, "lc_connected: release link");
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		l3ml3p(st, DL_ESTABLISH | CONFIRM);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_start_delay(struct FsmInst *fi, int event, void *arg)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       struct PStack *st = fi->userdata;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       FsmChangeState(fi, ST_L3_LC_REL_DELAY);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_start_delay_check(struct FsmInst *fi, int event, void *arg)
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       struct PStack *st = fi->userdata;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       FsmChangeState(fi, ST_L3_LC_REL_DELAY);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       /* 19/09/00 - GE timer not user for NI-1 */
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       if (st->protocol != ISDN_PTYPE_NI1)
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_release_req(struct FsmInst *fi, int event, void *arg)
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (st->l3.debug)
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			l3_debug(st, "lc_release_req: l2 blocked");
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* restart release timer */
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FsmChangeState(fi, ST_L3_LC_REL_WAIT);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_release_ind(struct FsmInst *fi, int event, void *arg)
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmDelTimer(&st->l3.l3m_timer, 52);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_REL);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&st->l3.squeue);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3ml3p(st, DL_RELEASE | INDICATION);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslc_release_cnf(struct FsmInst *fi, int event, void *arg)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *st = fi->userdata;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmChangeState(fi, ST_L3_LC_REL);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&st->l3.squeue);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3ml3p(st, DL_RELEASE | CONFIRM);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* *INDENT-OFF* */
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct FsmNode L3FnList[] __initdata =
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL,		EV_ESTABLISH_REQ,	lc_activate},
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL,		EV_ESTABLISH_IND,	lc_connect},
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL,		EV_ESTABLISH_CNF,	lc_connect},
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB_WAIT,	EV_ESTABLISH_CNF,	lc_connected},
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_REQ,		lc_start_delay},
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_IND,		lc_release_ind},
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB,	EV_RELEASE_IND,		lc_release_ind},
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_ESTAB,	EV_RELEASE_REQ,		lc_start_delay_check},
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {ST_L3_LC_REL_DELAY,    EV_RELEASE_IND,         lc_release_ind},
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {ST_L3_LC_REL_DELAY,    EV_ESTABLISH_REQ,       lc_connected},
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {ST_L3_LC_REL_DELAY,    EV_TIMEOUT,             lc_release_req},
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL_WAIT,	EV_RELEASE_CNF,		lc_release_cnf},
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ST_L3_LC_REL_WAIT,	EV_ESTABLISH_REQ,	lc_activate},
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* *INDENT-ON* */
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsl3_msg(struct PStack *st, int pr, void *arg)
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (pr) {
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_DATA | REQUEST):
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				st->l3.l3l2(st, pr, arg);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct sk_buff *skb = arg;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_queue_tail(&st->l3.squeue, skb);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_ESTABLISH | REQUEST):
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_ESTABLISH | CONFIRM):
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_ESTABLISH | INDICATION):
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_RELEASE | INDICATION):
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_RELEASE | CONFIRM):
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case (DL_RELEASE | REQUEST):
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIsdnl3New(void)
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.state_count = L3_STATE_COUNT;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.event_count = L3_EVENT_COUNT;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.strEvent = strL3Event;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	l3fsm.strState = strL3State;
588ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469Karsten Keil	return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList));
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIsdnl3Free(void)
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FsmFree(&l3fsm);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
596