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++ & 0x80)) { 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 1156 for (i = 0; i < cnt; i++) { 1157 *t++ = ' '; 1158 *t++ = hex_asc_hi(p[i]); 1159 *t++ = hex_asc_lo(p[i]); 1160 } 1161 *t++ = 0; 1162 return (t - txt); 1163} 1164 1165void 1166LogFrame(struct IsdnCardState *cs, u_char *buf, int size) 1167{ 1168 char *dp; 1169 1170 if (size < 1) 1171 return; 1172 dp = cs->dlog; 1173 if (size < MAX_DLOG_SPACE / 3 - 10) { 1174 *dp++ = 'H'; 1175 *dp++ = 'E'; 1176 *dp++ = 'X'; 1177 *dp++ = ':'; 1178 dp += QuickHex(dp, buf, size); 1179 dp--; 1180 *dp++ = '\n'; 1181 *dp = 0; 1182 HiSax_putstatus(cs, NULL, "%s", cs->dlog); 1183 } else 1184 HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); 1185} 1186 1187void 1188dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) 1189{ 1190 u_char *bend, *buf; 1191 char *dp; 1192 unsigned char pd, cr_l, cr, mt; 1193 unsigned char sapi, tei, ftyp; 1194 int i, cset = 0, cs_old = 0, cs_fest = 0; 1195 int size, finish = 0; 1196 1197 if (skb->len < 3) 1198 return; 1199 /* display header */ 1200 dp = cs->dlog; 1201 dp += jiftime(dp, jiffies); 1202 *dp++ = ' '; 1203 sapi = skb->data[0] >> 2; 1204 tei = skb->data[1] >> 1; 1205 ftyp = skb->data[2]; 1206 buf = skb->data; 1207 dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); 1208 size = skb->len; 1209 1210 if (tei == GROUP_TEI) { 1211 if (sapi == CTRL_SAPI) { /* sapi 0 */ 1212 if (ftyp == 3) { 1213 dp += sprintf(dp, "broadcast\n"); 1214 buf += 3; 1215 size -= 3; 1216 } else { 1217 dp += sprintf(dp, "no UI broadcast\n"); 1218 finish = 1; 1219 } 1220 } else if (sapi == TEI_SAPI) { 1221 dp += sprintf(dp, "tei management\n"); 1222 finish = 1; 1223 } else { 1224 dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); 1225 finish = 1; 1226 } 1227 } else { 1228 if (sapi == CTRL_SAPI) { 1229 if (!(ftyp & 1)) { /* IFrame */ 1230 dp += sprintf(dp, "with tei %d\n", tei); 1231 buf += 4; 1232 size -= 4; 1233 } else { 1234 dp += sprintf(dp, "SFrame with tei %d\n", tei); 1235 finish = 1; 1236 } 1237 } else { 1238 dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); 1239 finish = 1; 1240 } 1241 } 1242 bend = skb->data + skb->len; 1243 if (buf >= bend) { 1244 dp += sprintf(dp, "frame too short\n"); 1245 finish = 1; 1246 } 1247 if (finish) { 1248 *dp = 0; 1249 HiSax_putstatus(cs, NULL, "%s", cs->dlog); 1250 return; 1251 } 1252 if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ 1253 /* locate message type */ 1254 pd = *buf++; 1255 cr_l = *buf++; 1256 if (cr_l) 1257 cr = *buf++; 1258 else 1259 cr = 0; 1260 mt = *buf++; 1261 if (pd == PROTO_DIS_N0) { /* N0 */ 1262 for (i = 0; i < MT_N0_LEN; i++) 1263 if (mt_n0[i].nr == mt) 1264 break; 1265 /* display message type if it exists */ 1266 if (i == MT_N0_LEN) 1267 dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", 1268 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1269 size, mt); 1270 else 1271 dp += sprintf(dp, "callref %d %s size %d message type %s\n", 1272 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1273 size, mt_n0[i].descr); 1274 } else { /* N1 */ 1275 for (i = 0; i < MT_N1_LEN; i++) 1276 if (mt_n1[i].nr == mt) 1277 break; 1278 /* display message type if it exists */ 1279 if (i == MT_N1_LEN) 1280 dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", 1281 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1282 size, mt); 1283 else 1284 dp += sprintf(dp, "callref %d %s size %d message type %s\n", 1285 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1286 size, mt_n1[i].descr); 1287 } 1288 1289 /* display each information element */ 1290 while (buf < bend) { 1291 /* Is it a single octet information element? */ 1292 if (*buf & 0x80) { 1293 switch ((*buf >> 4) & 7) { 1294 case 1: 1295 dp += sprintf(dp, " Shift %x\n", *buf & 0xf); 1296 cs_old = cset; 1297 cset = *buf & 7; 1298 cs_fest = *buf & 8; 1299 break; 1300 case 3: 1301 dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); 1302 break; 1303 case 2: 1304 if (*buf == 0xa0) { 1305 dp += sprintf(dp, " More data\n"); 1306 break; 1307 } 1308 if (*buf == 0xa1) { 1309 dp += sprintf(dp, " Sending complete\n"); 1310 } 1311 break; 1312 /* fall through */ 1313 default: 1314 dp += sprintf(dp, " Reserved %x\n", *buf); 1315 break; 1316 } 1317 buf++; 1318 continue; 1319 } 1320 /* No, locate it in the table */ 1321 if (cset == 0) { 1322 for (i = 0; i < WE_0_LEN; i++) 1323 if (*buf == we_0[i].nr) 1324 break; 1325 1326 /* When found, give appropriate msg */ 1327 if (i != WE_0_LEN) { 1328 dp += sprintf(dp, " %s\n", we_0[i].descr); 1329 dp += we_0[i].f(dp, buf); 1330 } else 1331 dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); 1332 } else if (cset == 6) { 1333 for (i = 0; i < WE_6_LEN; i++) 1334 if (*buf == we_6[i].nr) 1335 break; 1336 1337 /* When found, give appropriate msg */ 1338 if (i != WE_6_LEN) { 1339 dp += sprintf(dp, " %s\n", we_6[i].descr); 1340 dp += we_6[i].f(dp, buf); 1341 } else 1342 dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); 1343 } else 1344 dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); 1345 /* Skip to next element */ 1346 if (cs_fest == 8) { 1347 cset = cs_old; 1348 cs_old = 0; 1349 cs_fest = 0; 1350 } 1351 buf += buf[1] + 2; 1352 } 1353 } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ 1354 /* locate message type */ 1355 buf++; 1356 cr_l = *buf++; 1357 if (cr_l) 1358 cr = *buf++; 1359 else 1360 cr = 0; 1361 mt = *buf++; 1362 for (i = 0; i < MTSIZE; i++) 1363 if (mtlist[i].nr == mt) 1364 break; 1365 1366 /* display message type if it exists */ 1367 if (i == MTSIZE) 1368 dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", 1369 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1370 size, mt); 1371 else 1372 dp += sprintf(dp, "callref %d %s size %d message type %s\n", 1373 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1374 size, mtlist[i].descr); 1375 1376 /* display each information element */ 1377 while (buf < bend) { 1378 /* Is it a single octet information element? */ 1379 if (*buf & 0x80) { 1380 switch ((*buf >> 4) & 7) { 1381 case 1: 1382 dp += sprintf(dp, " Shift %x\n", *buf & 0xf); 1383 cs_old = cset; 1384 cset = *buf & 7; 1385 cs_fest = *buf & 8; 1386 break; 1387 default: 1388 dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); 1389 break; 1390 } 1391 buf++; 1392 continue; 1393 } 1394 /* No, locate it in the table */ 1395 if (cset == 0) { 1396 for (i = 0; i < IESIZE_NI1; i++) 1397 if (*buf == ielist_ni1[i].nr) 1398 break; 1399 1400 /* When not found, give appropriate msg */ 1401 if (i != IESIZE_NI1) { 1402 dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); 1403 dp += ielist_ni1[i].f(dp, buf); 1404 } else 1405 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); 1406 } else if (cset == 5) { 1407 for (i = 0; i < IESIZE_NI1_CS5; i++) 1408 if (*buf == ielist_ni1_cs5[i].nr) 1409 break; 1410 1411 /* When not found, give appropriate msg */ 1412 if (i != IESIZE_NI1_CS5) { 1413 dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); 1414 dp += ielist_ni1_cs5[i].f(dp, buf); 1415 } else 1416 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); 1417 } else if (cset == 6) { 1418 for (i = 0; i < IESIZE_NI1_CS6; i++) 1419 if (*buf == ielist_ni1_cs6[i].nr) 1420 break; 1421 1422 /* When not found, give appropriate msg */ 1423 if (i != IESIZE_NI1_CS6) { 1424 dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); 1425 dp += ielist_ni1_cs6[i].f(dp, buf); 1426 } else 1427 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); 1428 } else 1429 dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); 1430 1431 /* Skip to next element */ 1432 if (cs_fest == 8) { 1433 cset = cs_old; 1434 cs_old = 0; 1435 cs_fest = 0; 1436 } 1437 buf += buf[1] + 2; 1438 } 1439 } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ 1440 /* locate message type */ 1441 buf++; 1442 cr_l = *buf++; 1443 if (cr_l) 1444 cr = *buf++; 1445 else 1446 cr = 0; 1447 mt = *buf++; 1448 for (i = 0; i < MTSIZE; i++) 1449 if (mtlist[i].nr == mt) 1450 break; 1451 1452 /* display message type if it exists */ 1453 if (i == MTSIZE) 1454 dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", 1455 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1456 size, mt); 1457 else 1458 dp += sprintf(dp, "callref %d %s size %d message type %s\n", 1459 cr & 0x7f, (cr & 0x80) ? "called" : "caller", 1460 size, mtlist[i].descr); 1461 1462 /* display each information element */ 1463 while (buf < bend) { 1464 /* Is it a single octet information element? */ 1465 if (*buf & 0x80) { 1466 switch ((*buf >> 4) & 7) { 1467 case 1: 1468 dp += sprintf(dp, " Shift %x\n", *buf & 0xf); 1469 break; 1470 case 3: 1471 dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); 1472 break; 1473 case 5: 1474 dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); 1475 break; 1476 case 2: 1477 if (*buf == 0xa0) { 1478 dp += sprintf(dp, " More data\n"); 1479 break; 1480 } 1481 if (*buf == 0xa1) { 1482 dp += sprintf(dp, " Sending complete\n"); 1483 } 1484 break; 1485 /* fall through */ 1486 default: 1487 dp += sprintf(dp, " Reserved %x\n", *buf); 1488 break; 1489 } 1490 buf++; 1491 continue; 1492 } 1493 /* No, locate it in the table */ 1494 for (i = 0; i < IESIZE; i++) 1495 if (*buf == ielist[i].nr) 1496 break; 1497 1498 /* When not found, give appropriate msg */ 1499 if (i != IESIZE) { 1500 dp += sprintf(dp, " %s\n", ielist[i].descr); 1501 dp += ielist[i].f(dp, buf); 1502 } else 1503 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); 1504 1505 /* Skip to next element */ 1506 buf += buf[1] + 2; 1507 } 1508 } else { 1509 dp += sprintf(dp, "Unknown protocol %x!", buf[0]); 1510 } 1511 *dp = 0; 1512 HiSax_putstatus(cs, NULL, "%s", cs->dlog); 1513} 1514