error inside information elements are now reported inside trace and main log,
[lcr.git] / ie.cpp
1
2 /*****************************************************************************\
3 **                                                                           **
4 ** PBX4Linux                                                                 **
5 **                                                                           **
6 **---------------------------------------------------------------------------**
7 ** Copyright: Andreas Eversberg                                              **
8 **                                                                           **
9 ** information elements encode and decode                                    **
10 **                                                                           **
11 \*****************************************************************************/ 
12
13 /*
14  the pointer of enc_ie_* always points to the IE itself
15  if qi is not NULL (TE-mode), offset is set
16 */
17
18 /* support stuff */
19 static void strnncpy(unsigned char *dest, unsigned char *src, int len, int dst_len)
20 {
21         if (len > dst_len-1)
22                 len = dst_len-1;
23         UNCPY((char *)dest, (char *)src, len);
24         dest[len] = '\0';
25 }
26
27
28 /* IE_COMPLETE */
29 void Pdss1::enc_ie_complete(unsigned char **ntmode, msg_t *msg, int complete)
30 {
31         unsigned char *p;
32         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
33
34         if (complete<0 || complete>1)
35         {
36                 PERROR("complete(%d) is out of range.\n", complete);
37                 return;
38         }
39
40         if (complete)
41         {
42                 add_trace("complete", NULL, NULL);
43                 p = msg_put(msg, 1);
44                 if (p_m_d_ntmode)
45                 {
46                         *ntmode = p;
47                 } else
48                         qi->sending_complete.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
49                 p[0] = IE_COMPLETE;
50         }
51 }
52
53 void Pdss1::dec_ie_complete(unsigned char *p, Q931_info_t *qi, int *complete)
54 {
55         *complete = 0;
56         if (!p_m_d_ntmode)
57         {
58                 if (qi->sending_complete.off)
59                         *complete = 1;
60         } else
61         if (p)
62                 *complete = 1;
63
64         if (*complete)
65                 add_trace("complete", NULL, NULL);
66 }
67
68
69 /* IE_BEARER */
70 void Pdss1::enc_ie_bearer(unsigned char **ntmode, msg_t *msg, int coding, int capability, int mode, int rate, int multi, int user)
71 {
72         unsigned char *p;
73         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
74         int l;
75
76         if (coding<0 || coding>3)
77         {
78                 PERROR("coding(%d) is out of range.\n", coding);
79                 return;
80         }
81         if (capability<0 || capability>31)
82         {
83                 PERROR("capability(%d) is out of range.\n", capability);
84                 return;
85         }
86         if (mode<0 || mode>3)
87         {
88                 PERROR("mode(%d) is out of range.\n", mode);
89                 return;
90         }
91         if (rate<0 || rate>31)
92         {
93                 PERROR("rate(%d) is out of range.\n", rate);
94                 return;
95         }
96         if (multi>127)
97         {
98                 PERROR("multi(%d) is out of range.\n", multi);
99                 return;
100         }
101         if (user>31)
102         {
103                 PERROR("user L1(%d) is out of range.\n", user);
104                 return;
105         }
106         if (rate!=24 && multi>=0)
107         {
108                 PERROR("multi(%d) is only possible if rate(%d) would be 24.\n", multi, rate);
109                 multi = -1;
110         }
111
112         add_trace("bearer", "coding", "%d", coding);
113         add_trace("bearer", "capability", "%d", capability);
114         add_trace("bearer", "mode", "%d", mode);
115         add_trace("bearer", "rate", "%d", rate);
116         add_trace("bearer", "multi", "%d", multi);
117         add_trace("bearer", "user", "%d", user);
118
119         l = 2 + (multi>=0) + (user>=0);
120         p = msg_put(msg, l+2);
121         if (p_m_d_ntmode)
122                 *ntmode = p+1;
123         else
124                 qi->bearer_capability.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
125         p[0] = IE_BEARER;
126         p[1] = l;
127         p[2] = 0x80 + (coding<<5) + capability;
128         p[3] = 0x80 + (mode<<5) + rate;
129         if (multi >= 0)
130                 p[4] = 0x80 + multi;
131         if (user >= 0)
132                 p[4+(multi>=0)] = 0xa0 + user;
133 }
134
135 void Pdss1::dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capability, int *mode, int *rate, int *multi, int *user)
136 {
137         *coding = -1;
138         *capability = -1;
139         *mode = -1;
140         *rate = -1;
141         *multi = -1;
142         *user = -1;
143
144         if (!p_m_d_ntmode)
145         {
146                 p = NULL;
147                 if (qi->bearer_capability.off)
148                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->bearer_capability.off + 1;
149         }
150         if (!p)
151                 return;
152         if (p[0] < 2)
153         {
154                 add_trace("bearer", "error", "IE too short (len=%d)", p[0]);
155                 return;
156         }
157
158         *coding = (p[1]&0x60) >> 5;
159         *capability = p[1] & 0x1f;
160         if (p[0]>=2)
161         {
162                 *mode = (p[2]&0x60) >> 5;
163                 *rate = p[2] & 0x1f;
164         }
165         if (p[0]>=3 && *rate==0x18)
166         {
167                 *multi = p[3] & 0x7f;
168                 if (p[0]>=4)
169                         *user = p[4] & 0x1f;
170         } else
171         {
172                 if (p[0]>=3)
173                         *user = p[3] & 0x1f;
174         }
175
176         add_trace("bearer", "coding", "%d", *coding);
177         add_trace("bearer", "capability", "%d", *capability);
178         add_trace("bearer", "mode", "%d", *mode);
179         add_trace("bearer", "rate", "%d", *rate);
180         add_trace("bearer", "multi", "%d", *multi);
181         add_trace("bearer", "user", "%d", *user);
182 }
183
184
185 /* IE_HLC */
186 void Pdss1::enc_ie_hlc(unsigned char **ntmode, msg_t *msg, int coding, int interpretation, int presentation, int hlc, int exthlc)
187 {
188         unsigned char *p;
189         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
190         int l;
191
192         if (coding<0 || coding>3)
193         {
194                 PERROR("coding(%d) is out of range.\n", coding);
195                 return;
196         }
197         if (interpretation<0 || interpretation>7)
198         {
199                 PERROR("interpretation(%d) is out of range.\n", interpretation);
200                 return;
201         }
202         if (presentation<0 || presentation>3)
203         {
204                 PERROR("presentation(%d) is out of range.\n", presentation);
205                 return;
206         }
207         if (hlc<0 || hlc>127)
208         {
209                 PERROR("hlc(%d) is out of range.\n", hlc);
210                 return;
211         }
212         if (exthlc>127)
213         {
214                 PERROR("hlc(%d) is out of range.\n", exthlc);
215                 return;
216         }
217
218         add_trace("hlc", "coding", "%d", coding);
219         add_trace("hlc", "interpretation", "%d", interpretation);
220         add_trace("hlc", "presentation", "%d", presentation);
221         add_trace("hlc", "hlc", "%d", hlc);
222         if (exthlc >= 0)
223                 add_trace("hlc", "exthlc", "%d", exthlc);
224
225         l = 2 + (exthlc>=0);
226         p = msg_put(msg, l+2);
227         if (p_m_d_ntmode)
228                 *ntmode = p+1;
229         else
230                 qi->hlc.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
231         p[0] = IE_HLC;
232         p[1] = l;
233         p[2] = 0x80 + (coding<<5) + (interpretation<<2) + presentation;
234         if (exthlc >= 0)
235         {
236                 p[3] = hlc;
237                 p[4] = 0x80 + exthlc;
238         } else
239                 p[3] = 0x80 + hlc;
240 }
241
242 void Pdss1::dec_ie_hlc(unsigned char *p, Q931_info_t *qi, int *coding, int *interpretation, int *presentation, int *hlc, int *exthlc)
243 {
244         *coding = -1;
245         *interpretation = -1;
246         *presentation = -1;
247         *hlc = -1;
248         *exthlc = -1;
249
250         if (!p_m_d_ntmode)
251         {
252                 p = NULL;
253                 if (qi->hlc.off)
254                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->hlc.off + 1;
255         }
256         if (!p)
257                 return;
258         if (p[0] < 2)
259         {
260                 add_trace("hlc", "error", "IE too short (len=%d)", p[0]);
261                 return;
262         }
263
264         *coding = (p[1]&0x60) >> 5;
265         *interpretation = (p[1]&0x1c) >> 2;
266         *presentation = p[1] & 0x03;
267         *hlc = p[2] & 0x7f;
268         if (p[0]>=3)
269         {
270                 *exthlc = p[3] & 0x7f;
271         }
272
273         add_trace("hlc", "coding", "%d", *coding);
274         add_trace("hlc", "interpretation", "%d", *interpretation);
275         add_trace("hlc", "presentation", "%d", *presentation);
276         add_trace("hlc", "hlc", "%d", *hlc);
277         if (*exthlc >= 0)
278                 add_trace("hlc", "exthlc", "%d", *exthlc);
279 }
280
281
282 /* IE_CALL_ID */
283 void Pdss1::enc_ie_call_id(unsigned char **ntmode, msg_t *msg, unsigned char *callid, int callid_len)
284 {
285         unsigned char *p;
286         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
287         int l;
288
289         char buffer[25];
290         int i;
291
292         if (!callid || callid_len<=0)
293         {
294                 return;
295         }
296         if (callid_len > 8)
297         {
298                 PERROR("callid_len(%d) is out of range.\n", callid_len);
299                 return;
300         }
301
302         i = 0;
303         while(i < callid_len)
304         {
305                 UPRINT(buffer+(i*3), " %02x", callid[i]);
306                 i++;
307         }
308                 
309         add_trace("callid", NULL, "%s", buffer[0]?buffer+1:"<none>");
310
311         l = callid_len;
312         p = msg_put(msg, l+2);
313         if (p_m_d_ntmode)
314                 *ntmode = p+1;
315         else
316                 qi->call_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
317         p[0] = IE_CALL_ID;
318         p[1] = l;
319         memcpy(p+2, callid, callid_len);
320 }
321
322 void Pdss1::dec_ie_call_id(unsigned char *p, Q931_info_t *qi, unsigned char *callid, int *callid_len)
323 {
324         char buffer[25];
325         int i;
326
327         *callid_len = -1;
328
329         if (!p_m_d_ntmode)
330         {
331                 p = NULL;
332                 if (qi->call_id.off)
333                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->call_id.off + 1;
334         }
335         if (!p)
336                 return;
337         if (p[0] > 8)
338         {
339                 add_trace("callid", "error", "IE too long (len=%d)", p[0]);
340                 return;
341         }
342
343         *callid_len = p[0];
344         memcpy(callid, p+1, *callid_len);
345
346         i = 0;
347         while(i < *callid_len)
348         {
349                 UPRINT(buffer+(i*3), " %02x", callid[i]);
350                 i++;
351         }
352                 
353         add_trace("callid", NULL, "%s", buffer[0]?buffer+1:"<none>");
354 }
355
356
357 /* IE_CALLED_PN */
358 void Pdss1::enc_ie_called_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, unsigned char *number)
359 {
360         unsigned char *p;
361         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
362         int l;
363
364         if (type<0 || type>7)
365         {
366                 PERROR("type(%d) is out of range.\n", type);
367                 return;
368         }
369         if (plan<0 || plan>15)
370         {
371                 PERROR("plan(%d) is out of range.\n", plan);
372                 return;
373         }
374         if (!number[0])
375         {
376                 PERROR("number is not given.\n");
377                 return;
378         }
379
380         add_trace("called_pn", "type", "%d", type);
381         add_trace("called_pn", "plan", "%d", plan);
382         add_trace("called_pn", "number", "%s", number);
383
384         l = 1+strlen((char *)number);
385         p = msg_put(msg, l+2);
386         if (p_m_d_ntmode)
387                 *ntmode = p+1;
388         else
389                 qi->called_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
390         p[0] = IE_CALLED_PN;
391         p[1] = l;
392         p[2] = 0x80 + (type<<4) + plan;
393         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
394 }
395
396 void Pdss1::dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, unsigned char *number, int number_len)
397 {
398         *type = -1;
399         *plan = -1;
400         *number = '\0';
401
402         if (!p_m_d_ntmode)
403         {
404                 p = NULL;
405                 if (qi->called_nr.off)
406                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->called_nr.off + 1;
407         }
408         if (!p)
409                 return;
410         if (p[0] < 2)
411         {
412                 add_trace("called_pn", "error", "IE too short (len=%d)", p[0]);
413                 return;
414         }
415
416         *type = (p[1]&0x70) >> 4;
417         *plan = p[1] & 0xf;
418         strnncpy(number, p+2, p[0]-1, number_len);
419
420         add_trace("called_pn", "type", "%d", *type);
421         add_trace("called_pn", "plan", "%d", *plan);
422         add_trace("called_pn", "number", "%s", number);
423 }
424
425
426 /* IE_CALLING_PN */
427 void Pdss1::enc_ie_calling_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, unsigned char *number)
428 {
429         unsigned char *p;
430         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
431         int l;
432
433         if (type<0 || type>7)
434         {
435                 PERROR("type(%d) is out of range.\n", type);
436                 return;
437         }
438         if (plan<0 || plan>15)
439         {
440                 PERROR("plan(%d) is out of range.\n", plan);
441                 return;
442         }
443         if (present>3)
444         {
445                 PERROR("present(%d) is out of range.\n", present);
446                 return;
447         }
448         if (present >= 0) if (screen<0 || screen>3)
449         {
450                 PERROR("screen(%d) is out of range.\n", screen);
451                 return;
452         }
453
454         add_trace("calling_pn", "type", "%d", type);
455         add_trace("calling_pn", "plan", "%d", plan);
456         add_trace("calling_pn", "present", "%d", present);
457         add_trace("calling_pn", "screen", "%d", screen);
458         add_trace("calling_pn", "number", "%s", number);
459
460         l = 1;
461         if (number) if (number[0])
462                 l += strlen((char *)number);
463         if (present >= 0)
464                 l += 1;
465         p = msg_put(msg, l+2);
466         if (p_m_d_ntmode)
467                 *ntmode = p+1;
468         else
469                 qi->calling_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
470         p[0] = IE_CALLING_PN;
471         p[1] = l;
472         if (present >= 0)
473         {
474                 p[2] = 0x00 + (type<<4) + plan;
475                 p[3] = 0x80 + (present<<5) + screen;
476                 if (number) if (number[0])
477                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
478         } else
479         {
480                 p[2] = 0x80 + (type<<4) + plan;
481                 if (number) if (number[0])
482                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
483         }
484 }
485
486 void Pdss1::dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len)
487 {
488         *type = -1;
489         *plan = -1;
490         *present = -1;
491         *screen = -1;
492         *number = '\0';
493
494         if (!p_m_d_ntmode)
495         {
496                 p = NULL;
497                 if (qi->calling_nr.off)
498                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->calling_nr.off + 1;
499         }
500         if (!p)
501                 return;
502         if (p[0] < 1)
503         {
504                 add_trace("calling_pn", "error", "IE too short (len=%d)", p[0]);
505                 return;
506         }
507
508         *type = (p[1]&0x70) >> 4;
509         *plan = p[1] & 0xf;
510         if (!(p[1] & 0x80))
511         {
512                 if (p[0] < 2)
513                 {
514                         add_trace("calling_pn", "error", "IE too short (len=%d)", p[0]);
515                         return;
516                 }
517                 *present = (p[2]&0x60) >> 5;
518                 *screen = p[2] & 0x3;
519                 strnncpy(number, p+3, p[0]-2, number_len);
520         } else
521         {
522                 strnncpy(number, p+2, p[0]-1, number_len);
523         }
524
525         add_trace("calling_pn", "type", "%d", *type);
526         add_trace("calling_pn", "plan", "%d", *plan);
527         add_trace("calling_pn", "present", "%d", *present);
528         add_trace("calling_pn", "screen", "%d", *screen);
529         add_trace("calling_pn", "number", "%s", number);
530 }
531
532
533 /* IE_CONNECTED_PN */
534 void Pdss1::enc_ie_connected_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, unsigned char *number)
535 {
536         unsigned char *p;
537         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
538         int l;
539
540         if (type<0 || type>7)
541         {
542                 PERROR("type(%d) is out of range.\n", type);
543                 return;
544         }
545         if (plan<0 || plan>15)
546         {
547                 PERROR("plan(%d) is out of range.\n", plan);
548                 return;
549         }
550         if (present>3)
551         {
552                 PERROR("present(%d) is out of range.\n", present);
553                 return;
554         }
555         if (present >= 0) if (screen<0 || screen>3)
556         {
557                 PERROR("screen(%d) is out of range.\n", screen);
558                 return;
559         }
560
561         add_trace("connect_pn", "type", "%d", type);
562         add_trace("connect_pn", "plan", "%d", plan);
563         add_trace("connect_pn", "present", "%d", present);
564         add_trace("connect_pn", "screen", "%d", screen);
565         add_trace("connect_pn", "number", "%s", number);
566
567         l = 1;
568         if (number) if (number[0])
569                 l += strlen((char *)number);
570         if (present >= 0)
571                 l += 1;
572         p = msg_put(msg, l+2);
573         if (p_m_d_ntmode)
574                 *ntmode = p+1;
575         else
576                 qi->connected_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
577         p[0] = IE_CONNECT_PN;
578         p[1] = l;
579         if (present >= 0)
580         {
581                 p[2] = 0x00 + (type<<4) + plan;
582                 p[3] = 0x80 + (present<<5) + screen;
583                 if (number) if (number[0])
584                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
585         } else
586         {
587                 p[2] = 0x80 + (type<<4) + plan;
588                 if (number) if (number[0])
589                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
590         }
591 }
592
593 void Pdss1::dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len)
594 {
595         *type = -1;
596         *plan = -1;
597         *present = -1;
598         *screen = -1;
599         *number = '\0';
600
601         if (!p_m_d_ntmode)
602         {
603                 p = NULL;
604                 if (qi->connected_nr.off)
605                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->connected_nr.off + 1;
606         }
607         if (!p)
608                 return;
609         if (p[0] < 1)
610         {
611                 add_trace("connect_pn", "error", "IE too short (len=%d)", p[0]);
612                 return;
613         }
614
615         *type = (p[1]&0x70) >> 4;
616         *plan = p[1] & 0xf;
617         if (!(p[1] & 0x80))
618         {
619                 if (p[0] < 2)
620                 {
621                         add_trace("connect_pn", "error", "IE too short (len=%d)", p[0]);
622                         return;
623                 }
624                 *present = (p[2]&0x60) >> 5;
625                 *screen = p[2] & 0x3;
626                 strnncpy(number, p+3, p[0]-2, number_len);
627         } else
628         {
629                 strnncpy(number, p+2, p[0]-1, number_len);
630         }
631
632         add_trace("connect_pn", "type", "%d", *type);
633         add_trace("connect_pn", "plan", "%d", *plan);
634         add_trace("connect_pn", "present", "%d", *present);
635         add_trace("connect_pn", "screen", "%d", *screen);
636         add_trace("connect_pn", "number", "%s", number);
637 }
638
639
640 /* IE_CAUSE */
641 void Pdss1::enc_ie_cause(unsigned char **ntmode, msg_t *msg, int location, int cause)
642 {
643         unsigned char *p;
644         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
645         int l;
646
647         if (location<0 || location>7)
648         {
649                 PERROR("location(%d) is out of range.\n", location);
650                 return;
651         }
652         if (cause<0 || cause>127)
653         {
654                 PERROR("cause(%d) is out of range.\n", cause);
655                 return;
656         }
657
658         add_trace("cause", "location", "%d", location);
659         add_trace("cause", "value", "%d", cause);
660
661         l = 2;
662         p = msg_put(msg, l+2);
663         if (p_m_d_ntmode)
664                 *ntmode = p+1;
665         else
666                 qi->cause.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
667         p[0] = IE_CAUSE;
668         p[1] = l;
669         p[2] = 0x80 + location;
670         p[3] = 0x80 + cause;
671 }
672 void enc_ie_cause_standalone(unsigned char **ntmode, msg_t *msg, int location, int cause)
673 {
674         unsigned char *p = msg_put(msg, 4);
675         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
676         if (ntmode)
677                 *ntmode = p+1;
678         else
679                 qi->cause.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
680         p[0] = IE_CAUSE;
681         p[1] = 2;
682         p[2] = 0x80 + location;
683         p[3] = 0x80 + cause;
684 }
685
686
687 void Pdss1::dec_ie_cause(unsigned char *p, Q931_info_t *qi, int *location, int *cause)
688 {
689         *location = -1;
690         *cause = -1;
691
692         if (!p_m_d_ntmode)
693         {
694                 p = NULL;
695                 if (qi->cause.off)
696                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->cause.off + 1;
697         }
698         if (!p)
699                 return;
700         if (p[0] < 2)
701         {
702                 add_trace("cause", "error", "IE too short (len=%d)", p[0]);
703                 return;
704         }
705
706         *location = p[1] & 0x0f;
707         *cause = p[2] & 0x7f;
708
709         add_trace("cause", "location", "%d", *location);
710         add_trace("cause", "value", "%d", *cause);
711 }
712
713
714 /* IE_CHANNEL_ID */
715 void Pdss1::enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int channel)
716 {
717         unsigned char *p;
718         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
719         int l;
720         int pri = p_m_mISDNport->pri;
721
722         if (exclusive<0 || exclusive>1)
723         {
724                 PERROR("exclusive(%d) is out of range.\n", exclusive);
725                 return;
726         }
727         if ((channel<=0 && channel!=CHANNEL_NO && channel!=CHANNEL_ANY)
728          || (!pri && channel>2)
729          || (pri && channel>127)
730          || (pri && channel==16))
731         {
732                 PERROR("channel(%d) is out of range.\n", channel);
733                 return;
734         }
735
736         add_trace("channel_id", "exclusive", "%d", exclusive);
737         switch(channel)
738         {
739                 case CHANNEL_ANY:
740                 add_trace("channel_id", "channel", "any channel");
741                 break;
742                 case CHANNEL_NO:
743                 add_trace("channel_id", "channel", "no channel");
744                 break;
745                 default:
746                 add_trace("channel_id", "channel", "%d", channel);
747         }
748
749         if (!pri)
750         {
751                 /* BRI */
752                 l = 1;
753                 p = msg_put(msg, l+2);
754                 if (p_m_d_ntmode)
755                         *ntmode = p+1;
756                 else
757                         qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
758                 p[0] = IE_CHANNEL_ID;
759                 p[1] = l;
760                 if (channel == CHANNEL_NO)
761                         channel = 0;
762                 else if (channel == CHANNEL_ANY)
763                         channel = 3;
764                 p[2] = 0x80 + (exclusive<<3) + channel;
765         } else
766         {
767                 /* PRI */
768                 if (channel == CHANNEL_NO) /* no channel */
769                         return; /* IE not present */
770                 if (channel == CHANNEL_ANY) /* any channel */
771                 {
772                         l = 1;
773                         p = msg_put(msg, l+2);
774                         if (p_m_d_ntmode)
775                                 *ntmode = p+1;
776                         else
777                                 qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
778                         p[0] = IE_CHANNEL_ID;
779                         p[1] = l;
780                         p[2] = 0x80 + 0x20 + 0x03;
781                         return; /* end */
782                 }
783                 l = 3;
784                 p = msg_put(msg, l+2);
785                 if (p_m_d_ntmode)
786                         *ntmode = p+1;
787                 else
788                         qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
789                 p[0] = IE_CHANNEL_ID;
790                 p[1] = l;
791                 p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
792                 p[3] = 0x80 + 3; /* CCITT, Number, B-type */
793                 p[4] = 0x80 + channel;
794         }
795 }
796
797 void Pdss1::dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive, int *channel)
798 {
799         int pri = p_m_mISDNport->pri;
800
801         *exclusive = -1;
802         *channel = -1;
803
804         if (!p_m_d_ntmode)
805         {
806                 p = NULL;
807                 if (qi->channel_id.off)
808                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->channel_id.off + 1;
809         }
810         if (!p)
811                 return;
812         if (p[0] < 1)
813         {
814                 add_trace("channel_id", "error", "IE too short (len=%d)", p[0]);
815                 return;
816         }
817
818         if (p[1] & 0x40)
819         {
820                 add_trace("channel_id", "error", "refering to channels of other interfaces is not supported");
821                 return;
822         }
823         if (p[1] & 0x04)
824         {
825                 add_trace("channel_id", "error", "using d-channel is not supported");
826                 return;
827         }
828
829         *exclusive = (p[1]&0x08) >> 3;
830         if (!pri)
831         {
832                 /* BRI */
833                 if (p[1] & 0x20)
834                 {
835                         add_trace("channel_id", "error", "extended channel ID with non PRI interface");
836                         return;
837                 }
838                 *channel = p[1] & 0x03;
839                 if (*channel == 3)
840                         *channel = CHANNEL_ANY;
841                 else if (*channel == 0)
842                         *channel = CHANNEL_NO;
843         } else
844         {
845                 /* PRI */
846                 if (p[0] < 1)
847                 {
848
849                         add_trace("channel_id", "error", "IE too short for PRI (len=%d)", p[0]);
850                         return;
851                 }
852                 if (!(p[1] & 0x20))
853                 {
854                         add_trace("channel_id", "error", "basic channel ID with PRI interface");
855                         return;
856                 }
857                 if ((p[1]&0x03) == 0x00)
858                 {
859                         /* no channel */
860                         *channel = CHANNEL_NO;
861                         return;
862                 }
863                 if ((p[1]&0x03) == 0x03)
864                 {
865                         /* any channel */
866                         *channel = CHANNEL_ANY;
867                         return;
868                 }
869                 if (p[0] < 3)
870                 {
871                         add_trace("channel_id", "error", "IE too short for PRI with channel (len=%d)", p[0]);
872                         return;
873                 }
874                 if (p[2] & 0x10)
875                 {
876                         add_trace("channel_id", "error", "channel map not supported");
877                         return;
878                 }
879                 *channel = p[3] & 0x7f;
880                 if (*channel<1 | *channel==16)
881                 {
882                         add_trace("channel_id", "error", "PRI interface channel out of range (%d)", *channel);
883                         return;
884                 }
885         }
886
887         add_trace("channel_id", "exclusive", "%d", *exclusive);
888         switch(*channel)
889         {
890                 case CHANNEL_ANY:
891                 add_trace("channel_id", "channel", "any channel");
892                 break;
893                 case CHANNEL_NO:
894                 add_trace("channel_id", "channel", "no channel");
895                 break;
896                 default:
897                 add_trace("channel_id", "channel", "%d", *channel);
898         }
899 }
900
901
902 /* IE_DATE */
903 void Pdss1::enc_ie_date(unsigned char **ntmode, msg_t *msg, time_t ti, int no_seconds)
904 {
905         unsigned char *p;
906         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
907         int l;
908
909         struct tm *tm;
910
911         tm = localtime(&ti);
912         if (!tm)
913         {
914                 PERROR("localtime() returned NULL.\n");
915                 return;
916         }
917
918         add_trace("date", "day", "%d.%d.%d", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100);
919         add_trace("date", "time", "%d:%d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec);
920
921         l = 5 + (!no_seconds);
922         p = msg_put(msg, l+2);
923         if (p_m_d_ntmode)
924                 *ntmode = p+1;
925         else
926                 qi->date.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
927         p[0] = IE_DATE;
928         p[1] = l;
929         p[2] = tm->tm_year % 100;
930         p[3] = tm->tm_mon + 1;
931         p[4] = tm->tm_mday;
932         p[5] = tm->tm_hour;
933         p[6] = tm->tm_min;
934         if (!no_seconds)
935                 p[7] = tm->tm_sec;
936 }
937
938
939 /* IE_DISPLAY */
940 void Pdss1::enc_ie_display(unsigned char **ntmode, msg_t *msg, unsigned char *display)
941 {
942         unsigned char *p;
943         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
944         int l;
945
946         if (!display[0])
947         {
948                 PERROR("display text not given.\n");
949                 return;
950         }
951
952         if (strlen((char *)display) > 80)
953         {
954                 PERROR("display text too long (max 80 chars), cutting.\n");
955                 display[80] = '\0';
956         }
957
958         add_trace("display", NULL, "%s", display);
959
960         l = strlen((char *)display);
961         p = msg_put(msg, l+2);
962         if (p_m_d_ntmode)
963                 *ntmode = p+1;
964         else
965                 qi->display.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
966         p[0] = IE_DISPLAY;
967         p[1] = l;
968         UNCPY((char *)p+2, (char *)display, strlen((char *)display));
969 }
970
971 void Pdss1::dec_ie_display(unsigned char *p, Q931_info_t *qi, unsigned char *display, int display_len)
972 {
973         *display = '\0';
974
975         if (!p_m_d_ntmode)
976         {
977                 p = NULL;
978                 if (qi->display.off)
979                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->display.off + 1;
980         }
981         if (!p)
982                 return;
983         if (p[0] < 1)
984         {
985                 add_trace("display", "error", "IE too short (len=%d)", p[0]);
986                 return;
987         }
988
989         strnncpy(display, p+1, p[0], display_len);
990
991         add_trace("display", NULL, "%s", display);
992 }
993
994
995 /* IE_KEYPAD */
996 void Pdss1::enc_ie_keypad(unsigned char **ntmode, msg_t *msg, unsigned char *keypad)
997 {
998         unsigned char *p;
999         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1000         int l;
1001
1002         if (!keypad[0])
1003         {
1004                 PERROR("keypad info not given.\n");
1005                 return;
1006         }
1007
1008         add_trace("keypad", NULL, "%s", keypad);
1009
1010         l = strlen((char *)keypad);
1011         p = msg_put(msg, l+2);
1012         if (p_m_d_ntmode)
1013                 *ntmode = p+1;
1014         else
1015                 qi->keypad.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1016         p[0] = IE_KEYPAD;
1017         p[1] = l;
1018         UNCPY((char *)p+2, (char *)keypad, strlen((char *)keypad));
1019 }
1020
1021 void Pdss1::dec_ie_keypad(unsigned char *p, Q931_info_t *qi, unsigned char *keypad, int keypad_len)
1022 {
1023         *keypad = '\0';
1024
1025         if (!p_m_d_ntmode)
1026         {
1027                 p = NULL;
1028                 if (qi->keypad.off)
1029                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->keypad.off + 1;
1030         }
1031         if (!p)
1032                 return;
1033         if (p[0] < 1)
1034         {
1035                 add_trace("keypad", "error", "IE too short (len=%d)", p[0]);
1036                 return;
1037         }
1038
1039         strnncpy(keypad, p+1, p[0], keypad_len);
1040
1041         add_trace("keypad", NULL, "%s", keypad);
1042 }
1043
1044
1045 /* IE_NOTIFY */
1046 void Pdss1::enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify)
1047 {
1048         unsigned char *p;
1049         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1050         int l;
1051
1052         if (notify<0 || notify>0x7f)
1053         {
1054                 PERROR("notify(%d) is out of range.\n", notify);
1055                 return;
1056         }
1057
1058         add_trace("notify", NULL, "%d", notify);
1059
1060         l = 1;
1061         p = msg_put(msg, l+2);
1062         if (p_m_d_ntmode)
1063                 *ntmode = p+1;
1064         else
1065                 qi->notify.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1066         p[0] = IE_NOTIFY;
1067         p[1] = l;
1068         p[2] = 0x80 + notify;
1069 }
1070
1071 void Pdss1::dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify)
1072 {
1073         *notify = -1;
1074
1075         if (!p_m_d_ntmode)
1076         {
1077                 p = NULL;
1078                 if (qi->notify.off)
1079                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->notify.off + 1;
1080         }
1081         if (!p)
1082                 return;
1083         if (p[0] < 1)
1084         {
1085                 add_trace("notify", "error", "IE too short (len=%d)", p[0]);
1086                 return;
1087         }
1088
1089         *notify = p[1] & 0x7f;
1090
1091         add_trace("notify", NULL, "%d", *notify);
1092 }
1093
1094
1095 /* IE_PROGRESS */
1096 void Pdss1::enc_ie_progress(unsigned char **ntmode, msg_t *msg, int coding, int location, int progress)
1097 {
1098         unsigned char *p;
1099         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1100         int l;
1101
1102         if (coding<0 || coding>0x03)
1103         {
1104                 PERROR("coding(%d) is out of range.\n", coding);
1105                 return;
1106         }
1107         if (location<0 || location>0x0f)
1108         {
1109                 PERROR("location(%d) is out of range.\n", location);
1110                 return;
1111         }
1112         if (progress<0 || progress>0x7f)
1113         {
1114                 PERROR("progress(%d) is out of range.\n", progress);
1115                 return;
1116         }
1117
1118         add_trace("progress", "codeing", "%d", coding);
1119         add_trace("progress", "location", "%d", location);
1120         add_trace("progress", "indicator", "%d", progress);
1121
1122         l = 2;
1123         p = msg_put(msg, l+2);
1124         if (p_m_d_ntmode)
1125                 *ntmode = p+1;
1126         else
1127                 qi->progress.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1128         p[0] = IE_PROGRESS;
1129         p[1] = l;
1130         p[2] = 0x80 + (coding<<5) + location;
1131         p[3] = 0x80 + progress;
1132 }
1133
1134 void Pdss1::dec_ie_progress(unsigned char *p, Q931_info_t *qi, int *coding, int *location, int *progress)
1135 {
1136         *coding = -1;
1137         *location = -1;
1138         *progress = -1;
1139
1140         if (!p_m_d_ntmode)
1141         {
1142                 p = NULL;
1143                 if (qi->progress.off)
1144                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->progress.off + 1;
1145         }
1146         if (!p)
1147                 return;
1148         if (p[0] < 1)
1149         {
1150                 add_trace("progress", "error", "IE too short (len=%d)", p[0]);
1151                 return;
1152         }
1153
1154         *coding = (p[1]&0x60) >> 5;
1155         *location = p[1] & 0x0f;
1156         *progress = p[2] & 0x7f;
1157
1158         add_trace("progress", "codeing", "%d", *coding);
1159         add_trace("progress", "location", "%d", *location);
1160         add_trace("progress", "indicator", "%d", *progress);
1161 }
1162
1163
1164 /* IE_REDIR_NR (redirecting = during MT_SETUP) */
1165 void Pdss1::enc_ie_redir_nr(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, int reason, unsigned char *number)
1166 {
1167         unsigned char *p;
1168         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1169         int l;
1170
1171         if (type<0 || type>7)
1172         {
1173                 PERROR("type(%d) is out of range.\n", type);
1174                 return;
1175         }
1176         if (plan<0 || plan>15)
1177         {
1178                 PERROR("plan(%d) is out of range.\n", plan);
1179                 return;
1180         }
1181         if (present > 3)
1182         {
1183                 PERROR("present(%d) is out of range.\n", present);
1184                 return;
1185         }
1186         if (present >= 0) if (screen<0 || screen>3)
1187         {
1188                 PERROR("screen(%d) is out of range.\n", screen);
1189                 return;
1190         }
1191         if (reason > 0x0f)
1192         {
1193                 PERROR("reason(%d) is out of range.\n", reason);
1194                 return;
1195         }
1196
1197         add_trace("redir'ing", "type", "%d", type);
1198         add_trace("redir'ing", "plan", "%d", plan);
1199         add_trace("redir'ing", "present", "%d", present);
1200         add_trace("redir'ing", "screen", "%d", screen);
1201         add_trace("redir'ing", "reason", "%d", reason);
1202         add_trace("redir'ing", "number", "%s", number);
1203
1204         l = 1;
1205         if (number)
1206                 l += strlen((char *)number);
1207         if (present >= 0)
1208         {
1209                 l += 1;
1210                 if (reason >= 0)
1211                         l += 1;
1212         }
1213         p = msg_put(msg, l+2);
1214         if (p_m_d_ntmode)
1215                 *ntmode = p+1;
1216         else
1217                 qi->redirect_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1218         p[0] = IE_REDIR_NR;
1219         p[1] = l;
1220         if (present >= 0)
1221         {
1222                 if (reason >= 0)
1223                 {
1224                         p[2] = 0x00 + (type<<4) + plan;
1225                         p[3] = 0x00 + (present<<5) + screen;
1226                         p[4] = 0x80 + reason;
1227                         if (number)
1228                                 UNCPY((char *)p+5, (char *)number, strlen((char *)number));
1229                 } else
1230                 {
1231                         p[2] = 0x00 + (type<<4) + plan;
1232                         p[3] = 0x80 + (present<<5) + screen;
1233                         if (number)
1234                                 UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1235                 }
1236         } else
1237         {
1238                 p[2] = 0x80 + (type<<4) + plan;
1239                 if (number) if (number[0])
1240                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1241         }
1242 }
1243
1244 void Pdss1::dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, int *reason, unsigned char *number, int number_len)
1245 {
1246         *type = -1;
1247         *plan = -1;
1248         *present = -1;
1249         *screen = -1;
1250         *reason = -1;
1251         *number = '\0';
1252
1253         if (!p_m_d_ntmode)
1254         {
1255                 p = NULL;
1256                 if (qi->redirect_nr.off)
1257                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_nr.off + 1;
1258         }
1259         if (!p)
1260                 return;
1261         if (p[0] < 1)
1262         {
1263                 add_trace("redir'ing", "error", "IE too short (len=%d)", p[0]);
1264                 return;
1265         }
1266
1267         *type = (p[1]&0x70) >> 4;
1268         *plan = p[1] & 0xf;
1269         if (!(p[1] & 0x80))
1270         {
1271                 *present = (p[2]&0x60) >> 5;
1272                 *screen = p[2] & 0x3;
1273                 if (!(p[2] & 0x80))
1274                 {
1275                         *reason = p[3] & 0x0f;
1276                         strnncpy(number, p+4, p[0]-3, number_len);
1277                 } else
1278                 {
1279                         strnncpy(number, p+3, p[0]-2, number_len);
1280                 }
1281         } else
1282         {
1283                 strnncpy(number, p+2, p[0]-1, number_len);
1284         }
1285
1286         add_trace("redir'ing", "type", "%d", *type);
1287         add_trace("redir'ing", "plan", "%d", *plan);
1288         add_trace("redir'ing", "present", "%d", *present);
1289         add_trace("redir'ing", "screen", "%d", *screen);
1290         add_trace("redir'ing", "reason", "%d", *reason);
1291         add_trace("redir'ing", "number", "%s", number);
1292 }
1293
1294
1295 /* IE_REDIR_DN (redirection = during MT_NOTIFY) */
1296 void Pdss1::enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, unsigned char *number)
1297 {
1298         unsigned char *p;
1299         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1300         int l;
1301
1302         if (type<0 || type>7)
1303         {
1304                 PERROR("type(%d) is out of range.\n", type);
1305                 return;
1306         }
1307         if (plan<0 || plan>15)
1308         {
1309                 PERROR("plan(%d) is out of range.\n", plan);
1310                 return;
1311         }
1312         if (present > 3)
1313         {
1314                 PERROR("present(%d) is out of range.\n", present);
1315                 return;
1316         }
1317
1318         add_trace("redir'tion", "type", "%d", type);
1319         add_trace("redir'tion", "plan", "%d", plan);
1320         add_trace("redir'tion", "present", "%d", present);
1321         add_trace("redir'tion", "number", "%s", number);
1322
1323         l = 1;
1324         if (number)
1325                 l += strlen((char *)number);
1326         if (present >= 0)
1327                 l += 1;
1328         p = msg_put(msg, l+2);
1329         if (p_m_d_ntmode)
1330                 *ntmode = p+1;
1331         else
1332                 qi->redirect_dn.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1333         p[0] = IE_REDIR_DN;
1334         p[1] = l;
1335         if (present >= 0)
1336         {
1337                 p[2] = 0x00 + (type<<4) + plan;
1338                 p[3] = 0x80 + (present<<5);
1339                 if (number)
1340                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1341         } else
1342         {
1343                 p[2] = 0x80 + (type<<4) + plan;
1344                 if (number)
1345                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1346         }
1347 }
1348
1349 void Pdss1::dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, unsigned char *number, int number_len)
1350 {
1351         *type = -1;
1352         *plan = -1;
1353         *present = -1;
1354         *number = '\0';
1355
1356         if (!p_m_d_ntmode)
1357         {
1358                 p = NULL;
1359                 if (qi->redirect_dn.off)
1360                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_dn.off + 1;
1361         }
1362         if (!p)
1363                 return;
1364         if (p[0] < 1)
1365         {
1366                 add_trace("redir'tion", "error", "IE too short (len=%d)", p[0]);
1367                 return;
1368         }
1369
1370         *type = (p[1]&0x70) >> 4;
1371         *plan = p[1] & 0xf;
1372         if (!(p[1] & 0x80))
1373         {
1374                 *present = (p[2]&0x60) >> 5;
1375                 strnncpy(number, p+3, p[0]-2, number_len);
1376         } else
1377         {
1378                 strnncpy(number, p+2, p[0]-1, number_len);
1379         }
1380
1381         add_trace("redir'tion", "type", "%d", *type);
1382         add_trace("redir'tion", "plan", "%d", *plan);
1383         add_trace("redir'tion", "present", "%d", *present);
1384         add_trace("redir'tion", "number", "%s", number);
1385 }
1386
1387
1388 /* IE_FACILITY */
1389 void Pdss1::enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len)
1390 {
1391         unsigned char *p;
1392         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1393         int l;
1394
1395         char buffer[768];
1396         int i;
1397
1398         if (!facility || facility_len<=0)
1399         {
1400                 return;
1401         }
1402
1403         i = 0;
1404         while(i < facility_len)
1405         {
1406                 UPRINT(buffer+(i*3), " %02x", facility[i]);
1407                 i++;
1408         }
1409                 
1410         add_trace("facility", NULL, "%s", buffer+1);
1411
1412         l = facility_len;
1413         p = msg_put(msg, l+2);
1414         if (p_m_d_ntmode)
1415                 *ntmode = p+1;
1416         else
1417                 qi->facility.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1418         p[0] = IE_FACILITY;
1419         p[1] = l;
1420         memcpy(p+2, facility, facility_len);
1421 }
1422
1423 void Pdss1::dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *facility, int *facility_len)
1424 {
1425         char debug[768];
1426         int i;
1427
1428         *facility_len = 0;
1429
1430         if (!p_m_d_ntmode)
1431         {
1432                 p = NULL;
1433                 if (qi->facility.off)
1434                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->facility.off + 1;
1435         }
1436         if (!p)
1437                 return;
1438
1439         *facility_len = p[0];
1440         memcpy(facility, p+1, *facility_len);
1441
1442         i = 0;
1443         while(i < *facility_len)
1444         {
1445                 UPRINT(debug+(i*3), " %02x", facility[i]);
1446                 i++;
1447         }
1448         debug[i*3] = '\0';
1449                 
1450         add_trace("facility", NULL, "%s", debug[0]?debug+1:"<none>");
1451 }
1452
1453
1454 void Pdss1::dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len)
1455 {
1456         unsigned char centrex[256];
1457         char debug[768];
1458         int facility_len = 0;
1459         int i = 0, j;
1460         *cnip = '\0';
1461
1462         dec_ie_facility(p, qi, centrex, &facility_len);
1463         if (facility_len >= 2)
1464         {
1465                 if (centrex[i++] != CENTREX_FAC)
1466                         return;
1467                 if (centrex[i++] != CENTREX_ID)
1468                         return;
1469         }
1470
1471         /* loop sub IEs of facility */
1472         while(facility_len > i+1)
1473         {
1474                 if (centrex[i+1]+i+1 > facility_len)
1475                 {
1476                         PERROR("short read of centrex facility.\n");
1477                         return;
1478                 }
1479                 switch(centrex[i])
1480                 {
1481                         case 0x80:
1482                         strnncpy(cnip, &centrex[i+2], centrex[i+1], cnip_len);
1483                         add_trace("facility", "cnip", "%s", cnip);
1484                         break;
1485
1486                         default:
1487                         j = 0;
1488                         while(j < centrex[i+1])
1489                         {
1490                                 UPRINT(debug+(j*3), " %02x", centrex[i+1+j]);
1491                                 i++;
1492                         }
1493                         add_trace("facility", "CENTREX", "unknown=0x%02x len=%d%s\n", centrex[i], centrex[i+1], debug);
1494                 }
1495                 i += 1+centrex[i+1];
1496         }
1497 }
1498
1499
1500 /* IE_USERUSER */
1501 void Pdss1::enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned char *user, int user_len)
1502 {
1503         unsigned char *p;
1504         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1505         int l;
1506
1507         char buffer[768];
1508         int i;
1509
1510         if (protocol<0 || protocol>127)
1511         {
1512                 PERROR("protocol(%d) is out of range.\n", protocol);
1513                 return;
1514         }
1515         if (!user || user_len<=0)
1516         {
1517                 return;
1518         }
1519
1520         i = 0;
1521         while(i < user_len)
1522         {
1523                 UPRINT(buffer+(i*3), " %02x", user[i]);
1524                 i++;
1525         }
1526                 
1527         add_trace("useruser", "protocol", "%d", protocol);
1528         add_trace("useruser", "value", "%s", buffer);
1529
1530         l = user_len;
1531         p = msg_put(msg, l+3);
1532         if (p_m_d_ntmode)
1533                 *ntmode = p+1;
1534         else
1535                 qi->useruser.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1536         p[0] = IE_USER_USER;
1537         p[1] = l;
1538         p[2] = 0x80 + protocol;
1539         memcpy(p+3, user, user_len);
1540 }
1541
1542 void Pdss1::dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned char *user, int *user_len)
1543 {
1544         char buffer[768];
1545         int i;
1546
1547         *user_len = 0;
1548         *protocol = -1;
1549
1550         if (!p_m_d_ntmode)
1551         {
1552                 p = NULL;
1553                 if (qi->useruser.off)
1554                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->useruser.off + 1;
1555         }
1556         if (!p)
1557                 return;
1558
1559         *user_len = p[0]-1;
1560         if (p[0] < 1)
1561                 return;
1562         *protocol = p[1];
1563         memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
1564
1565         i = 0;
1566         while(i < *user_len)
1567         {
1568                 UPRINT(buffer+(i*3), " %02x", user[i]);
1569                 i++;
1570         }
1571         buffer[i*3] = '\0';
1572                 
1573         add_trace("useruser", "protocol", "%d", *protocol);
1574         add_trace("useruser", "value", "%s", buffer);
1575 }
1576
1577