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