Pull ngam-maule-steiner into release branch
[linux-2.6] / drivers / isdn / hisax / q931.c
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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; i++)
1406                                         if (*buf == ielist_ni1[i].nr)
1407                                                 break;
1408
1409                                 /* When not found, give appropriate msg */
1410                                 if (i != IESIZE) {
1411                                         dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
1412                                         dp += ielist_ni1[i].f(dp, buf);
1413                                 } else
1414                                         dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1415                         } else if (cset == 5) {
1416                                 for (i = 0; i < IESIZE_NI1_CS5; i++)
1417                                         if (*buf == ielist_ni1_cs5[i].nr)
1418                                                 break;
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 }