patch-2.0.36 linux/drivers/isdn/hisax/isdnl3.c

Next file: linux/drivers/isdn/hisax/isdnl3.h
Previous file: linux/drivers/isdn/hisax/isdnl2.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.35/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
@@ -1,44 +1,51 @@
-/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $
+/* $Id: isdnl3.c,v 1.10.2.6 1998/11/03 00:07:06 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: isdnl3.c,v $
- * Revision 1.10  1997/04/06 22:54:16  keil
- * Using SKB's
+ * Revision 1.10.2.6  1998/11/03 00:07:06  keil
+ * certification related changes
+ * fixed logging for smaller stack use
  *
- * Revision 1.9  1997/03/25 23:11:25  keil
- * US NI-1 protocol
+ * Revision 1.10.2.5  1998/09/27 13:06:39  keil
+ * Apply most changes from 2.1.X (HiSax 3.1)
  *
- * Revision 1.8  1997/03/21 18:53:44  keil
- * Report no protocol error to syslog too
+ * Revision 1.10.2.4  1998/05/27 18:05:59  keil
+ * HiSax 3.0
  *
- * Revision 1.7  1997/03/17 18:34:38  keil
- * fixed oops if no protocol selected during config
+ * Revision 1.10.2.3  1997/11/15 18:54:09  keil
+ * cosmetics
  *
- * Revision 1.6  1997/02/16 01:04:08  fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
+ * Revision 1.10.2.2  1997/10/17 22:14:05  keil
+ * update to last hisax version
  *
- * Revision 1.5  1997/02/09 00:26:27  keil
- * new interface handling, one interface per card
- * leased line changes
+ * Revision 2.1  1997/08/03 14:36:32  keil
+ * Implement RESTART procedure
  *
- * Revision 1.4  1997/01/27 23:17:44  keil
- * delete timers while unloading
+ * Revision 2.0  1997/07/27 21:15:42  keil
+ * New Callref based layer3
  *
- * Revision 1.3  1997/01/21 22:31:12  keil
- * new statemachine; L3 timers
+ * Revision 1.11  1997/06/26 11:11:44  keil
+ * SET_SKBFREE now on creation of a SKB
  *
- * Revision 1.2  1996/11/05 19:42:04  keil
- * using config.h
+ * Revision 1.10  1997/04/06 22:54:16  keil
+ * Using SKB's
  *
- * Revision 1.1  1996/10/13 20:04:54  keil
- * Initial revision
+ * Revision 1.9  1997/03/25 23:11:25  keil
+ * US NI-1 protocol
  *
+ * Revision 1.8  1997/03/21 18:53:44  keil
+ * Report no protocol error to syslog too
  *
+ * Remove old logs /KKe
  *
  */
 #define __NO_VERSION__
@@ -46,42 +53,145 @@
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 1.10 $";
+const char *l3_revision = "$Revision: 1.10.2.6 $";
 
