blob: 8b853d58e8208e7ca64adacd2b197609a2ba3133 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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
Karsten Keilba2d6cc2009-07-24 18:26:08 +0200143#define MTSIZE ARRAY_SIZE(mtlist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
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
Karsten Keilba2d6cc2009-07-24 18:26:08 +0200160#define MT_N0_LEN ARRAY_SIZE(mt_n0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
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
Karsten Keilba2d6cc2009-07-24 18:26:08 +0200197#define MT_N1_LEN ARRAY_SIZE(mt_n1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
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
Karsten Keilba2d6cc2009-07-24 18:26:08 +0200441#define CVSIZE ARRAY_SIZE(cvlist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
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
Karsten Keilba2d6cc2009-07-24 18:26:08 +0200519static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521static int
522prcause_1tr6(char *dest, u_char * p)
523{
524 char *dp = dest;
525 int i, cause;
526
527 p++;
528 if (0 == *p) {
529 dp += sprintf(dp, " OK (cause length=0)\n");
530 return (dp - dest);
531 } else if (*p > 1) {
532 dp += sprintf(dp, " coding ");
533 dp += prbits(dp, p[2], 7, 2);
534 dp += sprintf(dp, " location ");
535 dp += prbits(dp, p[2], 4, 4);
536 *dp++ = '\n';
537 }
538 p++;
539 cause = 0x7f & *p;
540
541 /* locate cause value */
542 for (i = 0; i < cause_1tr6_len; i++)
543 if (cause_1tr6[i].nr == cause)
544 break;
545
546 /* display cause value if it exists */
547 if (i == cause_1tr6_len)
548 dp += sprintf(dp, "Unknown cause type %x!\n", cause);
549 else
550 dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
551
552 return (dp - dest);
553
554}
555
556static int
557prchident(char *dest, u_char * p)
558{
559 char *dp = dest;
560
561 p += 2;
562 dp += sprintf(dp, " octet 3 ");
563 dp += prbits(dp, *p, 8, 8);
564 *dp++ = '\n';
565 return (dp - dest);
566}
567
568static int
569prcalled(char *dest, u_char * p)
570{
571 int l;
572 char *dp = dest;
573
574 p++;
575 l = *p++ - 1;
576 dp += sprintf(dp, " octet 3 ");
577 dp += prbits(dp, *p++, 8, 8);
578 *dp++ = '\n';
579 dp += sprintf(dp, " number digits ");
580 while (l--)
581 *dp++ = *p++;
582 *dp++ = '\n';
583 return (dp - dest);
584}
585static int
586prcalling(char *dest, u_char * p)
587{
588 int l;
589 char *dp = dest;
590
591 p++;
592 l = *p++ - 1;
593 dp += sprintf(dp, " octet 3 ");
594 dp += prbits(dp, *p, 8, 8);
595 *dp++ = '\n';
596 if (!(*p & 0x80)) {
597 dp += sprintf(dp, " octet 3a ");
598 dp += prbits(dp, *++p, 8, 8);
599 *dp++ = '\n';
600 l--;
601 };
602 p++;
603
604 dp += sprintf(dp, " number digits ");
605 while (l--)
606 *dp++ = *p++;
607 *dp++ = '\n';
608 return (dp - dest);
609}
610
611static
612int
613prbearer(char *dest, u_char * p)
614{
615 char *dp = dest, ch;
616
617 p += 2;
618 dp += sprintf(dp, " octet 3 ");
619 dp += prbits(dp, *p++, 8, 8);
620 *dp++ = '\n';
621 dp += sprintf(dp, " octet 4 ");
622 dp += prbits(dp, *p, 8, 8);
623 *dp++ = '\n';
624 if ((*p++ & 0x1f) == 0x18) {
625 dp += sprintf(dp, " octet 4.1 ");
626 dp += prbits(dp, *p++, 8, 8);
627 *dp++ = '\n';
628 }
629 /* check for user information layer 1 */
630 if ((*p & 0x60) == 0x20) {
631 ch = ' ';
632 do {
633 dp += sprintf(dp, " octet 5%c ", ch);
634 dp += prbits(dp, *p, 8, 8);
635 *dp++ = '\n';
636 if (ch == ' ')
637 ch = 'a';
638 else
639 ch++;
640 }
641 while (!(*p++ & 0x80));
642 }
643 /* check for user information layer 2 */
644 if ((*p & 0x60) == 0x40) {
645 dp += sprintf(dp, " octet 6 ");
646 dp += prbits(dp, *p++, 8, 8);
647 *dp++ = '\n';
648 }
649 /* check for user information layer 3 */
650 if ((*p & 0x60) == 0x60) {
651 dp += sprintf(dp, " octet 7 ");
652 dp += prbits(dp, *p++, 8, 8);
653 *dp++ = '\n';
654 }
655 return (dp - dest);
656}
657
658
659static
660int
661prbearer_ni1(char *dest, u_char * p)
662{
663 char *dp = dest;
664 u_char len;
665
666 p++;
667 len = *p++;
668 dp += sprintf(dp, " octet 3 ");
669 dp += prbits(dp, *p, 8, 8);
670 switch (*p++) {
671 case 0x80:
672 dp += sprintf(dp, " Speech");
673 break;
674 case 0x88:
675 dp += sprintf(dp, " Unrestricted digital information");
676 break;
677 case 0x90:
678 dp += sprintf(dp, " 3.1 kHz audio");
679 break;
680 default:
681 dp += sprintf(dp, " Unknown information-transfer capability");
682 }
683 *dp++ = '\n';
684 dp += sprintf(dp, " octet 4 ");
685 dp += prbits(dp, *p, 8, 8);
686 switch (*p++) {
687 case 0x90:
688 dp += sprintf(dp, " 64 kbps, circuit mode");
689 break;
690 case 0xc0:
691 dp += sprintf(dp, " Packet mode");
692 break;
693 default:
694 dp += sprintf(dp, " Unknown transfer mode");
695 }
696 *dp++ = '\n';
697 if (len > 2) {
698 dp += sprintf(dp, " octet 5 ");
699 dp += prbits(dp, *p, 8, 8);
700 switch (*p++) {
701 case 0x21:
702 dp += sprintf(dp, " Rate adaption\n");
703 dp += sprintf(dp, " octet 5a ");
704 dp += prbits(dp, *p, 8, 8);
705 break;
706 case 0xa2:
707 dp += sprintf(dp, " u-law");
708 break;
709 default:
710 dp += sprintf(dp, " Unknown UI layer 1 protocol");
711 }
712 *dp++ = '\n';
713 }
714 return (dp - dest);
715}
716
717static int
718general(char *dest, u_char * p)
719{
720 char *dp = dest;
721 char ch = ' ';
722 int l, octet = 3;
723
724 p++;
725 l = *p++;
726 /* Iterate over all octets in the information element */
727 while (l--) {
728 dp += sprintf(dp, " octet %d%c ", octet, ch);
729 dp += prbits(dp, *p++, 8, 8);
730 *dp++ = '\n';
731
732 /* last octet in group? */
733 if (*p & 0x80) {
734 octet++;
735 ch = ' ';
736 } else if (ch == ' ')
737 ch = 'a';
738 else
739 ch++;
740 }
741 return (dp - dest);
742}
743
744static int
745general_ni1(char *dest, u_char * p)
746{
747 char *dp = dest;
748 char ch = ' ';
749 int l, octet = 3;
750
751 p++;
752 l = *p++;
753 /* Iterate over all octets in the information element */
754 while (l--) {
755 dp += sprintf(dp, " octet %d%c ", octet, ch);
756 dp += prbits(dp, *p, 8, 8);
757 *dp++ = '\n';
758
759 /* last octet in group? */
760 if (*p++ & 0x80) {
761 octet++;
762 ch = ' ';
763 } else if (ch == ' ')
764 ch = 'a';
765 else
766 ch++;
767 }
768 return (dp - dest);
769}
770
771static int
772prcharge(char *dest, u_char * p)
773{
774 char *dp = dest;
775 int l;
776
777 p++;
778 l = *p++ - 1;
779 dp += sprintf(dp, " GEA ");
780 dp += prbits(dp, *p++, 8, 8);
781 dp += sprintf(dp, " Anzahl: ");
782 /* Iterate over all octets in the * information element */
783 while (l--)
784 *dp++ = *p++;
785 *dp++ = '\n';
786 return (dp - dest);
787}
788static int
789prtext(char *dest, u_char * p)
790{
791 char *dp = dest;
792 int l;
793
794 p++;
795 l = *p++;
796 dp += sprintf(dp, " ");
797 /* Iterate over all octets in the * information element */
798 while (l--)
799 *dp++ = *p++;
800 *dp++ = '\n';
801 return (dp - dest);
802}
803
804static int
805prfeatureind(char *dest, u_char * p)
806{
807 char *dp = dest;
808
809 p += 2; /* skip id, len */
810 dp += sprintf(dp, " octet 3 ");
811 dp += prbits(dp, *p, 8, 8);
812 *dp++ = '\n';
813 if (!(*p++ & 80)) {
814 dp += sprintf(dp, " octet 4 ");
815 dp += prbits(dp, *p++, 8, 8);
816 *dp++ = '\n';
817 }
818 dp += sprintf(dp, " Status: ");
819 switch (*p) {
820 case 0:
821 dp += sprintf(dp, "Idle");
822 break;
823 case 1:
824 dp += sprintf(dp, "Active");
825 break;
826 case 2:
827 dp += sprintf(dp, "Prompt");
828 break;
829 case 3:
830 dp += sprintf(dp, "Pending");
831 break;
832 default:
833 dp += sprintf(dp, "(Reserved)");
834 break;
835 }
836 *dp++ = '\n';
837 return (dp - dest);
838}
839
840static
841struct DTag { /* Display tags */
842 u_char nr;
843 char *descr;
844} dtaglist[] = {
845 { 0x82, "Continuation" },
846 { 0x83, "Called address" },
847 { 0x84, "Cause" },
848 { 0x85, "Progress indicator" },
849 { 0x86, "Notification indicator" },
850 { 0x87, "Prompt" },
851 { 0x88, "Accumlated digits" },
852 { 0x89, "Status" },
853 { 0x8a, "Inband" },
854 { 0x8b, "Calling address" },
855 { 0x8c, "Reason" },
856 { 0x8d, "Calling party name" },
857 { 0x8e, "Called party name" },
858 { 0x8f, "Orignal called name" },
859 { 0x90, "Redirecting name" },
860 { 0x91, "Connected name" },
861 { 0x92, "Originating restrictions" },
862 { 0x93, "Date & time of day" },
863 { 0x94, "Call Appearance ID" },
864 { 0x95, "Feature address" },
865 { 0x96, "Redirection name" },
866 { 0x9e, "Text" },
867};
Karsten Keilba2d6cc2009-07-24 18:26:08 +0200868#define DTAGSIZE ARRAY_SIZE(dtaglist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
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
Adrian Bunk672c3fd2005-06-25 14:59:18 -0700938static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939prfacility(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
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001077#define IESIZE ARRAY_SIZE(ielist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
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
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001105#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107static
1108struct InformationElement ielist_ni1_cs5[] = {
1109 { 0x1d, "Operator system access", general_ni1 },
1110 { 0x2a, "Display text", disptext_ni1 },
1111};
1112
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001113#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115static
1116struct InformationElement ielist_ni1_cs6[] = {
1117 { 0x7b, "Call appearance", general_ni1 },
1118};
1119
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001120#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
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
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001136#define WE_0_LEN ARRAY_SIZE(we_0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
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};
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001148#define WE_6_LEN ARRAY_SIZE(we_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
1150int
1151QuickHex(char *txt, u_char * p, int cnt)
1152{
1153 register int i;
1154 register char *t = txt;
1155 register u_char w;
1156
1157 for (i = 0; i < cnt; i++) {
1158 *t++ = ' ';
1159 w = (p[i] >> 4) & 0x0f;
1160 if (w < 10)
1161 *t++ = '0' + w;
1162 else
1163 *t++ = 'A' - 10 + w;
1164 w = p[i] & 0x0f;
1165 if (w < 10)
1166 *t++ = '0' + w;
1167 else
1168 *t++ = 'A' - 10 + w;
1169 }
1170 *t++ = 0;
1171 return (t - txt);
1172}
1173
1174void
1175LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
1176{
1177 char *dp;
1178
1179 if (size < 1)
1180 return;
1181 dp = cs->dlog;
1182 if (size < MAX_DLOG_SPACE / 3 - 10) {
1183 *dp++ = 'H';
1184 *dp++ = 'E';
1185 *dp++ = 'X';
1186 *dp++ = ':';
1187 dp += QuickHex(dp, buf, size);
1188 dp--;
1189 *dp++ = '\n';
1190 *dp = 0;
1191 HiSax_putstatus(cs, NULL, cs->dlog);
1192 } else
1193 HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
1194}
1195
1196void
1197dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
1198{
1199 u_char *bend, *buf;
1200 char *dp;
1201 unsigned char pd, cr_l, cr, mt;
1202 unsigned char sapi, tei, ftyp;
1203 int i, cset = 0, cs_old = 0, cs_fest = 0;
1204 int size, finish = 0;
1205
1206 if (skb->len < 3)
1207 return;
1208 /* display header */
1209 dp = cs->dlog;
1210 dp += jiftime(dp, jiffies);
1211 *dp++ = ' ';
1212 sapi = skb->data[0] >> 2;
1213 tei = skb->data[1] >> 1;
1214 ftyp = skb->data[2];
1215 buf = skb->data;
1216 dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
1217 size = skb->len;
1218
1219 if (tei == GROUP_TEI) {
1220 if (sapi == CTRL_SAPI) { /* sapi 0 */
1221 if (ftyp == 3) {
1222 dp += sprintf(dp, "broadcast\n");
1223 buf += 3;
1224 size -= 3;
1225 } else {
1226 dp += sprintf(dp, "no UI broadcast\n");
1227 finish = 1;
1228 }
1229 } else if (sapi == TEI_SAPI) {
1230 dp += sprintf(dp, "tei management\n");
1231 finish = 1;
1232 } else {
1233 dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
1234 finish = 1;
1235 }
1236 } else {
1237 if (sapi == CTRL_SAPI) {
1238 if (!(ftyp & 1)) { /* IFrame */
1239 dp += sprintf(dp, "with tei %d\n", tei);
1240 buf += 4;
1241 size -= 4;
1242 } else {
1243 dp += sprintf(dp, "SFrame with tei %d\n", tei);
1244 finish = 1;
1245 }
1246 } else {
1247 dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1248 finish = 1;
1249 }
1250 }
1251 bend = skb->data + skb->len;
1252 if (buf >= bend) {
1253 dp += sprintf(dp, "frame too short\n");
1254 finish = 1;
1255 }
1256 if (finish) {
1257 *dp = 0;
1258 HiSax_putstatus(cs, NULL, cs->dlog);
1259 return;
1260 }
1261 if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
1262 /* locate message type */
1263 pd = *buf++;
1264 cr_l = *buf++;
1265 if (cr_l)
1266 cr = *buf++;
1267 else
1268 cr = 0;
1269 mt = *buf++;
1270 if (pd == PROTO_DIS_N0) { /* N0 */
1271 for (i = 0; i < MT_N0_LEN; i++)
1272 if (mt_n0[i].nr == mt)
1273 break;
1274 /* display message type if it exists */
1275 if (i == MT_N0_LEN)
1276 dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
1277 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1278 size, mt);
1279 else
1280 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1281 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1282 size, mt_n0[i].descr);
1283 } else { /* N1 */
1284 for (i = 0; i < MT_N1_LEN; i++)
1285 if (mt_n1[i].nr == mt)
1286 break;
1287 /* display message type if it exists */
1288 if (i == MT_N1_LEN)
1289 dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
1290 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1291 size, mt);
1292 else
1293 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1294 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1295 size, mt_n1[i].descr);
1296 }
1297
1298 /* display each information element */
1299 while (buf < bend) {
1300 /* Is it a single octet information element? */
1301 if (*buf & 0x80) {
1302 switch ((*buf >> 4) & 7) {
1303 case 1:
1304 dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
1305 cs_old = cset;
1306 cset = *buf & 7;
1307 cs_fest = *buf & 8;
1308 break;
1309 case 3:
1310 dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
1311 break;
1312 case 2:
1313 if (*buf == 0xa0) {
1314 dp += sprintf(dp, " More data\n");
1315 break;
1316 }
1317 if (*buf == 0xa1) {
1318 dp += sprintf(dp, " Sending complete\n");
1319 }
1320 break;
1321 /* fall through */
1322 default:
1323 dp += sprintf(dp, " Reserved %x\n", *buf);
1324 break;
1325 }
1326 buf++;
1327 continue;
1328 }
1329 /* No, locate it in the table */
1330 if (cset == 0) {
1331 for (i = 0; i < WE_0_LEN; i++)
1332 if (*buf == we_0[i].nr)
1333 break;
1334
1335 /* When found, give appropriate msg */
1336 if (i != WE_0_LEN) {
1337 dp += sprintf(dp, " %s\n", we_0[i].descr);
1338 dp += we_0[i].f(dp, buf);
1339 } else
1340 dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1341 } else if (cset == 6) {
1342 for (i = 0; i < WE_6_LEN; i++)
1343 if (*buf == we_6[i].nr)
1344 break;
1345
1346 /* When found, give appropriate msg */
1347 if (i != WE_6_LEN) {
1348 dp += sprintf(dp, " %s\n", we_6[i].descr);
1349 dp += we_6[i].f(dp, buf);
1350 } else
1351 dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1352 } else
1353 dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1354 /* Skip to next element */
1355 if (cs_fest == 8) {
1356 cset = cs_old;
1357 cs_old = 0;
1358 cs_fest = 0;
1359 }
1360 buf += buf[1] + 2;
1361 }
1362 } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */
1363 /* locate message type */
1364 buf++;
1365 cr_l = *buf++;
1366 if (cr_l)
1367 cr = *buf++;
1368 else
1369 cr = 0;
1370 mt = *buf++;
1371 for (i = 0; i < MTSIZE; i++)
1372 if (mtlist[i].nr == mt)
1373 break;
1374
1375 /* display message type if it exists */
1376 if (i == MTSIZE)
1377 dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1378 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1379 size, mt);
1380 else
1381 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1382 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1383 size, mtlist[i].descr);
1384
1385 /* display each information element */
1386 while (buf < bend) {
1387 /* Is it a single octet information element? */
1388 if (*buf & 0x80) {
1389 switch ((*buf >> 4) & 7) {
1390 case 1:
1391 dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
1392 cs_old = cset;
1393 cset = *buf & 7;
1394 cs_fest = *buf & 8;
1395 break;
1396 default:
1397 dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf);
1398 break;
1399 }
1400 buf++;
1401 continue;
1402 }
1403 /* No, locate it in the table */
1404 if (cset == 0) {
Eric Sesterhenn9f13fae2006-06-26 00:25:32 -07001405 for (i = 0; i < IESIZE_NI1; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (*buf == ielist_ni1[i].nr)
1407 break;
1408
1409 /* When not found, give appropriate msg */
Eric Sesterhenn9f13fae2006-06-26 00:25:32 -07001410 if (i != IESIZE_NI1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 dp += sprintf(dp, " %s\n", ielist_ni1[i].descr);
1412 dp += ielist_ni1[i].f(dp, buf);
1413 } else
1414 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1415 } else if (cset == 5) {
1416 for (i = 0; i < IESIZE_NI1_CS5; i++)
1417 if (*buf == ielist_ni1_cs5[i].nr)
1418 break;
1419
1420 /* When not found, give appropriate msg */
1421 if (i != IESIZE_NI1_CS5) {
1422 dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr);
1423 dp += ielist_ni1_cs5[i].f(dp, buf);
1424 } else
1425 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1426 } else if (cset == 6) {
1427 for (i = 0; i < IESIZE_NI1_CS6; i++)
1428 if (*buf == ielist_ni1_cs6[i].nr)
1429 break;
1430
1431 /* When not found, give appropriate msg */
1432 if (i != IESIZE_NI1_CS6) {
1433 dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr);
1434 dp += ielist_ni1_cs6[i].f(dp, buf);
1435 } else
1436 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1437 } else
1438 dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1439
1440 /* Skip to next element */
1441 if (cs_fest == 8) {
1442 cset = cs_old;
1443 cs_old = 0;
1444 cs_fest = 0;
1445 }
1446 buf += buf[1] + 2;
1447 }
1448 } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
1449 /* locate message type */
1450 buf++;
1451 cr_l = *buf++;
1452 if (cr_l)
1453 cr = *buf++;
1454 else
1455 cr = 0;
1456 mt = *buf++;
1457 for (i = 0; i < MTSIZE; i++)
1458 if (mtlist[i].nr == mt)
1459 break;
1460
1461 /* display message type if it exists */
1462 if (i == MTSIZE)
1463 dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1464 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1465 size, mt);
1466 else
1467 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1468 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1469 size, mtlist[i].descr);
1470
1471 /* display each information element */
1472 while (buf < bend) {
1473 /* Is it a single octet information element? */
1474 if (*buf & 0x80) {
1475 switch ((*buf >> 4) & 7) {
1476 case 1:
1477 dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
1478 break;
1479 case 3:
1480 dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
1481 break;
1482 case 5:
1483 dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
1484 break;
1485 case 2:
1486 if (*buf == 0xa0) {
1487 dp += sprintf(dp, " More data\n");
1488 break;
1489 }
1490 if (*buf == 0xa1) {
1491 dp += sprintf(dp, " Sending complete\n");
1492 }
1493 break;
1494 /* fall through */
1495 default:
1496 dp += sprintf(dp, " Reserved %x\n", *buf);
1497 break;
1498 }
1499 buf++;
1500 continue;
1501 }
1502 /* No, locate it in the table */
1503 for (i = 0; i < IESIZE; i++)
1504 if (*buf == ielist[i].nr)
1505 break;
1506
1507 /* When not found, give appropriate msg */
1508 if (i != IESIZE) {
1509 dp += sprintf(dp, " %s\n", ielist[i].descr);
1510 dp += ielist[i].f(dp, buf);
1511 } else
1512 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1513
1514 /* Skip to next element */
1515 buf += buf[1] + 2;
1516 }
1517 } else {
1518 dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1519 }
1520 *dp = 0;
1521 HiSax_putstatus(cs, NULL, cs->dlog);
1522}