[Fuel-plugin] Install kernel in post-deployment.
[kvmfornfv.git] / kernel / 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 ARRAY_SIZE(mtlist)
144
145 static
146 struct MessageType mt_n0[] =
147 {
148         {MT_N0_REG_IND, "REGister INDication"},
149         {MT_N0_CANC_IND, "CANCel INDication"},
150         {MT_N0_FAC_STA, "FACility STAtus"},
151         {MT_N0_STA_ACK, "STAtus ACKnowledge"},
152         {MT_N0_STA_REJ, "STAtus REJect"},
153         {MT_N0_FAC_INF, "FACility INFormation"},
154         {MT_N0_INF_ACK, "INFormation ACKnowledge"},
155         {MT_N0_INF_REJ, "INFormation REJect"},
156         {MT_N0_CLOSE, "CLOSE"},
157         {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
158 };
159
160 #define MT_N0_LEN ARRAY_SIZE(mt_n0)
161
162 static
163 struct MessageType mt_n1[] =
164 {
165         {MT_N1_ESC, "ESCape"},
166         {MT_N1_ALERT, "ALERT"},
167         {MT_N1_CALL_SENT, "CALL SENT"},
168         {MT_N1_CONN, "CONNect"},
169         {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
170         {MT_N1_SETUP, "SETUP"},
171         {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
172         {MT_N1_RES, "RESume"},
173         {MT_N1_RES_ACK, "RESume ACKnowledge"},
174         {MT_N1_RES_REJ, "RESume REJect"},
175         {MT_N1_SUSP, "SUSPend"},
176         {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
177         {MT_N1_SUSP_REJ, "SUSPend REJect"},
178         {MT_N1_USER_INFO, "USER INFO"},
179         {MT_N1_DET, "DETach"},
180         {MT_N1_DISC, "DISConnect"},
181         {MT_N1_REL, "RELease"},
182         {MT_N1_REL_ACK, "RELease ACKnowledge"},
183         {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
184         {MT_N1_CANC_REJ, "CANCel REJect"},
185         {MT_N1_CON_CON, "CONgestion CONtrol"},
186         {MT_N1_FAC, "FACility"},
187         {MT_N1_FAC_ACK, "FACility ACKnowledge"},
188         {MT_N1_FAC_CAN, "FACility CANcel"},
189         {MT_N1_FAC_REG, "FACility REGister"},
190         {MT_N1_FAC_REJ, "FACility REJect"},
191         {MT_N1_INFO, "INFOrmation"},
192         {MT_N1_REG_ACK, "REGister ACKnowledge"},
193         {MT_N1_REG_REJ, "REGister REJect"},
194         {MT_N1_STAT, "STATus"}
195 };
196
197 #define MT_N1_LEN ARRAY_SIZE(mt_n1)
198
199
200 static int
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 ARRAY_SIZE(cvlist)
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 = ARRAY_SIZE(cause_1tr6);
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++ & 0x80)) {
814                 dp += sprintf(dp, "    octet 4  ");
815                 dp += prbits(dp, *p++, 8, 8);
816                 *dp++ = '\n';
817         }
818         dp += sprintf(dp, "    Status:  ");
819         switch (*p) {
820         case 0:
821                 dp += sprintf(dp, "Idle");
822                 break;
823         case 1:
824                 dp += sprintf(dp, "Active");
825                 break;
826         case 2:
827                 dp += sprintf(dp, "Prompt");
828                 break;
829         case 3:
830                 dp += sprintf(dp, "Pending");
831                 break;
832         default:
833                 dp += sprintf(dp, "(Reserved)");
834                 break;
835         }
836         *dp++ = '\n';
837         return (dp - dest);
838 }
839
840 static
841 struct DTag { /* Display tags */
842         u_char nr;
843         char *descr;
844 } dtaglist[] = {
845         { 0x82, "Continuation" },
846         { 0x83, "Called address" },
847         { 0x84, "Cause" },
848         { 0x85, "Progress indicator" },
849         { 0x86, "Notification indicator" },
850         { 0x87, "Prompt" },
851         { 0x88, "Accumlated digits" },
852         { 0x89, "Status" },
853         { 0x8a, "Inband" },
854         { 0x8b, "Calling address" },
855         { 0x8c, "Reason" },
856         { 0x8d, "Calling party name" },
857         { 0x8e, "Called party name" },
858         { 0x8f, "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 ARRAY_SIZE(dtaglist)
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 ARRAY_SIZE(ielist)
1078
1079 static
1080 struct InformationElement ielist_ni1[] = {
1081         { 0x04, "Bearer Capability", prbearer_ni1 },
1082         { 0x08, "Cause", prcause },
1083         { 0x14, "Call State", general_ni1 },
1084         { 0x18, "Channel Identification", prchident },
1085         { 0x1e, "Progress Indicator", general_ni1 },
1086         { 0x27, "Notification Indicator", general_ni1 },
1087         { 0x2c, "Keypad Facility", prtext },
1088         { 0x32, "Information Request", general_ni1 },
1089         { 0x34, "Signal", general_ni1 },
1090         { 0x38, "Feature Activation", general_ni1 },
1091         { 0x39, "Feature Indication", prfeatureind },
1092         { 0x3a, "Service Profile Identification (SPID)", prtext },
1093         { 0x3b, "Endpoint Identifier", general_ni1 },
1094         { 0x6c, "Calling Party Number", prcalling },
1095         { 0x6d, "Calling Party Subaddress", general_ni1 },
1096         { 0x70, "Called Party Number", prcalled },
1097         { 0x71, "Called Party Subaddress", general_ni1 },
1098         { 0x74, "Redirecting Number", general_ni1 },
1099         { 0x78, "Transit Network Selection", general_ni1 },
1100         { 0x7c, "Low Layer Compatibility", general_ni1 },
1101         { 0x7d, "High Layer Compatibility", general_ni1 },
1102 };
1103
1104
1105 #define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
1106
1107 static
1108 struct InformationElement ielist_ni1_cs5[] = {
1109         { 0x1d, "Operator system access", general_ni1 },
1110         { 0x2a, "Display text", disptext_ni1 },
1111 };
1112
1113 #define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
1114
1115 static
1116 struct InformationElement ielist_ni1_cs6[] = {
1117         { 0x7b, "Call appearance", general_ni1 },
1118 };
1119
1120 #define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
1121
1122 static struct InformationElement we_0[] =
1123 {
1124         {WE0_cause, "Cause", prcause_1tr6},
1125         {WE0_connAddr, "Connecting Address", prcalled},
1126         {WE0_callID, "Call IDentity", general},
1127         {WE0_chanID, "Channel IDentity", general},
1128         {WE0_netSpecFac, "Network Specific Facility", general},
1129         {WE0_display, "Display", general},
1130         {WE0_keypad, "Keypad", general},
1131         {WE0_origAddr, "Origination Address", prcalled},
1132         {WE0_destAddr, "Destination Address", prcalled},
1133         {WE0_userInfo, "User Info", general}
1134 };
1135
1136 #define WE_0_LEN ARRAY_SIZE(we_0)
1137
1138 static struct InformationElement we_6[] =
1139 {
1140         {WE6_serviceInd, "Service Indicator", general},
1141         {WE6_chargingInfo, "Charging Information", prcharge},
1142         {WE6_date, "Date", prtext},
1143         {WE6_facSelect, "Facility Select", general},
1144         {WE6_facStatus, "Facility Status", general},
1145         {WE6_statusCalled, "Status Called", general},
1146         {WE6_addTransAttr, "Additional Transmission Attributes", general}
1147 };
1148 #define WE_6_LEN ARRAY_SIZE(we_6)
1149
1150 int
1151 QuickHex(char *txt, u_char *p, int cnt)
1152 {
1153         register int i;
1154         register char *t = txt;
1155
1156         for (i = 0; i < cnt; i++) {
1157                 *t++ = ' ';
1158                 *t++ = hex_asc_hi(p[i]);
1159                 *t++ = hex_asc_lo(p[i]);
1160         }
1161         *t++ = 0;
1162         return (t - txt);
1163 }
1164
1165 void
1166 LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
1167 {
1168         char *dp;
1169
1170         if (size < 1)
1171                 return;
1172         dp = cs->dlog;
1173         if (size < MAX_DLOG_SPACE / 3 - 10) {
1174                 *dp++ = 'H';
1175                 *dp++ = 'E';
1176                 *dp++ = 'X';
1177                 *dp++ = ':';
1178                 dp += QuickHex(dp, buf, size);
1179                 dp--;
1180                 *dp++ = '\n';
1181                 *dp = 0;
1182                 HiSax_putstatus(cs, NULL, cs->dlog);
1183         } else
1184                 HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
1185 }
1186
1187 void
1188 dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
1189 {
1190         u_char *bend, *buf;
1191         char *dp;
1192         unsigned char pd, cr_l, cr, mt;
1193         unsigned char sapi, tei, ftyp;
1194         int i, cset = 0, cs_old = 0, cs_fest = 0;
1195         int size, finish = 0;
1196
1197         if (skb->len < 3)
1198                 return;
1199         /* display header */
1200         dp = cs->dlog;
1201         dp += jiftime(dp, jiffies);
1202         *dp++ = ' ';
1203         sapi = skb->data[0] >> 2;
1204         tei  = skb->data[1] >> 1;
1205         ftyp = skb->data[2];
1206         buf = skb->data;
1207         dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
1208         size = skb->len;
1209
1210         if (tei == GROUP_TEI) {
1211                 if (sapi == CTRL_SAPI) { /* sapi 0 */
1212                         if (ftyp == 3) {
1213                                 dp += sprintf(dp, "broadcast\n");
1214                                 buf += 3;
1215                                 size -= 3;
1216                         } else {
1217                                 dp += sprintf(dp, "no UI broadcast\n");
1218                                 finish = 1;
1219                         }
1220                 } else if (sapi == TEI_SAPI) {
1221                         dp += sprintf(dp, "tei management\n");
1222                         finish = 1;
1223                 } else {
1224                         dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
1225                         finish = 1;
1226                 }
1227         } else {
1228                 if (sapi == CTRL_SAPI) {
1229                         if (!(ftyp & 1)) { /* IFrame */
1230                                 dp += sprintf(dp, "with tei %d\n", tei);
1231                                 buf += 4;
1232                                 size -= 4;
1233                         } else {
1234                                 dp += sprintf(dp, "SFrame with tei %d\n", tei);
1235                                 finish = 1;
1236                         }
1237                 } else {
1238                         dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1239                         finish = 1;
1240                 }
1241         }
1242         bend = skb->data + skb->len;
1243         if (buf >= bend) {
1244                 dp += sprintf(dp, "frame too short\n");
1245                 finish = 1;
1246         }
1247         if (finish) {
1248                 *dp = 0;
1249                 HiSax_putstatus(cs, NULL, cs->dlog);
1250                 return;
1251         }
1252         if ((0xfe & buf[0]) == PROTO_DIS_N0) {  /* 1TR6 */
1253                 /* locate message type */
1254                 pd = *buf++;
1255                 cr_l = *buf++;
1256                 if (cr_l)
1257                         cr = *buf++;
1258                 else
1259                         cr = 0;
1260                 mt = *buf++;
1261                 if (pd == PROTO_DIS_N0) {       /* N0 */
1262                         for (i = 0; i < MT_N0_LEN; i++)
1263                                 if (mt_n0[i].nr == mt)
1264                                         break;
1265                         /* display message type if it exists */
1266                         if (i == MT_N0_LEN)
1267                                 dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
1268                                               cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1269                                               size, mt);
1270                         else
1271                                 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1272                                               cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1273                                               size, mt_n0[i].descr);
1274                 } else {        /* N1 */
1275                         for (i = 0; i < MT_N1_LEN; i++)
1276                                 if (mt_n1[i].nr == mt)
1277                                         break;
1278                         /* display message type if it exists */
1279                         if (i == MT_N1_LEN)
1280                                 dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
1281                                               cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1282                                               size, mt);
1283                         else
1284                                 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1285                                               cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1286                                               size, mt_n1[i].descr);
1287                 }
1288
1289                 /* display each information element */
1290                 while (buf < bend) {
1291                         /* Is it a single octet information element? */
1292                         if (*buf & 0x80) {
1293                                 switch ((*buf >> 4) & 7) {
1294                                 case 1:
1295                                         dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1296                                         cs_old = cset;
1297                                         cset = *buf & 7;
1298                                         cs_fest = *buf & 8;
1299                                         break;
1300                                 case 3:
1301                                         dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1302                                         break;
1303                                 case 2:
1304                                         if (*buf == 0xa0) {
1305                                                 dp += sprintf(dp, "  More data\n");
1306                                                 break;
1307                                         }
1308                                         if (*buf == 0xa1) {
1309                                                 dp += sprintf(dp, "  Sending complete\n");
1310                                         }
1311                                         break;
1312                                         /* fall through */
1313                                 default:
1314                                         dp += sprintf(dp, "  Reserved %x\n", *buf);
1315                                         break;
1316                                 }
1317                                 buf++;
1318                                 continue;
1319                         }
1320                         /* No, locate it in the table */
1321                         if (cset == 0) {
1322                                 for (i = 0; i < WE_0_LEN; i++)
1323                                         if (*buf == we_0[i].nr)
1324                                                 break;
1325
1326                                 /* When found, give appropriate msg */
1327                                 if (i != WE_0_LEN) {
1328                                         dp += sprintf(dp, "  %s\n", we_0[i].descr);
1329                                         dp += we_0[i].f(dp, buf);
1330                                 } else
1331                                         dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1332                         } else if (cset == 6) {
1333                                 for (i = 0; i < WE_6_LEN; i++)
1334                                         if (*buf == we_6[i].nr)
1335                                                 break;
1336
1337                                 /* When found, give appropriate msg */
1338                                 if (i != WE_6_LEN) {
1339                                         dp += sprintf(dp, "  %s\n", we_6[i].descr);
1340                                         dp += we_6[i].f(dp, buf);
1341                                 } else
1342                                         dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1343                         } else
1344                                 dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1345                         /* Skip to next element */
1346                         if (cs_fest == 8) {
1347                                 cset = cs_old;
1348                                 cs_old = 0;
1349                                 cs_fest = 0;
1350                         }
1351                         buf += buf[1] + 2;
1352                 }
1353         } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */
1354                 /* locate message type */
1355                 buf++;
1356                 cr_l = *buf++;
1357                 if (cr_l)
1358                         cr = *buf++;
1359                 else
1360                         cr = 0;
1361                 mt = *buf++;
1362                 for (i = 0; i < MTSIZE; i++)
1363                         if (mtlist[i].nr == mt)
1364                                 break;
1365
1366                 /* display message type if it exists */
1367                 if (i == MTSIZE)
1368                         dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1369                                       cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1370                                       size, mt);
1371                 else
1372                         dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1373                                       cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1374                                       size, mtlist[i].descr);
1375
1376                 /* display each information element */
1377                 while (buf < bend) {
1378                         /* Is it a single octet information element? */
1379                         if (*buf & 0x80) {
1380                                 switch ((*buf >> 4) & 7) {
1381                                 case 1:
1382                                         dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1383                                         cs_old = cset;
1384                                         cset = *buf & 7;
1385                                         cs_fest = *buf & 8;
1386                                         break;
1387                                 default:
1388                                         dp += sprintf(dp, "  Unknown single-octet IE %x\n", *buf);
1389                                         break;
1390                                 }
1391                                 buf++;
1392                                 continue;
1393                         }
1394                         /* No, locate it in the table */
1395                         if (cset == 0) {
1396                                 for (i = 0; i < IESIZE_NI1; i++)
1397                                         if (*buf == ielist_ni1[i].nr)
1398                                                 break;
1399
1400                                 /* When not found, give appropriate msg */
1401                                 if (i != IESIZE_NI1) {
1402                                         dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
1403                                         dp += ielist_ni1[i].f(dp, buf);
1404                                 } else
1405                                         dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1406                         } else if (cset == 5) {
1407                                 for (i = 0; i < IESIZE_NI1_CS5; i++)
1408                                         if (*buf == ielist_ni1_cs5[i].nr)
1409                                                 break;
1410
1411                                 /* When not found, give appropriate msg */
1412                                 if (i != IESIZE_NI1_CS5) {
1413                                         dp += sprintf(dp, "  %s\n", ielist_ni1_cs5[i].descr);
1414                                         dp += ielist_ni1_cs5[i].f(dp, buf);
1415                                 } else
1416                                         dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1417                         } else if (cset == 6) {
1418                                 for (i = 0; i < IESIZE_NI1_CS6; i++)
1419                                         if (*buf == ielist_ni1_cs6[i].nr)
1420                                                 break;
1421
1422                                 /* When not found, give appropriate msg */
1423                                 if (i != IESIZE_NI1_CS6) {
1424                                         dp += sprintf(dp, "  %s\n", ielist_ni1_cs6[i].descr);
1425                                         dp += ielist_ni1_cs6[i].f(dp, buf);
1426                                 } else
1427                                         dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1428                         } else
1429                                 dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1430
1431                         /* Skip to next element */
1432                         if (cs_fest == 8) {
1433                                 cset = cs_old;
1434                                 cs_old = 0;
1435                                 cs_fest = 0;
1436                         }
1437                         buf += buf[1] + 2;
1438                 }
1439         } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
1440                 /* locate message type */
1441                 buf++;
1442                 cr_l = *buf++;
1443                 if (cr_l)
1444                         cr = *buf++;
1445                 else
1446                         cr = 0;
1447                 mt = *buf++;
1448                 for (i = 0; i < MTSIZE; i++)
1449                         if (mtlist[i].nr == mt)
1450                                 break;
1451
1452                 /* display message type if it exists */
1453                 if (i == MTSIZE)
1454                         dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1455                                       cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1456                                       size, mt);
1457                 else
1458                         dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1459                                       cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1460                                       size, mtlist[i].descr);
1461
1462                 /* display each information element */
1463                 while (buf < bend) {
1464                         /* Is it a single octet information element? */
1465                         if (*buf & 0x80) {
1466                                 switch ((*buf >> 4) & 7) {
1467                                 case 1:
1468                                         dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
1469                                         break;
1470                                 case 3:
1471                                         dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
1472                                         break;
1473                                 case 5:
1474                                         dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
1475                                         break;
1476                                 case 2:
1477                                         if (*buf == 0xa0) {
1478                                                 dp += sprintf(dp, "  More data\n");
1479                                                 break;
1480                                         }
1481                                         if (*buf == 0xa1) {
1482                                                 dp += sprintf(dp, "  Sending complete\n");
1483                                         }
1484                                         break;
1485                                         /* fall through */
1486                                 default:
1487                                         dp += sprintf(dp, "  Reserved %x\n", *buf);
1488                                         break;
1489                                 }
1490                                 buf++;
1491                                 continue;
1492                         }
1493                         /* No, locate it in the table */
1494                         for (i = 0; i < IESIZE; i++)
1495                                 if (*buf == ielist[i].nr)
1496                                         break;
1497
1498                         /* When not found, give appropriate msg */
1499                         if (i != IESIZE) {
1500                                 dp += sprintf(dp, "  %s\n", ielist[i].descr);
1501                                 dp += ielist[i].f(dp, buf);
1502                         } else
1503                                 dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
1504
1505                         /* Skip to next element */
1506                         buf += buf[1] + 2;
1507                 }
1508         } else {
1509                 dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1510         }
1511         *dp = 0;
1512         HiSax_putstatus(cs, NULL, cs->dlog);
1513 }