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