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