1 /* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $
2  *
3  * code to decode ITU Q.931 call control messages
4  *
5  * Author       Jan den Ouden
6  * Copyright    by Jan den Ouden
7  *
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  * Changelog:
12  *
13  * Pauline Middelink    general improvements
14  * Beat Doebeli         cause texts, display information element
15  * Karsten Keil         cause texts, display information element for 1TR6
16  *
17  */
18 
19 
20 #include "hisax.h"
21 #include "l3_1tr6.h"
22 
23 void
iecpy(u_char * dest,u_char * iestart,int ieoffset)24 iecpy(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  */
39 static
40 struct MessageType {
41 	u_char nr;
42 	char *descr;
43 } mtlist[] = {
44 
45 	{
46 		0x1, "ALERTING"
47 	},
48 	{
49 		0x2, "CALL PROCEEDING"
50 	},
51 	{
52 		0x7, "CONNECT"
53 	},
54 	{
55 		0xf, "CONNECT ACKNOWLEDGE"
56 	},
57 	{
58 		0x3, "PROGRESS"
59 	},
60 	{
61 		0x5, "SETUP"
62 	},
63 	{
64 		0xd, "SETUP ACKNOWLEDGE"
65 	},
66 	{
67 		0x24, "HOLD"
68 	},
69 	{
70 		0x28, "HOLD ACKNOWLEDGE"
71 	},
72 	{
73 		0x30, "HOLD REJECT"
74 	},
75 	{
76 		0x31, "RETRIEVE"
77 	},
78 	{
79 		0x33, "RETRIEVE ACKNOWLEDGE"
80 	},
81 	{
82 		0x37, "RETRIEVE REJECT"
83 	},
84 	{
85 		0x26, "RESUME"
86 	},
87 	{
88 		0x2e, "RESUME ACKNOWLEDGE"
89 	},
90 	{
91 		0x22, "RESUME REJECT"
92 	},
93 	{
94 		0x25, "SUSPEND"
95 	},
96 	{
97 		0x2d, "SUSPEND ACKNOWLEDGE"
98 	},
99 	{
100 		0x21, "SUSPEND REJECT"
101 	},
102 	{
103 		0x20, "USER INFORMATION"
104 	},
105 	{
106 		0x45, "DISCONNECT"
107 	},
108 	{
109 		0x4d, "RELEASE"
110 	},
111 	{
112 		0x5a, "RELEASE COMPLETE"
113 	},
114 	{
115 		0x46, "RESTART"
116 	},
117 	{
118 		0x4e, "RESTART ACKNOWLEDGE"
119 	},
120 	{
121 		0x60, "SEGMENT"
122 	},
123 	{
124 		0x79, "CONGESTION CONTROL"
125 	},
126 	{
127 		0x7b, "INFORMATION"
128 	},
129 	{
130 		0x62, "FACILITY"
131 	},
132 	{
133 		0x6e, "NOTIFY"
134 	},
135 	{
136 		0x7d, "STATUS"
137 	},
138 	{
139 		0x75, "STATUS ENQUIRY"
140 	}
141 };
142 
143 #define MTSIZE ARRAY_SIZE(mtlist)
144 
145 static
146 struct MessageType mt_n0[] =
147 {
148 	{MT_N0_REG_IND, "REGister INDication"},
149 	{MT_N0_CANC_IND, "CANCel INDication"},
150 	{MT_N0_FAC_STA, "FACility STAtus"},
151 	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
152 	{MT_N0_STA_REJ, "STAtus REJect"},
153 	{MT_N0_FAC_INF, "FACility INFormation"},
154 	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
155 	{MT_N0_INF_REJ, "INFormation REJect"},
156 	{MT_N0_CLOSE, "CLOSE"},
157 	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
158 };
159 
160 #define MT_N0_LEN ARRAY_SIZE(mt_n0)
161 
162 static
163 struct MessageType mt_n1[] =
164 {
165 	{MT_N1_ESC, "ESCape"},
166 	{MT_N1_ALERT, "ALERT"},
167 	{MT_N1_CALL_SENT, "CALL SENT"},
168 	{MT_N1_CONN, "CONNect"},
169 	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
170 	{MT_N1_SETUP, "SETUP"},
171 	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
172 	{MT_N1_RES, "RESume"},
173 	{MT_N1_RES_ACK, "RESume ACKnowledge"},
174 	{MT_N1_RES_REJ, "RESume REJect"},
175 	{MT_N1_SUSP, "SUSPend"},
176 	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
177 	{MT_N1_SUSP_REJ, "SUSPend REJect"},
178 	{MT_N1_USER_INFO, "USER INFO"},
179 	{MT_N1_DET, "DETach"},
180 	{MT_N1_DISC, "DISConnect"},
181 	{MT_N1_REL, "RELease"},
182 	{MT_N1_REL_ACK, "RELease ACKnowledge"},
183 	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
184 	{MT_N1_CANC_REJ, "CANCel REJect"},
185 	{MT_N1_CON_CON, "CONgestion CONtrol"},
186 	{MT_N1_FAC, "FACility"},
187 	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
188 	{MT_N1_FAC_CAN, "FACility CANcel"},
189 	{MT_N1_FAC_REG, "FACility REGister"},
190 	{MT_N1_FAC_REJ, "FACility REJect"},
191 	{MT_N1_INFO, "INFOrmation"},
192 	{MT_N1_REG_ACK, "REGister ACKnowledge"},
193 	{MT_N1_REG_REJ, "REGister REJect"},
194 	{MT_N1_STAT, "STATus"}
195 };
196 
197 #define MT_N1_LEN ARRAY_SIZE(mt_n1)
198 
199 
200 static int
prbits(char * dest,u_char b,int start,int len)201 prbits(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 
216 static
217 u_char *
skipext(u_char * p)218 skipext(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 
231 static
232 struct CauseValue {
233 	u_char nr;
234 	char *edescr;
235 	char *ddescr;
236 } cvlist[] = {
237 
238 	{
239 		0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
240 	},
241 	{
242 		0x02, "No route to specified transit network", ""
243 	},
244 	{
245 		0x03, "No route to destination", ""
246 	},
247 	{
248 		0x04, "Send special information tone", ""
249 	},
250 	{
251 		0x05, "Misdialled trunk prefix", ""
252 	},
253 	{
254 		0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
255 	},
256 	{
257 		0x07, "Channel awarded and being delivered in an established channel", ""
258 	},
259 	{
260 		0x08, "Preemption", ""
261 	},
262 	{
263 		0x09, "Preemption - circuit reserved for reuse", ""
264 	},
265 	{
266 		0x10, "Normal call clearing", "Normale Ausloesung"
267 	},
268 	{
269 		0x11, "User busy", "TNB besetzt"
270 	},
271 	{
272 		0x12, "No user responding", ""
273 	},
274 	{
275 		0x13, "No answer from user (user alerted)", ""
276 	},
277 	{
278 		0x14, "Subscriber absent", ""
279 	},
280 	{
281 		0x15, "Call rejected", ""
282 	},
283 	{
284 		0x16, "Number changed", ""
285 	},
286 	{
287 		0x1a, "non-selected user clearing", ""
288 	},
289 	{
290 		0x1b, "Destination out of order", ""
291 	},
292 	{
293 		0x1c, "Invalid number format (address incomplete)", ""
294 	},
295 	{
296 		0x1d, "Facility rejected", ""
297 	},
298 	{
299 		0x1e, "Response to Status enquiry", ""
300 	},
301 	{
302 		0x1f, "Normal, unspecified", ""
303 	},
304 	{
305 		0x22, "No circuit/channel available", ""
306 	},
307 	{
308 		0x26, "Network out of order", ""
309 	},
310 	{
311 		0x27, "Permanent frame mode connection out-of-service", ""
312 	},
313 	{
314 		0x28, "Permanent frame mode connection operational", ""
315 	},
316 	{
317 		0x29, "Temporary failure", ""
318 	},
319 	{
320 		0x2a, "Switching equipment congestion", ""
321 	},
322 	{
323 		0x2b, "Access information discarded", ""
324 	},
325 	{
326 		0x2c, "Requested circuit/channel not available", ""
327 	},
328 	{
329 		0x2e, "Precedence call blocked", ""
330 	},
331 	{
332 		0x2f, "Resource unavailable, unspecified", ""
333 	},
334 	{
335 		0x31, "Quality of service unavailable", ""
336 	},
337 	{
338 		0x32, "Requested facility not subscribed", ""
339 	},
340 	{
341 		0x35, "Outgoing calls barred within CUG", ""
342 	},
343 	{
344 		0x37, "Incoming calls barred within CUG", ""
345 	},
346 	{
347 		0x39, "Bearer capability not authorized", ""
348 	},
349 	{
350 		0x3a, "Bearer capability not presently available", ""
351 	},
352 	{
353 		0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
354 	},
355 	{
356 		0x3f, "Service or option not available, unspecified", ""
357 	},
358 	{
359 		0x41, "Bearer capability not implemented", ""
360 	},
361 	{
362 		0x42, "Channel type not implemented", ""
363 	},
364 	{
365 		0x43, "Requested facility not implemented", ""
366 	},
367 	{
368 		0x44, "Only restricted digital information bearer capability is available", ""
369 	},
370 	{
371 		0x4f, "Service or option not implemented", ""
372 	},
373 	{
374 		0x51, "Invalid call reference value", ""
375 	},
376 	{
377 		0x52, "Identified channel does not exist", ""
378 	},
379 	{
380 		0x53, "A suspended call exists, but this call identity does not", ""
381 	},
382 	{
383 		0x54, "Call identity in use", ""
384 	},
385 	{
386 		0x55, "No call suspended", ""
387 	},
388 	{
389 		0x56, "Call having the requested call identity has been cleared", ""
390 	},
391 	{
392 		0x57, "User not member of CUG", ""
393 	},
394 	{
395 		0x58, "Incompatible destination", ""
396 	},
397 	{
398 		0x5a, "Non-existent CUG", ""
399 	},
400 	{
401 		0x5b, "Invalid transit network selection", ""
402 	},
403 	{
404 		0x5f, "Invalid message, unspecified", ""
405 	},
406 	{
407 		0x60, "Mandatory information element is missing", ""
408 	},
409 	{
410 		0x61, "Message type non-existent or not implemented", ""
411 	},
412 	{
413 		0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
414 	},
415 	{
416 		0x63, "Information element/parameter non-existent or not implemented", ""
417 	},
418 	{
419 		0x64, "Invalid information element contents", ""
420 	},
421 	{
422 		0x65, "Message not compatible with call state", ""
423 	},
424 	{
425 		0x66, "Recovery on timer expiry", ""
426 	},
427 	{
428 		0x67, "Parameter non-existent or not implemented - passed on", ""
429 	},
430 	{
431 		0x6e, "Message with unrecognized parameter discarded", ""
432 	},
433 	{
434 		0x6f, "Protocol error, unspecified", ""
435 	},
436 	{
437 		0x7f, "Interworking, unspecified", ""
438 	},
439 };
440 
441 #define CVSIZE ARRAY_SIZE(cvlist)
442 
443 static
444 int
prcause(char * dest,u_char * p)445 prcause(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 
488 static
489 struct 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 
519 static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
520 
521 static int
prcause_1tr6(char * dest,u_char * p)522 prcause_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 
556 static int
prchident(char * dest,u_char * p)557 prchident(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 
568 static int
prcalled(char * dest,u_char * p)569 prcalled(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 }
585 static int
prcalling(char * dest,u_char * p)586 prcalling(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 
611 static
612 int
prbearer(char * dest,u_char * p)613 prbearer(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 
659 static
660 int
prbearer_ni1(char * dest,u_char * p)661 prbearer_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 
717 static int
general(char * dest,u_char * p)718 general(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 
744 static int
general_ni1(char * dest,u_char * p)745 general_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 
771 static int
prcharge(char * dest,u_char * p)772 prcharge(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 }
788 static int
prtext(char * dest,u_char * p)789 prtext(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 
804 static int
prfeatureind(char * dest,u_char * p)805 prfeatureind(char *dest, u_char *p)
806 {
807 	char *dp = dest;
808 
809 	p += 2; /* skip id, len */
810 	dp += sprintf(dp, "    octet 3  ");
811 	dp += prbits(dp, *p, 8, 8);
812 	*dp++ = '\n';
813 	if (!(*p++ & 0x80)) {
814 		dp += sprintf(dp, "    octet 4  ");
815 		dp += prbits(dp, *p++, 8, 8);
816 		*dp++ = '\n';
817 	}
818 	dp += sprintf(dp, "    Status:  ");
819 	switch (*p) {
820 	case 0:
821 		dp += sprintf(dp, "Idle");
822 		break;
823 	case 1:
824 		dp += sprintf(dp, "Active");
825 		break;
826 	case 2:
827 		dp += sprintf(dp, "Prompt");
828 		break;
829 	case 3:
830 		dp += sprintf(dp, "Pending");
831 		break;
832 	default:
833 		dp += sprintf(dp, "(Reserved)");
834 		break;
835 	}
836 	*dp++ = '\n';
837 	return (dp - dest);
838 }
839 
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, "Original called name" },
859 	{ 0x90, "Redirecting name" },
860 	{ 0x91, "Connected name" },
861 	{ 0x92, "Originating restrictions" },
862 	{ 0x93, "Date & time of day" },
863 	{ 0x94, "Call Appearance ID" },
864 	{ 0x95, "Feature address" },
865 	{ 0x96, "Redirection name" },
866 	{ 0x9e, "Text" },
867 };
868 #define DTAGSIZE ARRAY_SIZE(dtaglist)
869 
870 static int
disptext_ni1(char * dest,u_char * p)871 disptext_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 }
909 static int
display(char * dest,u_char * p)910 display(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 
938 static int
prfacility(char * dest,u_char * p)939 prfacility(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 
968 static
969 struct InformationElement {
970 	u_char nr;
971 	char *descr;
972 	int (*f) (char *, u_char *);
973 } ielist[] = {
974 
975 	{
976 		0x00, "Segmented message", general
977 	},
978 	{
979 		0x04, "Bearer capability", prbearer
980 	},
981 	{
982 		0x08, "Cause", prcause
983 	},
984 	{
985 		0x10, "Call identity", general
986 	},
987 	{
988 		0x14, "Call state", general
989 	},
990 	{
991 		0x18, "Channel identification", prchident
992 	},
993 	{
994 		0x1c, "Facility", prfacility
995 	},
996 	{
997 		0x1e, "Progress indicator", general
998 	},
999 	{
1000 		0x20, "Network-specific facilities", general
1001 	},
1002 	{
1003 		0x27, "Notification indicator", general
1004 	},
1005 	{
1006 		0x28, "Display", display
1007 	},
1008 	{
1009 		0x29, "Date/Time", general
1010 	},
1011 	{
1012 		0x2c, "Keypad facility", general
1013 	},
1014 	{
1015 		0x34, "Signal", general
1016 	},
1017 	{
1018 		0x40, "Information rate", general
1019 	},
1020 	{
1021 		0x42, "End-to-end delay", general
1022 	},
1023 	{
1024 		0x43, "Transit delay selection and indication", general
1025 	},
1026 	{
1027 		0x44, "Packet layer binary parameters", general
1028 	},
1029 	{
1030 		0x45, "Packet layer window size", general
1031 	},
1032 	{
1033 		0x46, "Packet size", general
1034 	},
1035 	{
1036 		0x47, "Closed user group", general
1037 	},
1038 	{
1039 		0x4a, "Reverse charge indication", general
1040 	},
1041 	{
1042 		0x6c, "Calling party number", prcalling
1043 	},
1044 	{
1045 		0x6d, "Calling party subaddress", general
1046 	},
1047 	{
1048 		0x70, "Called party number", prcalled
1049 	},
1050 	{
1051 		0x71, "Called party subaddress", general
1052 	},
1053 	{
1054 		0x74, "Redirecting number", general
1055 	},
1056 	{
1057 		0x78, "Transit network selection", general
1058 	},
1059 	{
1060 		0x79, "Restart indicator", general
1061 	},
1062 	{
1063 		0x7c, "Low layer compatibility", general
1064 	},
1065 	{
1066 		0x7d, "High layer compatibility", general
1067 	},
1068 	{
1069 		0x7e, "User-user", general
1070 	},
1071 	{
1072 		0x7f, "Escape for extension", general
1073 	},
1074 };
1075 
1076 
1077 #define IESIZE ARRAY_SIZE(ielist)
1078 
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 },
1102 };
1103 
1104 
1105 #define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
1106 
1107 static
1108 struct InformationElement ielist_ni1_cs5[] = {
1109 	{ 0x1d, "Operator system access", general_ni1 },
1110 	{ 0x2a, "Display text", disptext_ni1 },
1111 };
1112 
1113 #define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
1114 
1115 static
1116 struct InformationElement ielist_ni1_cs6[] = {
1117 	{ 0x7b, "Call appearance", general_ni1 },
1118 };
1119 
1120 #define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
1121 
1122 static struct InformationElement we_0[] =
1123 {
1124 	{WE0_cause, "Cause", prcause_1tr6},
1125 	{WE0_connAddr, "Connecting Address", prcalled},
1126 	{WE0_callID, "Call IDentity", general},
1127 	{WE0_chanID, "Channel IDentity", general},
1128 	{WE0_netSpecFac, "Network Specific Facility", general},
1129 	{WE0_display, "Display", general},
1130 	{WE0_keypad, "Keypad", general},
1131 	{WE0_origAddr, "Origination Address", prcalled},
1132 	{WE0_destAddr, "Destination Address", prcalled},
1133 	{WE0_userInfo, "User Info", general}
1134 };
1135 
1136 #define WE_0_LEN ARRAY_SIZE(we_0)
1137 
1138 static struct InformationElement we_6[] =
1139 {
1140 	{WE6_serviceInd, "Service Indicator", general},
1141 	{WE6_chargingInfo, "Charging Information", prcharge},
1142 	{WE6_date, "Date", prtext},
1143 	{WE6_facSelect, "Facility Select", general},
1144 	{WE6_facStatus, "Facility Status", general},
1145 	{WE6_statusCalled, "Status Called", general},
1146 	{WE6_addTransAttr, "Additional Transmission Attributes", general}
1147 };
1148 #define WE_6_LEN ARRAY_SIZE(we_6)
1149 
1150 int
QuickHex(char * txt,u_char * p,int cnt)1151 QuickHex(char *txt, u_char *p, int cnt)
1152 {
1153 	register int i;
1154 	register char *t = txt;
1155 
1156 	for (i = 0; i < cnt; i++) {
1157 		*t++ = ' ';
1158 		*t++ = hex_asc_hi(p[i]);
1159 		*t++ = hex_asc_lo(p[i]);
1160 	}
1161 	*t++ = 0;
1162 	return (t - txt);
1163 }
1164 
1165 void
LogFrame(struct IsdnCardState * cs,u_char * buf,int size)1166 LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
1167 {
1168 	char *dp;
1169 
1170 	if (size < 1)
1171 		return;
1172 	dp = cs->dlog;
1173 	if (size < MAX_DLOG_SPACE / 3 - 10) {
1174 		*dp++ = 'H';
1175 		*dp++ = 'E';
1176 		*dp++ = 'X';
1177 		*dp++ = ':';
1178 		dp += QuickHex(dp, buf, size);
1179 		dp--;
1180 		*dp++ = '\n';
1181 		*dp = 0;
1182 		HiSax_putstatus(cs, NULL, cs->dlog);
1183 	} else
1184 		HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
1185 }
1186 
1187 void
dlogframe(struct IsdnCardState * cs,struct sk_buff * skb,int dir)1188 dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
1189 {
1190 	u_char *bend, *buf;
1191 	char *dp;
1192 	unsigned char pd, cr_l, cr, mt;
1193 	unsigned char sapi, tei, ftyp;
1194 	int i, cset = 0, cs_old = 0, cs_fest = 0;
1195 	int size, finish = 0;
1196 
1197 	if (skb->len < 3)
1198 		return;
1199 	/* display header */
1200 	dp = cs->dlog;
1201 	dp += jiftime(dp, jiffies);
1202 	*dp++ = ' ';
1203 	sapi = skb->data[0] >> 2;
1204 	tei  = skb->data[1] >> 1;
1205 	ftyp = skb->data[2];
1206 	buf = skb->data;
1207 	dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
1208 	size = skb->len;
1209 
1210 	if (tei == GROUP_TEI) {
1211 		if (sapi == CTRL_SAPI) { /* sapi 0 */
1212 			if (ftyp == 3) {
1213 				dp += sprintf(dp, "broadcast\n");
1214 				buf += 3;
1215 				size -= 3;
1216 			} else {
1217 				dp += sprintf(dp, "no UI broadcast\n");
1218 				finish = 1;
1219 			}
1220 		} else if (sapi == TEI_SAPI) {
1221 			dp += sprintf(dp, "tei management\n");
1222 			finish = 1;
1223 		} else {
1224 			dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
1225 			finish = 1;
1226 		}
1227 	} else {
1228 		if (sapi == CTRL_SAPI) {
1229 			if (!(ftyp & 1)) { /* IFrame */
1230 				dp += sprintf(dp, "with tei %d\n", tei);
1231 				buf += 4;
1232 				size -= 4;
1233 			} else {
1234 				dp += sprintf(dp, "SFrame with tei %d\n", tei);
1235 				finish = 1;
1236 			}
1237 		} else {
1238 			dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1239 			finish = 1;
1240 		}
1241 	}
1242 	bend = skb->data + skb->len;
1243 	if (buf >= bend) {
1244 		dp += sprintf(dp, "frame too short\n");
1245 		finish = 1;
1246 	}
1247 	if (finish) {
1248 		*dp = 0;
1249 		HiSax_putstatus(cs, NULL, cs->dlog);
1250 		return;
1251 	}
1252 	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
1253 		/* locate message type */
1254 		pd = *buf++;
1255 		cr_l = *buf++;
1256 		if (cr_l)
1257 			cr = *buf++;
1258 		else
1259 			cr = 0;
1260 		mt = *buf++;
1261 		if (pd == PROTO_DIS_N0) {	/* N0 */
1262 			for (i = 0; i < MT_N0_LEN; i++)
1263 				if (mt_n0[i].nr == mt)
1264 					break;
1265 			/* display message type if it exists */
1266 			if (i == MT_N0_LEN)
1267 				dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
1268 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1269 					      size, mt);
1270 			else
1271 				dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1272 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1273 					      size, mt_n0[i].descr);
1274 		} else {	/* N1 */
1275 			for (i = 0; i < MT_N1_LEN; i++)
1276 				if (mt_n1[i].nr == mt)
1277 					break;
1278 			/* display message type if it exists */
1279 			if (i == MT_N1_LEN)
1280 				dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
1281 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1282 					      size, mt);
1283 			else
1284 				dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1285 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1286 					      size, mt_n1[i].descr);
1287 		}
1288 
1289 		/* display each information element */
1290 		while (buf < bend) {
1291 			/* Is it a single octet information element? */
1292 			if (*buf & 0x80) {
1293 				switch ((*buf >> 4) & 7) {
1294 				case 1:
1295 					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1296 					cs_old = cset;
1297 					cset = *buf & 7;
1298 					cs_fest = *buf & 8;
1299 					break;
1300 				case 3:
1301 					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1302 					break;
1303 				case 2:
1304 					if (*buf == 0xa0) {
1305 						dp += sprintf(dp, "  More data\n");
1306 						break;
1307 					}
1308 					if (*buf == 0xa1) {
1309 						dp += sprintf(dp, "  Sending complete\n");
1310 					}
1311 					break;
1312 					/* fall through */
1313 				default:
1314 					dp += sprintf(dp, "  Reserved %x\n", *buf);
1315 					break;
1316 				}
1317 				buf++;
1318 				continue;
1319 			}
1320 			/* No, locate it in the table */
1321 			if (cset == 0) {
1322 				for (i = 0; i < WE_0_LEN; i++)
1323 					if (*buf == we_0[i].nr)
1324 						break;
1325 
1326 				/* When found, give appropriate msg */
1327 				if (i != WE_0_LEN) {
1328 					dp += sprintf(dp, "  %s\n", we_0[i].descr);
1329 					dp += we_0[i].f(dp, buf);
1330 				} else
1331 					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1332 			} else if (cset == 6) {
1333 				for (i = 0; i < WE_6_LEN; i++)
1334 					if (*buf == we_6[i].nr)
1335 						break;
1336 
1337 				/* When found, give appropriate msg */
1338 				if (i != WE_6_LEN) {
1339 					dp += sprintf(dp, "  %s\n", we_6[i].descr);
1340 					dp += we_6[i].f(dp, buf);
1341 				} else
1342 					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1343 			} else
1344 				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1345 			/* Skip to next element */
1346 			if (cs_fest == 8) {
1347 				cset = cs_old;
1348 				cs_old = 0;
1349 				cs_fest = 0;
1350 			}
1351 			buf += buf[1] + 2;
1352 		}
1353 	} else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) {	/* NI-1 */
1354 		/* locate message type */
1355 		buf++;
1356 		cr_l = *buf++;
1357 		if (cr_l)
1358 			cr = *buf++;
1359 		else
1360 			cr = 0;
1361 		mt = *buf++;
1362 		for (i = 0; i < MTSIZE; i++)
1363 			if (mtlist[i].nr == mt)
1364 				break;
1365 
1366 		/* display message type if it exists */
1367 		if (i == MTSIZE)
1368 			dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1369 				      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1370 				      size, mt);
1371 		else
1372 			dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1373 				      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1374 				      size, mtlist[i].descr);
1375 
1376 		/* display each information element */
1377 		while (buf < bend) {
1378 			/* Is it a single octet information element? */
1379 			if (*buf & 0x80) {
1380 				switch ((*buf >> 4) & 7) {
1381 				case 1:
1382 					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1383 					cs_old = cset;
1384 					cset = *buf & 7;
1385 					cs_fest = *buf & 8;
1386 					break;
1387 				default:
1388 					dp += sprintf(dp, "  Unknown single-octet IE %x\n", *buf);
1389 					break;
1390 				}
1391 				buf++;
1392 				continue;
1393 			}
1394 			/* No, locate it in the table */
1395 			if (cset == 0) {
1396 				for (i = 0; i < IESIZE_NI1; i++)
1397 					if (*buf == ielist_ni1[i].nr)
1398 						break;
1399 
1400 				/* When not found, give appropriate msg */
1401 				if (i != IESIZE_NI1) {
1402 					dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
1403 					dp += ielist_ni1[i].f(dp, buf);
1404 				} else
1405 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1406 			} else if (cset == 5) {
1407 				for (i = 0; i < IESIZE_NI1_CS5; i++)
1408 					if (*buf == ielist_ni1_cs5[i].nr)
1409 						break;
1410 
1411 				/* When not found, give appropriate msg */
1412 				if (i != IESIZE_NI1_CS5) {
1413 					dp += sprintf(dp, "  %s\n", ielist_ni1_cs5[i].descr);
1414 					dp += ielist_ni1_cs5[i].f(dp, buf);
1415 				} else
1416 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1417 			} else if (cset == 6) {
1418 				for (i = 0; i < IESIZE_NI1_CS6; i++)
1419 					if (*buf == ielist_ni1_cs6[i].nr)
1420 						break;
1421 
1422 				/* When not found, give appropriate msg */
1423 				if (i != IESIZE_NI1_CS6) {
1424 					dp += sprintf(dp, "  %s\n", ielist_ni1_cs6[i].descr);
1425 					dp += ielist_ni1_cs6[i].f(dp, buf);
1426 				} else
1427 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1428 			} else
1429 				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1430 
1431 			/* Skip to next element */
1432 			if (cs_fest == 8) {
1433 				cset = cs_old;
1434 				cs_old = 0;
1435 				cs_fest = 0;
1436 			}
1437 			buf += buf[1] + 2;
1438 		}
1439 	} else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
1440 		/* locate message type */
1441 		buf++;
1442 		cr_l = *buf++;
1443 		if (cr_l)
1444 			cr = *buf++;
1445 		else
1446 			cr = 0;
1447 		mt = *buf++;
1448 		for (i = 0; i < MTSIZE; i++)
1449 			if (mtlist[i].nr == mt)
1450 				break;
1451 
1452 		/* display message type if it exists */
1453 		if (i == MTSIZE)
1454 			dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1455 				      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1456 				      size, mt);
1457 		else
1458 			dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1459 				      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1460 				      size, mtlist[i].descr);
1461 
1462 		/* display each information element */
1463 		while (buf < bend) {
1464 			/* Is it a single octet information element? */
1465 			if (*buf & 0x80) {
1466 				switch ((*buf >> 4) & 7) {
1467 				case 1:
1468 					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1469 					break;
1470 				case 3:
1471 					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1472 					break;
1473 				case 5:
1474 					dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
1475 					break;
1476 				case 2:
1477 					if (*buf == 0xa0) {
1478 						dp += sprintf(dp, "  More data\n");
1479 						break;
1480 					}
1481 					if (*buf == 0xa1) {
1482 						dp += sprintf(dp, "  Sending complete\n");
1483 					}
1484 					break;
1485 					/* fall through */
1486 				default:
1487 					dp += sprintf(dp, "  Reserved %x\n", *buf);
1488 					break;
1489 				}
1490 				buf++;
1491 				continue;
1492 			}
1493 			/* No, locate it in the table */
1494 			for (i = 0; i < IESIZE; i++)
1495 				if (*buf == ielist[i].nr)
1496 					break;
1497 
1498 			/* When not found, give appropriate msg */
1499 			if (i != IESIZE) {
1500 				dp += sprintf(dp, "  %s\n", ielist[i].descr);
1501 				dp += ielist[i].f(dp, buf);
1502 			} else
1503 				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1504 
1505 			/* Skip to next element */
1506 			buf += buf[1] + 2;
1507 		}
1508 	} else {
1509 		dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1510 	}
1511 	*dp = 0;
1512 	HiSax_putstatus(cs, NULL, cs->dlog);
1513 }
1514