linux/drivers/isdn/hisax/l3_1tr6.c
<<
>>
Prefs
   1/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $
   2 *
   3 * German 1TR6 D-channel protocol
   4 *
   5 * Author       Karsten Keil
   6 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 * For changes and modifications please read
  12 * Documentation/isdn/HiSax.cert
  13 *
  14 */
  15
  16#include "hisax.h"
  17#include "l3_1tr6.h"
  18#include "isdnl3.h"
  19#include <linux/ctype.h>
  20
  21extern char *HiSax_getrev(const char *revision);
  22static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
  23
  24#define MsgHead(ptr, cref, mty, dis)            \
  25        *ptr++ = dis;                           \
  26        *ptr++ = 0x1;                           \
  27        *ptr++ = cref ^ 0x80;                   \
  28        *ptr++ = mty
  29
  30static void
  31l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
  32{
  33        struct sk_buff *skb;
  34        u_char *p;
  35
  36        if (!(skb = l3_alloc_skb(4)))
  37                return;
  38        p = skb_put(skb, 4);
  39        MsgHead(p, pc->callref, mt, pd);
  40        l3_msg(pc->st, DL_DATA | REQUEST, skb);
  41}
  42
  43static void
  44l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
  45{
  46        StopAllL3Timer(pc);
  47        newl3state(pc, 19);
  48        l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
  49        L3AddTimer(&pc->timer, T308, CC_T308_1);
  50}
  51
  52static void
  53l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
  54{
  55        struct sk_buff *skb = arg;
  56
  57        dev_kfree_skb(skb);
  58        l3_1tr6_release_req(pc, 0, NULL);
  59}
  60
  61static void
  62l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
  63{
  64        dev_kfree_skb(skb);
  65        if (pc->st->l3.debug & L3_DEB_WARN)
  66                l3_debug(pc->st, "%s", msg);
  67        l3_1tr6_release_req(pc, 0, NULL);
  68}
  69
  70static void
  71l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
  72{
  73        struct sk_buff *skb;
  74        u_char tmp[128];
  75        u_char *p = tmp;
  76        u_char *teln;
  77        u_char *eaz;
  78        u_char channel = 0;
  79        int l;
  80
  81        MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
  82        teln = pc->para.setup.phone;
  83        pc->para.spv = 0;
  84        if (!isdigit(*teln)) {
  85                switch (0x5f & *teln) {
  86                case 'S':
  87                        pc->para.spv = 1;
  88                        break;
  89                case 'C':
  90                        channel = 0x08;
  91                        /* fall through */
  92                case 'P':
  93                        channel |= 0x80;
  94                        teln++;
  95                        if (*teln == '1')
  96                                channel |= 0x01;
  97                        else
  98                                channel |= 0x02;
  99                        break;
 100                default:
 101                        if (pc->st->l3.debug & L3_DEB_WARN)
 102                                l3_debug(pc->st, "Wrong MSN Code");
 103                        break;
 104                }
 105                teln++;
 106        }
 107        if (channel) {
 108                *p++ = 0x18;    /* channel indicator */
 109                *p++ = 1;
 110                *p++ = channel;
 111        }
 112        if (pc->para.spv) {     /* SPV ? */
 113                /* NSF SPV */
 114                *p++ = WE0_netSpecFac;
 115                *p++ = 4;       /* Laenge */
 116                *p++ = 0;
 117                *p++ = FAC_SPV; /* SPV */
 118                *p++ = pc->para.setup.si1;      /* 0 for all Services */
 119                *p++ = pc->para.setup.si2;      /* 0 for all Services */
 120                *p++ = WE0_netSpecFac;
 121                *p++ = 4;       /* Laenge */
 122                *p++ = 0;
 123                *p++ = FAC_Activate;    /* aktiviere SPV (default) */
 124                *p++ = pc->para.setup.si1;      /* 0 for all Services */
 125                *p++ = pc->para.setup.si2;      /* 0 for all Services */
 126        }
 127        eaz = pc->para.setup.eazmsn;
 128        if (*eaz) {
 129                *p++ = WE0_origAddr;
 130                *p++ = strlen(eaz) + 1;
 131                /* Classify as AnyPref. */
 132                *p++ = 0x81;    /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
 133                while (*eaz)
 134                        *p++ = *eaz++ & 0x7f;
 135        }
 136        *p++ = WE0_destAddr;
 137        *p++ = strlen(teln) + 1;
 138        /* Classify as AnyPref. */
 139        *p++ = 0x81;            /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
 140        while (*teln)
 141                *p++ = *teln++ & 0x7f;
 142
 143        *p++ = WE_Shift_F6;
 144        /* Codesatz 6 fuer Service */
 145        *p++ = WE6_serviceInd;
 146        *p++ = 2;               /* len=2 info,info2 */
 147        *p++ = pc->para.setup.si1;
 148        *p++ = pc->para.setup.si2;
 149
 150        l = p - tmp;
 151        if (!(skb = l3_alloc_skb(l)))
 152                return;
 153        skb_put_data(skb, tmp, l);
 154        L3DelTimer(&pc->timer);
 155        L3AddTimer(&pc->timer, T303, CC_T303);
 156        newl3state(pc, 1);
 157        l3_msg(pc->st, DL_DATA | REQUEST, skb);
 158}
 159
 160static void
 161l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
 162{
 163        u_char *p;
 164        int bcfound = 0;
 165        struct sk_buff *skb = arg;
 166
 167        /* Channel Identification */
 168        p = findie(skb->data, skb->len, WE0_chanID, 0);
 169        if (p) {
 170                if (p[1] != 1) {
 171                        l3_1tr6_error(pc, "setup wrong chanID len", skb);
 172                        return;
 173                }
 174                if ((p[2] & 0xf4) != 0x80) {
 175                        l3_1tr6_error(pc, "setup wrong WE0_chanID", skb);
 176                        return;
 177                }
 178                if ((pc->para.bchannel = p[2] & 0x3))
 179                        bcfound++;
 180        } else {
 181                l3_1tr6_error(pc, "missing setup chanID", skb);
 182                return;
 183        }
 184
 185        p = skb->data;
 186        if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
 187                pc->para.setup.si1 = p[2];
 188                pc->para.setup.si2 = p[3];
 189        } else {
 190                l3_1tr6_error(pc, "missing setup SI", skb);
 191                return;
 192        }
 193
 194        p = skb->data;
 195        if ((p = findie(p, skb->len, WE0_destAddr, 0)))
 196                iecpy(pc->para.setup.eazmsn, p, 1);
 197        else
 198                pc->para.setup.eazmsn[0] = 0;
 199
 200        p = skb->data;
 201        if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
 202                iecpy(pc->para.setup.phone, p, 1);
 203        } else
 204                pc->para.setup.phone[0] = 0;
 205
 206        p = skb->data;
 207        pc->para.spv = 0;
 208        if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
 209                if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
 210                        pc->para.spv = 1;
 211        }
 212        dev_kfree_skb(skb);
 213
 214        /* Signal all services, linklevel takes care of Service-Indicator */
 215        if (bcfound) {
 216                if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) {
 217                        l3_debug(pc->st, "non-digital call: %s -> %s",
 218                                pc->para.setup.phone,
 219                                pc->para.setup.eazmsn);
 220                }
 221                newl3state(pc, 6);
 222                pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
 223        } else
 224                release_l3_process(pc);
 225}
 226
 227static void
 228l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
 229{
 230        u_char *p;
 231        struct sk_buff *skb = arg;
 232
 233        L3DelTimer(&pc->timer);
 234        p = skb->data;
 235        newl3state(pc, 2);
 236        if ((p = findie(p, skb->len, WE0_chanID, 0))) {
 237                if (p[1] != 1) {
 238                        l3_1tr6_error(pc, "setup_ack wrong chanID len", skb);
 239                        return;
 240                }
 241                if ((p[2] & 0xf4) != 0x80) {
 242                        l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb);
 243                        return;
 244                }
 245                pc->para.bchannel = p[2] & 0x3;
 246        } else {
 247                l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb);
 248                return;
 249        }
 250        dev_kfree_skb(skb);
 251        L3AddTimer(&pc->timer, T304, CC_T304);
 252        pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 253}
 254
 255static void
 256l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
 257{
 258        u_char *p;
 259        struct sk_buff *skb = arg;
 260
 261        L3DelTimer(&pc->timer);
 262        p = skb->data;
 263        if ((p = findie(p, skb->len, WE0_chanID, 0))) {
 264                if (p[1] != 1) {
 265                        l3_1tr6_error(pc, "call sent wrong chanID len", skb);
 266                        return;
 267                }
 268                if ((p[2] & 0xf4) != 0x80) {
 269                        l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb);
 270                        return;
 271                }
 272                if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) {
 273                        l3_1tr6_error(pc, "call sent wrong chanID value", skb);
 274                        return;
 275                }
 276                pc->para.bchannel = p[2] & 0x3;
 277        } else {
 278                l3_1tr6_error(pc, "missing call sent WE0_chanID", skb);
 279                return;
 280        }
 281        dev_kfree_skb(skb);
 282        L3AddTimer(&pc->timer, T310, CC_T310);
 283        newl3state(pc, 3);
 284        pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
 285}
 286
 287static void
 288l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
 289{
 290        struct sk_buff *skb = arg;
 291
 292        dev_kfree_skb(skb);
 293        L3DelTimer(&pc->timer); /* T304 */
 294        newl3state(pc, 4);
 295        pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
 296}
 297
 298static void
 299l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
 300{
 301        u_char *p;
 302        int i, tmpcharge = 0;
 303        char a_charge[8];
 304        struct sk_buff *skb = arg;
 305
 306        p = skb->data;
 307        if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
 308                iecpy(a_charge, p, 1);
 309                for (i = 0; i < strlen(a_charge); i++) {
 310                        tmpcharge *= 10;
 311                        tmpcharge += a_charge[i] & 0xf;
 312                }
 313                if (tmpcharge > pc->para.chargeinfo) {
 314                        pc->para.chargeinfo = tmpcharge;
 315                        pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
 316                }
 317                if (pc->st->l3.debug & L3_DEB_CHARGE) {
 318                        l3_debug(pc->st, "charging info %d",
 319                                 pc->para.chargeinfo);
 320                }
 321        } else if (pc->st->l3.debug & L3_DEB_CHARGE)
 322                l3_debug(pc->st, "charging info not found");
 323        dev_kfree_skb(skb);
 324
 325}
 326
 327static void
 328l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
 329{
 330        struct sk_buff *skb = arg;
 331
 332        dev_kfree_skb(skb);
 333}
 334
 335static void
 336l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
 337{
 338        struct sk_buff *skb = arg;
 339
 340        L3DelTimer(&pc->timer); /* T310 */
 341        if (!findie(skb->data, skb->len, WE6_date, 6)) {
 342                l3_1tr6_error(pc, "missing connect date", skb);
 343                return;
 344        }
 345        newl3state(pc, 10);
 346        dev_kfree_skb(skb);
 347        pc->para.chargeinfo = 0;
 348        pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 349}
 350
 351static void
 352l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
 353{
 354        struct sk_buff *skb = arg;
 355        u_char *p;
 356
 357        p = skb->data;
 358        if ((p = findie(p, skb->len, WE0_cause, 0))) {
 359                if (p[1] > 0) {
 360                        pc->para.cause = p[2];
 361                        if (p[1] > 1)
 362                                pc->para.loc = p[3];
 363                        else
 364                                pc->para.loc = 0;
 365                } else {
 366                        pc->para.cause = 0;
 367                        pc->para.loc = 0;
 368                }
 369        } else {
 370                pc->para.cause = NO_CAUSE;
 371                l3_1tr6_error(pc, "missing REL cause", skb);
 372                return;
 373        }
 374        dev_kfree_skb(skb);
 375        StopAllL3Timer(pc);
 376        newl3state(pc, 0);
 377        l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
 378        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 379        release_l3_process(pc);
 380}
 381
 382static void
 383l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
 384{
 385        struct sk_buff *skb = arg;
 386
 387        dev_kfree_skb(skb);
 388        StopAllL3Timer(pc);
 389        newl3state(pc, 0);
 390        pc->para.cause = NO_CAUSE;
 391        pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
 392        release_l3_process(pc);
 393}
 394
 395static void
 396l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
 397{
 398        struct sk_buff *skb = arg;
 399        u_char *p;
 400        int i, tmpcharge = 0;
 401        char a_charge[8];
 402
 403        StopAllL3Timer(pc);
 404        p = skb->data;
 405        if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
 406                iecpy(a_charge, p, 1);
 407                for (i = 0; i < strlen(a_charge); i++) {
 408                        tmpcharge *= 10;
 409                        tmpcharge += a_charge[i] & 0xf;
 410                }
 411                if (tmpcharge > pc->para.chargeinfo) {
 412                        pc->para.chargeinfo = tmpcharge;
 413                        pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
 414                }
 415                if (pc->st->l3.debug & L3_DEB_CHARGE) {
 416                        l3_debug(pc->st, "charging info %d",
 417                                 pc->para.chargeinfo);
 418                }
 419        } else if (pc->st->l3.debug & L3_DEB_CHARGE)
 420                l3_debug(pc->st, "charging info not found");
 421
 422
 423        p = skb->data;
 424        if ((p = findie(p, skb->len, WE0_cause, 0))) {
 425                if (p[1] > 0) {
 426                        pc->para.cause = p[2];
 427                        if (p[1] > 1)
 428                                pc->para.loc = p[3];
 429                        else
 430                                pc->para.loc = 0;
 431                } else {
 432                        pc->para.cause = 0;
 433                        pc->para.loc = 0;
 434                }
 435        } else {
 436                if (pc->st->l3.debug & L3_DEB_WARN)
 437                        l3_debug(pc->st, "cause not found");
 438                pc->para.cause = NO_CAUSE;
 439        }
 440        if (!findie(skb->data, skb->len, WE6_date, 6)) {
 441                l3_1tr6_error(pc, "missing connack date", skb);
 442                return;
 443        }
 444        dev_kfree_skb(skb);
 445        newl3state(pc, 12);
 446        pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
 447}
 448
 449
 450static void
 451l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 452{
 453        struct sk_buff *skb = arg;
 454
 455        if (!findie(skb->data, skb->len, WE6_date, 6)) {
 456                l3_1tr6_error(pc, "missing connack date", skb);
 457                return;
 458        }
 459        dev_kfree_skb(skb);
 460        newl3state(pc, 10);
 461        pc->para.chargeinfo = 0;
 462        L3DelTimer(&pc->timer);
 463        pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 464}
 465
 466static void
 467l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
 468{
 469        newl3state(pc, 7);
 470        l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
 471}
 472
 473static void
 474l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
 475{
 476        struct sk_buff *skb;
 477        u_char tmp[24];
 478        u_char *p = tmp;
 479        int l;
 480
 481        MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
 482        if (pc->para.spv) {     /* SPV ? */
 483                /* NSF SPV */
 484                *p++ = WE0_netSpecFac;
 485                *p++ = 4;       /* Laenge */
 486                *p++ = 0;
 487                *p++ = FAC_SPV; /* SPV */
 488                *p++ = pc->para.setup.si1;
 489                *p++ = pc->para.setup.si2;
 490                *p++ = WE0_netSpecFac;
 491                *p++ = 4;       /* Laenge */
 492                *p++ = 0;
 493                *p++ = FAC_Activate;    /* aktiviere SPV */
 494                *p++ = pc->para.setup.si1;
 495                *p++ = pc->para.setup.si2;
 496        }
 497        newl3state(pc, 8);
 498        l = p - tmp;
 499        if (!(skb = l3_alloc_skb(l)))
 500                return;
 501        skb_put_data(skb, tmp, l);
 502        l3_msg(pc->st, DL_DATA | REQUEST, skb);
 503        L3DelTimer(&pc->timer);
 504        L3AddTimer(&pc->timer, T313, CC_T313);
 505}
 506
 507static void
 508l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
 509{
 510        release_l3_process(pc);
 511}
 512
 513static void
 514l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
 515{
 516        struct sk_buff *skb;
 517        u_char tmp[16];
 518        u_char *p = tmp;
 519        int l;
 520        u_char cause = 0x10;
 521        u_char clen = 1;
 522
 523        if (pc->para.cause > 0)
 524                cause = pc->para.cause;
 525        /* Map DSS1 causes */
 526        switch (cause & 0x7f) {
 527        case 0x10:
 528                clen = 0;
 529                break;
 530        case 0x11:
 531                cause = CAUSE_UserBusy;
 532                break;
 533        case 0x15:
 534                cause = CAUSE_CallRejected;
 535                break;
 536        }
 537        StopAllL3Timer(pc);
 538        MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1);
 539        *p++ = WE0_cause;
 540        *p++ = clen;            /* Laenge */
 541        if (clen)
 542                *p++ = cause | 0x80;
 543        newl3state(pc, 11);
 544        l = p - tmp;
 545        if (!(skb = l3_alloc_skb(l)))
 546                return;
 547        skb_put_data(skb, tmp, l);
 548        l3_msg(pc->st, DL_DATA | REQUEST, skb);
 549        L3AddTimer(&pc->timer, T305, CC_T305);
 550}
 551
 552static void
 553l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
 554{
 555        if (pc->N303 > 0) {
 556                pc->N303--;
 557                L3DelTimer(&pc->timer);
 558                l3_1tr6_setup_req(pc, pr, arg);
 559        } else {
 560                L3DelTimer(&pc->timer);
 561                pc->para.cause = 0;
 562                l3_1tr6_disconnect_req(pc, 0, NULL);
 563        }
 564}
 565
 566static void
 567l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
 568{
 569        L3DelTimer(&pc->timer);
 570        pc->para.cause = 0xE6;
 571        l3_1tr6_disconnect_req(pc, pr, NULL);
 572        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 573}
 574
 575static void
 576l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
 577{
 578        struct sk_buff *skb;
 579        u_char tmp[16];
 580        u_char *p = tmp;
 581        int l;
 582        u_char cause = 0x90;
 583        u_char clen = 1;
 584
 585        L3DelTimer(&pc->timer);
 586        if (pc->para.cause != NO_CAUSE)
 587                cause = pc->para.cause;
 588        /* Map DSS1 causes */
 589        switch (cause & 0x7f) {
 590        case 0x10:
 591                clen = 0;
 592                break;
 593        case 0x15:
 594                cause = CAUSE_CallRejected;
 595                break;
 596        }
 597        MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1);
 598        *p++ = WE0_cause;
 599        *p++ = clen;            /* Laenge */
 600        if (clen)
 601                *p++ = cause;
 602        newl3state(pc, 19);
 603        l = p - tmp;
 604        if (!(skb = l3_alloc_skb(l)))
 605                return;
 606        skb_put_data(skb, tmp, l);
 607        l3_msg(pc->st, DL_DATA | REQUEST, skb);
 608        L3AddTimer(&pc->timer, T308, CC_T308_1);
 609}
 610
 611static void
 612l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
 613{
 614        L3DelTimer(&pc->timer);
 615        pc->para.cause = 0xE6;
 616        l3_1tr6_disconnect_req(pc, pr, NULL);
 617        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 618}
 619
 620static void
 621l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
 622{
 623        L3DelTimer(&pc->timer);
 624        pc->para.cause = 0xE6;
 625        l3_1tr6_disconnect_req(pc, pr, NULL);
 626        pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
 627}
 628
 629static void
 630l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg)
 631{
 632        L3DelTimer(&pc->timer);
 633        l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
 634        L3AddTimer(&pc->timer, T308, CC_T308_2);
 635        newl3state(pc, 19);
 636}
 637
 638static void
 639l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
 640{
 641        L3DelTimer(&pc->timer);
 642        pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
 643        release_l3_process(pc);
 644}
 645
 646static void
 647l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
 648{
 649        pc->para.cause = CAUSE_LocalProcErr;
 650        l3_1tr6_disconnect_req(pc, pr, NULL);
 651        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 652}
 653
 654static void
 655l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
 656{
 657        newl3state(pc, 0);
 658        pc->para.cause = 0x1b;          /* Destination out of order */
 659        pc->para.loc = 0;
 660        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 661        release_l3_process(pc);
 662}
 663
 664/* *INDENT-OFF* */
 665static struct stateentry downstl[] =
 666{
 667        {SBIT(0),
 668         CC_SETUP | REQUEST, l3_1tr6_setup_req},
 669        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
 670         SBIT(10),
 671         CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req},
 672        {SBIT(12),
 673         CC_RELEASE | REQUEST, l3_1tr6_release_req},
 674        {SBIT(6),
 675         CC_IGNORE | REQUEST, l3_1tr6_reset},
 676        {SBIT(6),
 677         CC_REJECT | REQUEST, l3_1tr6_disconnect_req},
 678        {SBIT(6),
 679         CC_ALERTING | REQUEST, l3_1tr6_alert_req},
 680        {SBIT(6) | SBIT(7),
 681         CC_SETUP | RESPONSE, l3_1tr6_setup_rsp},
 682        {SBIT(1),
 683         CC_T303, l3_1tr6_t303},
 684        {SBIT(2),
 685         CC_T304, l3_1tr6_t304},
 686        {SBIT(3),
 687         CC_T310, l3_1tr6_t310},
 688        {SBIT(8),
 689         CC_T313, l3_1tr6_t313},
 690        {SBIT(11),
 691         CC_T305, l3_1tr6_t305},
 692        {SBIT(19),
 693         CC_T308_1, l3_1tr6_t308_1},
 694        {SBIT(19),
 695         CC_T308_2, l3_1tr6_t308_2},
 696};
 697
 698static struct stateentry datastln1[] =
 699{
 700        {SBIT(0),
 701         MT_N1_INVALID, l3_1tr6_invalid},
 702        {SBIT(0),
 703         MT_N1_SETUP, l3_1tr6_setup},
 704        {SBIT(1),
 705         MT_N1_SETUP_ACK, l3_1tr6_setup_ack},
 706        {SBIT(1) | SBIT(2),
 707         MT_N1_CALL_SENT, l3_1tr6_call_sent},
 708        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
 709         MT_N1_DISC, l3_1tr6_disc},
 710        {SBIT(2) | SBIT(3) | SBIT(4),
 711         MT_N1_ALERT, l3_1tr6_alert},
 712        {SBIT(2) | SBIT(3) | SBIT(4),
 713         MT_N1_CONN, l3_1tr6_connect},
 714        {SBIT(2),
 715         MT_N1_INFO, l3_1tr6_info_s2},
 716        {SBIT(8),
 717         MT_N1_CONN_ACK, l3_1tr6_connect_ack},
 718        {SBIT(10),
 719         MT_N1_INFO, l3_1tr6_info},
 720        {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
 721         SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
 722         MT_N1_REL, l3_1tr6_rel},
 723        {SBIT(19),
 724         MT_N1_REL, l3_1tr6_rel_ack},
 725        {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
 726         SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
 727         MT_N1_REL_ACK, l3_1tr6_invalid},
 728        {SBIT(19),
 729         MT_N1_REL_ACK, l3_1tr6_rel_ack}
 730};
 731
 732static struct stateentry manstatelist[] =
 733{
 734        {SBIT(2),
 735         DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset},
 736        {ALL_STATES,
 737         DL_RELEASE | INDICATION, l3_1tr6_dl_release},
 738};
 739
 740/* *INDENT-ON* */
 741
 742static void
 743up1tr6(struct PStack *st, int pr, void *arg)
 744{
 745        int i, mt, cr;
 746        struct l3_process *proc;
 747        struct sk_buff *skb = arg;
 748
 749        switch (pr) {
 750        case (DL_DATA | INDICATION):
 751        case (DL_UNIT_DATA | INDICATION):
 752                break;
 753        case (DL_ESTABLISH | CONFIRM):
 754        case (DL_ESTABLISH | INDICATION):
 755        case (DL_RELEASE | INDICATION):
 756        case (DL_RELEASE | CONFIRM):
 757                l3_msg(st, pr, arg);
 758                return;
 759                break;
 760        }
 761        if (skb->len < 4) {
 762                if (st->l3.debug & L3_DEB_PROTERR) {
 763                        l3_debug(st, "up1tr6 len only %d", skb->len);
 764                }
 765                dev_kfree_skb(skb);
 766                return;
 767        }
 768        if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
 769                if (st->l3.debug & L3_DEB_PROTERR) {
 770                        l3_debug(st, "up1tr6%sunexpected discriminator %x message len %d",
 771                                (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
 772                                skb->data[0], skb->len);
 773                }
 774                dev_kfree_skb(skb);
 775                return;
 776        }
 777        if (skb->data[1] != 1) {
 778                if (st->l3.debug & L3_DEB_PROTERR) {
 779                        l3_debug(st, "up1tr6 CR len not 1");
 780                }
 781                dev_kfree_skb(skb);
 782                return;
 783        }
 784        cr = skb->data[2];
 785        mt = skb->data[3];
 786        if (skb->data[0] == PROTO_DIS_N0) {
 787                dev_kfree_skb(skb);
 788                if (st->l3.debug & L3_DEB_STATE) {
 789                        l3_debug(st, "up1tr6%s N0 mt %x unhandled",
 790                                (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt);
 791                }
 792        } else if (skb->data[0] == PROTO_DIS_N1) {
 793                if (!(proc = getl3proc(st, cr))) {
 794                        if (mt == MT_N1_SETUP) {
 795                                if (cr < 128) {
 796                                        if (!(proc = new_l3_process(st, cr))) {
 797                                                if (st->l3.debug & L3_DEB_PROTERR) {
 798                                                        l3_debug(st, "up1tr6 no roc mem");
 799                                                }
 800                                                dev_kfree_skb(skb);
 801                                                return;
 802                                        }
 803                                } else {
 804                                        dev_kfree_skb(skb);
 805                                        return;
 806                                }
 807                        } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) ||
 808                                   (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) ||
 809                                   (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) ||
 810                                   (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) ||
 811                                   (mt == MT_N1_INFO)) {
 812                                dev_kfree_skb(skb);
 813                                return;
 814                        } else {
 815                                if (!(proc = new_l3_process(st, cr))) {
 816                                        if (st->l3.debug & L3_DEB_PROTERR) {
 817                                                l3_debug(st, "up1tr6 no roc mem");
 818                                        }
 819                                        dev_kfree_skb(skb);
 820                                        return;
 821                                }
 822                                mt = MT_N1_INVALID;
 823                        }
 824                }
 825                for (i = 0; i < ARRAY_SIZE(datastln1); i++)
 826                        if ((mt == datastln1[i].primitive) &&
 827                            ((1 << proc->state) & datastln1[i].state))
 828                                break;
 829                if (i == ARRAY_SIZE(datastln1)) {
 830                        dev_kfree_skb(skb);
 831                        if (st->l3.debug & L3_DEB_STATE) {
 832                                l3_debug(st, "up1tr6%sstate %d mt %x unhandled",
 833                                        (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
 834                                        proc->state, mt);
 835                        }
 836                        return;
 837                } else {
 838                        if (st->l3.debug & L3_DEB_STATE) {
 839                                l3_debug(st, "up1tr6%sstate %d mt %x",
 840                                        (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
 841                                        proc->state, mt);
 842                        }
 843                        datastln1[i].rout(proc, pr, skb);
 844                }
 845        }
 846}
 847
 848static void
 849down1tr6(struct PStack *st, int pr, void *arg)
 850{
 851        int i, cr;
 852        struct l3_process *proc;
 853        struct Channel *chan;
 854
 855        if ((DL_ESTABLISH | REQUEST) == pr) {
 856                l3_msg(st, pr, NULL);
 857                return;
 858        } else if ((CC_SETUP | REQUEST) == pr) {
 859                chan = arg;
 860                cr = newcallref();
 861                cr |= 0x80;
 862                if (!(proc = new_l3_process(st, cr))) {
 863                        return;
 864                } else {
 865                        proc->chan = chan;
 866                        chan->proc = proc;
 867                        memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
 868                        proc->callref = cr;
 869                }
 870        } else {
 871                proc = arg;
 872        }
 873
 874        for (i = 0; i < ARRAY_SIZE(downstl); i++)
 875                if ((pr == downstl[i].primitive) &&
 876                    ((1 << proc->state) & downstl[i].state))
 877                        break;
 878        if (i == ARRAY_SIZE(downstl)) {
 879                if (st->l3.debug & L3_DEB_STATE) {
 880                        l3_debug(st, "down1tr6 state %d prim %d unhandled",
 881                                proc->state, pr);
 882                }
 883        } else {
 884                if (st->l3.debug & L3_DEB_STATE) {
 885                        l3_debug(st, "down1tr6 state %d prim %d",
 886                                proc->state, pr);
 887                }
 888                downstl[i].rout(proc, pr, arg);
 889        }
 890}
 891
 892static void
 893man1tr6(struct PStack *st, int pr, void *arg)
 894{
 895        int i;
 896        struct l3_process *proc = arg;
 897
 898        if (!proc) {
 899                printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
 900                return;
 901        }
 902        for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
 903                if ((pr == manstatelist[i].primitive) &&
 904                    ((1 << proc->state) & manstatelist[i].state))
 905                        break;
 906        if (i == ARRAY_SIZE(manstatelist)) {
 907                if (st->l3.debug & L3_DEB_STATE) {
 908                        l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
 909                                 proc->callref & 0x7f, proc->state, pr);
 910                }
 911        } else {
 912                if (st->l3.debug & L3_DEB_STATE) {
 913                        l3_debug(st, "cr %d man1tr6 state %d prim %d",
 914                                 proc->callref & 0x7f, proc->state, pr);
 915                }
 916                manstatelist[i].rout(proc, pr, arg);
 917        }
 918}
 919
 920void
 921setstack_1tr6(struct PStack *st)
 922{
 923        char tmp[64];
 924
 925        st->lli.l4l3 = down1tr6;
 926        st->l2.l2l3 = up1tr6;
 927        st->l3.l3ml3 = man1tr6;
 928        st->l3.N303 = 0;
 929
 930        strcpy(tmp, l3_1tr6_revision);
 931        printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
 932}
 933