File: /usr/src/linux/drivers/isdn/hisax/isdnl3.c
1 /* $Id: isdnl3.c,v 2.17.6.4 2001/06/09 15:14:17 kai Exp $
2 *
3 * Author Karsten Keil (keil@isdn4linux.de)
4 * based on the teles driver from Jan den Ouden
5 *
6 * This file is (c) under GNU General Public License
7 * For changes and modifications please read
8 * ../../../Documentation/isdn/HiSax.cert
9 *
10 * Thanks to Jan den Ouden
11 * Fritz Elfert
12 *
13 */
14
15 #define __NO_VERSION__
16 #include <linux/init.h>
17 #include "hisax.h"
18 #include "isdnl3.h"
19 #include <linux/config.h>
20
21 const char *l3_revision = "$Revision: 2.17.6.4 $";
22
23 static struct Fsm l3fsm;
24
25 enum {
26 ST_L3_LC_REL,
27 ST_L3_LC_ESTAB_WAIT,
28 ST_L3_LC_REL_DELAY,
29 ST_L3_LC_REL_WAIT,
30 ST_L3_LC_ESTAB,
31 };
32
33 #define L3_STATE_COUNT (ST_L3_LC_ESTAB+1)
34
35 static char *strL3State[] =
36 {
37 "ST_L3_LC_REL",
38 "ST_L3_LC_ESTAB_WAIT",
39 "ST_L3_LC_REL_DELAY",
40 "ST_L3_LC_REL_WAIT",
41 "ST_L3_LC_ESTAB",
42 };
43
44 enum {
45 EV_ESTABLISH_REQ,
46 EV_ESTABLISH_IND,
47 EV_ESTABLISH_CNF,
48 EV_RELEASE_REQ,
49 EV_RELEASE_CNF,
50 EV_RELEASE_IND,
51 EV_TIMEOUT,
52 };
53
54 #define L3_EVENT_COUNT (EV_TIMEOUT+1)
55
56 static char *strL3Event[] =
57 {
58 "EV_ESTABLISH_REQ",
59 "EV_ESTABLISH_IND",
60 "EV_ESTABLISH_CNF",
61 "EV_RELEASE_REQ",
62 "EV_RELEASE_CNF",
63 "EV_RELEASE_IND",
64 "EV_TIMEOUT",
65 };
66
67 static void
68 l3m_debug(struct FsmInst *fi, char *fmt, ...)
69 {
70 va_list args;
71 struct PStack *st = fi->userdata;
72
73 va_start(args, fmt);
74 VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
75 va_end(args);
76 }
77
78 u_char *
79 findie(u_char * p, int size, u_char ie, int wanted_set)
80 {
81 int l, codeset, maincodeset;
82 u_char *pend = p + size;
83
84 /* skip protocol discriminator, callref and message type */
85 p++;
86 l = (*p++) & 0xf;
87 p += l;
88 p++;
89 codeset = 0;
90 maincodeset = 0;
91 /* while there are bytes left... */
92 while (p < pend) {
93 if ((*p & 0xf0) == 0x90) {
94 codeset = *p & 0x07;
95 if (!(*p & 0x08))
96 maincodeset = codeset;
97 }
98 if (*p & 0x80)
99 p++;
100 else {
101 if (codeset == wanted_set) {
102 if (*p == ie)
103 { /* improved length check (Werner Cornelius) */
104 if ((pend - p) < 2)
105 return(NULL);
106 if (*(p+1) > (pend - (p+2)))
107 return(NULL);
108 return (p);
109 }
110
111 if (*p > ie)
112 return (NULL);
113 }
114 p++;
115 l = *p++;
116 p += l;
117 codeset = maincodeset;
118 }
119 }
120 return (NULL);
121 }
122
123 int
124 getcallref(u_char * p)
125 {
126 int l, cr = 0;
127
128 p++; /* prot discr */
129 if (*p & 0xfe) /* wrong callref BRI only 1 octet*/
130 return(-2);
131 l = 0xf & *p++; /* callref length */
132 if (!l) /* dummy CallRef */
133 return(-1);
134 cr = *p++;
135 return (cr);
136 }
137
138 static int OrigCallRef = 0;
139
140 int
141 newcallref(void)
142 {
143 if (OrigCallRef == 127)
144 OrigCallRef = 1;
145 else
146 OrigCallRef++;
147 return (OrigCallRef);
148 }
149
150 void
151 newl3state(struct l3_process *pc, int state)
152 {
153 if (pc->debug & L3_DEB_STATE)
154 l3_debug(pc->st, "newstate cr %d %d --> %d",
155 pc->callref & 0x7F,
156 pc->state, state);
157 pc->state = state;
158 }
159
160 static void
161 L3ExpireTimer(struct L3Timer *t)
162 {
163 t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
164 }
165
166 void
167 L3InitTimer(struct l3_process *pc, struct L3Timer *t)
168 {
169 t->pc = pc;
170 t->tl.function = (void *) L3ExpireTimer;
171 t->tl.data = (long) t;
172 init_timer(&t->tl);
173 }
174
175 void
176 L3DelTimer(struct L3Timer *t)
177 {
178 del_timer(&t->tl);
179 }
180
181 int
182 L3AddTimer(struct L3Timer *t,
183 int millisec, int event)
184 {
185 if (timer_pending(&t->tl)) {
186 printk(KERN_WARNING "L3AddTimer: timer already active!\n");
187 return -1;
188 }
189 init_timer(&t->tl);
190 t->event = event;
191 t->tl.expires = jiffies + (millisec * HZ) / 1000;
192 add_timer(&t->tl);
193 return 0;
194 }
195
196 void
197 StopAllL3Timer(struct l3_process *pc)
198 {
199 L3DelTimer(&pc->timer);
200 }
201
202 struct sk_buff *
203 l3_alloc_skb(int len)
204 {
205 struct sk_buff *skb;
206
207 if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
208 printk(KERN_WARNING "HiSax: No skb for D-channel\n");
209 return (NULL);
210 }
211 skb_reserve(skb, MAX_HEADER_LEN);
212 return (skb);
213 }
214
215 static void
216 no_l3_proto(struct PStack *st, int pr, void *arg)
217 {
218 struct sk_buff *skb = arg;
219
220 HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
221 if (skb) {
222 dev_kfree_skb(skb);
223 }
224 }
225
226 static int
227 no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
228 {
229 printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n",ic->arg & 0xFF);
230 return(-1);
231 }
232
233 #ifdef CONFIG_HISAX_EURO
234 extern void setstack_dss1(struct PStack *st);
235 #endif
236
237 #ifdef CONFIG_HISAX_NI1
238 extern void setstack_ni1(struct PStack *st);
239 #endif
240
241 #ifdef CONFIG_HISAX_1TR6
242 extern void setstack_1tr6(struct PStack *st);
243 #endif
244
245 struct l3_process
246 *getl3proc(struct PStack *st, int cr)
247 {
248 struct l3_process *p = st->l3.proc;
249
250 while (p)
251 if (p->callref == cr)
252 return (p);
253 else
254 p = p->next;
255 return (NULL);
256 }
257
258 struct l3_process
259 *new_l3_process(struct PStack *st, int cr)
260 {
261 struct l3_process *p, *np;
262
263 if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
264 printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
265 return (NULL);
266 }
267 if (!st->l3.proc)
268 st->l3.proc = p;
269 else {
270 np = st->l3.proc;
271 while (np->next)
272 np = np->next;
273 np->next = p;
274 }
275 p->next = NULL;
276 p->debug = st->l3.debug;
277 p->callref = cr;
278 p->state = 0;
279 p->chan = NULL;
280 p->st = st;
281 p->N303 = st->l3.N303;
282 L3InitTimer(p, &p->timer);
283 return (p);
284 };
285
286 void
287 release_l3_process(struct l3_process *p)
288 {
289 struct l3_process *np, *pp = NULL;
290
291 if (!p)
292 return;
293 np = p->st->l3.proc;
294 while (np) {
295 if (np == p) {
296 StopAllL3Timer(p);
297 if (pp)
298 pp->next = np->next;
299 else if (!(p->st->l3.proc = np->next) &&
300 !test_bit(FLG_PTP, &p->st->l2.flag)) {
301 if (p->debug)
302 l3_debug(p->st, "release_l3_process: last process");
303 if (!skb_queue_len(&p->st->l3.squeue)) {
304 if (p->debug)
305 l3_debug(p->st, "release_l3_process: release link");
306 if (p->st->protocol != ISDN_PTYPE_NI1)
307 FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
308 else
309 FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
310 } else {
311 if (p->debug)
312 l3_debug(p->st, "release_l3_process: not release link");
313 }
314 }
315 kfree(p);
316 return;
317 }
318 pp = np;
319 np = np->next;
320 }
321 printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
322 l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
323 };
324
325 static void
326 l3ml3p(struct PStack *st, int pr)
327 {
328 struct l3_process *p = st->l3.proc;
329 struct l3_process *np;
330
331 while (p) {
332 /* p might be kfreed under us, so we need to save where we want to go on */
333 np = p->next;
334 st->l3.l3ml3(st, pr, p);
335 p = np;
336 }
337 }
338
339 void
340 setstack_l3dc(struct PStack *st, struct Channel *chanp)
341 {
342 char tmp[64];
343
344 st->l3.proc = NULL;
345 st->l3.global = NULL;
346 skb_queue_head_init(&st->l3.squeue);
347 st->l3.l3m.fsm = &l3fsm;
348 st->l3.l3m.state = ST_L3_LC_REL;
349 st->l3.l3m.debug = 1;
350 st->l3.l3m.userdata = st;
351 st->l3.l3m.userint = 0;
352 st->l3.l3m.printdebug = l3m_debug;
353 FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
354 strcpy(st->l3.debug_id, "L3DC ");
355 st->lli.l4l3_proto = no_l3_proto_spec;
356
357 #ifdef CONFIG_HISAX_EURO
358 if (st->protocol == ISDN_PTYPE_EURO) {
359 setstack_dss1(st);
360 } else
361 #endif
362 #ifdef CONFIG_HISAX_NI1
363 if (st->protocol == ISDN_PTYPE_NI1) {
364 setstack_ni1(st);
365 } else
366 #endif
367 #ifdef CONFIG_HISAX_1TR6
368 if (st->protocol == ISDN_PTYPE_1TR6) {
369 setstack_1tr6(st);
370 } else
371 #endif
372 if (st->protocol == ISDN_PTYPE_LEASED) {
373 st->lli.l4l3 = no_l3_proto;
374 st->l2.l2l3 = no_l3_proto;
375 st->l3.l3ml3 = no_l3_proto;
376 printk(KERN_INFO "HiSax: Leased line mode\n");
377 } else {
378 st->lli.l4l3 = no_l3_proto;
379 st->l2.l2l3 = no_l3_proto;
380 st->l3.l3ml3 = no_l3_proto;
381 sprintf(tmp, "protocol %s not supported",
382 (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
383 (st->protocol == ISDN_PTYPE_EURO) ? "euro" :
384 (st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
385 "unknown");
386 printk(KERN_WARNING "HiSax: %s\n", tmp);
387 st->protocol = -1;
388 }
389 }
390
391 void
392 isdnl3_trans(struct PStack *st, int pr, void *arg) {
393 st->l3.l3l2(st, pr, arg);
394 }
395
396 void
397 releasestack_isdnl3(struct PStack *st)
398 {
399 while (st->l3.proc)
400 release_l3_process(st->l3.proc);
401 if (st->l3.global) {
402 StopAllL3Timer(st->l3.global);
403 kfree(st->l3.global);
404 st->l3.global = NULL;
405 }
406 FsmDelTimer(&st->l3.l3m_timer, 54);
407 skb_queue_purge(&st->l3.squeue);
408 }
409
410 void
411 setstack_l3bc(struct PStack *st, struct Channel *chanp)
412 {
413
414 st->l3.proc = NULL;
415 st->l3.global = NULL;
416 skb_queue_head_init(&st->l3.squeue);
417 st->l3.l3m.fsm = &l3fsm;
418 st->l3.l3m.state = ST_L3_LC_REL;
419 st->l3.l3m.debug = 1;
420 st->l3.l3m.userdata = st;
421 st->l3.l3m.userint = 0;
422 st->l3.l3m.printdebug = l3m_debug;
423 strcpy(st->l3.debug_id, "L3BC ");
424 st->lli.l4l3 = isdnl3_trans;
425 }
426
427 #define DREL_TIMER_VALUE 40000
428
429 static void
430 lc_activate(struct FsmInst *fi, int event, void *arg)
431 {
432 struct PStack *st = fi->userdata;
433
434 FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
435 st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
436 }
437
438 static void
439 lc_connect(struct FsmInst *fi, int event, void *arg)
440 {
441 struct PStack *st = fi->userdata;
442 struct sk_buff *skb = arg;
443 int dequeued = 0;
444
445 FsmChangeState(fi, ST_L3_LC_ESTAB);
446 while ((skb = skb_dequeue(&st->l3.squeue))) {
447 st->l3.l3l2(st, DL_DATA | REQUEST, skb);
448 dequeued++;
449 }
450 if ((!st->l3.proc) && dequeued) {
451 if (st->l3.debug)
452 l3_debug(st, "lc_connect: release link");
453 FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
454 } else
455 l3ml3p(st, DL_ESTABLISH | INDICATION);
456 }
457
458 static void
459 lc_connected(struct FsmInst *fi, int event, void *arg)
460 {
461 struct PStack *st = fi->userdata;
462 struct sk_buff *skb = arg;
463 int dequeued = 0;
464
465 FsmDelTimer(&st->l3.l3m_timer, 51);
466 FsmChangeState(fi, ST_L3_LC_ESTAB);
467 while ((skb = skb_dequeue(&st->l3.squeue))) {
468 st->l3.l3l2(st, DL_DATA | REQUEST, skb);
469 dequeued++;
470 }
471 if ((!st->l3.proc) && dequeued) {
472 if (st->l3.debug)
473 l3_debug(st, "lc_connected: release link");
474 FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
475 } else
476 l3ml3p(st, DL_ESTABLISH | CONFIRM);
477 }
478
479 static void
480 lc_start_delay(struct FsmInst *fi, int event, void *arg)
481 {
482 struct PStack *st = fi->userdata;
483
484 FsmChangeState(fi, ST_L3_LC_REL_DELAY);
485 FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
486 }
487
488 static void
489 lc_start_delay_check(struct FsmInst *fi, int event, void *arg)
490 /* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
491 {
492 struct PStack *st = fi->userdata;
493
494 FsmChangeState(fi, ST_L3_LC_REL_DELAY);
495 /* 19/09/00 - GE timer not user for NI-1 */
496 if (st->protocol != ISDN_PTYPE_NI1)
497 FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
498 }
499
500 static void
501 lc_release_req(struct FsmInst *fi, int event, void *arg)
502 {
503 struct PStack *st = fi->userdata;
504
505 if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
506 if (st->l3.debug)
507 l3_debug(st, "lc_release_req: l2 blocked");
508 /* restart release timer */
509 FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
510 } else {
511 FsmChangeState(fi, ST_L3_LC_REL_WAIT);
512 st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
513 }
514 }
515
516 static void
517 lc_release_ind(struct FsmInst *fi, int event, void *arg)
518 {
519 struct PStack *st = fi->userdata;
520
521 FsmDelTimer(&st->l3.l3m_timer, 52);
522 FsmChangeState(fi, ST_L3_LC_REL);
523 skb_queue_purge(&st->l3.squeue);
524 l3ml3p(st, DL_RELEASE | INDICATION);
525 }
526
527 static void
528 lc_release_cnf(struct FsmInst *fi, int event, void *arg)
529 {
530 struct PStack *st = fi->userdata;
531
532 FsmChangeState(fi, ST_L3_LC_REL);
533 skb_queue_purge(&st->l3.squeue);
534 l3ml3p(st, DL_RELEASE | CONFIRM);
535 }
536
537
538 /* *INDENT-OFF* */
539 static struct FsmNode L3FnList[] __initdata =
540 {
541 {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate},
542 {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect},
543 {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect},
544 {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected},
545 {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay},
546 {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind},
547 {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind},
548 {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check},
549 {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind},
550 {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected},
551 {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req},
552 {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf},
553 {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate},
554 };
555 /* *INDENT-ON* */
556
557 #define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
558
559 void
560 l3_msg(struct PStack *st, int pr, void *arg)
561 {
562 switch (pr) {
563 case (DL_DATA | REQUEST):
564 if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
565 st->l3.l3l2(st, pr, arg);
566 } else {
567 struct sk_buff *skb = arg;
568
569 skb_queue_tail(&st->l3.squeue, skb);
570 FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
571 }
572 break;
573 case (DL_ESTABLISH | REQUEST):
574 FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
575 break;
576 case (DL_ESTABLISH | CONFIRM):
577 FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
578 break;
579 case (DL_ESTABLISH | INDICATION):
580 FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
581 break;
582 case (DL_RELEASE | INDICATION):
583 FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
584 break;
585 case (DL_RELEASE | CONFIRM):
586 FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
587 break;
588 case (DL_RELEASE | REQUEST):
589 FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
590 break;
591 }
592 }
593
594 int __init
595 Isdnl3New(void)
596 {
597 l3fsm.state_count = L3_STATE_COUNT;
598 l3fsm.event_count = L3_EVENT_COUNT;
599 l3fsm.strEvent = strL3Event;
600 l3fsm.strState = strL3State;
601 return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
602 }
603
604 void
605 Isdnl3Free(void)
606 {
607 FsmFree(&l3fsm);
608 }
609