Completed GSM mobile station support with OsmocomBB
[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) /* no channel */
715                         return; /* IE not present */
716                 if (channel == CHANNEL_ANY) /* any channel */ {
717                         l = 1;
718                         p[0] = IE_CHANNEL_ID;
719                         p[1] = l;
720                         p[2] = 0x80 + 0x20 + 0x03;
721                         add_layer3_ie(l3m, p[0], p[1], p+2);
722                         return; /* end */
723                 }
724                 l = 3;
725                 p[0] = IE_CHANNEL_ID;
726                 p[1] = l;
727                 p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
728                 p[3] = 0x80 + 3; /* CCITT, Number, B-type */
729                 p[4] = 0x80 + channel;
730                 add_layer3_ie(l3m, p[0], p[1], p+2);
731         }
732 }
733
734 void Pdss1::dec_ie_channel_id(struct l3_msg *l3m, int *exclusive, int *channel)
735 {
736         int pri = p_m_mISDNport->pri;
737
738         *exclusive = -1;
739         *channel = -1;
740
741         unsigned char *p = l3m->channel_id;
742         if (!p)
743                 return;
744         if (p[0] < 1) {
745                 add_trace("channel_id", "error", "IE too short (len=%d)", p[0]);
746                 return;
747         }
748
749         if (p[1] & 0x40) {
750                 add_trace("channel_id", "error", "refering to channels of other interfaces is not supported");
751                 return;
752         }
753         if (p[1] & 0x04) {
754                 add_trace("channel_id", "error", "using d-channel is not supported");
755                 return;
756         }
757
758         *exclusive = (p[1]&0x08) >> 3;
759         if (!pri) {
760                 /* BRI */
761                 if (p[1] & 0x20) {
762                         add_trace("channel_id", "error", "extended channel ID with non PRI interface");
763                         return;
764                 }
765                 *channel = p[1] & 0x03;
766                 if (*channel == 3)
767                         *channel = CHANNEL_ANY;
768                 else if (*channel == 0)
769                         *channel = CHANNEL_NO;
770         } else {
771                 /* PRI */
772                 if (p[0] < 1) {
773
774                         add_trace("channel_id", "error", "IE too short for PRI (len=%d)", p[0]);
775                         return;
776                 }
777                 if (!(p[1] & 0x20)) {
778                         add_trace("channel_id", "error", "basic channel ID with PRI interface");
779                         return;
780                 }
781                 if ((p[1]&0x03) == 0x00) {
782                         /* no channel */
783                         *channel = CHANNEL_NO;
784                         return;
785                 }
786                 if ((p[1]&0x03) == 0x03) {
787                         /* any channel */
788                         *channel = CHANNEL_ANY;
789                         return;
790                 }
791                 if (p[0] < 3) {
792                         add_trace("channel_id", "error", "IE too short for PRI with channel (len=%d)", p[0]);
793                         return;
794                 }
795                 if (p[2] & 0x10) {
796                         add_trace("channel_id", "error", "channel map not supported");
797                         return;
798                 }
799                 *channel = p[3] & 0x7f;
800                 if ((*channel<1) || (*channel==16)) {
801                         add_trace("channel_id", "error", "PRI interface channel out of range (%d)", *channel);
802                         return;
803                 }
804         }
805
806         add_trace("channel_id", "exclusive", "%d", *exclusive);
807         switch(*channel) {
808                 case CHANNEL_ANY:
809                 add_trace("channel_id", "channel", "any channel");
810                 break;
811                 case CHANNEL_NO:
812                 add_trace("channel_id", "channel", "no channel");
813                 break;
814                 default:
815                 add_trace("channel_id", "channel", "%d", *channel);
816         }
817 }
818
819
820 /* IE_DATE */
821 void Pdss1::enc_ie_date(struct l3_msg *l3m, time_t ti, int no_seconds)
822 {
823         unsigned char p[256];
824         int l;
825
826         struct tm *tm;
827
828         tm = localtime(&ti);
829         if (!tm) {
830                 PERROR("localtime() returned NULL.\n");
831                 return;
832         }
833
834         add_trace("date", "day", "%d.%d.%d", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100);
835         add_trace("date", "time", "%d:%d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec);
836
837         l = 5 + (!no_seconds);
838         p[0] = IE_DATE;
839         p[1] = l;
840         p[2] = tm->tm_year % 100;
841         p[3] = tm->tm_mon + 1;
842         p[4] = tm->tm_mday;
843         p[5] = tm->tm_hour;
844         p[6] = tm->tm_min;
845         if (!no_seconds)
846                 p[7] = tm->tm_sec;
847         add_layer3_ie(l3m, p[0], p[1], p+2);
848 }
849
850
851 /* IE_DISPLAY */
852 void Pdss1::enc_ie_display(struct l3_msg *l3m, unsigned char *display)
853 {
854         unsigned char p[256];
855         int l;
856
857         if (!display[0]) {
858                 PERROR("display text not given.\n");
859                 return;
860         }
861
862         if (strlen((char *)display) > 80) {
863                 PERROR("display text too long (max 80 chars), cutting.\n");
864                 display[80] = '\0';
865         }
866
867         add_trace("display", NULL, "%s", display);
868
869         l = strlen((char *)display);
870         p[0] = IE_DISPLAY;
871         p[1] = l;
872         UNCPY((char *)p+2, (char *)display, strlen((char *)display));
873         add_layer3_ie(l3m, p[0], p[1], p+2);
874 }
875
876 void Pdss1::dec_ie_display(struct l3_msg *l3m, unsigned char *display, int display_len)
877 {
878         *display = '\0';
879
880         unsigned char *p = l3m->display;
881         if (!p)
882                 return;
883         if (p[0] < 1) {
884                 add_trace("display", "error", "IE too short (len=%d)", p[0]);
885                 return;
886         }
887
888         strnncpy(display, p+1, p[0], display_len);
889
890         add_trace("display", NULL, "%s", display);
891 }
892
893
894 /* IE_KEYPAD */
895 void Pdss1::enc_ie_keypad(struct l3_msg *l3m, unsigned char *keypad)
896 {
897         unsigned char p[256];
898         int l;
899
900         if (!keypad[0]) {
901                 PERROR("keypad info not given.\n");
902                 return;
903         }
904
905         add_trace("keypad", NULL, "%s", keypad);
906
907         l = strlen((char *)keypad);
908         p[0] = IE_KEYPAD;
909         p[1] = l;
910         UNCPY((char *)p+2, (char *)keypad, strlen((char *)keypad));
911         add_layer3_ie(l3m, p[0], p[1], p+2);
912 }
913
914 void Pdss1::dec_ie_keypad(struct l3_msg *l3m, unsigned char *keypad, int keypad_len)
915 {
916         *keypad = '\0';
917
918         unsigned char *p = l3m->keypad;
919         if (!p)
920                 return;
921         if (p[0] < 1) {
922                 add_trace("keypad", "error", "IE too short (len=%d)", p[0]);
923                 return;
924         }
925
926         strnncpy(keypad, p+1, p[0], keypad_len);
927
928         add_trace("keypad", NULL, "%s", keypad);
929 }
930
931
932 /* IE_NOTIFY */
933 void Pdss1::enc_ie_notify(struct l3_msg *l3m, int notify)
934 {
935         unsigned char p[256];
936         int l;
937
938         if (notify<0 || notify>0x7f) {
939                 PERROR("notify(%d) is out of range.\n", notify);
940                 return;
941         }
942
943         add_trace("notify", NULL, "%d", notify);
944
945         l = 1;
946         p[0] = IE_NOTIFY;
947         p[1] = l;
948         p[2] = 0x80 + notify;
949         add_layer3_ie(l3m, p[0], p[1], p+2);
950 }
951
952 void Pdss1::dec_ie_notify(struct l3_msg *l3m, int *notify)
953 {
954         *notify = -1;
955
956         unsigned char *p = l3m->notify;
957         if (!p)
958                 return;
959         if (p[0] < 1) {
960                 add_trace("notify", "error", "IE too short (len=%d)", p[0]);
961                 return;
962         }
963
964         *notify = p[1] & 0x7f;
965
966         add_trace("notify", NULL, "%d", *notify);
967 }
968
969
970 /* IE_PROGRESS */
971 void Pdss1::enc_ie_progress(struct l3_msg *l3m, int coding, int location, int progress)
972 {
973         unsigned char p[256];
974         int l;
975
976         if (coding<0 || coding>0x03) {
977                 PERROR("coding(%d) is out of range.\n", coding);
978                 return;
979         }
980         if (location<0 || location>0x0f) {
981                 PERROR("location(%d) is out of range.\n", location);
982                 return;
983         }
984         if (progress<0 || progress>0x7f) {
985                 PERROR("progress(%d) is out of range.\n", progress);
986                 return;
987         }
988
989         add_trace("progress", "codeing", "%d", coding);
990         add_trace("progress", "location", "%d", location);
991         add_trace("progress", "indicator", "%d", progress);
992
993         l = 2;
994         p[0] = IE_PROGRESS;
995         p[1] = l;
996         p[2] = 0x80 + (coding<<5) + location;
997         p[3] = 0x80 + progress;
998         add_layer3_ie(l3m, p[0], p[1], p+2);
999 }
1000
1001 void Pdss1::dec_ie_progress(struct l3_msg *l3m, int *coding, int *location, int *progress)
1002 {
1003         *coding = -1;
1004         *location = -1;
1005         *progress = -1;
1006
1007         unsigned char *p = l3m->progress;
1008         if (!p)
1009                 return;
1010         if (p[0] < 1) {
1011                 add_trace("progress", "error", "IE too short (len=%d)", p[0]);
1012                 return;
1013         }
1014
1015         *coding = (p[1]&0x60) >> 5;
1016         *location = p[1] & 0x0f;
1017         *progress = p[2] & 0x7f;
1018
1019         add_trace("progress", "codeing", "%d", *coding);
1020         add_trace("progress", "location", "%d", *location);
1021         add_trace("progress", "indicator", "%d", *progress);
1022 }
1023
1024
1025 /* IE_REDIR_NR (redirecting = during MT_SETUP) */
1026 void Pdss1::enc_ie_redir_nr(struct l3_msg *l3m, int type, int plan, int present, int screen, int reason, unsigned char *number)
1027 {
1028         unsigned char p[256];
1029         int l;
1030
1031         if (type<0 || type>7) {
1032                 PERROR("type(%d) is out of range.\n", type);
1033                 return;
1034         }
1035         if (plan<0 || plan>15) {
1036                 PERROR("plan(%d) is out of range.\n", plan);
1037                 return;
1038         }
1039         if (present > 3) {
1040                 PERROR("present(%d) is out of range.\n", present);
1041                 return;
1042         }
1043         if (present >= 0) if (screen<0 || screen>3) {
1044                 PERROR("screen(%d) is out of range.\n", screen);
1045                 return;
1046         }
1047         if (reason > 0x0f) {
1048                 PERROR("reason(%d) is out of range.\n", reason);
1049                 return;
1050         }
1051
1052         add_trace("redir'ing", "type", "%d", type);
1053         add_trace("redir'ing", "plan", "%d", plan);
1054         add_trace("redir'ing", "present", "%d", present);
1055         add_trace("redir'ing", "screen", "%d", screen);
1056         add_trace("redir'ing", "reason", "%d", reason);
1057         add_trace("redir'ing", "number", "%s", number);
1058
1059         l = 1;
1060         if (number)
1061                 l += strlen((char *)number);
1062         if (present >= 0) {
1063                 l += 1;
1064                 if (reason >= 0)
1065                         l += 1;
1066         }
1067         p[0] = IE_REDIR_NR;
1068         p[1] = l;
1069         if (present >= 0) {
1070                 if (reason >= 0) {
1071                         p[2] = 0x00 + (type<<4) + plan;
1072                         p[3] = 0x00 + (present<<5) + screen;
1073                         p[4] = 0x80 + reason;
1074                         if (number)
1075                                 UNCPY((char *)p+5, (char *)number, strlen((char *)number));
1076                 } else {
1077                         p[2] = 0x00 + (type<<4) + plan;
1078                         p[3] = 0x80 + (present<<5) + screen;
1079                         if (number)
1080                                 UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1081                 }
1082         } else {
1083                 p[2] = 0x80 + (type<<4) + plan;
1084                 if (number) if (number[0])
1085                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1086         }
1087         add_layer3_ie(l3m, p[0], p[1], p+2);
1088 }
1089
1090 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)
1091 {
1092         *type = -1;
1093         *plan = -1;
1094         *present = -1;
1095         *screen = -1;
1096         *reason = -1;
1097         *number = '\0';
1098
1099         unsigned char *p = l3m->redirect_nr;
1100         if (!p)
1101                 return;
1102         if (p[0] < 1) {
1103                 add_trace("redir'ing", "error", "IE too short (len=%d)", p[0]);
1104                 return;
1105         }
1106
1107         *type = (p[1]&0x70) >> 4;
1108         *plan = p[1] & 0xf;
1109         if (!(p[1] & 0x80)) {
1110                 *present = (p[2]&0x60) >> 5;
1111                 *screen = p[2] & 0x3;
1112                 if (!(p[2] & 0x80)) {
1113                         *reason = p[3] & 0x0f;
1114                         strnncpy(number, p+4, p[0]-3, number_len);
1115                 } else {
1116                         strnncpy(number, p+3, p[0]-2, number_len);
1117                 }
1118         } else {
1119                 strnncpy(number, p+2, p[0]-1, number_len);
1120         }
1121
1122         add_trace("redir'ing", "type", "%d", *type);
1123         add_trace("redir'ing", "plan", "%d", *plan);
1124         add_trace("redir'ing", "present", "%d", *present);
1125         add_trace("redir'ing", "screen", "%d", *screen);
1126         add_trace("redir'ing", "reason", "%d", *reason);
1127         add_trace("redir'ing", "number", "%s", number);
1128 }
1129
1130
1131 /* IE_REDIR_DN (redirection = during MT_NOTIFY) */
1132 void Pdss1::enc_ie_redir_dn(struct l3_msg *l3m, int type, int plan, int present, unsigned char *number)
1133 {
1134         unsigned char p[256];
1135         int l;
1136
1137         if (type<0 || type>7) {
1138                 PERROR("type(%d) is out of range.\n", type);
1139                 return;
1140         }
1141         if (plan<0 || plan>15) {
1142                 PERROR("plan(%d) is out of range.\n", plan);
1143                 return;
1144         }
1145         if (present > 3) {
1146                 PERROR("present(%d) is out of range.\n", present);
1147                 return;
1148         }
1149
1150         add_trace("redir'tion", "type", "%d", type);
1151         add_trace("redir'tion", "plan", "%d", plan);
1152         add_trace("redir'tion", "present", "%d", present);
1153         add_trace("redir'tion", "number", "%s", number);
1154
1155         l = 1;
1156         if (number)
1157                 l += strlen((char *)number);
1158         if (present >= 0)
1159                 l += 1;
1160         p[0] = IE_REDIR_DN;
1161         p[1] = l;
1162         if (present >= 0) {
1163                 p[2] = 0x00 + (type<<4) + plan;
1164                 p[3] = 0x80 + (present<<5);
1165                 if (number)
1166                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1167         } else {
1168                 p[2] = 0x80 + (type<<4) + plan;
1169                 if (number)
1170                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1171         }
1172         add_layer3_ie(l3m, p[0], p[1], p+2);
1173 }
1174
1175 void Pdss1::dec_ie_redir_dn(struct l3_msg *l3m, int *type, int *plan, int *present, unsigned char *number, int number_len)
1176 {
1177         *type = -1;
1178         *plan = -1;
1179         *present = -1;
1180         *number = '\0';
1181
1182         unsigned char *p = l3m->redirect_dn;
1183         if (!p)
1184                 return;
1185         if (p[0] < 1) {
1186                 add_trace("redir'tion", "error", "IE too short (len=%d)", p[0]);
1187                 return;
1188         }
1189
1190         *type = (p[1]&0x70) >> 4;
1191         *plan = p[1] & 0xf;
1192         if (!(p[1] & 0x80)) {
1193                 *present = (p[2]&0x60) >> 5;
1194                 strnncpy(number, p+3, p[0]-2, number_len);
1195         } else {
1196                 strnncpy(number, p+2, p[0]-1, number_len);
1197         }
1198
1199         add_trace("redir'tion", "type", "%d", *type);
1200         add_trace("redir'tion", "plan", "%d", *plan);
1201         add_trace("redir'tion", "present", "%d", *present);
1202         add_trace("redir'tion", "number", "%s", number);
1203 }
1204
1205
1206 /* IE_FACILITY */
1207 void Pdss1::enc_ie_facility(struct l3_msg *l3m, unsigned char *facility, int facility_len)
1208 {
1209         unsigned char p[256];
1210         int l;
1211
1212         char buffer[768];
1213         int i;
1214
1215         if (!facility || facility_len<=0) {
1216                 return;
1217         }
1218
1219         i = 0;
1220         while(i < facility_len) {
1221                 UPRINT(buffer+(i*3), " %02x", facility[i]);
1222                 i++;
1223         }
1224                 
1225         add_trace("facility", NULL, "%s", buffer+1);
1226
1227         l = facility_len;
1228         p[0] = IE_FACILITY;
1229         p[1] = l;
1230         memcpy(p+2, facility, facility_len);
1231         add_layer3_ie(l3m, p[0], p[1], p+2);
1232 }
1233
1234 void Pdss1::dec_ie_facility(struct l3_msg *l3m, unsigned char *facility, int *facility_len)
1235 {
1236         char debug[768];
1237         int i;
1238
1239         *facility_len = 0;
1240
1241         unsigned char *p = l3m->facility;
1242         if (!p)
1243                 return;
1244
1245         *facility_len = p[0];
1246         memcpy(facility, p+1, *facility_len);
1247
1248         i = 0;
1249         while(i < *facility_len) {
1250                 UPRINT(debug+(i*3), " %02x", facility[i]);
1251                 i++;
1252         }
1253         debug[i*3] = '\0';
1254                 
1255         add_trace("facility", NULL, "%s", debug[0]?debug+1:"<none>");
1256 }
1257
1258
1259 void Pdss1::dec_facility_centrex(struct l3_msg *l3m, unsigned char *cnip, int cnip_len)
1260 {
1261         unsigned char centrex[256];
1262         char debug[768];
1263         int facility_len = 0;
1264         int i = 0, j;
1265         *cnip = '\0';
1266
1267         dec_ie_facility(l3m, centrex, &facility_len);
1268         if (facility_len >= 2) {
1269                 if (centrex[i++] != CENTREX_FAC)
1270                         return;
1271                 if (centrex[i++] != CENTREX_ID)
1272                         return;
1273         }
1274
1275         /* loop sub IEs of facility */
1276         while(facility_len > i+1) {
1277                 if (centrex[i+1]+i+1 > facility_len) {
1278                         PERROR("short read of centrex facility.\n");
1279                         return;
1280                 }
1281                 switch(centrex[i]) {
1282                         case 0x80:
1283                         strnncpy(cnip, &centrex[i+2], centrex[i+1], cnip_len);
1284                         add_trace("facility", "cnip", "%s", cnip);
1285                         break;
1286
1287                         default:
1288                         j = 0;
1289                         while(j < centrex[i+1]) {
1290                                 UPRINT(debug+(j*3), " %02x", centrex[i+1+j]);
1291                                 i++;
1292                         }
1293                         add_trace("facility", "CENTREX", "unknown=0x%02x len=%d%s\n", centrex[i], centrex[i+1], debug);
1294                 }
1295                 i += 1+centrex[i+1];
1296         }
1297 }
1298
1299
1300 /* IE_USERUSER */
1301 void Pdss1::enc_ie_useruser(struct l3_msg *l3m, int protocol, unsigned char *user, int user_len)
1302 {
1303         unsigned char p[256];
1304         int l;
1305
1306         char buffer[768];
1307         int i;
1308
1309         if (protocol<0 || protocol>127) {
1310                 PERROR("protocol(%d) is out of range.\n", protocol);
1311                 return;
1312         }
1313         if (!user || user_len<=0) {
1314                 return;
1315         }
1316
1317         i = 0;
1318         while(i < user_len) {
1319                 UPRINT(buffer+(i*3), " %02x", user[i]);
1320                 i++;
1321         }
1322                 
1323         add_trace("useruser", "protocol", "%d", protocol);
1324         add_trace("useruser", "value", "%s", buffer);
1325
1326         l = user_len;
1327         p[0] = IE_USER_USER;
1328         p[1] = l;
1329         p[2] = 0x80 + protocol;
1330         memcpy(p+3, user, user_len);
1331         add_layer3_ie(l3m, p[0], p[1], p+2);
1332 }
1333
1334 void Pdss1::dec_ie_useruser(struct l3_msg *l3m, int *protocol, unsigned char *user, int *user_len)
1335 {
1336         char buffer[768];
1337         int i;
1338
1339         *user_len = 0;
1340         *protocol = -1;
1341
1342         unsigned char *p = l3m->useruser;
1343         if (!p)
1344                 return;
1345
1346         *user_len = p[0]-1;
1347         if (p[0] < 1)
1348                 return;
1349         *protocol = p[1];
1350         memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
1351
1352         i = 0;
1353         while(i < *user_len) {
1354                 UPRINT(buffer+(i*3), " %02x", user[i]);
1355                 i++;
1356         }
1357         buffer[i*3] = '\0';
1358                 
1359         add_trace("useruser", "protocol", "%d", *protocol);
1360         add_trace("useruser", "value", "%s", buffer);
1361 }
1362
1363