75b86f4ac01eed0b66f0d9f52b0d5f66711e8644
[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                 PERROR("IE too short (%d).\n", 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                 PERROR("IE too short (%d).\n", 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                 PERROR("IE too long (%d).\n", 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                 PERROR("IE too short (%d).\n", 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                 PERROR("IE too short (%d).\n", 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                         PERROR("IE too short (%d).\n", 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                 PERROR("IE too short (%d).\n", 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                         PERROR("IE too short (%d).\n", 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                 PERROR("IE too short (%d).\n", 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         add_trace("channel_id", "channel", "%d", channel);
738
739         if (!pri)
740         {
741                 /* BRI */
742                 l = 1;
743                 p = msg_put(msg, l+2);
744                 if (p_m_d_ntmode)
745                         *ntmode = p+1;
746                 else
747                         qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
748                 p[0] = IE_CHANNEL_ID;
749                 p[1] = l;
750                 if (channel == CHANNEL_NO)
751                         channel = 0;
752                 else if (channel == CHANNEL_ANY)
753                         channel = 3;
754                 p[2] = 0x80 + (exclusive<<3) + channel;
755         } else
756         {
757                 /* PRI */
758                 if (channel == CHANNEL_NO) /* no channel */
759                         return; /* IE not present */
760                 if (channel == CHANNEL_ANY) /* any channel */
761                 {
762                         l = 1;
763                         p = msg_put(msg, l+2);
764                         if (p_m_d_ntmode)
765                                 *ntmode = p+1;
766                         else
767                                 qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
768                         p[0] = IE_CHANNEL_ID;
769                         p[1] = l;
770                         p[2] = 0x80 + 0x20 + 0x03;
771                         return; /* end */
772                 }
773                 l = 3;
774                 p = msg_put(msg, l+2);
775                 if (p_m_d_ntmode)
776                         *ntmode = p+1;
777                 else
778                         qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
779                 p[0] = IE_CHANNEL_ID;
780                 p[1] = l;
781                 p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
782                 p[3] = 0x80 + 3; /* CCITT, Number, B-type */
783                 p[4] = 0x80 + channel;
784         }
785 }
786
787 void Pdss1::dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive, int *channel)
788 {
789         int pri = p_m_mISDNport->pri;
790
791         *exclusive = -1;
792         *channel = -1;
793
794         if (!p_m_d_ntmode)
795         {
796                 p = NULL;
797                 if (qi->channel_id.off)
798                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->channel_id.off + 1;
799         }
800         if (!p)
801                 return;
802         if (p[0] < 1)
803         {
804                 PERROR("IE too short (%d).\n", p[0]);
805                 return;
806         }
807
808         if (p[1] & 0x40)
809         {
810                 PERROR("refering to channels of other interfaces is not supported.\n");
811                 return;
812         }
813         if (p[1] & 0x04)
814         {
815                 PERROR("using d-channel is not supported.\n");
816                 return;
817         }
818
819         *exclusive = (p[1]&0x08) >> 3;
820         if (!pri)
821         {
822                 /* BRI */
823                 if (p[1] & 0x20)
824                 {
825                         PERROR("extended channel ID with non PRI interface.\n");
826                         return;
827                 }
828                 *channel = p[1] & 0x03;
829                 if (*channel == 3)
830                         *channel = CHANNEL_ANY;
831                 else if (*channel == 0)
832                         *channel = CHANNEL_NO;
833         } else
834         {
835                 /* PRI */
836                 if (p[0] < 1)
837                 {
838                         PERROR("IE too short for PRI (%d).\n", p[0]);
839                         return;
840                 }
841                 if (!(p[1] & 0x20))
842                 {
843                         PERROR("basic channel ID with PRI interface.\n");
844                         return;
845                 }
846                 if ((p[1]&0x03) == 0x00)
847                 {
848                         /* no channel */
849                         *channel = CHANNEL_NO;
850                         return;
851                 }
852                 if ((p[1]&0x03) == 0x03)
853                 {
854                         /* any channel */
855                         *channel = CHANNEL_ANY;
856                         return;
857                 }
858                 if (p[0] < 3)
859                 {
860                         PERROR("%s: ERROR: IE too short for PRI with channel(%d).\n", __FUNCTION__, p[0]);
861                         return;
862                 }
863                 if (p[2] & 0x10)
864                 {
865                         PERROR("channel map not supported.\n");
866                         return;
867                 }
868                 *channel = p[3] & 0x7f;
869                 if (*channel<1 | *channel==16)
870                 {
871                         PERROR("PRI interface channel out of range (%d).\n", *channel);
872                         return;
873                 }
874         }
875
876         add_trace("channel_id", "exclusive", "%d", *exclusive);
877         add_trace("channel_id", "channel", "%d", *channel);
878 }
879
880
881 /* IE_DATE */
882 void Pdss1::enc_ie_date(unsigned char **ntmode, msg_t *msg, time_t ti, int no_seconds)
883 {
884         unsigned char *p;
885         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
886         int l;
887
888         struct tm *tm;
889
890         tm = localtime(&ti);
891         if (!tm)
892         {
893                 PERROR("localtime() returned NULL.\n");
894                 return;
895         }
896
897         add_trace("date", "day", "%d.%d.%d", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100);
898         add_trace("date", "time", "%d:%d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec);
899
900         l = 5 + (!no_seconds);
901         p = msg_put(msg, l+2);
902         if (p_m_d_ntmode)
903                 *ntmode = p+1;
904         else
905                 qi->date.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
906         p[0] = IE_DATE;
907         p[1] = l;
908         p[2] = tm->tm_year % 100;
909         p[3] = tm->tm_mon + 1;
910         p[4] = tm->tm_mday;
911         p[5] = tm->tm_hour;
912         p[6] = tm->tm_min;
913         if (!no_seconds)
914                 p[7] = tm->tm_sec;
915 }
916
917
918 /* IE_DISPLAY */
919 void Pdss1::enc_ie_display(unsigned char **ntmode, msg_t *msg, unsigned char *display)
920 {
921         unsigned char *p;
922         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
923         int l;
924
925         if (!display[0])
926         {
927                 PERROR("display text not given.\n");
928                 return;
929         }
930
931         if (strlen((char *)display) > 80)
932         {
933                 PERROR("display text too long (max 80 chars), cutting.\n");
934                 display[80] = '\0';
935         }
936
937         add_trace("display", NULL, "%s", display);
938
939         l = strlen((char *)display);
940         p = msg_put(msg, l+2);
941         if (p_m_d_ntmode)
942                 *ntmode = p+1;
943         else
944                 qi->display.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
945         p[0] = IE_DISPLAY;
946         p[1] = l;
947         UNCPY((char *)p+2, (char *)display, strlen((char *)display));
948 }
949
950 void Pdss1::dec_ie_display(unsigned char *p, Q931_info_t *qi, unsigned char *display, int display_len)
951 {
952         *display = '\0';
953
954         if (!p_m_d_ntmode)
955         {
956                 p = NULL;
957                 if (qi->display.off)
958                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->display.off + 1;
959         }
960         if (!p)
961                 return;
962         if (p[0] < 1)
963         {
964                 PERROR("IE too short (%d).\n", p[0]);
965                 return;
966         }
967
968         strnncpy(display, p+1, p[0], display_len);
969
970         add_trace("display", NULL, "%s", display);
971 }
972
973
974 /* IE_KEYPAD */
975 void Pdss1::enc_ie_keypad(unsigned char **ntmode, msg_t *msg, unsigned char *keypad)
976 {
977         unsigned char *p;
978         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
979         int l;
980
981         if (!keypad[0])
982         {
983                 PERROR("keypad info not given.\n");
984                 return;
985         }
986
987         add_trace("keypad", NULL, "%s", keypad);
988
989         l = strlen((char *)keypad);
990         p = msg_put(msg, l+2);
991         if (p_m_d_ntmode)
992                 *ntmode = p+1;
993         else
994                 qi->keypad.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
995         p[0] = IE_KEYPAD;
996         p[1] = l;
997         UNCPY((char *)p+2, (char *)keypad, strlen((char *)keypad));
998 }
999
1000 void Pdss1::dec_ie_keypad(unsigned char *p, Q931_info_t *qi, unsigned char *keypad, int keypad_len)
1001 {
1002         *keypad = '\0';
1003
1004         if (!p_m_d_ntmode)
1005         {
1006                 p = NULL;
1007                 if (qi->keypad.off)
1008                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->keypad.off + 1;
1009         }
1010         if (!p)
1011                 return;
1012         if (p[0] < 1)
1013         {
1014                 PERROR("IE too short (%d).\n", p[0]);
1015                 return;
1016         }
1017
1018         strnncpy(keypad, p+1, p[0], keypad_len);
1019
1020         add_trace("keypad", NULL, "%s", keypad);
1021 }
1022
1023
1024 /* IE_NOTIFY */
1025 void Pdss1::enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify)
1026 {
1027         unsigned char *p;
1028         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1029         int l;
1030
1031         if (notify<0 || notify>0x7f)
1032         {
1033                 PERROR("notify(%d) is out of range.\n", notify);
1034                 return;
1035         }
1036
1037         add_trace("notify", NULL, "%d", notify);
1038
1039         l = 1;
1040         p = msg_put(msg, l+2);
1041         if (p_m_d_ntmode)
1042                 *ntmode = p+1;
1043         else
1044                 qi->notify.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1045         p[0] = IE_NOTIFY;
1046         p[1] = l;
1047         p[2] = 0x80 + notify;
1048 }
1049
1050 void Pdss1::dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify)
1051 {
1052         *notify = -1;
1053
1054         if (!p_m_d_ntmode)
1055         {
1056                 p = NULL;
1057                 if (qi->notify.off)
1058                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->notify.off + 1;
1059         }
1060         if (!p)
1061                 return;
1062         if (p[0] < 1)
1063         {
1064                 PERROR("IE too short (%d).\n", p[0]);
1065                 return;
1066         }
1067
1068         *notify = p[1] & 0x7f;
1069
1070         add_trace("notify", NULL, "%d", *notify);
1071 }
1072
1073
1074 /* IE_PROGRESS */
1075 void Pdss1::enc_ie_progress(unsigned char **ntmode, msg_t *msg, int coding, int location, int progress)
1076 {
1077         unsigned char *p;
1078         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1079         int l;
1080
1081         if (coding<0 || coding>0x03)
1082         {
1083                 PERROR("coding(%d) is out of range.\n", coding);
1084                 return;
1085         }
1086         if (location<0 || location>0x0f)
1087         {
1088                 PERROR("location(%d) is out of range.\n", location);
1089                 return;
1090         }
1091         if (progress<0 || progress>0x7f)
1092         {
1093                 PERROR("progress(%d) is out of range.\n", progress);
1094                 return;
1095         }
1096
1097         add_trace("progress", "codeing", "%d", coding);
1098         add_trace("progress", "location", "%d", location);
1099         add_trace("progress", "indicator", "%d", progress);
1100
1101         l = 2;
1102         p = msg_put(msg, l+2);
1103         if (p_m_d_ntmode)
1104                 *ntmode = p+1;
1105         else
1106                 qi->progress.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1107         p[0] = IE_PROGRESS;
1108         p[1] = l;
1109         p[2] = 0x80 + (coding<<5) + location;
1110         p[3] = 0x80 + progress;
1111 }
1112
1113 void Pdss1::dec_ie_progress(unsigned char *p, Q931_info_t *qi, int *coding, int *location, int *progress)
1114 {
1115         *coding = -1;
1116         *location = -1;
1117         *progress = -1;
1118
1119         if (!p_m_d_ntmode)
1120         {
1121                 p = NULL;
1122                 if (qi->progress.off)
1123                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->progress.off + 1;
1124         }
1125         if (!p)
1126                 return;
1127         if (p[0] < 1)
1128         {
1129                 PERROR("IE too short (%d).\n", p[0]);
1130                 return;
1131         }
1132
1133         *coding = (p[1]&0x60) >> 5;
1134         *location = p[1] & 0x0f;
1135         *progress = p[2] & 0x7f;
1136
1137         add_trace("progress", "codeing", "%d", *coding);
1138         add_trace("progress", "location", "%d", *location);
1139         add_trace("progress", "indicator", "%d", *progress);
1140 }
1141
1142
1143 /* IE_REDIR_NR (redirecting = during MT_SETUP) */
1144 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)
1145 {
1146         unsigned char *p;
1147         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1148         int l;
1149
1150         if (type<0 || type>7)
1151         {
1152                 PERROR("type(%d) is out of range.\n", type);
1153                 return;
1154         }
1155         if (plan<0 || plan>15)
1156         {
1157                 PERROR("plan(%d) is out of range.\n", plan);
1158                 return;
1159         }
1160         if (present > 3)
1161         {
1162                 PERROR("present(%d) is out of range.\n", present);
1163                 return;
1164         }
1165         if (present >= 0) if (screen<0 || screen>3)
1166         {
1167                 PERROR("screen(%d) is out of range.\n", screen);
1168                 return;
1169         }
1170         if (reason > 0x0f)
1171         {
1172                 PERROR("reason(%d) is out of range.\n", reason);
1173                 return;
1174         }
1175
1176         add_trace("redir'ing", "type", "%d", type);
1177         add_trace("redir'ing", "plan", "%d", plan);
1178         add_trace("redir'ing", "present", "%d", present);
1179         add_trace("redir'ing", "screen", "%d", screen);
1180         add_trace("redir'ing", "reason", "%d", reason);
1181         add_trace("redir'ing", "number", "%s", number);
1182
1183         l = 1;
1184         if (number)
1185                 l += strlen((char *)number);
1186         if (present >= 0)
1187         {
1188                 l += 1;
1189                 if (reason >= 0)
1190                         l += 1;
1191         }
1192         p = msg_put(msg, l+2);
1193         if (p_m_d_ntmode)
1194                 *ntmode = p+1;
1195         else
1196                 qi->redirect_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1197         p[0] = IE_REDIR_NR;
1198         p[1] = l;
1199         if (present >= 0)
1200         {
1201                 if (reason >= 0)
1202                 {
1203                         p[2] = 0x00 + (type<<4) + plan;
1204                         p[3] = 0x00 + (present<<5) + screen;
1205                         p[4] = 0x80 + reason;
1206                         if (number)
1207                                 UNCPY((char *)p+5, (char *)number, strlen((char *)number));
1208                 } else
1209                 {
1210                         p[2] = 0x00 + (type<<4) + plan;
1211                         p[3] = 0x80 + (present<<5) + screen;
1212                         if (number)
1213                                 UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1214                 }
1215         } else
1216         {
1217                 p[2] = 0x80 + (type<<4) + plan;
1218                 if (number) if (number[0])
1219                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1220         }
1221 }
1222
1223 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)
1224 {
1225         *type = -1;
1226         *plan = -1;
1227         *present = -1;
1228         *screen = -1;
1229         *reason = -1;
1230         *number = '\0';
1231
1232         if (!p_m_d_ntmode)
1233         {
1234                 p = NULL;
1235                 if (qi->redirect_nr.off)
1236                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_nr.off + 1;
1237         }
1238         if (!p)
1239                 return;
1240         if (p[0] < 1)
1241         {
1242                 PERROR("IE too short (%d).\n", p[0]);
1243                 return;
1244         }
1245
1246         *type = (p[1]&0x70) >> 4;
1247         *plan = p[1] & 0xf;
1248         if (!(p[1] & 0x80))
1249         {
1250                 *present = (p[2]&0x60) >> 5;
1251                 *screen = p[2] & 0x3;
1252                 if (!(p[2] & 0x80))
1253                 {
1254                         *reason = p[3] & 0x0f;
1255                         strnncpy(number, p+4, p[0]-3, number_len);
1256                 } else
1257                 {
1258                         strnncpy(number, p+3, p[0]-2, number_len);
1259                 }
1260         } else
1261         {
1262                 strnncpy(number, p+2, p[0]-1, number_len);
1263         }
1264
1265         add_trace("redir'ing", "type", "%d", *type);
1266         add_trace("redir'ing", "plan", "%d", *plan);
1267         add_trace("redir'ing", "present", "%d", *present);
1268         add_trace("redir'ing", "screen", "%d", *screen);
1269         add_trace("redir'ing", "reason", "%d", *reason);
1270         add_trace("redir'ing", "number", "%s", number);
1271 }
1272
1273
1274 /* IE_REDIR_DN (redirection = during MT_NOTIFY) */
1275 void Pdss1::enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, unsigned char *number)
1276 {
1277         unsigned char *p;
1278         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1279         int l;
1280
1281         if (type<0 || type>7)
1282         {
1283                 PERROR("type(%d) is out of range.\n", type);
1284                 return;
1285         }
1286         if (plan<0 || plan>15)
1287         {
1288                 PERROR("plan(%d) is out of range.\n", plan);
1289                 return;
1290         }
1291         if (present > 3)
1292         {
1293                 PERROR("present(%d) is out of range.\n", present);
1294                 return;
1295         }
1296
1297         add_trace("redir'tion", "type", "%d", type);
1298         add_trace("redir'tion", "plan", "%d", plan);
1299         add_trace("redir'tion", "present", "%d", present);
1300         add_trace("redir'tion", "number", "%s", number);
1301
1302         l = 1;
1303         if (number)
1304                 l += strlen((char *)number);
1305         if (present >= 0)
1306                 l += 1;
1307         p = msg_put(msg, l+2);
1308         if (p_m_d_ntmode)
1309                 *ntmode = p+1;
1310         else
1311                 qi->redirect_dn.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1312         p[0] = IE_REDIR_DN;
1313         p[1] = l;
1314         if (present >= 0)
1315         {
1316                 p[2] = 0x00 + (type<<4) + plan;
1317                 p[3] = 0x80 + (present<<5);
1318                 if (number)
1319                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1320         } else
1321         {
1322                 p[2] = 0x80 + (type<<4) + plan;
1323                 if (number)
1324                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1325         }
1326 }
1327
1328 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)
1329 {
1330         *type = -1;
1331         *plan = -1;
1332         *present = -1;
1333         *number = '\0';
1334
1335         if (!p_m_d_ntmode)
1336         {
1337                 p = NULL;
1338                 if (qi->redirect_dn.off)
1339                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_dn.off + 1;
1340         }
1341         if (!p)
1342                 return;
1343         if (p[0] < 1)
1344         {
1345                 PERROR("IE too short (%d).\n", p[0]);
1346                 return;
1347         }
1348
1349         *type = (p[1]&0x70) >> 4;
1350         *plan = p[1] & 0xf;
1351         if (!(p[1] & 0x80))
1352         {
1353                 *present = (p[2]&0x60) >> 5;
1354                 strnncpy(number, p+3, p[0]-2, number_len);
1355         } else
1356         {
1357                 strnncpy(number, p+2, p[0]-1, number_len);
1358         }
1359
1360         add_trace("redir'tion", "type", "%d", *type);
1361         add_trace("redir'tion", "plan", "%d", *plan);
1362         add_trace("redir'tion", "present", "%d", *present);
1363         add_trace("redir'tion", "number", "%s", number);
1364 }
1365
1366
1367 /* IE_FACILITY */
1368 void Pdss1::enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len)
1369 {
1370         unsigned char *p;
1371         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1372         int l;
1373
1374         char buffer[768];
1375         int i;
1376
1377         if (!facility || facility_len<=0)
1378         {
1379                 return;
1380         }
1381
1382         i = 0;
1383         while(i < facility_len)
1384         {
1385                 UPRINT(buffer+(i*3), " %02x", facility[i]);
1386                 i++;
1387         }
1388                 
1389         add_trace("facility", NULL, "%s", buffer+1);
1390
1391         l = facility_len;
1392         p = msg_put(msg, l+2);
1393         if (p_m_d_ntmode)
1394                 *ntmode = p+1;
1395         else
1396                 qi->facility.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1397         p[0] = IE_FACILITY;
1398         p[1] = l;
1399         memcpy(p+2, facility, facility_len);
1400 }
1401
1402 void Pdss1::dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *facility, int *facility_len)
1403 {
1404         char debug[768];
1405         int i;
1406
1407         *facility_len = 0;
1408
1409         if (!p_m_d_ntmode)
1410         {
1411                 p = NULL;
1412                 if (qi->facility.off)
1413                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->facility.off + 1;
1414         }
1415         if (!p)
1416                 return;
1417
1418         *facility_len = p[0];
1419         memcpy(facility, p+1, *facility_len);
1420
1421         i = 0;
1422         while(i < *facility_len)
1423         {
1424                 UPRINT(debug+(i*3), " %02x", facility[i]);
1425                 i++;
1426         }
1427         debug[i*3] = '\0';
1428                 
1429         add_trace("facility", NULL, "%s", debug[0]?debug+1:"<none>");
1430 }
1431
1432
1433 /* facility for siemens CENTEX (known parts implemented only) */
1434 void Pdss1::enc_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup)
1435 {
1436         unsigned char centrex[256];
1437         int i = 0;
1438
1439         if (!cnip)
1440                 return;
1441
1442         /* centrex facility */
1443         centrex[i++] = CENTREX_FAC;
1444         centrex[i++] = CENTREX_ID;
1445
1446         /* cnip */
1447         if (strlen((char *)cnip) > 15)
1448         {
1449                 PDEBUG(DEBUG_PORT, "%s: CNIP/CONP text too long (max 13 chars), cutting.\n");
1450                 cnip[15] = '\0';
1451         }
1452         // dunno what the 8 bytes mean
1453         if (setup)
1454         {
1455                 centrex[i++] = 0x17;
1456                 centrex[i++] = 0x02;
1457                 centrex[i++] = 0x02;
1458                 centrex[i++] = 0x44;
1459                 centrex[i++] = 0x18;
1460                 centrex[i++] = 0x02;
1461                 centrex[i++] = 0x01;
1462                 centrex[i++] = 0x09;
1463         } else
1464         {
1465                 centrex[i++] = 0x18;
1466                 centrex[i++] = 0x02;
1467                 centrex[i++] = 0x02;
1468                 centrex[i++] = 0x81;
1469                 centrex[i++] = 0x09;
1470                 centrex[i++] = 0x02;
1471                 centrex[i++] = 0x01;
1472                 centrex[i++] = 0x0a;
1473         }
1474
1475         centrex[i++] = 0x80;
1476         centrex[i++] = strlen((char *)cnip);
1477         UCPY((char *)(&centrex[i]), (char *)cnip);
1478         i += strlen((char *)cnip);
1479         add_trace("facility", "cnip", "%s", cnip);
1480
1481         /* encode facility */
1482         enc_ie_facility(ntmode, msg, centrex, i);
1483 }
1484
1485 void Pdss1::dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len)
1486 {
1487         unsigned char centrex[256];
1488         char debug[768];
1489         int facility_len = 0;
1490         int i = 0, j;
1491         *cnip = '\0';
1492
1493         dec_ie_facility(p, qi, centrex, &facility_len);
1494         if (facility_len >= 2)
1495         {
1496                 if (centrex[i++] != CENTREX_FAC)
1497                         return;
1498                 if (centrex[i++] != CENTREX_ID)
1499                         return;
1500         }
1501
1502         /* loop sub IEs of facility */
1503         while(facility_len > i+1)
1504         {
1505                 if (centrex[i+1]+i+1 > facility_len)
1506                 {
1507                         PERROR("short read of centrex facility.\n");
1508                         return;
1509                 }
1510                 switch(centrex[i])
1511                 {
1512                         case 0x80:
1513                         strnncpy(cnip, &centrex[i+2], centrex[i+1], cnip_len);
1514                         add_trace("facility", "cnip", "%s", cnip);
1515                         break;
1516
1517                         default:
1518                         j = 0;
1519                         while(j < centrex[i+1])
1520                         {
1521                                 UPRINT(debug+(j*3), " %02x", centrex[i+1+j]);
1522                                 i++;
1523                         }
1524                         add_trace("facility", "CENTREX", "unknown=0x%02x len=%d%s\n", centrex[i], centrex[i+1], debug);
1525                 }
1526                 i += 1+centrex[i+1];
1527         }
1528 }
1529
1530
1531 /* IE_USERUSER */
1532 void Pdss1::enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned char *user, int user_len)
1533 {
1534         unsigned char *p;
1535         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1536         int l;
1537
1538         char buffer[768];
1539         int i;
1540
1541         if (protocol<0 || protocol>127)
1542         {
1543                 PERROR("protocol(%d) is out of range.\n", protocol);
1544                 return;
1545         }
1546         if (!user || user_len<=0)
1547         {
1548                 return;
1549         }
1550
1551         i = 0;
1552         while(i < user_len)
1553         {
1554                 UPRINT(buffer+(i*3), " %02x", user[i]);
1555                 i++;
1556         }
1557                 
1558         add_trace("useruser", "protocol", "%d", protocol);
1559         add_trace("useruser", "value", "%s", buffer);
1560
1561         l = user_len;
1562         p = msg_put(msg, l+3);
1563         if (p_m_d_ntmode)
1564                 *ntmode = p+1;
1565         else
1566                 qi->useruser.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1567         p[0] = IE_USER_USER;
1568         p[1] = l;
1569         p[2] = 0x80 + protocol;
1570         memcpy(p+3, user, user_len);
1571 }
1572
1573 void Pdss1::dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned char *user, int *user_len)
1574 {
1575         char buffer[768];
1576         int i;
1577
1578         *user_len = 0;
1579         *protocol = -1;
1580
1581         if (!p_m_d_ntmode)
1582         {
1583                 p = NULL;
1584                 if (qi->useruser.off)
1585                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->useruser.off + 1;
1586         }
1587         if (!p)
1588                 return;
1589
1590         *user_len = p[0]-1;
1591         if (p[0] < 1)
1592                 return;
1593         *protocol = p[1];
1594         memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
1595
1596         i = 0;
1597         while(i < *user_len)
1598         {
1599                 UPRINT(buffer+(i*3), " %02x", user[i]);
1600                 i++;
1601         }
1602         buffer[i*3] = '\0';
1603                 
1604         add_trace("useruser", "protocol", "%d", *protocol);
1605         add_trace("useruser", "value", "%s", buffer);
1606 }
1607
1608