[PATCH] W1: w1_netlink: New init/fini netlink callbacks.
[linux-2.6/verdex.git] / drivers / isdn / hisax / q931.c
blobabecabf8c271326d201dc2b3e1c78bcd369af6fd
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 sizeof(mtlist)/sizeof(struct MessageType)
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 (sizeof(mt_n0) / sizeof(struct MessageType))
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 (sizeof(mt_n1) / sizeof(struct MessageType))
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 sizeof(cvlist)/sizeof(struct CauseValue)
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 = (sizeof(cause_1tr6) / sizeof(struct MessageType));
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++ & 80)) {
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 sizeof(dtaglist)/sizeof(struct DTag)
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 sizeof(ielist)/sizeof(struct InformationElement)
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 sizeof(ielist_ni1)/sizeof(struct InformationElement)
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 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
1115 static
1116 struct InformationElement ielist_ni1_cs6[] = {
1117 { 0x7b, "Call appearance", general_ni1 },
1120 #define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
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 (sizeof(we_0) / sizeof(struct InformationElement))
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 (sizeof(we_6) / sizeof(struct InformationElement))
1151 QuickHex(char *txt, u_char * p, int cnt)
1153 register int i;
1154 register char *t = txt;
1155 register u_char w;
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;
1170 *t++ = 0;
1171 return (t - txt);
1174 void
1175 LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
1177 char *dp;
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);
1196 void
1197 dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
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;
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;
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;
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;
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;
1246 } else {
1247 dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1248 finish = 1;
1251 bend = skb->data + skb->len;
1252 if (buf >= bend) {
1253 dp += sprintf(dp, "frame too short\n");
1254 finish = 1;
1256 if (finish) {
1257 *dp = 0;
1258 HiSax_putstatus(cs, NULL, cs->dlog);
1259 return;
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);
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;
1317 if (*buf == 0xa1) {
1318 dp += sprintf(dp, " Sending complete\n");
1320 break;
1321 /* fall through */
1322 default:
1323 dp += sprintf(dp, " Reserved %x\n", *buf);
1324 break;
1326 buf++;
1327 continue;
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;
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;
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;
1360 buf += buf[1] + 2;
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;
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);
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;
1400 buf++;
1401 continue;
1403 /* No, locate it in the table */
1404 if (cset == 0) {
1405 for (i = 0; i < IESIZE; i++)
1406 if (*buf == ielist_ni1[i].nr)
1407 break;
1409 /* When not found, give appropriate msg */
1410 if (i != IESIZE) {
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;
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;
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]);
1440 /* Skip to next element */
1441 if (cs_fest == 8) {
1442 cset = cs_old;
1443 cs_old = 0;
1444 cs_fest = 0;
1446 buf += buf[1] + 2;
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;
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);
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;
1490 if (*buf == 0xa1) {
1491 dp += sprintf(dp, " Sending complete\n");
1493 break;
1494 /* fall through */
1495 default:
1496 dp += sprintf(dp, " Reserved %x\n", *buf);
1497 break;
1499 buf++;
1500 continue;
1502 /* No, locate it in the table */
1503 for (i = 0; i < IESIZE; i++)
1504 if (*buf == ielist[i].nr)
1505 break;
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]);
1514 /* Skip to next element */
1515 buf += buf[1] + 2;
1517 } else {
1518 dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1520 *dp = 0;
1521 HiSax_putstatus(cs, NULL, cs->dlog);