-void
-l3_debug(struct PStack *st, char *s)
+static
+struct Fsm l3fsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L3_LC_REL,
+	ST_L3_LC_ESTAB_WAIT,
+	ST_L3_LC_REL_WAIT,
+	ST_L3_LC_ESTAB,
+};
+
+#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1)
+
+static char *strL3State[] =
+{
+	"ST_L3_LC_REL",
+	"ST_L3_LC_ESTAB_WAIT",
+	"ST_L3_LC_REL_WAIT",
+	"ST_L3_LC_ESTAB",
+};
+
+enum {
+	EV_ESTABLISH_REQ,
+	EV_ESTABLISH_IND,
+	EV_ESTABLISH_CNF,
+	EV_RELEASE_REQ,
+	EV_RELEASE_CNF,
+	EV_RELEASE_IND,
+};
+
+#define L3_EVENT_COUNT (EV_RELEASE_IND+1)
+
+static char *strL3Event[] =
+{
+	"EV_ESTABLISH_REQ",
+	"EV_ESTABLISH_IND",
+	"EV_ESTABLISH_CNF",
+	"EV_RELEASE_REQ",
+	"EV_RELEASE_CNF",
+	"EV_RELEASE_IND",
+};
+
+static void
+l3m_debug(struct FsmInst *fi, char *fmt, ...)
 {
-	char str[256], tm[32];
+	va_list args;
+	struct PStack *st = fi->userdata;
 
-	jiftime(tm, jiffies);
-	sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
-	HiSax_putstatus(st->l1.hardware, str);
+	va_start(args, fmt);
+	VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
+	va_end(args);
 }
 
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
+{
+	int l, codeset, maincodeset;
+	u_char *pend = p + size;
 
+	/* skip protocol discriminator, callref and message type */
+	p++;
+	l = (*p++) & 0xf;
+	p += l;
+	p++;
+	codeset = 0;
+	maincodeset = 0;
+	/* while there are bytes left... */
+	while (p < pend) {
+		if ((*p & 0xf0) == 0x90) {
+			codeset = *p & 0x07;
+			if (!(*p & 0x08))
+				maincodeset = codeset;
+		}
+		if (*p & 0x80)
+			p++;
+		else {
+			if (codeset == wanted_set) {
+				if (*p == ie)
+					return (p);
+				if (*p > ie)
+					return (NULL);
+			}
+			p++;
+			l = *p++;
+			p += l;
+			codeset = maincodeset;
+		}
+	}
+	return (NULL);
+}
 
-void
-newl3state(struct PStack *st, int state)
+int
+getcallref(u_char * p)
 {
-	char tmp[80];
-
-	if (st->l3.debug & L3_DEB_STATE) {
-		sprintf(tmp, "newstate  %d --> %d", st->l3.state, state);
-		l3_debug(st, tmp);
+	int l, m = 1, cr = 0;
+	p++;			/* prot discr */
+	l = 0xf & *p++;		/* callref length */
+	if (!l)			/* dummy CallRef */
+		return(-1);
+	while (l--) {
+		cr += m * (*p++);
+		m *= 8;
 	}
-	st->l3.state = state;
+	return (cr);
+}
+
+static int OrigCallRef = 0;
+
+int
+newcallref(void)
+{
+	if (OrigCallRef == 127)
+		OrigCallRef = 1;
+	else
+		OrigCallRef++;
+	return (OrigCallRef);
+}
+
+void
+newl3state(struct l3_process *pc, int state)
+{
+	if (pc->debug & L3_DEB_STATE)
+		l3_debug(pc->st, "newstate cr %d %d --> %d", pc->callref,
+			pc->state, state);
+	pc->state = state;
 }
 
 static void
 L3ExpireTimer(struct L3Timer *t)
 {
-	t->st->l4.l4l3(t->st, t->event, NULL);
+	t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
 }
 
 void
-L3InitTimer(struct PStack *st, struct L3Timer *t)
+L3InitTimer(struct l3_process *pc, struct L3Timer *t)
 {
-	t->st = st;
+	t->pc = pc;
 	t->tl.function = (void *) L3ExpireTimer;
 	t->tl.data = (long) t;
 	init_timer(&t->tl);
@@ -109,9 +219,9 @@
 }
 
 void
-StopAllL3Timer(struct PStack *st)
+StopAllL3Timer(struct l3_process *pc)
 {
-	L3DelTimer(&st->l3.timer);
+	L3DelTimer(&pc->timer);
 }
 
 struct sk_buff *
@@ -133,9 +243,10 @@
 {
 	struct sk_buff *skb = arg;
 
-	l3_debug(st, "no protocol");
-	if (skb)
+	HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
+	if (skb) {
 		dev_kfree_skb(skb, FREE_READ);
+	}
 }
 
 #ifdef	CONFIG_HISAX_EURO
@@ -150,14 +261,87 @@
 extern void setstack_1tr6(struct PStack *st);
 #endif
 
+struct l3_process
+*getl3proc(struct PStack *st, int cr)
+{
+	struct l3_process *p = st->l3.proc;
+
+	while (p)
+		if (p->callref == cr)
+			return (p);
+		else
+			p = p->next;
+	return (NULL);
+}
+
+struct l3_process
+*new_l3_process(struct PStack *st, int cr)
+{
+	struct l3_process *p, *np;
+
+	if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+		printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
+		return (NULL);
+	}
+	if (!st->l3.proc)
+		st->l3.proc = p;
+	else {
+		np = st->l3.proc;
+		while (np->next)
+			np = np->next;
+		np->next = p;
+	}
+	p->next = NULL;
+	p->debug = L3_DEB_WARN;
+	p->callref = cr;
+	p->state = 0;
+	p->chan = NULL;
+	p->st = st;
+	p->N303 = st->l3.N303;
+	L3InitTimer(p, &p->timer);
+	return (p);
+};
+
+void
+release_l3_process(struct l3_process *p)
+{
+	struct l3_process *np, *pp = NULL;
+
+	if (!p)
+		return;
+	np = p->st->l3.proc;
+	while (np) {
+		if (np == p) {
+			StopAllL3Timer(p);
+			if (pp)
+				pp->next = np->next;
+			else
+				p->st->l3.proc = np->next;
+			kfree(p);
+			return;
+		}
+		pp = np;
+		np = np->next;
+	}
+	printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
+	l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
+};
+
 void
