• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 sizeof(mtlist)/sizeof(struct MessageType)
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 (sizeof(mt_n0) / sizeof(struct MessageType))
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 (sizeof(mt_n1) / sizeof(struct MessageType))
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 sizeof(cvlist)/sizeof(struct CauseValue)
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 = (sizeof(cause_1tr6) / sizeof(struct MessageType));
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++ & 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 
840 static
841 struct DTag { /* Display tags */
842 	u_char nr;
843 	char *descr;
844 } dtaglist[] = {
845 	{ 0x82, "Continuation" },
846 	{ 0x83, "Called address" },
847 	{ 0x84, "Cause" },
848 	{ 0x85, "Progress indicator" },
849 	{ 0x86, "Notification indicator" },
850 	{ 0x87, "Prompt" },
851 	{ 0x88, "Accumlated digits" },
852 	{ 0x89, "Status" },
853 	{ 0x8a, "Inband" },
854 	{ 0x8b, "Calling address" },
855 	{ 0x8c, "Reason" },
856 	{ 0x8d, "Calling party name" },
857 	{ 0x8e, "Called party name" },
858 	{ 0x8f, "Orignal called name" },
859 	{ 0x90, "Redirecting name" },
860 	{ 0x91, "Connected name" },
861 	{ 0x92, "Originating restrictions" },
862 	{ 0x93, "Date & time of day" },
863 	{ 0x94, "Call Appearance ID" },
864 	{ 0x95, "Feature address" },
865 	{ 0x96, "Redirection name" },
866 	{ 0x9e, "Text" },
867 };
868 #define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
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 sizeof(ielist)/sizeof(struct InformationElement)
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 sizeof(ielist_ni1)/sizeof(struct InformationElement)
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 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
1114 
1115 static
1116 struct InformationElement ielist_ni1_cs6[] = {
1117 	{ 0x7b, "Call appearance", general_ni1 },
1118 };
1119 
1120 #define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
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 (sizeof(we_0) / sizeof(struct InformationElement))
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 (sizeof(we_6) / sizeof(struct InformationElement))
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 	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 
1174 void
LogFrame(struct IsdnCardState * cs,u_char * buf,int size)1175 LogFrame(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 
1196 void
dlogframe(struct IsdnCardState * cs,struct sk_buff * skb,int dir)1197 dlogframe(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) {
1405 				for (i = 0; i < IESIZE_NI1; i++)
1406 					if (*buf == ielist_ni1[i].nr)
1407 						break;
1408 
1409 				/* When not found, give appropriate msg */
1410 				if (i != IESIZE_NI1) {
1411 					dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
1412 					dp += ielist_ni1[i].f(dp, buf);
1413 				} else
1414 					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1415 			} else if (cset == 5) {
1416 				for (i = 0; i < IESIZE_NI1_CS5; i++)
1417 					if (*buf == ielist_ni1_cs5[i].nr)
1418 						break;
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 }
1523