1 /* $Id: q931.c,v 1.1.4.1 2001/11/20 14:19:36 kai 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 #define __NO_VERSION__
21 #include "hisax.h"
22 #include "l3_1tr6.h"
23 
24 void
iecpy(u_char * dest,u_char * iestart,int ieoffset)25 iecpy(u_char * dest, u_char * iestart, int ieoffset)
26 {
27 	u_char *p;
28 	int l;
29 
30 	p = iestart + ieoffset + 2;
31 	l = iestart[1] - ieoffset;
32 	while (l--)
33 		*dest++ = *p++;
34 	*dest++ = '\0';
35 }
36 
37 /*
38  * According to Table 4-2/Q.931
39  */
40 static
41 struct MessageType {
42 	u_char nr;
43 	char *descr;
44 } mtlist[] = {
45 
46 	{
47 		0x1, "ALERTING"
48 	},
49 	{
50 		0x2, "CALL PROCEEDING"
51 	},
52 	{
53 		0x7, "CONNECT"
54 	},
55 	{
56 		0xf, "CONNECT ACKNOWLEDGE"
57 	},
58 	{
59 		0x3, "PROGRESS"
60 	},
61 	{
62 		0x5, "SETUP"
63 	},
64 	{
65 		0xd, "SETUP ACKNOWLEDGE"
66 	},
67 	{
68 		0x24, "HOLD"
69 	},
70 	{
71 		0x28, "HOLD ACKNOWLEDGE"
72 	},
73 	{
74 		0x30, "HOLD REJECT"
75 	},
76 	{
77 		0x31, "RETRIEVE"
78 	},
79 	{
80 		0x33, "RETRIEVE ACKNOWLEDGE"
81 	},
82 	{
83 		0x37, "RETRIEVE REJECT"
84 	},
85 	{
86 		0x26, "RESUME"
87 	},
88 	{
89 		0x2e, "RESUME ACKNOWLEDGE"
90 	},
91 	{
92 		0x22, "RESUME REJECT"
93 	},
94 	{
95 		0x25, "SUSPEND"
96 	},
97 	{
98 		0x2d, "SUSPEND ACKNOWLEDGE"
99 	},
100 	{
101 		0x21, "SUSPEND REJECT"
102 	},
103 	{
104 		0x20, "USER INFORMATION"
105 	},
106 	{
107 		0x45, "DISCONNECT"
108 	},
109 	{
110 		0x4d, "RELEASE"
111 	},
112 	{
113 		0x5a, "RELEASE COMPLETE"
114 	},
115 	{
116 		0x46, "RESTART"
117 	},
118 	{
119 		0x4e, "RESTART ACKNOWLEDGE"
120 	},
121 	{
122 		0x60, "SEGMENT"
123 	},
124 	{
125 		0x79, "CONGESTION CONTROL"
126 	},
127 	{
128 		0x7b, "INFORMATION"
129 	},
130 	{
131 		0x62, "FACILITY"
132 	},
133 	{
134 		0x6e, "NOTIFY"
135 	},
136 	{
137 		0x7d, "STATUS"
138 	},
139 	{
140 		0x75, "STATUS ENQUIRY"
141 	}
142 };
143 
144 #define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
145 
146 static
147 struct MessageType mt_n0[] =
148 {
149 	{MT_N0_REG_IND, "REGister INDication"},
150 	{MT_N0_CANC_IND, "CANCel INDication"},
151 	{MT_N0_FAC_STA, "FACility STAtus"},
152 	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
153 	{MT_N0_STA_REJ, "STAtus REJect"},
154 	{MT_N0_FAC_INF, "FACility INFormation"},
155 	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
156 	{MT_N0_INF_REJ, "INFormation REJect"},
157 	{MT_N0_CLOSE, "CLOSE"},
158 	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
159 };
160 
161 #define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType))
162 
163 static
164 struct MessageType mt_n1[] =
165 {
166 	{MT_N1_ESC, "ESCape"},
167 	{MT_N1_ALERT, "ALERT"},
168 	{MT_N1_CALL_SENT, "CALL SENT"},
169 	{MT_N1_CONN, "CONNect"},
170 	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
171 	{MT_N1_SETUP, "SETUP"},
172 	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
173 	{MT_N1_RES, "RESume"},
174 	{MT_N1_RES_ACK, "RESume ACKnowledge"},
175 	{MT_N1_RES_REJ, "RESume REJect"},
176 	{MT_N1_SUSP, "SUSPend"},
177 	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
178 	{MT_N1_SUSP_REJ, "SUSPend REJect"},
179 	{MT_N1_USER_INFO, "USER INFO"},
180 	{MT_N1_DET, "DETach"},
181 	{MT_N1_DISC, "DISConnect"},
182 	{MT_N1_REL, "RELease"},
183 	{MT_N1_REL_ACK, "RELease ACKnowledge"},
184 	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
185 	{MT_N1_CANC_REJ, "CANCel REJect"},
186 	{MT_N1_CON_CON, "CONgestion CONtrol"},
187 	{MT_N1_FAC, "FACility"},
188 	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
189 	{MT_N1_FAC_CAN, "FACility CANcel"},
190 	{MT_N1_FAC_REG, "FACility REGister"},
191 	{MT_N1_FAC_REJ, "FACility REJect"},
192 	{MT_N1_INFO, "INFOrmation"},
193 	{MT_N1_REG_ACK, "REGister ACKnowledge"},
194 	{MT_N1_REG_REJ, "REGister REJect"},
195 	{MT_N1_STAT, "STATus"}
196 };
197 
198 #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
199 
200 
201 static int
prbits(char * dest,u_char b,int start,int len)202 prbits(char *dest, u_char b, int start, int len)
203 {
204 	char *dp = dest;
205 
206 	b = b << (8 - start);
207 	while (len--) {
208 		if (b & 0x80)
209 			*dp++ = '1';
210 		else
211 			*dp++ = '0';
212 		b = b << 1;
213 	}
214 	return (dp - dest);
215 }
216 
217 static
218 u_char *
skipext(u_char * p)219 skipext(u_char * p)
220 {
221 	while (!(*p++ & 0x80));
222 	return (p);
223 }
224 
225 /*
226  * Cause Values According to Q.850
227  * edescr: English description
228  * ddescr: German description used by Swissnet II (Swiss Telecom
229  *         not yet written...
230  */
231 
232 static
233 struct CauseValue {
234 	u_char nr;
235 	char *edescr;
236 	char *ddescr;
237 } cvlist[] = {
238 
239 	{
240 		0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
241 	},
242 	{
243 		0x02, "No route to specified transit network", ""
244 	},
245 	{
246 		0x03, "No route to destination", ""
247 	},
248 	{
249 		0x04, "Send special information tone", ""
250 	},
251 	{
252 		0x05, "Misdialled trunk prefix", ""
253 	},
254 	{
255 		0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
256 	},
257 	{
258 		0x07, "Channel awarded and being delivered in an established channel", ""
259 	},
260 	{
261 		0x08, "Preemption", ""
262 	},
263 	{
264 		0x09, "Preemption - circuit reserved for reuse", ""
265 	},
266 	{
267 		0x10, "Normal call clearing", "Normale Ausloesung"
268 	},
269 	{
270 		0x11, "User busy", "TNB besetzt"
271 	},
272 	{
273 		0x12, "No user responding", ""
274 	},
275 	{
276 		0x13, "No answer from user (user alerted)", ""
277 	},
278 	{
279 		0x14, "Subscriber absent", ""
280 	},
281 	{
282 		0x15, "Call rejected", ""
283 	},
284 	{
285 		0x16, "Number changed", ""
286 	},
287 	{
288 		0x1a, "non-selected user clearing", ""
289 	},
290 	{
291 		0x1b, "Destination out of order", ""
292 	},
293 	{
294 		0x1c, "Invalid number format (address incomplete)", ""
295 	},
296 	{
297 		0x1d, "Facility rejected", ""
298 	},
299 	{
300 		0x1e, "Response to Status enquiry", ""
301 	},
302 	{
303 		0x1f, "Normal, unspecified", ""
304 	},
305 	{
306 		0x22, "No circuit/channel available", ""
307 	},
308 	{
309 		0x26, "Network out of order", ""
310 	},
311 	{
312 		0x27, "Permanent frame mode connection out-of-service", ""
313 	},
314 	{
315 		0x28, "Permanent frame mode connection operational", ""
316 	},
317 	{
318 		0x29, "Temporary failure", ""
319 	},
320 	{
321 		0x2a, "Switching equipment congestion", ""
322 	},
323 	{
324 		0x2b, "Access information discarded", ""
325 	},
326 	{
327 		0x2c, "Requested circuit/channel not available", ""
328 	},
329 	{
330 		0x2e, "Precedence call blocked", ""
331 	},
332 	{
333 		0x2f, "Resource unavailable, unspecified", ""
334 	},
335 	{
336 		0x31, "Quality of service unavailable", ""
337 	},
338 	{
339 		0x32, "Requested facility not subscribed", ""
340 	},
341 	{
342 		0x35, "Outgoing calls barred within CUG", ""
343 	},
344 	{
345 		0x37, "Incoming calls barred within CUG", ""
346 	},
347 	{
348 		0x39, "Bearer capability not authorized", ""
349 	},
350 	{
351 		0x3a, "Bearer capability not presently available", ""
352 	},
353 	{
354 		0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
355 	},
356 	{
357 		0x3f, "Service or option not available, unspecified", ""
358 	},
359 	{
360 		0x41, "Bearer capability not implemented", ""
361 	},
362 	{
363 		0x42, "Channel type not implemented", ""
364 	},
365 	{
366 		0x43, "Requested facility not implemented", ""
367 	},
368 	{
369 		0x44, "Only restricted digital information bearer capability is available", ""
370 	},
371 	{
372 		0x4f, "Service or option not implemented", ""
373 	},
374 	{
375 		0x51, "Invalid call reference value", ""
376 	},
377 	{
378 		0x52, "Identified channel does not exist", ""
379 	},
380 	{
381 		0x53, "A suspended call exists, but this call identity does not", ""
382 	},
383 	{
384 		0x54, "Call identity in use", ""
385 	},
386 	{
387 		0x55, "No call suspended", ""
388 	},
389 	{
390 		0x56, "Call having the requested call identity has been cleared", ""
391 	},
392 	{
393 		0x57, "User not member of CUG", ""
394 	},
395 	{
396 		0x58, "Incompatible destination", ""
397 	},
398 	{
399 		0x5a, "Non-existent CUG", ""
400 	},
401 	{
402 		0x5b, "Invalid transit network selection", ""
403 	},
404 	{
405 		0x5f, "Invalid message, unspecified", ""
406 	},
407 	{
408 		0x60, "Mandatory information element is missing", ""
409 	},
410 	{
411 		0x61, "Message type non-existent or not implemented", ""
412 	},
413 	{
414 		0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
415 	},
416 	{
417 		0x63, "Information element/parameter non-existent or not implemented", ""
418 	},
419 	{
420 		0x64, "Invalid information element contents", ""
421 	},
422 	{
423 		0x65, "Message not compatible with call state", ""
424 	},
425 	{
426 		0x66, "Recovery on timer expiry", ""
427 	},
428 	{
429 		0x67, "Parameter non-existent or not implemented - passed on", ""
430 	},
431 	{
432 		0x6e, "Message with unrecognized parameter discarded", ""
433 	},
434 	{
435 		0x6f, "Protocol error, unspecified", ""
436 	},
437 	{
438 		0x7f, "Interworking, unspecified", ""
439 	},
440 };
441 
442 #define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
443 
444 static
445 int
prcause(char * dest,u_char * p)446 prcause(char *dest, u_char * p)
447 {
448 	u_char *end;
449 	char *dp = dest;
450 	int i, cause;
451 
452 	end = p + p[1] + 1;
453 	p += 2;
454 	dp += sprintf(dp, "    coding ");
455 	dp += prbits(dp, *p, 7, 2);
456 	dp += sprintf(dp, " location ");
457 	dp += prbits(dp, *p, 4, 4);
458 	*dp++ = '\n';
459 	p = skipext(p);
460 
461 	cause = 0x7f & *p++;
462 
463 	/* locate cause value */
464 	for (i = 0; i < CVSIZE; i++)
465 		if (cvlist[i].nr == cause)
466 			break;
467 
468 	/* display cause value if it exists */
469 	if (i == CVSIZE)
470 		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
471 	else
472 		dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
473 
474 	while (!0) {
475 		if (p > end)
476 			break;
477 		dp += sprintf(dp, "    diag attribute %d ", *p++ & 0x7f);
478 		dp += sprintf(dp, " rej %d ", *p & 0x7f);
479 		if (*p & 0x80) {
480 			*dp++ = '\n';
481 			break;
482 		} else
483 			dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
484 	}
485 	return (dp - dest);
486 
487 }
488 
489 static
490 struct MessageType cause_1tr6[] =
491 {
492 	{CAUSE_InvCRef, "Invalid Call Reference"},
493 	{CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
494 	{CAUSE_CIDunknown, "Caller Identity unknown"},
495 	{CAUSE_CIDinUse, "Caller Identity in Use"},
496 	{CAUSE_NoChans, "No Channels available"},
497 	{CAUSE_FacNotImpl, "Facility Not Implemented"},
498 	{CAUSE_FacNotSubscr, "Facility Not Subscribed"},
499 	{CAUSE_OutgoingBarred, "Outgoing calls barred"},
500 	{CAUSE_UserAccessBusy, "User Access Busy"},
501 	{CAUSE_NegativeGBG, "Negative GBG"},
502 	{CAUSE_UnknownGBG, "Unknown  GBG"},
503 	{CAUSE_NoSPVknown, "No SPV known"},
504 	{CAUSE_DestNotObtain, "Destination not obtainable"},
505 	{CAUSE_NumberChanged, "Number changed"},
506 	{CAUSE_OutOfOrder, "Out Of Order"},
507 	{CAUSE_NoUserResponse, "No User Response"},
508 	{CAUSE_UserBusy, "User Busy"},
509 	{CAUSE_IncomingBarred, "Incoming Barred"},
510 	{CAUSE_CallRejected, "Call Rejected"},
511 	{CAUSE_NetworkCongestion, "Network Congestion"},
512 	{CAUSE_RemoteUser, "Remote User initiated"},
513 	{CAUSE_LocalProcErr, "Local Procedure Error"},
514 	{CAUSE_RemoteProcErr, "Remote Procedure Error"},
515 	{CAUSE_RemoteUserSuspend, "Remote User Suspend"},
516 	{CAUSE_RemoteUserResumed, "Remote User Resumed"},
517 	{CAUSE_UserInfoDiscarded, "User Info Discarded"}
518 };
519 
520 int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
521 
522 static int
prcause_1tr6(char * dest,u_char * p)523 prcause_1tr6(char *dest, u_char * p)
524 {
525 	char *dp = dest;
526 	int i, cause;
527 
528 	p++;
529 	if (0 == *p) {
530 		dp += sprintf(dp, "   OK (cause length=0)\n");
531 		return (dp - dest);
532 	} else if (*p > 1) {
533 		dp += sprintf(dp, "    coding ");
534 		dp += prbits(dp, p[2], 7, 2);
535 		dp += sprintf(dp, " location ");
536 		dp += prbits(dp, p[2], 4, 4);
537 		*dp++ = '\n';
538 	}
539 	p++;
540 	cause = 0x7f & *p;
541 
542 	/* locate cause value */
543 	for (i = 0; i < cause_1tr6_len; i++)
544 		if (cause_1tr6[i].nr == cause)
545 			break;
546 
547 	/* display cause value if it exists */
548 	if (i == cause_1tr6_len)
549 		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
550 	else
551 		dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
552 
553 	return (dp - dest);
554 
555 }
556 
557 static int
prchident(char * dest,u_char * p)558 prchident(char *dest, u_char * p)
559 {
560 	char *dp = dest;
561 
562 	p += 2;
563 	dp += sprintf(dp, "    octet 3 ");
564 	dp += prbits(dp, *p, 8, 8);
565 	*dp++ = '\n';
566 	return (dp - dest);
567 }
568 
569 static int
prcalled(char * dest,u_char * p)570 prcalled(char *dest, u_char * p)
571 {
572 	int l;
573 	char *dp = dest;
574 
575 	p++;
576 	l = *p++ - 1;
577 	dp += sprintf(dp, "    octet 3 ");
578 	dp += prbits(dp, *p++, 8, 8);
579 	*dp++ = '\n';
580 	dp += sprintf(dp, "    number digits ");
581 	while (l--)
582 		*dp++ = *p++;
583 	*dp++ = '\n';
584 	return (dp - dest);
585 }
586 static int
prcalling(char * dest,u_char * p)587 prcalling(char *dest, u_char * p)
588 {
589 	int l;
590 	char *dp = dest;
591 
592 	p++;
593 	l = *p++ - 1;
594 	dp += sprintf(dp, "    octet 3 ");
595 	dp += prbits(dp, *p, 8, 8);
596 	*dp++ = '\n';
597 	if (!(*p & 0x80)) {
598 		dp += sprintf(dp, "    octet 3a ");
599 		dp += prbits(dp, *++p, 8, 8);
600 		*dp++ = '\n';
601 		l--;
602 	};
603 	p++;
604 
605 	dp += sprintf(dp, "    number digits ");
606 	while (l--)
607 		*dp++ = *p++;
608 	*dp++ = '\n';
609 	return (dp - dest);
610 }
611 
612 static
613 int
prbearer(char * dest,u_char * p)614 prbearer(char *dest, u_char * p)
615 {
616 	char *dp = dest, ch;
617 
618 	p += 2;
619 	dp += sprintf(dp, "    octet 3  ");
620 	dp += prbits(dp, *p++, 8, 8);
621 	*dp++ = '\n';
622 	dp += sprintf(dp, "    octet 4  ");
623 	dp += prbits(dp, *p, 8, 8);
624 	*dp++ = '\n';
625 	if ((*p++ & 0x1f) == 0x18) {
626 		dp += sprintf(dp, "    octet 4.1 ");
627 		dp += prbits(dp, *p++, 8, 8);
628 		*dp++ = '\n';
629 	}
630 	/* check for user information layer 1 */
631 	if ((*p & 0x60) == 0x20) {
632 		ch = ' ';
633 		do {
634 			dp += sprintf(dp, "    octet 5%c ", ch);
635 			dp += prbits(dp, *p, 8, 8);
636 			*dp++ = '\n';
637 			if (ch == ' ')
638 				ch = 'a';
639 			else
640 				ch++;
641 		}
642 		while (!(*p++ & 0x80));
643 	}
644 	/* check for user information layer 2 */
645 	if ((*p & 0x60) == 0x40) {
646 		dp += sprintf(dp, "    octet 6  ");
647 		dp += prbits(dp, *p++, 8, 8);
648 		*dp++ = '\n';
649 	}
650 	/* check for user information layer 3 */
651 	if ((*p & 0x60) == 0x60) {
652 		dp += sprintf(dp, "    octet 7  ");
653 		dp += prbits(dp, *p++, 8, 8);
654 		*dp++ = '\n';
655 	}
656 	return (dp - dest);
657 }
658 
659 
660 static
661 int
prbearer_ni1(char * dest,u_char * p)662 prbearer_ni1(char *dest, u_char * p)
663 {
664 	char *dp = dest;
665 	u_char len;
666 
667 	p++;
668 	len = *p++;
669 	dp += sprintf(dp, "    octet 3  ");
670 	dp += prbits(dp, *p, 8, 8);
671 	switch (*p++) {
672 		case 0x80:
673 			dp += sprintf(dp, " Speech");
674 			break;
675 		case 0x88:
676 			dp += sprintf(dp, " Unrestricted digital information");
677 			break;
678 		case 0x90:
679 			dp += sprintf(dp, " 3.1 kHz audio");
680 			break;
681 		default:
682 			dp += sprintf(dp, " Unknown information-transfer capability");
683 	}
684 	*dp++ = '\n';
685 	dp += sprintf(dp, "    octet 4  ");
686 	dp += prbits(dp, *p, 8, 8);
687 	switch (*p++) {
688 		case 0x90:
689 			dp += sprintf(dp, " 64 kbps, circuit mode");
690 			break;
691 		case 0xc0:
692 			dp += sprintf(dp, " Packet mode");
693 			break;
694 		default:
695 			dp += sprintf(dp, " Unknown transfer mode");
696 	}
697 	*dp++ = '\n';
698 	if (len > 2) {
699 		dp += sprintf(dp, "    octet 5  ");
700 		dp += prbits(dp, *p, 8, 8);
701 		switch (*p++) {
702 			case 0x21:
703 				dp += sprintf(dp, " Rate adaption\n");
704 				dp += sprintf(dp, "    octet 5a ");
705 				dp += prbits(dp, *p, 8, 8);
706 				break;
707 			case 0xa2:
708 				dp += sprintf(dp, " u-law");
709 				break;
710 			default:
711 				dp += sprintf(dp, " Unknown UI layer 1 protocol");
712 		}
713 		*dp++ = '\n';
714 	}
715 	return (dp - dest);
716 }
717 
718 static int
general(char * dest,u_char * p)719 general(char *dest, u_char * p)
720 {
721 	char *dp = dest;
722 	char ch = ' ';
723 	int l, octet = 3;
724 
725 	p++;
726 	l = *p++;
727 	/* Iterate over all octets in the information element */
728 	while (l--) {
729 		dp += sprintf(dp, "    octet %d%c ", octet, ch);
730 		dp += prbits(dp, *p++, 8, 8);
731 		*dp++ = '\n';
732 
733 		/* last octet in group? */
734 		if (*p & 0x80) {
735 			octet++;
736 			ch = ' ';
737 		} else if (ch == ' ')
738 			ch = 'a';
739 		else
740 			ch++;
741 	}
742 	return (dp - dest);
743 }
744 
745 static int
general_ni1(char * dest,u_char * p)746 general_ni1(char *dest, u_char * p)
747 {
748 	char *dp = dest;
749 	char ch = ' ';
750 	int l, octet = 3;
751 
752 	p++;
753 	l = *p++;
754 	/* Iterate over all octets in the information element */
755 	while (l--) {
756 		dp += sprintf(dp, "    octet %d%c ", octet, ch);
757 		dp += prbits(dp, *p, 8, 8);
758 		*dp++ = '\n';
759 
760 		/* last octet in group? */
761 		if (*p++ & 0x80) {
762 			octet++;
763 			ch = ' ';
764 		} else if (ch == ' ')
765 			ch = 'a';
766 		else
767 			ch++;
768 	}
769 	return (dp - dest);
770 }
771 
772 static int
prcharge(char * dest,u_char * p)773 prcharge(char *dest, u_char * p)
774 {
775 	char *dp = dest;
776 	int l;
777 
778 	p++;
779 	l = *p++ - 1;
780 	dp += sprintf(dp, "    GEA ");
781 	dp += prbits(dp, *p++, 8, 8);
782 	dp += sprintf(dp, "  Anzahl: ");
783 	/* Iterate over all octets in the * information element */
784 	while (l--)
785 		*dp++ = *p++;
786 	*dp++ = '\n';
787 	return (dp - dest);
788 }
789 static int
prtext(char * dest,u_char * p)790 prtext(char *dest, u_char * p)
791 {
792 	char *dp = dest;
793 	int l;
794 
795 	p++;
796 	l = *p++;
797 	dp += sprintf(dp, "    ");
798 	/* Iterate over all octets in the * information element */
799 	while (l--)
800 		*dp++ = *p++;
801 	*dp++ = '\n';
802 	return (dp - dest);
803 }
804 
805 static int
prfeatureind(char * dest,u_char * p)806 prfeatureind(char *dest, u_char * p)
807 {
808 	char *dp = dest;
809 
810 	p += 2; /* skip id, len */
811 	dp += sprintf(dp, "    octet 3  ");
812 	dp += prbits(dp, *p, 8, 8);
813 	*dp++ = '\n';
814 	if (!(*p++ & 80)) {
815 		dp += sprintf(dp, "    octet 4  ");
816 		dp += prbits(dp, *p++, 8, 8);
817 		*dp++ = '\n';
818 	}
819 	dp += sprintf(dp, "    Status:  ");
820 	switch (*p) {
821 		case 0:
822 			dp += sprintf(dp, "Idle");
823 			break;
824 		case 1:
825 			dp += sprintf(dp, "Active");
826 			break;
827 		case 2:
828 			dp += sprintf(dp, "Prompt");
829 			break;
830 		case 3:
831 			dp += sprintf(dp, "Pending");
832 			break;
833 		default:
834 			dp += sprintf(dp, "(Reserved)");
835 			break;
836 	}
837 	*dp++ = '\n';
838 	return (dp - dest);
839 }
840 
841 static
842 struct DTag { /* Display tags */
843 	u_char nr;
844 	char *descr;
845 } dtaglist[] = {
846 	{ 0x82, "Continuation" },
847 	{ 0x83, "Called address" },
848 	{ 0x84, "Cause" },
849 	{ 0x85, "Progress indicator" },
850 	{ 0x86, "Notification indicator" },
851 	{ 0x87, "Prompt" },
852 	{ 0x88, "Accumlated digits" },
853 	{ 0x89, "Status" },
854 	{ 0x8a, "Inband" },
855 	{ 0x8b, "Calling address" },
856 	{ 0x8c, "Reason" },
857 	{ 0x8d, "Calling party name" },
858 	{ 0x8e, "Called party name" },
859 	{ 0x8f, "Orignal called name" },
860 	{ 0x90, "Redirecting name" },
861 	{ 0x91, "Connected name" },
862 	{ 0x92, "Originating restrictions" },
863 	{ 0x93, "Date & time of day" },
864 	{ 0x94, "Call Appearance ID" },
865 	{ 0x95, "Feature address" },
866 	{ 0x96, "Redirection name" },
867 	{ 0x9e, "Text" },
868 };
869 #define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
870 
871 static int
disptext_ni1(char * dest,u_char * p)872 disptext_ni1(char *dest, u_char * p)
873 {
874 	char *dp = dest;
875 	int l, tag, len, i;
876 
877 	p++;
878 	l = *p++ - 1;
879 	if (*p++ != 0x80) {
880 		dp += sprintf(dp, "    Unknown display type\n");
881 		return (dp - dest);
882 	}
883 	/* Iterate over all tag,length,text fields */
884 	while (l > 0) {
885 		tag = *p++;
886 		len = *p++;
887 		l -= len + 2;
888 		/* Don't space or skip */
889 		if ((tag == 0x80) || (tag == 0x81)) p++;
890 		else {
891 			for (i = 0; i < DTAGSIZE; i++)
892 				if (tag == dtaglist[i].nr)
893 					break;
894 
895 			/* When not found, give appropriate msg */
896 			if (i != DTAGSIZE) {
897 				dp += sprintf(dp, "    %s: ", dtaglist[i].descr);
898 				while (len--)
899 					*dp++ = *p++;
900 			} else {
901 				dp += sprintf(dp, "    (unknown display tag %2x): ", tag);
902 				while (len--)
903 					*dp++ = *p++;
904 			}
905 			dp += sprintf(dp, "\n");
906                 }
907 	}
908 	return (dp - dest);
909 }
910 static int
display(char * dest,u_char * p)911 display(char *dest, u_char * p)
912 {
913 	char *dp = dest;
914 	char ch = ' ';
915 	int l, octet = 3;
916 
917 	p++;
918 	l = *p++;
919 	/* Iterate over all octets in the * display-information element */
920 	dp += sprintf(dp, "   \"");
921 	while (l--) {
922 		dp += sprintf(dp, "%c", *p++);
923 
924 		/* last octet in group? */
925 		if (*p & 0x80) {
926 			octet++;
927 			ch = ' ';
928 		} else if (ch == ' ')
929 			ch = 'a';
930 
931 		else
932 			ch++;
933 	}
934 	*dp++ = '\"';
935 	*dp++ = '\n';
936 	return (dp - dest);
937 }
938 
939 int
prfacility(char * dest,u_char * p)940 prfacility(char *dest, u_char * p)
941 {
942 	char *dp = dest;
943 	int l, l2;
944 
945 	p++;
946 	l = *p++;
947 	dp += sprintf(dp, "    octet 3 ");
948 	dp += prbits(dp, *p++, 8, 8);
949 	dp += sprintf(dp, "\n");
950 	l -= 1;
951 
952 	while (l > 0) {
953 		dp += sprintf(dp, "   octet 4 ");
954 		dp += prbits(dp, *p++, 8, 8);
955 		dp += sprintf(dp, "\n");
956 		dp += sprintf(dp, "   octet 5 %d\n", l2 = *p++ & 0x7f);
957 		l -= 2;
958 		dp += sprintf(dp, "   contents ");
959 		while (l2--) {
960 			dp += sprintf(dp, "%2x ", *p++);
961 			l--;
962 		}
963 		dp += sprintf(dp, "\n");
964 	}
965 
966 	return (dp - dest);
967 }
968 
969 static
970 struct InformationElement {
971 	u_char nr;
972 	char *descr;
973 	int (*f) (char *, u_char *);
974 } ielist[] = {
975 
976 	{
977 		0x00, "Segmented message", general
978 	},
979 	{
980 		0x04, "Bearer capability", prbearer
981 	},
982 	{
983 		0x08, "Cause", prcause
984 	},
985 	{
986 		0x10, "Call identity", general
987 	},
988 	{
989 		0x14, "Call state", general
990 	},
991 	{
992 		0x18, "Channel identification", prchident
993 	},
994 	{
995 		0x1c, "Facility", prfacility
996 	},
997 	{
998 		0x1e, "Progress indicator", general
999 	},
1000 	{
1001 		0x20, "Network-specific facilities", general
1002 	},
1003 	{
1004 		0x27, "Notification indicator", general
1005 	},
1006 	{
1007 		0x28, "Display", display
1008 	},
1009 	{
1010 		0x29, "Date/Time", general
1011 	},
1012 	{
1013 		0x2c, "Keypad facility", general
1014 	},
1015 	{
1016 		0x34, "Signal", general
1017 	},
1018 	{
1019 		0x40, "Information rate", general
1020 	},
1021 	{
1022 		0x42, "End-to-end delay", general
1023 	},
1024 	{
1025 		0x43, "Transit delay selection and indication", general
1026 	},
1027 	{
1028 		0x44, "Packet layer binary parameters", general
1029 	},
1030 	{
1031 		0x45, "Packet layer window size", general
1032 	},
1033 	{
1034 		0x46, "Packet size", general
1035 	},
1036 	{
1037 		0x47, "Closed user group", general
1038 	},
1039 	{
1040 		0x4a, "Reverse charge indication", general
1041 	},
1042 	{
1043 		0x6c, "Calling party number", prcalling
1044 	},
1045 	{
1046 		0x6d, "Calling party subaddress", general
1047 	},
1048 	{
1049 		0x70, "Called party number", prcalled
1050 	},
1051 	{
1052 		0x71, "Called party subaddress", general
1053 	},
1054 	{
1055 		0x74, "Redirecting number", general
1056 	},
1057 	{
1058 		0x78, "Transit network selection", general
1059 	},
1060 	{
1061 		0x79, "Restart indicator", general
1062 	},
1063 	{
1064 		0x7c, "Low layer compatibility", general
1065 	},
1066 	{
1067 		0x7d, "High layer compatibility", general
1068 	},
1069 	{
1070 		0x7e, "User-user", general
1071 	},
1072 	{
1073 		0x7f, "Escape for extension", general
1074 	},
1075 };
1076 
1077 
1078 #define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
1079 
1080 static
1081 struct InformationElement ielist_ni1[] = {
1082 	{ 0x04, "Bearer Capability", prbearer_ni1 },
1083 	{ 0x08, "Cause", prcause },
1084 	{ 0x14, "Call State", general_ni1 },
1085 	{ 0x18, "Channel Identification", prchident },
1086 	{ 0x1e, "Progress Indicator", general_ni1 },
1087 	{ 0x27, "Notification Indicator", general_ni1 },
1088 	{ 0x2c, "Keypad Facility", prtext },
1089 	{ 0x32, "Information Request", general_ni1 },
1090 	{ 0x34, "Signal", general_ni1 },
1091 	{ 0x38, "Feature Activation", general_ni1 },
1092 	{ 0x39, "Feature Indication", prfeatureind },
1093 	{ 0x3a, "Service Profile Identification (SPID)", prtext },
1094 	{ 0x3b, "Endpoint Identifier", general_ni1 },
1095 	{ 0x6c, "Calling Party Number", prcalling },
1096 	{ 0x6d, "Calling Party Subaddress", general_ni1 },
1097 	{ 0x70, "Called Party Number", prcalled },
1098 	{ 0x71, "Called Party Subaddress", general_ni1 },
1099 	{ 0x74, "Redirecting Number", general_ni1 },
1100 	{ 0x78, "Transit Network Selection", general_ni1 },
1101 	{ 0x7c, "Low Layer Compatibility", general_ni1 },
1102 	{ 0x7d, "High Layer Compatibility", general_ni1 },
1103 };
1104 
1105 
1106 #define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement)
1107 
1108 static
1109 struct InformationElement ielist_ni1_cs5[] = {
1110 	{ 0x1d, "Operator system access", general_ni1 },
1111 	{ 0x2a, "Display text", disptext_ni1 },
1112 };
1113 
1114 #define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
1115 
1116 static
1117 struct InformationElement ielist_ni1_cs6[] = {
1118 	{ 0x7b, "Call appearance", general_ni1 },
1119 };
1120 
1121 #define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
1122 
1123 static struct InformationElement we_0[] =
1124 {
1125 	{WE0_cause, "Cause", prcause_1tr6},
1126 	{WE0_connAddr, "Connecting Address", prcalled},
1127 	{WE0_callID, "Call IDentity", general},
1128 	{WE0_chanID, "Channel IDentity", general},
1129 	{WE0_netSpecFac, "Network Specific Facility", general},
1130 	{WE0_display, "Display", general},
1131 	{WE0_keypad, "Keypad", general},
1132 	{WE0_origAddr, "Origination Address", prcalled},
1133 	{WE0_destAddr, "Destination Address", prcalled},
1134 	{WE0_userInfo, "User Info", general}
1135 };
1136 
1137 #define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement))
1138 
1139 static struct InformationElement we_6[] =
1140 {
1141 	{WE6_serviceInd, "Service Indicator", general},
1142 	{WE6_chargingInfo, "Charging Information", prcharge},
1143 	{WE6_date, "Date", prtext},
1144 	{WE6_facSelect, "Facility Select", general},
1145 	{WE6_facStatus, "Facility Status", general},
1146 	{WE6_statusCalled, "Status Called", general},
1147 	{WE6_addTransAttr, "Additional Transmission Attributes", general}
1148 };
1149 #define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement))
1150 
1151 int
QuickHex(char * txt,u_char * p,int cnt)1152 QuickHex(char *txt, u_char * p, int cnt)
1153 {
1154 	register int i;
1155 	register char *t = txt;
1156 	register u_char w;
1157 
1158 	for (i = 0; i < cnt; i++) {
1159 		*t++ = ' ';
1160 		w = (p[i] >> 4) & 0x0f;
1161 		if (w < 10)
1162 			*t++ = '0' + w;
1163 		else
1164 			*t++ = 'A' - 10 + w;
1165 		w = p[i] & 0x0f;
1166 		if (w < 10)
1167 			*t++ = '0' + w;
1168 		else
1169 			*t++ = 'A' - 10 + w;
1170 	}
1171 	*t++ = 0;
1172 	return (t - txt);
1173 }
1174 
1175 void
LogFrame(struct IsdnCardState * cs,u_char * buf,int size)1176 LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
1177 {
1178 	char *dp;
1179 
1180 	if (size < 1)
1181 		return;
1182 	dp = cs->dlog;
1183 	if (size < MAX_DLOG_SPACE / 3 - 10) {
1184 		*dp++ = 'H';
1185 		*dp++ = 'E';
1186 		*dp++ = 'X';
1187 		*dp++ = ':';
1188 		dp += QuickHex(dp, buf, size);
1189 		dp--;
1190 		*dp++ = '\n';
1191 		*dp = 0;
1192 		HiSax_putstatus(cs, NULL, cs->dlog);
1193 	} else
1194 		HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
1195 }
1196 
1197 void
dlogframe(struct IsdnCardState * cs,struct sk_buff * skb,int dir)1198 dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
1199 {
1200 	u_char *bend, *buf;
1201 	char *dp;
1202 	unsigned char pd, cr_l, cr, mt;
1203 	unsigned char sapi, tei, ftyp;
1204 	int i, cset = 0, cs_old = 0, cs_fest = 0;
1205 	int size, finish = 0;
1206 
1207 	if (skb->len < 3)
1208 		return;
1209 	/* display header */
1210 	dp = cs->dlog;
1211 	dp += jiftime(dp, jiffies);
1212 	*dp++ = ' ';
1213 	sapi = skb->data[0] >> 2;
1214 	tei  = skb->data[1] >> 1;
1215 	ftyp = skb->data[2];
1216 	buf = skb->data;
1217 	dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
1218 	size = skb->len;
1219 
1220 	if (tei == GROUP_TEI) {
1221 		if (sapi == CTRL_SAPI) { /* sapi 0 */
1222 			if (ftyp == 3) {
1223 				dp += sprintf(dp, "broadcast\n");
1224 				buf += 3;
1225 				size -= 3;
1226 			} else {
1227 				dp += sprintf(dp, "no UI broadcast\n");
1228 				finish = 1;
1229 			}
1230 		} else if (sapi == TEI_SAPI) {
1231 			dp += sprintf(dp, "tei management\n");
1232 			finish = 1;
1233 		} else {
1234 			dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
1235 			finish = 1;
1236 		}
1237 	} else {
1238 		if (sapi == CTRL_SAPI) {
1239 			if (!(ftyp & 1)) { /* IFrame */
1240 				dp += sprintf(dp, "with tei %d\n", tei);
1241 				buf += 4;
1242 				size -= 4;
1243 			} else {
1244 				dp += sprintf(dp, "SFrame with tei %d\n", tei);
1245 				finish = 1;
1246 			}
1247 		} else {
1248 			dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1249 			finish = 1;
1250 		}
1251 	}
1252 	bend = skb->data + skb->len;
1253 	if (buf >= bend) {
1254 		dp += sprintf(dp, "frame too short\n");
1255 		finish = 1;
1256 	}
1257 	if (finish) {
1258 		*dp = 0;
1259 		HiSax_putstatus(cs, NULL, cs->dlog);
1260 		return;
1261 	}
1262 	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
1263 		/* locate message type */
1264 		pd = *buf++;
1265 		cr_l = *buf++;
1266 		if (cr_l)
1267 			cr = *buf++;
1268 		else
1269 			cr = 0;
1270 		mt = *buf++;
1271 		if (pd == PROTO_DIS_N0) {	/* N0 */
1272 			for (i = 0; i < MT_N0_LEN; i++)
1273 				if (mt_n0[i].nr == mt)
1274 					break;
1275 			/* display message type if it exists */
1276 			if (i == MT_N0_LEN)
1277 				dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
1278 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1279 					      size, mt);
1280 			else
1281 				dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1282 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1283 					      size, mt_n0[i].descr);
1284 		} else {	/* N1 */
1285 			for (i = 0; i < MT_N1_LEN; i++)
1286 				if (mt_n1[i].nr == mt)
1287 					break;
1288 			/* display message type if it exists */
1289 			if (i == MT_N1_LEN)
1290 				dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
1291 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1292 					      size, mt);
1293 			else
1294 				dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1295 					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1296 					      size, mt_n1[i].descr);
1297 		}
1298 
1299 		/* display each information element */
1300 		while (buf < bend) {
1301 			/* Is it a single octet information element? */
1302 			if (*buf & 0x80) {
1303 				switch ((*buf >> 4) & 7) {
1304 					case 1:
1305 						dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1306 						cs_old = cset;
1307 						cset = *buf & 7;
1308 						cs_fest = *buf & 8;
1309 						break;
1310 					case 3:
1311 						dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1312 						break;
1313 					case 2:
1314 						if (*buf == 0xa0) {
1315 							dp += sprintf(dp, "  More data\n");
1316 							break;
1317 						}
1318 						if (*buf == 0xa1) {
1319 							dp += sprintf(dp, "  Sending complete\n");
1320 						}
1321 						break;
1322 						/* fall through */
1323 					default:
1324 						dp += sprintf(dp, "  Reserved %x\n", *buf);
1325 						break;
1326 				}
1327 				buf++;
1328 				continue;
1329 			}
1330 			/* No, locate it in the table */
1331 			if (cset == 0) {
1332 				for (i = 0; i < WE_0_LEN; i++)
1333 					if (*buf == we_0[i].nr)
1334 						break;
1335 
1336 				/* When found, give appropriate msg */
1337 				if (i != WE_0_LEN) {
1338 					dp += sprintf(dp, "  %s\n", we_0[i].descr);
1339 					dp += we_0[i].f(dp, buf);
1340 				} else
1341 					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1342 			} else if (cset == 6) {
1343 				for (i = 0; i < WE_6_LEN; i++)
1344 					if (*buf == we_6[i].nr)
1345 						break;
1346 
1347 				/* When found, give appropriate msg */
1348 				if (i != WE_6_LEN) {
1349 					dp += sprintf(dp, "  %s\n", we_6[i].descr);
1350 					dp += we_6[i].f(dp, buf);
1351 				} else
1352 					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1353 			} else
1354 				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1355 			/* Skip to next element */
1356 			if (cs_fest == 8) {
1357 				cset = cs_old;
1358 				cs_old = 0;
1359 				cs_fest = 0;
1360 			}
1361 			buf += buf[1] + 2;
1362 		}
1363 	} else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) {	/* NI-1 */
1364 		/* locate message type */
1365 		buf++;
1366 		cr_l = *buf++;
1367 		if (cr_l)
1368 			cr = *buf++;
1369 		else
1370 			cr = 0;
1371 		mt = *buf++;
1372 		for (i = 0; i < MTSIZE; i++)
1373 			if (mtlist[i].nr == mt)
1374 				break;
1375 
1376 		/* display message type if it exists */
1377 		if (i == MTSIZE)
1378 			dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1379 			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1380 				      size, mt);
1381 		else
1382 			dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1383 			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1384 				      size, mtlist[i].descr);
1385 
1386 		/* display each information element */
1387 		while (buf < bend) {
1388 			/* Is it a single octet information element? */
1389 			if (*buf & 0x80) {
1390 				switch ((*buf >> 4) & 7) {
1391 					case 1:
1392 						dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1393 						cs_old = cset;
1394 						cset = *buf & 7;
1395 						cs_fest = *buf & 8;
1396 						break;
1397 					default:
1398 						dp += sprintf(dp, "  Unknown single-octet IE %x\n", *buf);
1399 						break;
1400 				}
1401 				buf++;
1402 				continue;
1403 			}
1404 			/* No, locate it in the table */
1405 			if (cset == 0) {
1406 				for (i = 0; i < IESIZE; i++)
1407 					if (*buf == ielist_ni1[i].nr)
1408 						break;
1409 
1410 				/* When not found, give appropriate msg */
1411 				if (i != IESIZE) {
1412 					dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
1413 					dp += ielist_ni1[i].f(dp, buf);
1414 				} else
1415 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1416 			} else if (cset == 5) {
1417 				for (i = 0; i < IESIZE_NI1_CS5; i++)
1418 					if (*buf == ielist_ni1_cs5[i].nr)
1419 						break;
1420 
1421 				/* When not found, give appropriate msg */
1422 				if (i != IESIZE_NI1_CS5) {
1423 					dp += sprintf(dp, "  %s\n", ielist_ni1_cs5[i].descr);
1424 					dp += ielist_ni1_cs5[i].f(dp, buf);
1425 				} else
1426 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1427 			} else if (cset == 6) {
1428 				for (i = 0; i < IESIZE_NI1_CS6; i++)
1429 					if (*buf == ielist_ni1_cs6[i].nr)
1430 						break;
1431 
1432 				/* When not found, give appropriate msg */
1433 				if (i != IESIZE_NI1_CS6) {
1434 					dp += sprintf(dp, "  %s\n", ielist_ni1_cs6[i].descr);
1435 					dp += ielist_ni1_cs6[i].f(dp, buf);
1436 				} else
1437 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1438 			} else
1439 				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1440 
1441 			/* Skip to next element */
1442 			if (cs_fest == 8) {
1443 				cset = cs_old;
1444 				cs_old = 0;
1445 				cs_fest = 0;
1446 			}
1447 			buf += buf[1] + 2;
1448 		}
1449 	} else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
1450 		/* locate message type */
1451 		buf++;
1452 		cr_l = *buf++;
1453 		if (cr_l)
1454 			cr = *buf++;
1455 		else
1456 			cr = 0;
1457 		mt = *buf++;
1458 		for (i = 0; i < MTSIZE; i++)
1459 			if (mtlist[i].nr == mt)
1460 				break;
1461 
1462 		/* display message type if it exists */
1463 		if (i == MTSIZE)
1464 			dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1465 			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1466 				      size, mt);
1467 		else
1468 			dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1469 			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1470 				      size, mtlist[i].descr);
1471 
1472 		/* display each information element */
1473 		while (buf < bend) {
1474 			/* Is it a single octet information element? */
1475 			if (*buf & 0x80) {
1476 				switch ((*buf >> 4) & 7) {
1477 					case 1:
1478 						dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1479 						break;
1480 					case 3:
1481 						dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1482 						break;
1483 					case 5:
1484 						dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
1485 						break;
1486 					case 2:
1487 						if (*buf == 0xa0) {
1488 							dp += sprintf(dp, "  More data\n");
1489 							break;
1490 						}
1491 						if (*buf == 0xa1) {
1492 							dp += sprintf(dp, "  Sending complete\n");
1493 						}
1494 						break;
1495 						/* fall through */
1496 					default:
1497 						dp += sprintf(dp, "  Reserved %x\n", *buf);
1498 						break;
1499 				}
1500 				buf++;
1501 				continue;
1502 			}
1503 			/* No, locate it in the table */
1504 			for (i = 0; i < IESIZE; i++)
1505 				if (*buf == ielist[i].nr)
1506 					break;
1507 
1508 			/* When not found, give appropriate msg */
1509 			if (i != IESIZE) {
1510 				dp += sprintf(dp, "  %s\n", ielist[i].descr);
1511 				dp += ielist[i].f(dp, buf);
1512 			} else
1513 				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1514 
1515 			/* Skip to next element */
1516 			buf += buf[1] + 2;
1517 		}
1518 	} else {
1519 		dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1520 	}
1521 	*dp = 0;
1522 	HiSax_putstatus(cs, NULL, cs->dlog);
1523 }
1524