-setstack_isdnl3(struct PStack *st, struct Channel *chanp)
+setstack_l3dc(struct PStack *st, struct Channel *chanp)
 {
 	char tmp[64];
 
-	st->l3.debug = L3_DEB_WARN;
-	st->l3.channr = chanp->chan;
-	L3InitTimer(st, &st->l3.timer);
+	st->l3.proc   = NULL;
+	st->l3.global = NULL;
+	skb_queue_head_init(&st->l3.squeue);
+	st->l3.l3m.fsm = &l3fsm;
+	st->l3.l3m.state = ST_L3_LC_REL;
+	st->l3.l3m.debug = 1;
+	st->l3.l3m.userdata = st;
+	st->l3.l3m.userint = 0;
+	st->l3.l3m.printdebug = l3m_debug;
+	strcpy(st->l3.debug_id, "L3DC ");
 
 #ifdef	CONFIG_HISAX_EURO
 	if (st->protocol == ISDN_PTYPE_EURO) {
@@ -175,11 +359,11 @@
 	} else
 #endif
 	if (st->protocol == ISDN_PTYPE_LEASED) {
-		st->l4.l4l3 = no_l3_proto;
+		st->lli.l4l3 = no_l3_proto;
 		st->l2.l2l3 = no_l3_proto;
-		printk(KERN_NOTICE "HiSax: Leased line mode\n");
+		printk(KERN_INFO "HiSax: Leased line mode\n");
 	} else {
-		st->l4.l4l3 = no_l3_proto;
+		st->lli.l4l3 = no_l3_proto;
 		st->l2.l2l3 = no_l3_proto;
 		sprintf(tmp, "protocol %s not supported",
 			(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
@@ -187,15 +371,155 @@
 			(st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
 			"unknown");
 		printk(KERN_WARNING "HiSax: %s\n", tmp);
-		l3_debug(st, tmp);
 		st->protocol = -1;
 	}
-	st->l3.state = 0;
-	st->l3.callref = 0;
+}
+
+void
+isdnl3_trans(struct PStack *st, int pr, void *arg) {
+	st->l3.l3l2(st, pr, arg);
 }
 
 void
 releasestack_isdnl3(struct PStack *st)
 {
-	StopAllL3Timer(st);
+	while (st->l3.proc)
+		release_l3_process(st->l3.proc);
+	if (st->l3.global) {
+		StopAllL3Timer(st->l3.global);
+		kfree(st->l3.global);
+		st->l3.global = NULL;
+	}
+	discard_queue(&st->l3.squeue);
+}
+
+void
+setstack_l3bc(struct PStack *st, struct Channel *chanp)
+{
+
+	st->l3.proc   = NULL;
+	st->l3.global = NULL;
+	skb_queue_head_init(&st->l3.squeue);
+	st->l3.l3m.fsm = &l3fsm;
+	st->l3.l3m.state = ST_L3_LC_REL;
+	st->l3.l3m.debug = 1;
+	st->l3.l3m.userdata = st;
+	st->l3.l3m.userint = 0;
+	st->l3.l3m.printdebug = l3m_debug;
+	strcpy(st->l3.debug_id, "L3BC ");
+	st->lli.l4l3 = isdnl3_trans;
+}
+
+static void
+lc_activate(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
+	st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
+}
+
+static void
+lc_connect(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	FsmChangeState(fi, ST_L3_LC_ESTAB);
+	while ((skb = skb_dequeue(&st->l3.squeue))) {
+		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+	}
+	st->l3.l3l4(st, DL_ESTABLISH | INDICATION, NULL);
+}
+
+static void
+lc_release_req(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	if (fi->state == ST_L3_LC_ESTAB_WAIT)
+		FsmChangeState(fi, ST_L3_LC_REL);
+	else
+		FsmChangeState(fi, ST_L3_LC_REL_WAIT);
+	st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+}
+
+static void
+lc_release_ind(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	FsmChangeState(fi, ST_L3_LC_REL);
+	discard_queue(&st->l3.squeue);
+	st->l3.l3l4(st, DL_RELEASE | INDICATION, NULL);
+}
+
+/* *INDENT-OFF* */
+static struct FsmNode L3FnList[] HISAX_INITDATA =
+{
+	{ST_L3_LC_REL,		EV_ESTABLISH_REQ,	lc_activate},
+	{ST_L3_LC_REL,		EV_ESTABLISH_IND,	lc_connect},
+	{ST_L3_LC_REL,		EV_ESTABLISH_CNF,	lc_connect},
+	{ST_L3_LC_ESTAB_WAIT,	EV_ESTABLISH_CNF,	lc_connect},
+	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_REQ,		lc_release_req},
+	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_IND,		lc_release_ind},
+	{ST_L3_LC_ESTAB,	EV_RELEASE_IND,		lc_release_ind},
+	{ST_L3_LC_ESTAB,	EV_RELEASE_REQ,		lc_release_req},
+	{ST_L3_LC_REL_WAIT,	EV_RELEASE_CNF,		lc_release_ind},
+	{ST_L3_LC_REL_WAIT,	EV_ESTABLISH_REQ,	lc_activate},
+};
+/* *INDENT-ON* */
+
+#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
+
+void
+l3_msg(struct PStack *st, int pr, void *arg)
+{
+	
+	switch (pr) {
+		case (DL_DATA | REQUEST):
+			if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
+				st->l3.l3l2(st, pr, arg);
+			} else {
+				struct sk_buff *skb = arg;
+
+				skb_queue_head(&st->l3.squeue, skb);
+				FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); 
+			}
+			break;
+		case (DL_ESTABLISH | REQUEST):
+			FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
+			break;
+		case (DL_ESTABLISH | CONFIRM):
+			FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
+			break;
+		case (DL_ESTABLISH | INDICATION):
+			FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
+			break;
+		case (DL_RELEASE | INDICATION):
+			FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
+			break;
+		case (DL_RELEASE | CONFIRM):
+			FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
+			break;
+		case (DL_RELEASE | REQUEST):
+			FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
+			break;
+	}
+}
+
+HISAX_INITFUNC(void
+Isdnl3New(void))
+{
+	l3fsm.state_count = L3_STATE_COUNT;
+	l3fsm.event_count = L3_EVENT_COUNT;
+	l3fsm.strEvent = strL3Event;
+	l3fsm.strState = strL3State;
+	FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
+}
+
+void
+Isdnl3Free(void)
+{
+	FsmFree(&l3fsm);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov