Added display of current active TEI values (L2) at lcradmin.
[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, int number_len)
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         UNCPY((char *)p, (char *)number, number_len);
341         p[number_len] = '\0';
342         add_trace("called_pn", "number", "%s", p);
343
344         l = 1+number_len;
345         p[0] = IE_CALLED_PN;
346         p[1] = l;
347         p[2] = 0x80 + (type<<4) + plan;
348         UNCPY((char *)p+3, (char *)number, number_len);
349         add_layer3_ie(l3m, p[0], p[1], p+2);
350 }
351
352 void Pdss1::dec_ie_called_pn(struct l3_msg *l3m, int *type, int *plan, unsigned char *number, int number_len)
353 {
354         *type = -1;
355         *plan = -1;
356         *number = '\0';
357
358         unsigned char *p = l3m->called_nr;
359         if (!p)
360                 return;
361         if (p[0] < 2)
362         {
363                 add_trace("called_pn", "error", "IE too short (len=%d)", p[0]);
364                 return;
365         }
366
367         *type = (p[1]&0x70) >> 4;
368         *plan = p[1] & 0xf;
369         strnncpy(number, p+2, p[0]-1, number_len);
370
371         add_trace("called_pn", "type", "%d", *type);
372         add_trace("called_pn", "plan", "%d", *plan);
373         add_trace("called_pn", "number", "%s", number);
374 }
375
376
377 /* IE_CALLING_PN */
378 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)
379 {
380         unsigned char p[256];
381         int l;
382
383         if (type<0 || type>7)
384         {
385                 PERROR("type(%d) is out of range.\n", type);
386                 return;
387         }
388         if (plan<0 || plan>15)
389         {
390                 PERROR("plan(%d) is out of range.\n", plan);
391                 return;
392         }
393         if (present>3)
394         {
395                 PERROR("present(%d) is out of range.\n", present);
396                 return;
397         }
398         if (present >= 0) if (screen<0 || screen>3)
399         {
400                 PERROR("screen(%d) is out of range.\n", screen);
401                 return;
402         }
403
404         add_trace("calling_pn", "type", "%d", type);
405         add_trace("calling_pn", "plan", "%d", plan);
406         add_trace("calling_pn", "present", "%d", present);
407         add_trace("calling_pn", "screen", "%d", screen);
408         add_trace("calling_pn", "number", "%s", number);
409
410         l = 1;
411         if (number) if (number[0])
412                 l += strlen((char *)number);
413         if (present >= 0)
414                 l += 1;
415         p[0] = IE_CALLING_PN;
416         p[1] = l;
417         if (present >= 0)
418         {
419                 p[2] = 0x00 + (type<<4) + plan;
420                 p[3] = 0x80 + (present<<5) + screen;
421                 if (number) if (number[0])
422                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
423         } else
424         {
425                 p[2] = 0x80 + (type<<4) + plan;
426                 if (number) if (number[0])
427                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
428         }
429         add_layer3_ie(l3m, p[0], p[1], p+2);
430
431         /* second calling party number */
432         if (type2 < 0)
433                 return;
434         
435         if (type2>7)
436         {
437                 PERROR("type2(%d) is out of range.\n", type2);
438                 return;
439         }
440         if (plan2<0 || plan2>15)
441         {
442                 PERROR("plan2(%d) is out of range.\n", plan2);
443                 return;
444         }
445         if (present2>3)
446         {
447                 PERROR("present2(%d) is out of range.\n", present2);
448                 return;
449         }
450         if (present2 >= 0) if (screen2<0 || screen2>3)
451         {
452                 PERROR("screen2(%d) is out of range.\n", screen2);
453                 return;
454         }
455
456         add_trace("call_pn 2", "type", "%d", type2);
457         add_trace("call_pn 2", "plan", "%d", plan2);
458         add_trace("call_pn 2", "present", "%d", present2);
459         add_trace("call_pn 2", "screen", "%d", screen2);
460         add_trace("call_pn 2", "number", "%s", number2);
461
462         l = 1;
463         if (number2) if (number2[0])
464                 l += strlen((char *)number2);
465         if (present2 >= 0)
466                 l += 1;
467         p[0] = IE_CALLING_PN;
468         p[1] = l;
469         if (present2 >= 0)
470         {
471                 p[2] = 0x00 + (type2<<4) + plan2;
472                 p[3] = 0x80 + (present2<<5) + screen2;
473                 if (number2) if (number2[0])
474                         UNCPY((char *)p+4, (char *)number2, strlen((char *)number2));
475         } else
476         {
477                 p[2] = 0x80 + (type2<<4) + plan2;
478                 if (number2) if (number2[0])
479                         UNCPY((char *)p+3, (char *)number2, strlen((char *)number2));
480         }
481         add_layer3_ie(l3m, p[0], p[1], p+2);
482 }
483
484 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)
485 {
486         *type = -1;
487         *plan = -1;
488         *present = -1;
489         *screen = -1;
490         *number = '\0';
491         *type2 = -1;
492         *plan2 = -1;
493         *present2 = -1;
494         *screen2 = -1;
495         *number2 = '\0';
496         unsigned int numextra = sizeof(l3m->extra) / sizeof(struct m_extie);
497         unsigned int i;
498
499         unsigned char *p = l3m->calling_nr;
500         if (!p)
501                 return;
502         if (p[0] < 1)
503         {
504                 add_trace("calling_pn", "error", "IE too short (len=%d)", p[0]);
505                 return;
506         }
507
508         *type = (p[1]&0x70) >> 4;
509         *plan = p[1] & 0xf;
510         if (!(p[1] & 0x80))
511         {
512                 if (p[0] < 2)
513                 {
514                         add_trace("calling_pn", "error", "IE too short (len=%d)", p[0]);
515                         return;
516                 }
517                 *present = (p[2]&0x60) >> 5;
518                 *screen = p[2] & 0x3;
519                 strnncpy(number, p+3, p[0]-2, number_len);
520         } else
521         {
522                 strnncpy(number, p+2, p[0]-1, number_len);
523         }
524
525         add_trace("calling_pn", "type", "%d", *type);
526         add_trace("calling_pn", "plan", "%d", *plan);
527         add_trace("calling_pn", "present", "%d", *present);
528         add_trace("calling_pn", "screen", "%d", *screen);
529         add_trace("calling_pn", "number", "%s", number);
530
531         /* second calling party number */
532         p = NULL;
533         i = 0;
534         while(i < numextra)
535         {
536                 if (!l3m->extra[i].val)
537                         break;
538                 if (l3m->extra[i].ie == IE_CALLING_PN)
539                 {
540                         p = l3m->extra[i].val;
541                         break;
542                 }
543                 i++;
544         }
545         if (!p)
546                 return;
547         if (p[0] < 1)
548         {
549                 add_trace("calling_pn2", "error", "IE too short (len=%d)", p[0]);
550                 return;
551         }
552
553         *type2 = (p[1]&0x70) >> 4;
554         *plan2 = p[1] & 0xf;
555         if (!(p[1] & 0x80))
556         {
557                 if (p[0] < 2)
558                 {
559                         add_trace("calling_pn2", "error", "IE too short (len=%d)", p[0]);
560                         return;
561                 }
562                 *present2 = (p[2]&0x60) >> 5;
563                 *screen2 = p[2] & 0x3;
564                 strnncpy(number2, p+3, p[0]-2, number_len2);
565         } else
566         {
567                 strnncpy(number2, p+2, p[0]-1, number_len2);
568         }
569
570         add_trace("call_pn 2", "type", "%d", *type2);
571         add_trace("call_pn 2", "plan", "%d", *plan2);
572         add_trace("call_pn 2", "present", "%d", *present2);
573         add_trace("call_pn 2", "screen", "%d", *screen2);
574         add_trace("call_pn 2", "number", "%s", number2);
575 }
576
577
578 /* IE_CONNECTED_PN */
579 void Pdss1::enc_ie_connected_pn(struct l3_msg *l3m, int type, int plan, int present, int screen, unsigned char *number)
580 {
581         unsigned char p[256];
582         int l;
583
584         if (type<0 || type>7)
585         {
586                 PERROR("type(%d) is out of range.\n", type);
587                 return;
588         }
589         if (plan<0 || plan>15)
590         {
591                 PERROR("plan(%d) is out of range.\n", plan);
592                 return;
593         }
594         if (present>3)
595         {
596                 PERROR("present(%d) is out of range.\n", present);
597                 return;
598         }
599         if (present >= 0) if (screen<0 || screen>3)
600         {
601                 PERROR("screen(%d) is out of range.\n", screen);
602                 return;
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         l = 1;
612         if (number) if (number[0])
613                 l += strlen((char *)number);
614         if (present >= 0)
615                 l += 1;
616         p[0] = IE_CONNECT_PN;
617         p[1] = l;
618         if (present >= 0)
619         {
620                 p[2] = 0x00 + (type<<4) + plan;
621                 p[3] = 0x80 + (present<<5) + screen;
622                 if (number) if (number[0])
623                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
624         } else
625         {
626                 p[2] = 0x80 + (type<<4) + plan;
627                 if (number) if (number[0])
628                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
629         }
630         add_layer3_ie(l3m, p[0], p[1], p+2);
631 }
632
633 void Pdss1::dec_ie_connected_pn(struct l3_msg *l3m, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len)
634 {
635         *type = -1;
636         *plan = -1;
637         *present = -1;
638         *screen = -1;
639         *number = '\0';
640
641         unsigned char *p = l3m->connected_nr;
642         if (!p)
643                 return;
644         if (p[0] < 1)
645         {
646                 add_trace("connect_pn", "error", "IE too short (len=%d)", p[0]);
647                 return;
648         }
649
650         *type = (p[1]&0x70) >> 4;
651         *plan = p[1] & 0xf;
652         if (!(p[1] & 0x80))
653         {
654                 if (p[0] < 2)
655                 {
656                         add_trace("connect_pn", "error", "IE too short (len=%d)", p[0]);
657                         return;
658                 }
659                 *present = (p[2]&0x60) >> 5;
660                 *screen = p[2] & 0x3;
661                 strnncpy(number, p+3, p[0]-2, number_len);
662         } else
663         {
664                 strnncpy(number, p+2, p[0]-1, number_len);
665         }
666
667         add_trace("connect_pn", "type", "%d", *type);
668         add_trace("connect_pn", "plan", "%d", *plan);
669         add_trace("connect_pn", "present", "%d", *present);
670         add_trace("connect_pn", "screen", "%d", *screen);
671         add_trace("connect_pn", "number", "%s", number);
672 }
673
674
675 /* IE_CAUSE */
676 void Pdss1::enc_ie_cause(struct l3_msg *l3m, int location, int cause)
677 {
678         unsigned char p[256];
679         int l;
680
681         if (location<0 || location>7)
682         {
683                 PERROR("location(%d) is out of range.\n", location);
684                 return;
685         }
686         if (cause<0 || cause>127)
687         {
688                 PERROR("cause(%d) is out of range.\n", cause);
689                 return;
690         }
691
692         add_trace("cause", "location", "%d", location);
693         add_trace("cause", "value", "%d", cause);
694
695         l = 2;
696         p[0] = IE_CAUSE;
697         p[1] = l;
698         p[2] = 0x80 + location;
699         p[3] = 0x80 + cause;
700         add_layer3_ie(l3m, p[0], p[1], p+2);
701 }
702 void enc_ie_cause_standalone(struct l3_msg *l3m, int location, int cause)
703 {
704         unsigned char p[256];
705         p[0] = IE_CAUSE;
706         p[1] = 2;
707         p[2] = 0x80 + location;
708         p[3] = 0x80 + cause;
709         add_layer3_ie(l3m, p[0], p[1], p+2);
710 }
711
712
713 void Pdss1::dec_ie_cause(struct l3_msg *l3m, int *location, int *cause)
714 {
715         *location = -1;
716         *cause = -1;
717
718         unsigned char *p = l3m->cause;
719         if (!p)
720                 return;
721         if (p[0] < 2)
722         {
723                 add_trace("cause", "error", "IE too short (len=%d)", p[0]);
724                 return;
725         }
726
727         *location = p[1] & 0x0f;
728         *cause = p[2] & 0x7f;
729
730         add_trace("cause", "location", "%d", *location);
731         add_trace("cause", "value", "%d", *cause);
732 }
733
734
735 /* IE_CHANNEL_ID */
736 void Pdss1::enc_ie_channel_id(struct l3_msg *l3m, int exclusive, int channel)
737 {
738         unsigned char p[256];
739         int l;
740         int pri = p_m_mISDNport->pri;
741
742         if (exclusive<0 || exclusive>1)
743         {
744                 PERROR("exclusive(%d) is out of range.\n", exclusive);
745                 return;
746         }
747         if ((channel<=0 && channel!=CHANNEL_NO && channel!=CHANNEL_ANY)
748          || (!pri && channel>2)
749          || (pri && channel>127)
750          || (pri && channel==16))
751         {
752                 PERROR("channel(%d) is out of range.\n", channel);
753                 return;
754         }
755
756         add_trace("channel_id", "exclusive", "%d", exclusive);
757         switch(channel)
758         {
759                 case CHANNEL_ANY:
760                 add_trace("channel_id", "channel", "any channel");
761                 break;
762                 case CHANNEL_NO:
763                 add_trace("channel_id", "channel", "no channel");
764                 break;
765                 default:
766                 add_trace("channel_id", "channel", "%d", channel);
767         }
768
769         if (!pri)
770         {
771                 /* BRI */
772                 l = 1;
773                 p[0] = IE_CHANNEL_ID;
774                 p[1] = l;
775                 if (channel == CHANNEL_NO)
776                         channel = 0;
777                 else if (channel == CHANNEL_ANY)
778                         channel = 3;
779                 p[2] = 0x80 + (exclusive<<3) + channel;
780                 add_layer3_ie(l3m, p[0], p[1], p+2);
781         } else
782         {
783                 /* PRI */
784                 if (channel == CHANNEL_NO) /* no channel */
785                         return; /* IE not present */
786                 if (channel == CHANNEL_ANY) /* any channel */
787                 {
788                         l = 1;
789                         p[0] = IE_CHANNEL_ID;
790                         p[1] = l;
791                         p[2] = 0x80 + 0x20 + 0x03;
792                         add_layer3_ie(l3m, p[0], p[1], p+2);
793                         return; /* end */
794                 }
795                 l = 3;
796                 p[0] = IE_CHANNEL_ID;
797                 p[1] = l;
798                 p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
799                 p[3] = 0x80 + 3; /* CCITT, Number, B-type */
800                 p[4] = 0x80 + channel;
801                 add_layer3_ie(l3m, p[0], p[1], p+2);
802         }
803 }
804
805 void Pdss1::dec_ie_channel_id(struct l3_msg *l3m, int *exclusive, int *channel)
806 {
807         int pri = p_m_mISDNport->pri;
808
809         *exclusive = -1;
810         *channel = -1;
811
812         unsigned char *p = l3m->channel_id;
813         if (!p)
814                 return;
815         if (p[0] < 1)
816         {
817                 add_trace("channel_id", "error", "IE too short (len=%d)", p[0]);
818                 return;
819         }
820
821         if (p[1] & 0x40)
822         {
823                 add_trace("channel_id", "error", "refering to channels of other interfaces is not supported");
824                 return;
825         }
826         if (p[1] & 0x04)
827         {
828                 add_trace("channel_id", "error", "using d-channel is not supported");
829                 return;
830         }
831
832         *exclusive = (p[1]&0x08) >> 3;
833         if (!pri)
834         {
835                 /* BRI */
836                 if (p[1] & 0x20)
837                 {
838                         add_trace("channel_id", "error", "extended channel ID with non PRI interface");
839                         return;
840                 }
841                 *channel = p[1] & 0x03;
842                 if (*channel == 3)
843                         *channel = CHANNEL_ANY;
844                 else if (*channel == 0)
845                         *channel = CHANNEL_NO;
846         } else
847         {
848                 /* PRI */
849                 if (p[0] < 1)
850                 {
851
852                         add_trace("channel_id", "error", "IE too short for PRI (len=%d)", p[0]);
853                         return;
854                 }
855                 if (!(p[1] & 0x20))
856                 {
857                         add_trace("channel_id", "error", "basic channel ID with PRI interface");
858                         return;
859                 }
860                 if ((p[1]&0x03) == 0x00)
861                 {
862                         /* no channel */
863                         *channel = CHANNEL_NO;
864                         return;
865                 }
866                 if ((p[1]&0x03) == 0x03)
867                 {
868                         /* any channel */
869                         *channel = CHANNEL_ANY;
870                         return;
871                 }
872                 if (p[0] < 3)
873                 {
874                         add_trace("channel_id", "error", "IE too short for PRI with channel (len=%d)", p[0]);
875                         return;
876                 }
877                 if (p[2] & 0x10)
878                 {
879                         add_trace("channel_id", "error", "channel map not supported");
880                         return;
881                 }
882                 *channel = p[3] & 0x7f;
883                 if ((*channel<1) || (*channel==16))
884                 {
885                         add_trace("channel_id", "error", "PRI interface channel out of range (%d)", *channel);
886                         return;
887                 }
888         }
889
890         add_trace("channel_id", "exclusive", "%d", *exclusive);
891         switch(*channel)
892         {
893                 case CHANNEL_ANY:
894                 add_trace("channel_id", "channel", "any channel");
895                 break;
896                 case CHANNEL_NO:
897                 add_trace("channel_id", "channel", "no channel");
898                 break;
899                 default:
900                 add_trace("channel_id", "channel", "%d", *channel);
901         }
902 }
903
904
905 /* IE_DATE */
906 void Pdss1::enc_ie_date(struct l3_msg *l3m, time_t ti, int no_seconds)
907 {
908         unsigned char p[256];
909         int l;
910
911         struct tm *tm;
912
913         tm = localtime(&ti);
914         if (!tm)
915         {
916                 PERROR("localtime() returned NULL.\n");
917                 return;
918         }
919
920         add_trace("date", "day", "%d.%d.%d", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100);
921         add_trace("date", "time", "%d:%d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec);
922
923         l = 5 + (!no_seconds);
924         p[0] = IE_DATE;
925         p[1] = l;
926         p[2] = tm->tm_year % 100;
927         p[3] = tm->tm_mon + 1;
928         p[4] = tm->tm_mday;
929         p[5] = tm->tm_hour;
930         p[6] = tm->tm_min;
931         if (!no_seconds)
932                 p[7] = tm->tm_sec;
933         add_layer3_ie(l3m, p[0], p[1], p+2);
934 }
935
936
937 /* IE_DISPLAY */
938 void Pdss1::enc_ie_display(struct l3_msg *l3m, unsigned char *display)
939 {
940         unsigned char p[256];
941         int l;
942
943         if (!display[0])
944         {
945                 PERROR("display text not given.\n");
946                 return;
947         }
948
949         if (strlen((char *)display) > 80)
950         {
951                 PERROR("display text too long (max 80 chars), cutting.\n");
952                 display[80] = '\0';
953         }
954
955         add_trace("display", NULL, "%s", display);
956
957         l = strlen((char *)display);
958         p[0] = IE_DISPLAY;
959         p[1] = l;
960         UNCPY((char *)p+2, (char *)display, strlen((char *)display));
961         add_layer3_ie(l3m, p[0], p[1], p+2);
962 }
963
964 void Pdss1::dec_ie_display(struct l3_msg *l3m, unsigned char *display, int display_len)
965 {
966         *display = '\0';
967
968         unsigned char *p = l3m->display;
969         if (!p)
970                 return;
971         if (p[0] < 1)
972         {
973                 add_trace("display", "error", "IE too short (len=%d)", p[0]);
974                 return;
975         }
976
977         strnncpy(display, p+1, p[0], display_len);
978
979         add_trace("display", NULL, "%s", display);
980 }
981
982
983 /* IE_KEYPAD */
984 void Pdss1::enc_ie_keypad(struct l3_msg *l3m, unsigned char *keypad)
985 {
986         unsigned char p[256];
987         int l;
988
989         if (!keypad[0])
990         {
991                 PERROR("keypad info not given.\n");
992                 return;
993         }
994
995         add_trace("keypad", NULL, "%s", keypad);
996
997         l = strlen((char *)keypad);
998         p[0] = IE_KEYPAD;
999         p[1] = l;
1000         UNCPY((char *)p+2, (char *)keypad, strlen((char *)keypad));
1001         add_layer3_ie(l3m, p[0], p[1], p+2);
1002 }
1003
1004 void Pdss1::dec_ie_keypad(struct l3_msg *l3m, unsigned char *keypad, int keypad_len)
1005 {
1006         *keypad = '\0';
1007
1008         unsigned char *p = l3m->keypad;
1009         if (!p)
1010                 return;
1011         if (p[0] < 1)
1012         {
1013                 add_trace("keypad", "error", "IE too short (len=%d)", p[0]);
1014                 return;
1015         }
1016
1017         strnncpy(keypad, p+1, p[0], keypad_len);
1018
1019         add_trace("keypad", NULL, "%s", keypad);
1020 }
1021
1022
1023 /* IE_NOTIFY */
1024 void Pdss1::enc_ie_notify(struct l3_msg *l3m, int notify)
1025 {
1026         unsigned char p[256];
1027         int l;
1028
1029         if (notify<0 || notify>0x7f)
1030         {
1031                 PERROR("notify(%d) is out of range.\n", notify);
1032                 return;
1033         }
1034
1035         add_trace("notify", NULL, "%d", notify);
1036
1037         l = 1;
1038         p[0] = IE_NOTIFY;
1039         p[1] = l;
1040         p[2] = 0x80 + notify;
1041         add_layer3_ie(l3m, p[0], p[1], p+2);
1042 }
1043
1044 void Pdss1::dec_ie_notify(struct l3_msg *l3m, int *notify)
1045 {
1046         *notify = -1;
1047
1048         unsigned char *p = l3m->notify;
1049         if (!p)
1050                 return;
1051         if (p[0] < 1)
1052         {
1053                 add_trace("notify", "error", "IE too short (len=%d)", p[0]);
1054                 return;
1055         }
1056
1057         *notify = p[1] & 0x7f;
1058
1059         add_trace("notify", NULL, "%d", *notify);
1060 }
1061
1062
1063 /* IE_PROGRESS */
1064 void Pdss1::enc_ie_progress(struct l3_msg *l3m, int coding, int location, int progress)
1065 {
1066         unsigned char p[256];
1067         int l;
1068
1069         if (coding<0 || coding>0x03)
1070         {
1071                 PERROR("coding(%d) is out of range.\n", coding);
1072                 return;
1073         }
1074         if (location<0 || location>0x0f)
1075         {
1076                 PERROR("location(%d) is out of range.\n", location);
1077                 return;
1078         }
1079         if (progress<0 || progress>0x7f)
1080         {
1081                 PERROR("progress(%d) is out of range.\n", progress);
1082                 return;
1083         }
1084
1085         add_trace("progress", "codeing", "%d", coding);
1086         add_trace("progress", "location", "%d", location);
1087         add_trace("progress", "indicator", "%d", progress);
1088
1089         l = 2;
1090         p[0] = IE_PROGRESS;
1091         p[1] = l;
1092         p[2] = 0x80 + (coding<<5) + location;
1093         p[3] = 0x80 + progress;
1094         add_layer3_ie(l3m, p[0], p[1], p+2);
1095 }
1096
1097 void Pdss1::dec_ie_progress(struct l3_msg *l3m, int *coding, int *location, int *progress)
1098 {
1099         *coding = -1;
1100         *location = -1;
1101         *progress = -1;
1102
1103         unsigned char *p = l3m->progress;
1104         if (!p)
1105                 return;
1106         if (p[0] < 1)
1107         {
1108                 add_trace("progress", "error", "IE too short (len=%d)", p[0]);
1109                 return;
1110         }
1111
1112         *coding = (p[1]&0x60) >> 5;
1113         *location = p[1] & 0x0f;
1114         *progress = p[2] & 0x7f;
1115
1116         add_trace("progress", "codeing", "%d", *coding);
1117         add_trace("progress", "location", "%d", *location);
1118         add_trace("progress", "indicator", "%d", *progress);
1119 }
1120
1121
1122 /* IE_REDIR_NR (redirecting = during MT_SETUP) */
1123 void Pdss1::enc_ie_redir_nr(struct l3_msg *l3m, int type, int plan, int present, int screen, int reason, unsigned char *number)
1124 {
1125         unsigned char p[256];
1126         int l;
1127
1128         if (type<0 || type>7)
1129         {
1130                 PERROR("type(%d) is out of range.\n", type);
1131                 return;
1132         }
1133         if (plan<0 || plan>15)
1134         {
1135                 PERROR("plan(%d) is out of range.\n", plan);
1136                 return;
1137         }
1138         if (present > 3)
1139         {
1140                 PERROR("present(%d) is out of range.\n", present);
1141                 return;
1142         }
1143         if (present >= 0) if (screen<0 || screen>3)
1144         {
1145                 PERROR("screen(%d) is out of range.\n", screen);
1146                 return;
1147         }
1148         if (reason > 0x0f)
1149         {
1150                 PERROR("reason(%d) is out of range.\n", reason);
1151                 return;
1152         }
1153
1154         add_trace("redir'ing", "type", "%d", type);
1155         add_trace("redir'ing", "plan", "%d", plan);
1156         add_trace("redir'ing", "present", "%d", present);
1157         add_trace("redir'ing", "screen", "%d", screen);
1158         add_trace("redir'ing", "reason", "%d", reason);
1159         add_trace("redir'ing", "number", "%s", number);
1160
1161         l = 1;
1162         if (number)
1163                 l += strlen((char *)number);
1164         if (present >= 0)
1165         {
1166                 l += 1;
1167                 if (reason >= 0)
1168                         l += 1;
1169         }
1170         p[0] = IE_REDIR_NR;
1171         p[1] = l;
1172         if (present >= 0)
1173         {
1174                 if (reason >= 0)
1175                 {
1176                         p[2] = 0x00 + (type<<4) + plan;
1177                         p[3] = 0x00 + (present<<5) + screen;
1178                         p[4] = 0x80 + reason;
1179                         if (number)
1180                                 UNCPY((char *)p+5, (char *)number, strlen((char *)number));
1181                 } else
1182                 {
1183                         p[2] = 0x00 + (type<<4) + plan;
1184                         p[3] = 0x80 + (present<<5) + screen;
1185                         if (number)
1186                                 UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1187                 }
1188         } else
1189         {
1190                 p[2] = 0x80 + (type<<4) + plan;
1191                 if (number) if (number[0])
1192                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1193         }
1194         add_layer3_ie(l3m, p[0], p[1], p+2);
1195 }
1196
1197 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)
1198 {
1199         *type = -1;
1200         *plan = -1;
1201         *present = -1;
1202         *screen = -1;
1203         *reason = -1;
1204         *number = '\0';
1205
1206         unsigned char *p = l3m->redirect_nr;
1207         if (!p)
1208                 return;
1209         if (p[0] < 1)
1210         {
1211                 add_trace("redir'ing", "error", "IE too short (len=%d)", p[0]);
1212                 return;
1213         }
1214
1215         *type = (p[1]&0x70) >> 4;
1216         *plan = p[1] & 0xf;
1217         if (!(p[1] & 0x80))
1218         {
1219                 *present = (p[2]&0x60) >> 5;
1220                 *screen = p[2] & 0x3;
1221                 if (!(p[2] & 0x80))
1222                 {
1223                         *reason = p[3] & 0x0f;
1224                         strnncpy(number, p+4, p[0]-3, number_len);
1225                 } else
1226                 {
1227                         strnncpy(number, p+3, p[0]-2, number_len);
1228                 }
1229         } else
1230         {
1231                 strnncpy(number, p+2, p[0]-1, number_len);
1232         }
1233
1234         add_trace("redir'ing", "type", "%d", *type);
1235         add_trace("redir'ing", "plan", "%d", *plan);
1236         add_trace("redir'ing", "present", "%d", *present);
1237         add_trace("redir'ing", "screen", "%d", *screen);
1238         add_trace("redir'ing", "reason", "%d", *reason);
1239         add_trace("redir'ing", "number", "%s", number);
1240 }
1241
1242
1243 /* IE_REDIR_DN (redirection = during MT_NOTIFY) */
1244 void Pdss1::enc_ie_redir_dn(struct l3_msg *l3m, int type, int plan, int present, unsigned char *number)
1245 {
1246         unsigned char p[256];
1247         int l;
1248
1249         if (type<0 || type>7)
1250         {
1251                 PERROR("type(%d) is out of range.\n", type);
1252                 return;
1253         }
1254         if (plan<0 || plan>15)
1255         {
1256                 PERROR("plan(%d) is out of range.\n", plan);
1257                 return;
1258         }
1259         if (present > 3)
1260         {
1261                 PERROR("present(%d) is out of range.\n", present);
1262                 return;
1263         }
1264
1265         add_trace("redir'tion", "type", "%d", type);
1266         add_trace("redir'tion", "plan", "%d", plan);
1267         add_trace("redir'tion", "present", "%d", present);
1268         add_trace("redir'tion", "number", "%s", number);
1269
1270         l = 1;
1271         if (number)
1272                 l += strlen((char *)number);
1273         if (present >= 0)
1274                 l += 1;
1275         p[0] = IE_REDIR_DN;
1276         p[1] = l;
1277         if (present >= 0)
1278         {
1279                 p[2] = 0x00 + (type<<4) + plan;
1280                 p[3] = 0x80 + (present<<5);
1281                 if (number)
1282                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1283         } else
1284         {
1285                 p[2] = 0x80 + (type<<4) + plan;
1286                 if (number)
1287                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1288         }
1289         add_layer3_ie(l3m, p[0], p[1], p+2);
1290 }
1291
1292 void Pdss1::dec_ie_redir_dn(struct l3_msg *l3m, int *type, int *plan, int *present, unsigned char *number, int number_len)
1293 {
1294         *type = -1;
1295         *plan = -1;
1296         *present = -1;
1297         *number = '\0';
1298
1299         unsigned char *p = l3m->redirect_dn;
1300         if (!p)
1301                 return;
1302         if (p[0] < 1)
1303         {
1304                 add_trace("redir'tion", "error", "IE too short (len=%d)", p[0]);
1305                 return;
1306         }
1307
1308         *type = (p[1]&0x70) >> 4;
1309         *plan = p[1] & 0xf;
1310         if (!(p[1] & 0x80))
1311         {
1312                 *present = (p[2]&0x60) >> 5;
1313                 strnncpy(number, p+3, p[0]-2, number_len);
1314         } else
1315         {
1316                 strnncpy(number, p+2, p[0]-1, number_len);
1317         }
1318
1319         add_trace("redir'tion", "type", "%d", *type);
1320         add_trace("redir'tion", "plan", "%d", *plan);
1321         add_trace("redir'tion", "present", "%d", *present);
1322         add_trace("redir'tion", "number", "%s", number);
1323 }
1324
1325
1326 /* IE_FACILITY */
1327 void Pdss1::enc_ie_facility(struct l3_msg *l3m, unsigned char *facility, int facility_len)
1328 {
1329         unsigned char p[256];
1330         int l;
1331
1332         char buffer[768];
1333         int i;
1334
1335         if (!facility || facility_len<=0)
1336         {
1337                 return;
1338         }
1339
1340         i = 0;
1341         while(i < facility_len)
1342         {
1343                 UPRINT(buffer+(i*3), " %02x", facility[i]);
1344                 i++;
1345         }
1346                 
1347         add_trace("facility", NULL, "%s", buffer+1);
1348
1349         l = facility_len;
1350         p[0] = IE_FACILITY;
1351         p[1] = l;
1352         memcpy(p+2, facility, facility_len);
1353         add_layer3_ie(l3m, p[0], p[1], p+2);
1354 }
1355
1356 void Pdss1::dec_ie_facility(struct l3_msg *l3m, unsigned char *facility, int *facility_len)
1357 {
1358         char debug[768];
1359         int i;
1360
1361         *facility_len = 0;
1362
1363         unsigned char *p = l3m->facility;
1364         if (!p)
1365                 return;
1366
1367         *facility_len = p[0];
1368         memcpy(facility, p+1, *facility_len);
1369
1370         i = 0;
1371         while(i < *facility_len)
1372         {
1373                 UPRINT(debug+(i*3), " %02x", facility[i]);
1374                 i++;
1375         }
1376         debug[i*3] = '\0';
1377                 
1378         add_trace("facility", NULL, "%s", debug[0]?debug+1:"<none>");
1379 }
1380
1381
1382 void Pdss1::dec_facility_centrex(struct l3_msg *l3m, unsigned char *cnip, int cnip_len)
1383 {
1384         unsigned char centrex[256];
1385         char debug[768];
1386         int facility_len = 0;
1387         int i = 0, j;
1388         *cnip = '\0';
1389
1390         dec_ie_facility(l3m, centrex, &facility_len);
1391         if (facility_len >= 2)
1392         {
1393                 if (centrex[i++] != CENTREX_FAC)
1394                         return;
1395                 if (centrex[i++] != CENTREX_ID)
1396                         return;
1397         }
1398
1399         /* loop sub IEs of facility */
1400         while(facility_len > i+1)
1401         {
1402                 if (centrex[i+1]+i+1 > facility_len)
1403                 {
1404                         PERROR("short read of centrex facility.\n");
1405                         return;
1406                 }
1407                 switch(centrex[i])
1408                 {
1409                         case 0x80:
1410                         strnncpy(cnip, &centrex[i+2], centrex[i+1], cnip_len);
1411                         add_trace("facility", "cnip", "%s", cnip);
1412                         break;
1413
1414                         default:
1415                         j = 0;
1416                         while(j < centrex[i+1])
1417                         {
1418                                 UPRINT(debug+(j*3), " %02x", centrex[i+1+j]);
1419                                 i++;
1420                         }
1421                         add_trace("facility", "CENTREX", "unknown=0x%02x len=%d%s\n", centrex[i], centrex[i+1], debug);
1422                 }
1423                 i += 1+centrex[i+1];
1424         }
1425 }
1426
1427
1428 /* IE_USERUSER */
1429 void Pdss1::enc_ie_useruser(struct l3_msg *l3m, int protocol, unsigned char *user, int user_len)
1430 {
1431         unsigned char p[256];
1432         int l;
1433
1434         char buffer[768];
1435         int i;
1436
1437         if (protocol<0 || protocol>127)
1438         {
1439                 PERROR("protocol(%d) is out of range.\n", protocol);
1440                 return;
1441         }
1442         if (!user || user_len<=0)
1443         {
1444                 return;
1445         }
1446
1447         i = 0;
1448         while(i < user_len)
1449         {
1450                 UPRINT(buffer+(i*3), " %02x", user[i]);
1451                 i++;
1452         }
1453                 
1454         add_trace("useruser", "protocol", "%d", protocol);
1455         add_trace("useruser", "value", "%s", buffer);
1456
1457         l = user_len;
1458         p[0] = IE_USER_USER;
1459         p[1] = l;
1460         p[2] = 0x80 + protocol;
1461         memcpy(p+3, user, user_len);
1462         add_layer3_ie(l3m, p[0], p[1], p+2);
1463 }
1464
1465 void Pdss1::dec_ie_useruser(struct l3_msg *l3m, int *protocol, unsigned char *user, int *user_len)
1466 {
1467         char buffer[768];
1468         int i;
1469
1470         *user_len = 0;
1471         *protocol = -1;
1472
1473         unsigned char *p = l3m->useruser;
1474         if (!p)
1475                 return;
1476
1477         *user_len = p[0]-1;
1478         if (p[0] < 1)
1479                 return;
1480         *protocol = p[1];
1481         memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
1482
1483         i = 0;
1484         while(i < *user_len)
1485         {
1486                 UPRINT(buffer+(i*3), " %02x", user[i]);
1487                 i++;
1488         }
1489         buffer[i*3] = '\0';
1490                 
1491         add_trace("useruser", "protocol", "%d", *protocol);
1492         add_trace("useruser", "value", "%s", buffer);
1493 }
1494
1495