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