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