linux/drivers/isdn/hisax/q931.c
<<
>>
Prefs
   1/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $
   2 *
   3 * code to decode ITU Q.931 call control messages
   4 *
   5 * Author       Jan den Ouden
   6 * Copyright    by Jan den Ouden
   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 * Changelog:
  12 *
  13 * Pauline Middelink    general improvements
  14 * Beat Doebeli         cause texts, display information element
  15 * Karsten Keil         cause texts, display information element for 1TR6
  16 *
  17 */
  18
  19
  20#include "hisax.h"
  21#include "l3_1tr6.h"
  22
  23void
  24iecpy(u_char * dest, u_char * iestart, int ieoffset)
  25{
  26        u_char *p;
  27        int l;
  28
  29        p = iestart + ieoffset + 2;
  30        l = iestart[1] - ieoffset;
  31        while (l--)
  32                *dest++ = *p++;
  33        *dest++ = '\0';
  34}
  35
  36/*
  37 * According to Table 4-2/Q.931
  38 */
  39static
  40struct MessageType {
  41        u_char nr;
  42        char *descr;
  43} mtlist[] = {
  44
  45        {
  46                0x1, "ALERTING"
  47        },
  48        {
  49                0x2, "CALL PROCEEDING"
  50        },
  51        {
  52                0x7, "CONNECT"
  53        },
  54        {
  55                0xf, "CONNECT ACKNOWLEDGE"
  56        },
  57        {
  58                0x3, "PROGRESS"
  59        },
  60        {
  61                0x5, "SETUP"
  62        },
  63        {
  64                0xd, "SETUP ACKNOWLEDGE"
  65        },
  66        {
  67                0x24, "HOLD"
  68        },
  69        {
  70                0x28, "HOLD ACKNOWLEDGE"
  71        },
  72        {
  73                0x30, "HOLD REJECT"
  74        },
  75        {
  76                0x31, "RETRIEVE"
  77        },
  78        {
  79                0x33, "RETRIEVE ACKNOWLEDGE"
  80        },
  81        {
  82                0x37, "RETRIEVE REJECT"
  83        },
  84        {
  85                0x26, "RESUME"
  86        },
  87        {
  88                0x2e, "RESUME ACKNOWLEDGE"
  89        },
  90        {
  91                0x22, "RESUME REJECT"
  92        },
  93        {
  94                0x25, "SUSPEND"
  95        },
  96        {
  97                0x2d, "SUSPEND ACKNOWLEDGE"
  98        },
  99        {
 100                0x21, "SUSPEND REJECT"
 101        },
 102        {
 103                0x20, "USER INFORMATION"
 104        },
 105        {
 106                0x45, "DISCONNECT"
 107        },
 108        {
 109                0x4d, "RELEASE"
 110        },
 111        {
 112                0x5a, "RELEASE COMPLETE"
 113        },
 114        {
 115                0x46, "RESTART"
 116        },
 117        {
 118                0x4e, "RESTART ACKNOWLEDGE"
 119        },
 120        {
 121                0x60, "SEGMENT"
 122        },
 123        {
 124                0x79, "CONGESTION CONTROL"
 125        },
 126        {
 127                0x7b, "INFORMATION"
 128        },
 129        {
 130                0x62, "FACILITY"
 131        },
 132        {
 133                0x6e, "NOTIFY"
 134        },
 135        {
 136                0x7d, "STATUS"
 137        },
 138        {
 139                0x75, "STATUS ENQUIRY"
 140        }
 141};
 142
 143#define MTSIZE ARRAY_SIZE(mtlist)
 144
 145static
 146struct MessageType mt_n0[] =
 147{
 148        {MT_N0_REG_IND, "REGister INDication"},
 149        {MT_N0_CANC_IND, "CANCel INDication"},
 150        {MT_N0_FAC_STA, "FACility STAtus"},
 151        {MT_N0_STA_ACK, "STAtus ACKnowledge"},
 152        {MT_N0_STA_REJ, "STAtus REJect"},
 153        {MT_N0_FAC_INF, "FACility INFormation"},
 154        {MT_N0_INF_ACK, "INFormation ACKnowledge"},
 155        {MT_N0_INF_REJ, "INFormation REJect"},
 156        {MT_N0_CLOSE, "CLOSE"},
 157        {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
 158};
 159
 160#define MT_N0_LEN ARRAY_SIZE(mt_n0)
 161
 162static
 163struct MessageType mt_n1[] =
 164{
 165        {MT_N1_ESC, "ESCape"},
 166        {MT_N1_ALERT, "ALERT"},
 167        {MT_N1_CALL_SENT, "CALL SENT"},
 168        {MT_N1_CONN, "CONNect"},
 169        {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
 170        {MT_N1_SETUP, "SETUP"},
 171        {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
 172        {MT_N1_RES, "RESume"},
 173        {MT_N1_RES_ACK, "RESume ACKnowledge"},
 174        {MT_N1_RES_REJ, "RESume REJect"},
 175        {MT_N1_SUSP, "SUSPend"},
 176        {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
 177        {MT_N1_SUSP_REJ, "SUSPend REJect"},
 178        {MT_N1_USER_INFO, "USER INFO"},
 179        {MT_N1_DET, "DETach"},
 180        {MT_N1_DISC, "DISConnect"},
 181        {MT_N1_REL, "RELease"},
 182        {MT_N1_REL_ACK, "RELease ACKnowledge"},
 183        {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
 184        {MT_N1_CANC_REJ, "CANCel REJect"},
 185        {MT_N1_CON_CON, "CONgestion CONtrol"},
 186        {MT_N1_FAC, "FACility"},
 187        {MT_N1_FAC_ACK, "FACility ACKnowledge"},
 188        {MT_N1_FAC_CAN, "FACility CANcel"},
 189        {MT_N1_FAC_REG, "FACility REGister"},
 190        {MT_N1_FAC_REJ, "FACility REJect"},
 191        {MT_N1_INFO, "INFOrmation"},
 192        {MT_N1_REG_ACK, "REGister ACKnowledge"},
 193        {MT_N1_REG_REJ, "REGister REJect"},
 194        {MT_N1_STAT, "STATus"}
 195};
 196
 197#define MT_N1_LEN ARRAY_SIZE(mt_n1)
 198
 199
 200static int
 201prbits(char *dest, u_char b, int start, int len)
 202{
 203        char *dp = dest;
 204
 205        b = b << (8 - start);
 206        while (len--) {
 207                if (b & 0x80)
 208                        *dp++ = '1';
 209                else
 210                        *dp++ = '0';
 211                b = b << 1;
 212        }
 213        return (dp - dest);
 214}
 215
 216static
 217u_char *
 218skipext(u_char * p)
 219{
 220        while (!(*p++ & 0x80));
 221        return (p);
 222}
 223
 224/*
 225 * Cause Values According to Q.850
 226 * edescr: English description
 227 * ddescr: German description used by Swissnet II (Swiss Telecom
 228 *         not yet written...
 229 */
 230
 231static
 232struct CauseValue {
 233        u_char nr;
 234        char *edescr;
 235        char *ddescr;
 236} cvlist[] = {
 237
 238        {
 239                0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
 240        },
 241        {
 242                0x02, "No route to specified transit network", ""
 243        },
 244        {
 245                0x03, "No route to destination", ""
 246        },
 247        {
 248                0x04, "Send special information tone", ""
 249        },
 250        {
 251                0x05, "Misdialled trunk prefix", ""
 252        },
 253        {
 254                0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
 255        },
 256        {
 257                0x07, "Channel awarded and being delivered in an established channel", ""
 258        },
 259        {
 260                0x08, "Preemption", ""
 261        },
 262        {
 263                0x09, "Preemption - circuit reserved for reuse", ""
 264        },
 265        {
 266                0x10, "Normal call clearing", "Normale Ausloesung"
 267        },
 268        {
 269                0x11, "User busy", "TNB besetzt"
 270        },
 271        {
 272                0x12, "No user responding", ""
 273        },
 274        {
 275                0x13, "No answer from user (user alerted)", ""
 276        },
 277        {
 278                0x14, "Subscriber absent", ""
 279        },
 280        {
 281                0x15, "Call rejected", ""
 282        },
 283        {
 284                0x16, "Number changed", ""
 285        },
 286        {
 287                0x1a, "non-selected user clearing", ""
 288        },
 289        {
 290                0x1b, "Destination out of order", ""
 291        },
 292        {
 293                0x1c, "Invalid number format (address incomplete)", ""
 294        },
 295        {
 296                0x1d, "Facility rejected", ""
 297        },
 298        {
 299                0x1e, "Response to Status enquiry", ""
 300        },
 301        {
 302                0x1f, "Normal, unspecified", ""
 303        },
 304        {
 305                0x22, "No circuit/channel available", ""
 306        },
 307        {
 308                0x26, "Network out of order", ""
 309        },
 310        {
 311                0x27, "Permanent frame mode connection out-of-service", ""
 312        },
 313        {
 314                0x28, "Permanent frame mode connection operational", ""
 315        },
 316        {
 317                0x29, "Temporary failure", ""
 318        },
 319        {
 320                0x2a, "Switching equipment congestion", ""
 321        },
 322        {
 323                0x2b, "Access information discarded", ""
 324        },
 325        {
 326                0x2c, "Requested circuit/channel not available", ""
 327        },
 328        {
 329                0x2e, "Precedence call blocked", ""
 330        },
 331        {
 332                0x2f, "Resource unavailable, unspecified", ""
 333        },
 334        {
 335                0x31, "Quality of service unavailable", ""
 336        },
 337        {
 338                0x32, "Requested facility not subscribed", ""
 339        },
 340        {
 341                0x35, "Outgoing calls barred within CUG", ""
 342        },
 343        {
 344                0x37, "Incoming calls barred within CUG", ""
 345        },
 346        {
 347                0x39, "Bearer capability not authorized", ""
 348        },
 349        {
 350                0x3a, "Bearer capability not presently available", ""
 351        },
 352        {
 353                0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
 354        },
 355        {
 356                0x3f, "Service or option not available, unspecified", ""
 357        },
 358        {
 359                0x41, "Bearer capability not implemented", ""
 360        },
 361        {
 362                0x42, "Channel type not implemented", ""
 363        },
 364        {
 365                0x43, "Requested facility not implemented", ""
 366        },
 367        {
 368                0x44, "Only restricted digital information bearer capability is available", ""
 369        },
 370        {
 371                0x4f, "Service or option not implemented", ""
 372        },
 373        {
 374                0x51, "Invalid call reference value", ""
 375        },
 376        {
 377                0x52, "Identified channel does not exist", ""
 378        },
 379        {
 380                0x53, "A suspended call exists, but this call identity does not", ""
 381        },
 382        {
 383                0x54, "Call identity in use", ""
 384        },
 385        {
 386                0x55, "No call suspended", ""
 387        },
 388        {
 389                0x56, "Call having the requested call identity has been cleared", ""
 390        },
 391        {
 392                0x57, "User not member of CUG", ""
 393        },
 394        {
 395                0x58, "Incompatible destination", ""
 396        },
 397        {
 398                0x5a, "Non-existent CUG", ""
 399        },
 400        {
 401                0x5b, "Invalid transit network selection", ""
 402        },
 403        {
 404                0x5f, "Invalid message, unspecified", ""
 405        },
 406        {
 407                0x60, "Mandatory information element is missing", ""
 408        },
 409        {
 410                0x61, "Message type non-existent or not implemented", ""
 411        },
 412        {
 413                0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
 414        },
 415        {
 416                0x63, "Information element/parameter non-existent or not implemented", ""
 417        },
 418        {
 419                0x64, "Invalid information element contents", ""
 420        },
 421        {
 422                0x65, "Message not compatible with call state", ""
 423        },
 424        {
 425                0x66, "Recovery on timer expiry", ""
 426        },
 427        {
 428                0x67, "Parameter non-existent or not implemented - passed on", ""
 429        },
 430        {
 431                0x6e, "Message with unrecognized parameter discarded", ""
 432        },
 433        {
 434                0x6f, "Protocol error, unspecified", ""
 435        },
 436        {
 437                0x7f, "Interworking, unspecified", ""
 438        },
 439};
 440
 441#define CVSIZE ARRAY_SIZE(cvlist)
 442
 443static
 444int
 445prcause(char *dest, u_char * p)
 446{
 447        u_char *end;
 448        char *dp = dest;
 449        int i, cause;
 450
 451        end = p + p[1] + 1;
 452        p += 2;
 453        dp += sprintf(dp, "    coding ");
 454        dp += prbits(dp, *p, 7, 2);
 455        dp += sprintf(dp, " location ");
 456        dp += prbits(dp, *p, 4, 4);
 457        *dp++ = '\n';
 458        p = skipext(p);
 459
 460        cause = 0x7f & *p++;
 461
 462        /* locate cause value */
 463        for (i = 0; i < CVSIZE; i++)
 464                if (cvlist[i].nr == cause)
 465                        break;
 466
 467        /* display cause value if it exists */
 468        if (i == CVSIZE)
 469                dp += sprintf(dp, "Unknown cause type %x!\n", cause);
 470        else
 471                dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
 472
 473        while (!0) {
 474                if (p > end)
 475                        break;
 476                dp += sprintf(dp, "    diag attribute %d ", *p++ & 0x7f);
 477                dp += sprintf(dp, " rej %d ", *p & 0x7f);
 478                if (*p & 0x80) {
 479                        *dp++ = '\n';
 480                        break;
 481                } else
 482                        dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
 483        }
 484        return (dp - dest);
 485
 486}
 487
 488static
 489struct MessageType cause_1tr6[] =
 490{
 491        {CAUSE_InvCRef, "Invalid Call Reference"},
 492        {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
 493        {CAUSE_CIDunknown, "Caller Identity unknown"},
 494        {CAUSE_CIDinUse, "Caller Identity in Use"},
 495        {CAUSE_NoChans, "No Channels available"},
 496        {CAUSE_FacNotImpl, "Facility Not Implemented"},
 497        {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
 498        {CAUSE_OutgoingBarred, "Outgoing calls barred"},
 499        {CAUSE_UserAccessBusy, "User Access Busy"},
 500        {CAUSE_NegativeGBG, "Negative GBG"},
 501        {CAUSE_UnknownGBG, "Unknown  GBG"},
 502        {CAUSE_NoSPVknown, "No SPV known"},
 503        {CAUSE_DestNotObtain, "Destination not obtainable"},
 504        {CAUSE_NumberChanged, "Number changed"},
 505        {CAUSE_OutOfOrder, "Out Of Order"},
 506        {CAUSE_NoUserResponse, "No User Response"},
 507        {CAUSE_UserBusy, "User Busy"},
 508        {CAUSE_IncomingBarred, "Incoming Barred"},
 509        {CAUSE_CallRejected, "Call Rejected"},
 510        {CAUSE_NetworkCongestion, "Network Congestion"},
 511        {CAUSE_RemoteUser, "Remote User initiated"},
 512        {CAUSE_LocalProcErr, "Local Procedure Error"},
 513        {CAUSE_RemoteProcErr, "Remote Procedure Error"},
 514        {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
 515        {CAUSE_RemoteUserResumed, "Remote User Resumed"},
 516        {CAUSE_UserInfoDiscarded, "User Info Discarded"}
 517};
 518
 519static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
 520
 521static int
 522prcause_1tr6(char *dest, u_char * p)
 523{
 524        char *dp = dest;
 525        int i, cause;
 526
 527        p++;
 528        if (0 == *p) {
 529                dp += sprintf(dp, "   OK (cause length=0)\n");
 530                return (dp - dest);
 531        } else if (*p > 1) {
 532                dp += sprintf(dp, "    coding ");
 533                dp += prbits(dp, p[2], 7, 2);
 534                dp += sprintf(dp, " location ");
 535                dp += prbits(dp, p[2], 4, 4);
 536                *dp++ = '\n';
 537        }
 538        p++;
 539        cause = 0x7f & *p;
 540
 541        /* locate cause value */
 542        for (i = 0; i < cause_1tr6_len; i++)
 543                if (cause_1tr6[i].nr == cause)
 544                        break;
 545
 546        /* display cause value if it exists */
 547        if (i == cause_1tr6_len)
 548                dp += sprintf(dp, "Unknown cause type %x!\n", cause);
 549        else
 550                dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
 551
 552        return (dp - dest);
 553
 554}
 555
 556static int
 557prchident(char *dest, u_char * p)
 558{
 559        char *dp = dest;
 560
 561        p += 2;
 562        dp += sprintf(dp, "    octet 3 ");
 563        dp += prbits(dp, *p, 8, 8);
 564        *dp++ = '\n';
 565        return (dp - dest);
 566}
 567
 568static int
 569prcalled(char *dest, u_char * p)
 570{
 571        int l;
 572        char *dp = dest;
 573
 574        p++;
 575        l = *p++ - 1;
 576        dp += sprintf(dp, "    octet 3 ");
 577        dp += prbits(dp, *p++, 8, 8);
 578        *dp++ = '\n';
 579        dp += sprintf(dp, "    number digits ");
 580        while (l--)
 581                *dp++ = *p++;
 582        *dp++ = '\n';
 583        return (dp - dest);
 584}
 585static int
 586prcalling(char *dest, u_char * p)
 587{
 588        int l;
 589        char *dp = dest;
 590
 591        p++;
 592        l = *p++ - 1;
 593        dp += sprintf(dp, "    octet 3 ");
 594        dp += prbits(dp, *p, 8, 8);
 595        *dp++ = '\n';
 596        if (!(*p & 0x80)) {
 597                dp += sprintf(dp, "    octet 3a ");
 598                dp += prbits(dp, *++p, 8, 8);
 599                *dp++ = '\n';
 600                l--;
 601        };
 602        p++;
 603
 604        dp += sprintf(dp, "    number digits ");
 605        while (l--)
 606                *dp++ = *p++;
 607        *dp++ = '\n';
 608        return (dp - dest);
 609}
 610
 611static
 612int
 613prbearer(char *dest, u_char * p)
 614{
 615        char *dp = dest, ch;
 616
 617        p += 2;
 618        dp += sprintf(dp, "    octet 3  ");
 619        dp += prbits(dp, *p++, 8, 8);
 620        *dp++ = '\n';
 621        dp += sprintf(dp, "    octet 4  ");
 622        dp += prbits(dp, *p, 8, 8);
 623        *dp++ = '\n';
 624        if ((*p++ & 0x1f) == 0x18) {
 625                dp += sprintf(dp, "    octet 4.1 ");
 626                dp += prbits(dp, *p++, 8, 8);
 627                *dp++ = '\n';
 628        }
 629        /* check for user information layer 1 */
 630        if ((*p & 0x60) == 0x20) {
 631                ch = ' ';
 632                do {
 633                        dp += sprintf(dp, "    octet 5%c ", ch);
 634                        dp += prbits(dp, *p, 8, 8);
 635                        *dp++ = '\n';
 636                        if (ch == ' ')
 637                                ch = 'a';
 638                        else
 639                                ch++;
 640                }
 641                while (!(*p++ & 0x80));
 642        }
 643        /* check for user information layer 2 */
 644        if ((*p & 0x60) == 0x40) {
 645                dp += sprintf(dp, "    octet 6  ");
 646                dp += prbits(dp, *p++, 8, 8);
 647                *dp++ = '\n';
 648        }
 649        /* check for user information layer 3 */
 650        if ((*p & 0x60) == 0x60) {
 651                dp += sprintf(dp, "    octet 7  ");
 652                dp += prbits(dp, *p++, 8, 8);
 653                *dp++ = '\n';
 654        }
 655        return (dp - dest);
 656}
 657
 658
 659static
 660int
 661prbearer_ni1(char *dest, u_char * p)
 662{
 663        char *dp = dest;
 664        u_char len;
 665
 666        p++;
 667        len = *p++;
 668        dp += sprintf(dp, "    octet 3  ");
 669        dp += prbits(dp, *p, 8, 8);
 670        switch (*p++) {
 671                case 0x80:
 672                        dp += sprintf(dp, " Speech");
 673                        break;
 674                case 0x88:
 675                        dp += sprintf(dp, " Unrestricted digital information");
 676                        break;
 677                case 0x90:
 678                        dp += sprintf(dp, " 3.1 kHz audio");
 679                        break;
 680                default:
 681                        dp += sprintf(dp, " Unknown information-transfer capability");
 682        }
 683        *dp++ = '\n';
 684        dp += sprintf(dp, "    octet 4  ");
 685        dp += prbits(dp, *p, 8, 8);
 686        switch (*p++) {
 687                case 0x90:
 688                        dp += sprintf(dp, " 64 kbps, circuit mode");
 689                        break;
 690                case 0xc0:
 691                        dp += sprintf(dp, " Packet mode");
 692                        break;
 693                default:
 694                        dp += sprintf(dp, " Unknown transfer mode");
 695        }
 696        *dp++ = '\n';
 697        if (len > 2) {
 698                dp += sprintf(dp, "    octet 5  ");
 699                dp += prbits(dp, *p, 8, 8);
 700                switch (*p++) {
 701                        case 0x21:
 702                                dp += sprintf(dp, " Rate adaption\n");
 703                                dp += sprintf(dp, "    octet 5a ");
 704                                dp += prbits(dp, *p, 8, 8);
 705                                break;
 706                        case 0xa2:
 707                                dp += sprintf(dp, " u-law");
 708                                break;
 709                        default:
 710                                dp += sprintf(dp, " Unknown UI layer 1 protocol");
 711                }
 712                *dp++ = '\n';
 713        }
 714        return (dp - dest);
 715}
 716
 717static int
 718general(char *dest, u_char * p)
 719{
 720        char *dp = dest;
 721        char ch = ' ';
 722        int l, octet = 3;
 723
 724        p++;
 725        l = *p++;
 726        /* Iterate over all octets in the information element */
 727        while (l--) {
 728                dp += sprintf(dp, "    octet %d%c ", octet, ch);
 729                dp += prbits(dp, *p++, 8, 8);
 730                *dp++ = '\n';
 731
 732                /* last octet in group? */
 733                if (*p & 0x80) {
 734                        octet++;
 735                        ch = ' ';
 736                } else if (ch == ' ')
 737                        ch = 'a';
 738                else
 739                        ch++;
 740        }
 741        return (dp - dest);
 742}
 743
 744static int
 745general_ni1(char *dest, u_char * p)
 746{
 747        char *dp = dest;
 748        char ch = ' ';
 749        int l, octet = 3;
 750
 751        p++;
 752        l = *p++;
 753        /* Iterate over all octets in the information element */
 754        while (l--) {
 755                dp += sprintf(dp, "    octet %d%c ", octet, ch);
 756                dp += prbits(dp, *p, 8, 8);
 757                *dp++ = '\n';
 758
 759                /* last octet in group? */
 760                if (*p++ & 0x80) {
 761                        octet++;
 762                        ch = ' ';
 763                } else if (ch == ' ')
 764                        ch = 'a';
 765                else
 766                        ch++;
 767        }
 768        return (dp - dest);
 769}
 770
 771static int
 772prcharge(char *dest, u_char * p)
 773{
 774        char *dp = dest;
 775        int l;
 776
 777        p++;
 778        l = *p++ - 1;
 779        dp += sprintf(dp, "    GEA ");
 780        dp += prbits(dp, *p++, 8, 8);
 781        dp += sprintf(dp, "  Anzahl: ");
 782        /* Iterate over all octets in the * information element */
 783        while (l--)
 784                *dp++ = *p++;
 785        *dp++ = '\n';
 786        return (dp - dest);
 787}
 788static int
 789prtext(char *dest, u_char * p)
 790{
 791        char *dp = dest;
 792        int l;
 793
 794        p++;
 795        l = *p++;
 796        dp += sprintf(dp, "    ");
 797        /* Iterate over all octets in the * information element */
 798        while (l--)
 799                *dp++ = *p++;
 800        *dp++ = '\n';
 801        return (dp - dest);
 802}
 803
 804static int
 805prfeatureind(char *dest, u_char * p)
 806{
 807        char *dp = dest;
 808
 809        p += 2; /* skip id, len */
 810        dp += sprintf(dp, "    octet 3  ");
 811        dp += prbits(dp, *p, 8, 8);
 812        *dp++ = '\n';
 813        if (!(*p++ & 80)) {
 814                dp += sprintf(dp, "    octet 4  ");
 815                dp += prbits(dp, *p++, 8, 8);
 816                *dp++ = '\n';
 817        }
 818        dp += sprintf(dp, "    Status:  ");
 819        switch (*p) {
 820                case 0:
 821                        dp += sprintf(dp, "Idle");
 822                        break;
 823                case 1:
 824                        dp += sprintf(dp, "Active");
 825                        break;
 826                case 2:
 827                        dp += sprintf(dp, "Prompt");
 828                        break;
 829                case 3:
 830                        dp += sprintf(dp, "Pending");
 831                        break;
 832                default:
 833                        dp += sprintf(dp, "(Reserved)");
 834                        break;
 835        }
 836        *dp++ = '\n';
 837        return (dp - dest);
 838}
 839
 840static
 841struct DTag { /* Display tags */
 842        u_char nr;
 843        char *descr;
 844} dtaglist[] = {
 845        { 0x82, "Continuation" },
 846        { 0x83, "Called address" },
 847        { 0x84, "Cause" },
 848        { 0x85, "Progress indicator" },
 849        { 0x86, "Notification indicator" },
 850        { 0x87, "Prompt" },
 851        { 0x88, "Accumlated digits" },
 852        { 0x89, "Status" },
 853        { 0x8a, "Inband" },
 854        { 0x8b, "Calling address" },
 855        { 0x8c, "Reason" },
 856        { 0x8d, "Calling party name" },
 857        { 0x8e, "Called party name" },
 858        { 0x8f, "Orignal called name" },
 859        { 0x90, "Redirecting name" },
 860        { 0x91, "Connected name" },
 861        { 0x92, "Originating restrictions" },
 862        { 0x93, "Date & time of day" },
 863        { 0x94, "Call Appearance ID" },
 864        { 0x95, "Feature address" },
 865        { 0x96, "Redirection name" },
 866        { 0x9e, "Text" },
 867};
 868#define DTAGSIZE ARRAY_SIZE(dtaglist)
 869
 870static int
 871disptext_ni1(char *dest, u_char * p)
 872{
 873        char *dp = dest;
 874        int l, tag, len, i;
 875
 876        p++;
 877        l = *p++ - 1;
 878        if (*p++ != 0x80) {
 879                dp += sprintf(dp, "    Unknown display type\n");
 880                return (dp - dest);
 881        }
 882        /* Iterate over all tag,length,text fields */
 883        while (l > 0) {
 884                tag = *p++;
 885                len = *p++;
 886                l -= len + 2;
 887                /* Don't space or skip */
 888                if ((tag == 0x80) || (tag == 0x81)) p++;
 889                else {
 890                        for (i = 0; i < DTAGSIZE; i++)
 891                                if (tag == dtaglist[i].nr)
 892                                        break;
 893
 894                        /* When not found, give appropriate msg */
 895                        if (i != DTAGSIZE) {
 896                                dp += sprintf(dp, "    %s: ", dtaglist[i].descr);
 897                                while (len--)
 898                                        *dp++ = *p++;
 899                        } else {
 900                                dp += sprintf(dp, "    (unknown display tag %2x): ", tag);
 901                                while (len--)
 902                                        *dp++ = *p++;
 903                        }
 904                        dp += sprintf(dp, "\n");
 905                }
 906        }
 907        return (dp - dest);
 908}
 909static int
 910display(char *dest, u_char * p)
 911{
 912        char *dp = dest;
 913        char ch = ' ';
 914        int l, octet = 3;
 915
 916        p++;
 917        l = *p++;
 918        /* Iterate over all octets in the * display-information element */
 919        dp += sprintf(dp, "   \"");
 920        while (l--) {
 921                dp += sprintf(dp, "%c", *p++);
 922
 923                /* last octet in group? */
 924                if (*p & 0x80) {
 925                        octet++;
 926                        ch = ' ';
 927                } else if (ch == ' ')
 928                        ch = 'a';
 929
 930                else
 931                        ch++;
 932        }
 933        *dp++ = '\"';
 934        *dp++ = '\n';
 935        return (dp - dest);
 936}
 937
 938static int
 939prfacility(char *dest, u_char * p)
 940{
 941        char *dp = dest;
 942        int l, l2;
 943
 944        p++;
 945        l = *p++;
 946        dp += sprintf(dp, "    octet 3 ");
 947        dp += prbits(dp, *p++, 8, 8);
 948        dp += sprintf(dp, "\n");
 949        l -= 1;
 950
 951        while (l > 0) {
 952                dp += sprintf(dp, "   octet 4 ");
 953                dp += prbits(dp, *p++, 8, 8);
 954                dp += sprintf(dp, "\n");
 955                dp += sprintf(dp, "   octet 5 %d\n", l2 = *p++ & 0x7f);
 956                l -= 2;
 957                dp += sprintf(dp, "   contents ");
 958                while (l2--) {
 959                        dp += sprintf(dp, "%2x ", *p++);
 960                        l--;
 961                }
 962                dp += sprintf(dp, "\n");
 963        }
 964
 965        return (dp - dest);
 966}
 967
 968static
 969struct InformationElement {
 970        u_char nr;
 971        char *descr;
 972        int (*f) (char *, u_char *);
 973} ielist[] = {
 974
 975        {
 976                0x00, "Segmented message", general
 977        },
 978        {
 979                0x04, "Bearer capability", prbearer
 980        },
 981        {
 982                0x08, "Cause", prcause
 983        },
 984        {
 985                0x10, "Call identity", general
 986        },
 987        {
 988                0x14, "Call state", general
 989        },
 990        {
 991                0x18, "Channel identification", prchident
 992        },
 993        {
 994                0x1c, "Facility", prfacility
 995        },
 996        {
 997                0x1e, "Progress indicator", general
 998        },
 999        {
1000                0x20, "Network-specific facilities", general
1001        },
1002        {
1003                0x27, "Notification indicator", general
1004        },
1005        {
1006                0x28, "Display", display
1007        },
1008        {
1009                0x29, "Date/Time", general
1010        },
1011        {
1012                0x2c, "Keypad facility", general
1013        },
1014        {
1015                0x34, "Signal", general
1016        },
1017        {
1018                0x40, "Information rate", general
1019        },
1020        {
1021                0x42, "End-to-end delay", general
1022        },
1023        {
1024                0x43, "Transit delay selection and indication", general
1025        },
1026        {
1027                0x44, "Packet layer binary parameters", general
1028        },
1029        {
1030                0x45, "Packet layer window size", general
1031        },
1032        {
1033                0x46, "Packet size", general
1034        },
1035        {
1036                0x47, "Closed user group", general
1037        },
1038        {
1039                0x4a, "Reverse charge indication", general
1040        },
1041        {
1042                0x6c, "Calling party number", prcalling
1043        },
1044        {
1045                0x6d, "Calling party subaddress", general
1046        },
1047        {
1048                0x70, "Called party number", prcalled
1049        },
1050        {
1051                0x71, "Called party subaddress", general
1052        },
1053        {
1054                0x74, "Redirecting number", general
1055        },
1056        {
1057                0x78, "Transit network selection", general
1058        },
1059        {
1060                0x79, "Restart indicator", general
1061        },
1062        {
1063                0x7c, "Low layer compatibility", general
1064        },
1065        {
1066                0x7d, "High layer compatibility", general
1067        },
1068        {
1069                0x7e, "User-user", general
1070        },
1071        {
1072                0x7f, "Escape for extension", general
1073        },
1074};
1075
1076
1077#define IESIZE ARRAY_SIZE(ielist)
1078
1079static
1080struct InformationElement ielist_ni1[] = {
1081        { 0x04, "Bearer Capability", prbearer_ni1 },
1082        { 0x08, "Cause", prcause },
1083        { 0x14, "Call State", general_ni1 },
1084        { 0x18, "Channel Identification", prchident },
1085        { 0x1e, "Progress Indicator", general_ni1 },
1086        { 0x27, "Notification Indicator", general_ni1 },
1087        { 0x2c, "Keypad Facility", prtext },
1088        { 0x32, "Information Request", general_ni1 },
1089        { 0x34, "Signal", general_ni1 },
1090        { 0x38, "Feature Activation", general_ni1 },
1091        { 0x39, "Feature Indication", prfeatureind },
1092        { 0x3a, "Service Profile Identification (SPID)", prtext },
1093        { 0x3b, "Endpoint Identifier", general_ni1 },
1094        { 0x6c, "Calling Party Number", prcalling },
1095        { 0x6d, "Calling Party Subaddress", general_ni1 },
1096        { 0x70, "Called Party Number", prcalled },
1097        { 0x71, "Called Party Subaddress", general_ni1 },
1098        { 0x74, "Redirecting Number", general_ni1 },
1099        { 0x78, "Transit Network Selection", general_ni1 },
1100        { 0x7c, "Low Layer Compatibility", general_ni1 },
1101        { 0x7d, "High Layer Compatibility", general_ni1 },
1102};
1103
1104
1105#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
1106
1107static
1108struct InformationElement ielist_ni1_cs5[] = {
1109        { 0x1d, "Operator system access", general_ni1 },
1110        { 0x2a, "Display text", disptext_ni1 },
1111};
1112
1113#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
1114
1115static
1116struct InformationElement ielist_ni1_cs6[] = {
1117        { 0x7b, "Call appearance", general_ni1 },
1118};
1119
1120#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
1121
1122static struct InformationElement we_0[] =
1123{
1124        {WE0_cause, "Cause", prcause_1tr6},
1125        {WE0_connAddr, "Connecting Address", prcalled},
1126        {WE0_callID, "Call IDentity", general},
1127        {WE0_chanID, "Channel IDentity", general},
1128        {WE0_netSpecFac, "Network Specific Facility", general},
1129        {WE0_display, "Display", general},
1130        {WE0_keypad, "Keypad", general},
1131        {WE0_origAddr, "Origination Address", prcalled},
1132        {WE0_destAddr, "Destination Address", prcalled},
1133        {WE0_userInfo, "User Info", general}
1134};
1135
1136#define WE_0_LEN ARRAY_SIZE(we_0)
1137
1138static struct InformationElement we_6[] =
1139{
1140        {WE6_serviceInd, "Service Indicator", general},
1141        {WE6_chargingInfo, "Charging Information", prcharge},
1142        {WE6_date, "Date", prtext},
1143        {WE6_facSelect, "Facility Select", general},
1144        {WE6_facStatus, "Facility Status", general},
1145        {WE6_statusCalled, "Status Called", general},
1146        {WE6_addTransAttr, "Additional Transmission Attributes", general}
1147};
1148#define WE_6_LEN ARRAY_SIZE(we_6)
1149
1150int
1151QuickHex(char *txt, u_char * p, int cnt)
1152{
1153        register int i;
1154        register char *t = txt;
1155        register u_char w;
1156
1157        for (i = 0; i < cnt; i++) {
1158                *t++ = ' ';
1159                w = (p[i] >> 4) & 0x0f;
1160                if (w < 10)
1161                        *t++ = '0' + w;
1162                else
1163                        *t++ = 'A' - 10 + w;
1164                w = p[i] & 0x0f;
1165                if (w < 10)
1166                        *t++ = '0' + w;
1167                else
1168                        *t++ = 'A' - 10 + w;
1169        }
1170        *t++ = 0;
1171        return (t - txt);
1172}
1173
1174void
1175LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
1176{
1177        char *dp;
1178
1179        if (size < 1)
1180                return;
1181        dp = cs->dlog;
1182        if (size < MAX_DLOG_SPACE / 3 - 10) {
1183                *dp++ = 'H';
1184                *dp++ = 'E';
1185                *dp++ = 'X';
1186                *dp++ = ':';
1187                dp += QuickHex(dp, buf, size);
1188                dp--;
1189                *dp++ = '\n';
1190                *dp = 0;
1191                HiSax_putstatus(cs, NULL, cs->dlog);
1192        } else
1193                HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
1194}
1195
1196void
1197dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
1198{
1199        u_char *bend, *buf;
1200        char *dp;
1201        unsigned char pd, cr_l, cr, mt;
1202        unsigned char sapi, tei, ftyp;
1203        int i, cset = 0, cs_old = 0, cs_fest = 0;
1204        int size, finish = 0;
1205
1206        if (skb->len < 3)
1207                return;
1208        /* display header */
1209        dp = cs->dlog;
1210        dp += jiftime(dp, jiffies);
1211        *dp++ = ' ';
1212        sapi = skb->data[0] >> 2;
1213        tei  = skb->data[1] >> 1;
1214        ftyp = skb->data[2];
1215        buf = skb->data;
1216        dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
1217        size = skb->len;
1218        
1219        if (tei == GROUP_TEI) {
1220                if (sapi == CTRL_SAPI) { /* sapi 0 */
1221                        if (ftyp == 3) {
1222                                dp += sprintf(dp, "broadcast\n");
1223                                buf += 3;
1224                                size -= 3;
1225                        } else {
1226                                dp += sprintf(dp, "no UI broadcast\n");
1227                                finish = 1;
1228                        }
1229                } else if (sapi == TEI_SAPI) {
1230                        dp += sprintf(dp, "tei management\n");
1231                        finish = 1;
1232                } else {
1233                        dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
1234                        finish = 1;
1235                }
1236        } else {
1237                if (sapi == CTRL_SAPI) {
1238                        if (!(ftyp & 1)) { /* IFrame */
1239                                dp += sprintf(dp, "with tei %d\n", tei);
1240                                buf += 4;
1241                                size -= 4;
1242                        } else {
1243                                dp += sprintf(dp, "SFrame with tei %d\n", tei);
1244                                finish = 1;
1245                        }
1246                } else {
1247                        dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1248                        finish = 1;
1249                }
1250        }
1251        bend = skb->data + skb->len;
1252        if (buf >= bend) {
1253                dp += sprintf(dp, "frame too short\n");
1254                finish = 1;
1255        }
1256        if (finish) {
1257                *dp = 0;
1258                HiSax_putstatus(cs, NULL, cs->dlog);
1259                return;
1260        }
1261        if ((0xfe & buf[0]) == PROTO_DIS_N0) {  /* 1TR6 */
1262                /* locate message type */
1263                pd = *buf++;
1264                cr_l = *buf++;
1265                if (cr_l)
1266                        cr = *buf++;
1267                else
1268                        cr = 0;
1269                mt = *buf++;
1270                if (pd == PROTO_DIS_N0) {       /* N0 */
1271                        for (i = 0; i < MT_N0_LEN; i++)
1272                                if (mt_n0[i].nr == mt)
1273                                        break;
1274                        /* display message type if it exists */
1275                        if (i == MT_N0_LEN)
1276                                dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
1277                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1278                                              size, mt);
1279                        else
1280                                dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1281                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1282                                              size, mt_n0[i].descr);
1283                } else {        /* N1 */
1284                        for (i = 0; i < MT_N1_LEN; i++)
1285                                if (mt_n1[i].nr == mt)
1286                                        break;
1287                        /* display message type if it exists */
1288                        if (i == MT_N1_LEN)
1289                                dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
1290                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1291                                              size, mt);
1292                        else
1293                                dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1294                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1295                                              size, mt_n1[i].descr);
1296                }
1297
1298                /* display each information element */
1299                while (buf < bend) {
1300                        /* Is it a single octet information element? */
1301                        if (*buf & 0x80) {
1302                                switch ((*buf >> 4) & 7) {
1303                                        case 1:
1304                                                dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1305                                                cs_old = cset;
1306                                                cset = *buf & 7;
1307                                                cs_fest = *buf & 8;
1308                                                break;
1309                                        case 3:
1310                                                dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1311                                                break;
1312                                        case 2:
1313                                                if (*buf == 0xa0) {
1314                                                        dp += sprintf(dp, "  More data\n");
1315                                                        break;
1316                                                }
1317                                                if (*buf == 0xa1) {
1318                                                        dp += sprintf(dp, "  Sending complete\n");
1319                                                }
1320                                                break;
1321                                                /* fall through */
1322                                        default:
1323                                                dp += sprintf(dp, "  Reserved %x\n", *buf);
1324                                                break;
1325                                }
1326                                buf++;
1327                                continue;
1328                        }
1329                        /* No, locate it in the table */
1330                        if (cset == 0) {
1331                                for (i = 0; i < WE_0_LEN; i++)
1332                                        if (*buf == we_0[i].nr)
1333                                                break;
1334
1335                                /* When found, give appropriate msg */
1336                                if (i != WE_0_LEN) {
1337                                        dp += sprintf(dp, "  %s\n", we_0[i].descr);
1338                                        dp += we_0[i].f(dp, buf);
1339                                } else
1340                                        dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1341                        } else if (cset == 6) {
1342                                for (i = 0; i < WE_6_LEN; i++)
1343                                        if (*buf == we_6[i].nr)
1344                                                break;
1345
1346                                /* When found, give appropriate msg */
1347                                if (i != WE_6_LEN) {
1348                                        dp += sprintf(dp, "  %s\n", we_6[i].descr);
1349                                        dp += we_6[i].f(dp, buf);
1350                                } else
1351                                        dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1352                        } else
1353                                dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1354                        /* Skip to next element */
1355                        if (cs_fest == 8) {
1356                                cset = cs_old;
1357                                cs_old = 0;
1358                                cs_fest = 0;
1359                        }
1360                        buf += buf[1] + 2;
1361                }
1362        } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */
1363                /* locate message type */
1364                buf++;
1365                cr_l = *buf++;
1366                if (cr_l)
1367                        cr = *buf++;
1368                else
1369                        cr = 0;
1370                mt = *buf++;
1371                for (i = 0; i < MTSIZE; i++)
1372                        if (mtlist[i].nr == mt)
1373                                break;
1374
1375                /* display message type if it exists */
1376                if (i == MTSIZE)
1377                        dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1378                            cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1379                                      size, mt);
1380                else
1381                        dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1382                            cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1383                                      size, mtlist[i].descr);
1384
1385                /* display each information element */
1386                while (buf < bend) {
1387                        /* Is it a single octet information element? */
1388                        if (*buf & 0x80) {
1389                                switch ((*buf >> 4) & 7) {
1390                                        case 1:
1391                                                dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1392                                                cs_old = cset;
1393                                                cset = *buf & 7;
1394                                                cs_fest = *buf & 8;
1395                                                break;
1396                                        default:
1397                                                dp += sprintf(dp, "  Unknown single-octet IE %x\n", *buf);
1398                                                break;
1399                                }
1400                                buf++;
1401                                continue;
1402                        }
1403                        /* No, locate it in the table */
1404                        if (cset == 0) {
1405                                for (i = 0; i < IESIZE_NI1; i++)
1406                                        if (*buf == ielist_ni1[i].nr)
1407                                                break;
1408
1409                                /* When not found, give appropriate msg */
1410                                if (i != IESIZE_NI1) {
1411                                        dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
1412                                        dp += ielist_ni1[i].f(dp, buf);
1413                                } else
1414                                        dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1415                        } else if (cset == 5) {
1416                                for (i = 0; i < IESIZE_NI1_CS5; i++)
1417                                        if (*buf == ielist_ni1_cs5[i].nr)
1418                                                break;
1419
1420                                /* When not found, give appropriate msg */
1421                                if (i != IESIZE_NI1_CS5) {
1422                                        dp += sprintf(dp, "  %s\n", ielist_ni1_cs5[i].descr);
1423                                        dp += ielist_ni1_cs5[i].f(dp, buf);
1424                                } else
1425                                        dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1426                        } else if (cset == 6) {
1427                                for (i = 0; i < IESIZE_NI1_CS6; i++)
1428                                        if (*buf == ielist_ni1_cs6[i].nr)
1429                                                break;
1430
1431                                /* When not found, give appropriate msg */
1432                                if (i != IESIZE_NI1_CS6) {
1433                                        dp += sprintf(dp, "  %s\n", ielist_ni1_cs6[i].descr);
1434                                        dp += ielist_ni1_cs6[i].f(dp, buf);
1435                                } else
1436                                        dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1437                        } else
1438                                dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1439
1440                        /* Skip to next element */
1441                        if (cs_fest == 8) {
1442                                cset = cs_old;
1443                                cs_old = 0;
1444                                cs_fest = 0;
1445                        }
1446                        buf += buf[1] + 2;
1447                }
1448        } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
1449                /* locate message type */
1450                buf++;
1451                cr_l = *buf++;
1452                if (cr_l)
1453                        cr = *buf++;
1454                else
1455                        cr = 0;
1456                mt = *buf++;
1457                for (i = 0; i < MTSIZE; i++)
1458                        if (mtlist[i].nr == mt)
1459                                break;
1460
1461                /* display message type if it exists */
1462                if (i == MTSIZE)
1463                        dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1464                            cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1465                                      size, mt);
1466                else
1467                        dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1468                            cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1469                                      size, mtlist[i].descr);
1470
1471                /* display each information element */
1472                while (buf < bend) {
1473                        /* Is it a single octet information element? */
1474                        if (*buf & 0x80) {
1475                                switch ((*buf >> 4) & 7) {
1476                                        case 1:
1477                                                dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1478                                                break;
1479                                        case 3:
1480                                                dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1481                                                break;
1482                                        case 5:
1483                                                dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
1484                                                break;
1485                                        case 2:
1486                                                if (*buf == 0xa0) {
1487                                                        dp += sprintf(dp, "  More data\n");
1488                                                        break;
1489                                                }
1490                                                if (*buf == 0xa1) {
1491                                                        dp += sprintf(dp, "  Sending complete\n");
1492                                                }
1493                                                break;
1494                                                /* fall through */
1495                                        default:
1496                                                dp += sprintf(dp, "  Reserved %x\n", *buf);
1497                                                break;
1498                                }
1499                                buf++;
1500                                continue;
1501                        }
1502                        /* No, locate it in the table */
1503                        for (i = 0; i < IESIZE; i++)
1504                                if (*buf == ielist[i].nr)
1505                                        break;
1506
1507                        /* When not found, give appropriate msg */
1508                        if (i != IESIZE) {
1509                                dp += sprintf(dp, "  %s\n", ielist[i].descr);
1510                                dp += ielist[i].f(dp, buf);
1511                        } else
1512                                dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1513
1514                        /* Skip to next element */
1515                        buf += buf[1] + 2;
1516                }
1517        } else {
1518                dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1519        }
1520        *dp = 0;
1521        HiSax_putstatus(cs, NULL, cs->dlog);
1522}
1523