patch-2.3.14 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
- Lines: 344
- Date:
Thu Aug 12 09:42:33 1999
- Orig file:
v2.3.13/linux/drivers/isdn/hisax/isdnl3.c
- Orig date:
Sun May 23 10:03:41 1999
diff -u --recursive --new-file v2.3.13/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 2.8 1998/11/15 23:55:04 keil Exp $
+/* $Id: isdnl3.c,v 2.10 1999/07/21 14:46:19 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,12 @@
* Fritz Elfert
*
* $Log: isdnl3.c,v $
+ * Revision 2.10 1999/07/21 14:46:19 keil
+ * changes from EICON certification
+ *
+ * Revision 2.9 1999/07/01 08:11:53 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.8 1998/11/15 23:55:04 keil
* changes from 2.0
*
@@ -62,7 +68,7 @@
#include "isdnl3.h"
#include <linux/config.h>
-const char *l3_revision = "$Revision: 2.8 $";
+const char *l3_revision = "$Revision: 2.10 $";
static
struct Fsm l3fsm =
@@ -71,6 +77,7 @@
enum {
ST_L3_LC_REL,
ST_L3_LC_ESTAB_WAIT,
+ ST_L3_LC_REL_DELAY,
ST_L3_LC_REL_WAIT,
ST_L3_LC_ESTAB,
};
@@ -81,6 +88,7 @@
{
"ST_L3_LC_REL",
"ST_L3_LC_ESTAB_WAIT",
+ "ST_L3_LC_REL_DELAY",
"ST_L3_LC_REL_WAIT",
"ST_L3_LC_ESTAB",
};
@@ -92,9 +100,10 @@
EV_RELEASE_REQ,
EV_RELEASE_CNF,
EV_RELEASE_IND,
+ EV_TIMEOUT,
};
-#define L3_EVENT_COUNT (EV_RELEASE_IND+1)
+#define L3_EVENT_COUNT (EV_TIMEOUT+1)
static char *strL3Event[] =
{
@@ -104,6 +113,7 @@
"EV_RELEASE_REQ",
"EV_RELEASE_CNF",
"EV_RELEASE_IND",
+ "EV_TIMEOUT",
};
static void
@@ -142,7 +152,14 @@
else {
if (codeset == wanted_set) {
if (*p == ie)
- return (p);
+ { /* improved length check (Werner Cornelius) */
+ if ((pend - p) < 2)
+ return(NULL);
+ if (*(p+1) > (pend - (p+2)))
+ return(NULL);
+ return (p);
+ }
+
if (*p > ie)
return (NULL);
}
@@ -158,15 +175,15 @@
int
getcallref(u_char * p)
{
- int l, m = 1, cr = 0;
+ int l, cr = 0;
+
p++; /* prot discr */
+ if (*p & 0xfe) /* wrong callref BRI only 1 octet*/
+ return(-2);
l = 0xf & *p++; /* callref length */
if (!l) /* dummy CallRef */
return(-1);
- while (l--) {
- cr += m * (*p++);
- m *= 8;
- }
+ cr = *p++;
return (cr);
}
@@ -186,8 +203,9 @@
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);
+ l3_debug(pc->st, "newstate cr %d %d --> %d",
+ pc->callref & 0x7F,
+ pc->state, state);
pc->state = state;
}
@@ -242,6 +260,7 @@
printk(KERN_WARNING "HiSax: No skb for D-channel\n");
return (NULL);
}
+ SET_SKB_FREE(skb);
skb_reserve(skb, MAX_HEADER_LEN);
return (skb);
}
@@ -253,10 +272,17 @@
HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
if (skb) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
}
+static int
+no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
+{
+ printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n",ic->arg & 0xFF);
+ return(-1);
+}
+
#ifdef CONFIG_HISAX_EURO
extern void setstack_dss1(struct PStack *st);
#endif
@@ -300,7 +326,7 @@
np->next = p;
}
p->next = NULL;
- p->debug = L3_DEB_WARN;
+ p->debug = st->l3.debug;
p->callref = cr;
p->state = 0;
p->chan = NULL;
@@ -323,8 +349,19 @@
StopAllL3Timer(p);
if (pp)
pp->next = np->next;
- else
- p->st->l3.proc = np->next;
+ else if (!(p->st->l3.proc = np->next) &&
+ !test_bit(FLG_PTP, &p->st->l2.flag)) {
+ if (p->debug)
+ l3_debug(p->st, "release_l3_process: last process");
+ if (!skb_queue_len(&p->st->l3.squeue)) {
+ if (p->debug)
+ l3_debug(p->st, "release_l3_process: release link");
+ FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
+ } else {
+ if (p->debug)
+ l3_debug(p->st, "release_l3_process: not release link");
+ }
+ }
kfree(p);
return;
}
@@ -335,6 +372,17 @@
l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
};
+static void
+l3ml3p(struct PStack *st, int pr)
+{
+ struct l3_process *p = st->l3.proc;
+
+ while (p) {
+ st->l3.l3ml3(st, pr, p);
+ p = p->next;
+ }
+}
+
void
setstack_l3dc(struct PStack *st, struct Channel *chanp)
{
@@ -349,7 +397,9 @@
st->l3.l3m.userdata = st;
st->l3.l3m.userint = 0;
st->l3.l3m.printdebug = l3m_debug;
+ FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
strcpy(st->l3.debug_id, "L3DC ");
+ st->lli.l4l3_proto = no_l3_proto_spec;
#ifdef CONFIG_HISAX_EURO
if (st->protocol == ISDN_PTYPE_EURO) {
@@ -369,10 +419,12 @@
if (st->protocol == ISDN_PTYPE_LEASED) {
st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
+ st->l3.l3ml3 = no_l3_proto;
printk(KERN_INFO "HiSax: Leased line mode\n");
} else {
st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
+ st->l3.l3ml3 = no_l3_proto;
sprintf(tmp, "protocol %s not supported",
(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
(st->protocol == ISDN_PTYPE_EURO) ? "euro" :
@@ -398,6 +450,7 @@
kfree(st->l3.global);
st->l3.global = NULL;
}
+ FsmDelTimer(&st->l3.l3m_timer, 54);
discard_queue(&st->l3.squeue);
}
@@ -418,6 +471,8 @@
st->lli.l4l3 = isdnl3_trans;
}
+#define DREL_TIMER_VALUE 40000
+
static void
lc_activate(struct FsmInst *fi, int event, void *arg)
{
@@ -432,12 +487,49 @@
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
+ int dequeued = 0;
FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&st->l3.squeue))) {
st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+ dequeued++;
}
- st->l3.l3l4(st, DL_ESTABLISH | INDICATION, NULL);
+ if ((!st->l3.proc) && dequeued) {
+ if (st->l3.debug)
+ l3_debug(st, "lc_connect: release link");
+ FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
+ } else
+ l3ml3p(st, DL_ESTABLISH | INDICATION);
+}
+
+static void
+lc_connected(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int dequeued = 0;
+
+ FsmDelTimer(&st->l3.l3m_timer, 51);
+ FsmChangeState(fi, ST_L3_LC_ESTAB);
+ while ((skb = skb_dequeue(&st->l3.squeue))) {
+ st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+ dequeued++;
+ }
+ if ((!st->l3.proc) && dequeued) {
+ if (st->l3.debug)
+ l3_debug(st, "lc_connected: release link");
+ FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
+ } else
+ l3ml3p(st, DL_ESTABLISH | CONFIRM);
+}
+
+static void
+lc_start_delay(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L3_LC_REL_DELAY);
+ FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
}
static void
@@ -445,11 +537,15 @@
{
struct PStack *st = fi->userdata;
- if (fi->state == ST_L3_LC_ESTAB_WAIT)
- FsmChangeState(fi, ST_L3_LC_REL);
- else
+ if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
+ if (st->l3.debug)
+ l3_debug(st, "lc_release_req: l2 blocked");
+ /* restart release timer */
+ FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
+ } else {
FsmChangeState(fi, ST_L3_LC_REL_WAIT);
- st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+ st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+ }
}
static void
@@ -457,23 +553,38 @@
{
struct PStack *st = fi->userdata;
+ FsmDelTimer(&st->l3.l3m_timer, 52);
FsmChangeState(fi, ST_L3_LC_REL);
discard_queue(&st->l3.squeue);
- st->l3.l3l4(st, DL_RELEASE | INDICATION, NULL);
+ l3ml3p(st, DL_RELEASE | INDICATION);
}
+static void
+lc_release_cnf(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L3_LC_REL);
+ discard_queue(&st->l3.squeue);
+ l3ml3p(st, DL_RELEASE | CONFIRM);
+}
+
+
/* *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_ESTABLISH_CNF, lc_connected},
+ {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay},
{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_ESTAB, EV_RELEASE_REQ, lc_start_delay},
+ {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind},
+ {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected},
+ {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req},
+ {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf},
{ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate},
};
/* *INDENT-ON* */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)