PM / sleep: Asynchronous threads for suspend_noirq
[linux/fpc-iii.git] / drivers / isdn / hisax / q931.c
blobb420f8bd862e454df2cc08f4da84b8bc7ef76e57
1 /* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $
3 * code to decode ITU Q.931 call control messages
5 * Author Jan den Ouden
6 * Copyright by Jan den Ouden
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
11 * Changelog:
13 * Pauline Middelink general improvements
14 * Beat Doebeli cause texts, display information element
15 * Karsten Keil cause texts, display information element for 1TR6
20 #include "hisax.h"
21 #include "l3_1tr6.h"
23 void
24 iecpy(u_char *dest, u_char *iestart, int ieoffset)
26 u_char *p;
27 int l;
29 p = iestart + ieoffset + 2;
30 l = iestart[1] - ieoffset;
31 while (l--)
32 *dest++ = *p++;
33 *dest++ = '\0';
37 * According to Table 4-2/Q.931
39 static
40 struct MessageType {
41 u_char nr;
42 char *descr;
43 } mtlist[] = {
46 0x1, "ALERTING"
49 0x2, "CALL PROCEEDING"
52 0x7, "CONNECT"
55 0xf, "CONNECT ACKNOWLEDGE"
58 0x3, "PROGRESS"
61 0x5, "SETUP"
64 0xd, "SETUP ACKNOWLEDGE"
67 0x24, "HOLD"
70 0x28, "HOLD ACKNOWLEDGE"
73 0x30, "HOLD REJECT"
76 0x31, "RETRIEVE"
79 0x33, "RETRIEVE ACKNOWLEDGE"
82 0x37, "RETRIEVE REJECT"
85 0x26, "RESUME"
88 0x2e, "RESUME ACKNOWLEDGE"
91 0x22, "RESUME REJECT"
94 0x25, "SUSPEND"
97 0x2d, "SUSPEND ACKNOWLEDGE"
100 0x21, "SUSPEND REJECT"
103 0x20, "USER INFORMATION"
106 0x45, "DISCONNECT"
109 0x4d, "RELEASE"
112 0x5a, "RELEASE COMPLETE"
115 0x46, "RESTART"
118 0x4e, "RESTART ACKNOWLEDGE"
121 0x60, "SEGMENT"
124 0x79, "CONGESTION CONTROL"
127 0x7b, "INFORMATION"
130 0x62, "FACILITY"
133 0x6e, "NOTIFY"
136 0x7d, "STATUS"
139 0x75, "STATUS ENQUIRY"
143 #define MTSIZE ARRAY_SIZE(mtlist)
145 static
146 struct MessageType mt_n0[] =
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"}
160 #define MT_N0_LEN ARRAY_SIZE(mt_n0)
162 static
163 struct MessageType mt_n1[] =
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"}
197 #define MT_N1_LEN ARRAY_SIZE(mt_n1)
200 static int
201 prbits(char *dest, u_char b, int start, int len)
203 char *dp = dest;
205 b = b << (8 - start);
206 while (len--) {
207 if (b & 0x80)
208 *dp++ = '1';
209 else
210 *dp++ = '0';
211 b = b << 1;
213 return (dp - dest);
216 static
217 u_char *
218 skipext(u_char *p)
220 while (!(*p++ & 0x80));
221 return (p);
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...
231 static
232 struct CauseValue {
233 u_char nr;
234 char *edescr;
235 char *ddescr;
236 } cvlist[] = {
239 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
242 0x02, "No route to specified transit network", ""
245 0x03, "No route to destination", ""
248 0x04, "Send special information tone", ""
251 0x05, "Misdialled trunk prefix", ""
254 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
257 0x07, "Channel awarded and being delivered in an established channel", ""
260 0x08, "Preemption", ""
263 0x09, "Preemption - circuit reserved for reuse", ""
266 0x10, "Normal call clearing", "Normale Ausloesung"
269 0x11, "User busy", "TNB besetzt"
272 0x12, "No user responding", ""
275 0x13, "No answer from user (user alerted)", ""
278 0x14, "Subscriber absent", ""
281 0x15, "Call rejected", ""
284 0x16, "Number changed", ""
287 0x1a, "non-selected user clearing", ""
290 0x1b, "Destination out of order", ""
293 0x1c, "Invalid number format (address incomplete)", ""
296 0x1d, "Facility rejected", ""
299 0x1e, "Response to Status enquiry", ""
302 0x1f, "Normal, unspecified", ""
305 0x22, "No circuit/channel available", ""
308 0x26, "Network out of order", ""
311 0x27, "Permanent frame mode connection out-of-service", ""
314 0x28, "Permanent frame mode connection operational", ""
317 0x29, "Temporary failure", ""
320 0x2a, "Switching equipment congestion", ""
323 0x2b, "Access information discarded", ""
326 0x2c, "Requested circuit/channel not available", ""
329 0x2e, "Precedence call blocked", ""
332 0x2f, "Resource unavailable, unspecified", ""
335 0x31, "Quality of service unavailable", ""
338 0x32, "Requested facility not subscribed", ""
341 0x35, "Outgoing calls barred within CUG", ""
344 0x37, "Incoming calls barred within CUG", ""
347 0x39, "Bearer capability not authorized", ""
350 0x3a, "Bearer capability not presently available", ""
353 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
356 0x3f, "Service or option not available, unspecified", ""
359 0x41, "Bearer capability not implemented", ""
362 0x42, "Channel type not implemented", ""
365 0x43, "Requested facility not implemented", ""
368 0x44, "Only restricted digital information bearer capability is available", ""
371 0x4f, "Service or option not implemented", ""
374 0x51, "Invalid call reference value", ""
377 0x52, "Identified channel does not exist", ""
380 0x53, "A suspended call exists, but this call identity does not", ""
383 0x54, "Call identity in use", ""
386 0x55, "No call suspended", ""
389 0x56, "Call having the requested call identity has been cleared", ""
392 0x57, "User not member of CUG", ""
395 0x58, "Incompatible destination", ""
398 0x5a, "Non-existent CUG", ""
401 0x5b, "Invalid transit network selection", ""
404 0x5f, "Invalid message, unspecified", ""
407 0x60, "Mandatory information element is missing", ""
410 0x61, "Message type non-existent or not implemented", ""
413 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
416 0x63, "Information element/parameter non-existent or not implemented", ""
419 0x64, "Invalid information element contents", ""
422 0x65, "Message not compatible with call state", ""
425 0x66, "Recovery on timer expiry", ""
428 0x67, "Parameter non-existent or not implemented - passed on", ""
431 0x6e, "Message with unrecognized parameter discarded", ""
434 0x6f, "Protocol error, unspecified", ""
437 0x7f, "Interworking, unspecified", ""
441 #define CVSIZE ARRAY_SIZE(cvlist)
443 static
445 prcause(char *dest, u_char *p)
447 u_char *end;
448 char *dp = dest;
449 int i, cause;
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);
460 cause = 0x7f & *p++;
462 /* locate cause value */
463 for (i = 0; i < CVSIZE; i++)
464 if (cvlist[i].nr == cause)
465 break;
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);
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);
484 return (dp - dest);
488 static
489 struct MessageType cause_1tr6[] =
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"}
519 static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
521 static int
522 prcause_1tr6(char *dest, u_char *p)
524 char *dp = dest;
525 int i, cause;
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';
538 p++;
539 cause = 0x7f & *p;
541 /* locate cause value */
542 for (i = 0; i < cause_1tr6_len; i++)
543 if (cause_1tr6[i].nr == cause)
544 break;
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);
552 return (dp - dest);
556 static int
557 prchident(char *dest, u_char *p)
559 char *dp = dest;
561 p += 2;
562 dp += sprintf(dp, " octet 3 ");
563 dp += prbits(dp, *p, 8, 8);
564 *dp++ = '\n';
565 return (dp - dest);
568 static int
569 prcalled(char *dest, u_char *p)
571 int l;
572 char *dp = dest;
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);
585 static int
586 prcalling(char *dest, u_char *p)
588 int l;
589 char *dp = dest;
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--;
602 p++;
604 dp += sprintf(dp, " number digits ");
605 while (l--)
606 *dp++ = *p++;
607 *dp++ = '\n';
608 return (dp - dest);
611 static
613 prbearer(char *dest, u_char *p)
615 char *dp = dest, ch;
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';
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++;
641 while (!(*p++ & 0x80));
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';
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';
655 return (dp - dest);
659 static
661 prbearer_ni1(char *dest, u_char *p)
663 char *dp = dest;
664 u_char len;
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");
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");
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");
712 *dp++ = '\n';
714 return (dp - dest);
717 static int
718 general(char *dest, u_char *p)
720 char *dp = dest;
721 char ch = ' ';
722 int l, octet = 3;
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';
732 /* last octet in group? */
733 if (*p & 0x80) {
734 octet++;
735 ch = ' ';
736 } else if (ch == ' ')
737 ch = 'a';
738 else
739 ch++;
741 return (dp - dest);
744 static int
745 general_ni1(char *dest, u_char *p)
747 char *dp = dest;
748 char ch = ' ';
749 int l, octet = 3;
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';
759 /* last octet in group? */
760 if (*p++ & 0x80) {
761 octet++;
762 ch = ' ';
763 } else if (ch == ' ')
764 ch = 'a';
765 else
766 ch++;
768 return (dp - dest);
771 static int
772 prcharge(char *dest, u_char *p)
774 char *dp = dest;
775 int l;
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);
788 static int
789 prtext(char *dest, u_char *p)
791 char *dp = dest;
792 int l;
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);
804 static int
805 prfeatureind(char *dest, u_char *p)
807 char *dp = dest;
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';
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;
836 *dp++ = '\n';
837 return (dp - dest);
840 static
841 struct 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" },
868 #define DTAGSIZE ARRAY_SIZE(dtaglist)
870 static int
871 disptext_ni1(char *dest, u_char *p)
873 char *dp = dest;
874 int l, tag, len, i;
876 p++;
877 l = *p++ - 1;
878 if (*p++ != 0x80) {
879 dp += sprintf(dp, " Unknown display type\n");
880 return (dp - dest);
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;
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++;
904 dp += sprintf(dp, "\n");
907 return (dp - dest);
909 static int
910 display(char *dest, u_char *p)
912 char *dp = dest;
913 char ch = ' ';
914 int l, octet = 3;
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++);
923 /* last octet in group? */
924 if (*p & 0x80) {
925 octet++;
926 ch = ' ';
927 } else if (ch == ' ')
928 ch = 'a';
930 else
931 ch++;
933 *dp++ = '\"';
934 *dp++ = '\n';
935 return (dp - dest);
938 static int
939 prfacility(char *dest, u_char *p)
941 char *dp = dest;
942 int l, l2;
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;
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--;
962 dp += sprintf(dp, "\n");
965 return (dp - dest);
968 static
969 struct InformationElement {
970 u_char nr;
971 char *descr;
972 int (*f) (char *, u_char *);
973 } ielist[] = {
976 0x00, "Segmented message", general
979 0x04, "Bearer capability", prbearer
982 0x08, "Cause", prcause
985 0x10, "Call identity", general
988 0x14, "Call state", general
991 0x18, "Channel identification", prchident
994 0x1c, "Facility", prfacility
997 0x1e, "Progress indicator", general
1000 0x20, "Network-specific facilities", general
1003 0x27, "Notification indicator", general
1006 0x28, "Display", display
1009 0x29, "Date/Time", general
1012 0x2c, "Keypad facility", general
1015 0x34, "Signal", general
1018 0x40, "Information rate", general
1021 0x42, "End-to-end delay", general
1024 0x43, "Transit delay selection and indication", general
1027 0x44, "Packet layer binary parameters", general
1030 0x45, "Packet layer window size", general
1033 0x46, "Packet size", general
1036 0x47, "Closed user group", general
1039 0x4a, "Reverse charge indication", general
1042 0x6c, "Calling party number", prcalling
1045 0x6d, "Calling party subaddress", general
1048 0x70, "Called party number", prcalled
1051 0x71, "Called party subaddress", general
1054 0x74, "Redirecting number", general
1057 0x78, "Transit network selection", general
1060 0x79, "Restart indicator", general
1063 0x7c, "Low layer compatibility", general
1066 0x7d, "High layer compatibility", general
1069 0x7e, "User-user", general
1072 0x7f, "Escape for extension", general
1077 #define IESIZE ARRAY_SIZE(ielist)
1079 static
1080 struct 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 },
1105 #define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
1107 static
1108 struct InformationElement ielist_ni1_cs5[] = {
1109 { 0x1d, "Operator system access", general_ni1 },
1110 { 0x2a, "Display text", disptext_ni1 },
1113 #define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
1115 static
1116 struct InformationElement ielist_ni1_cs6[] = {
1117 { 0x7b, "Call appearance", general_ni1 },
1120 #define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
1122 static struct InformationElement we_0[] =
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}
1136 #define WE_0_LEN ARRAY_SIZE(we_0)
1138 static struct InformationElement we_6[] =
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}
1148 #define WE_6_LEN ARRAY_SIZE(we_6)
1151 QuickHex(char *txt, u_char *p, int cnt)
1153 register int i;
1154 register char *t = txt;
1156 for (i = 0; i < cnt; i++) {
1157 *t++ = ' ';
1158 *t++ = hex_asc_hi(p[i]);
1159 *t++ = hex_asc_lo(p[i]);
1161 *t++ = 0;
1162 return (t - txt);
1165 void
1166 LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
1168 char *dp;
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);
1187 void
1188 dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
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;
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;
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;
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;
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;
1237 } else {
1238 dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1239 finish = 1;
1242 bend = skb->data + skb->len;
1243 if (buf >= bend) {
1244 dp += sprintf(dp, "frame too short\n");
1245 finish = 1;
1247 if (finish) {
1248 *dp = 0;
1249 HiSax_putstatus(cs, NULL, "%s", cs->dlog);
1250 return;
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);
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;
1308 if (*buf == 0xa1) {
1309 dp += sprintf(dp, " Sending complete\n");
1311 break;
1312 /* fall through */
1313 default:
1314 dp += sprintf(dp, " Reserved %x\n", *buf);
1315 break;
1317 buf++;
1318 continue;
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;
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;
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;
1351 buf += buf[1] + 2;
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;
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);
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;
1391 buf++;
1392 continue;
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;
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;
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;
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]);
1431 /* Skip to next element */
1432 if (cs_fest == 8) {
1433 cset = cs_old;
1434 cs_old = 0;
1435 cs_fest = 0;
1437 buf += buf[1] + 2;
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;
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);
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;
1481 if (*buf == 0xa1) {
1482 dp += sprintf(dp, " Sending complete\n");
1484 break;
1485 /* fall through */
1486 default:
1487 dp += sprintf(dp, " Reserved %x\n", *buf);
1488 break;
1490 buf++;
1491 continue;
1493 /* No, locate it in the table */
1494 for (i = 0; i < IESIZE; i++)
1495 if (*buf == ielist[i].nr)
1496 break;
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]);
1505 /* Skip to next element */
1506 buf += buf[1] + 2;
1508 } else {
1509 dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1511 *dp = 0;
1512 HiSax_putstatus(cs, NULL, "%s", cs->dlog);