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