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