* first bits of decoding facility information elements
[asterisk/asterisk.git] / channels / misdn / fac.c
1
2 #include "fac.h"
3 #include "asn1.h"
4
5 #if 0
6 +-------------------------------
7 | IE_IDENTIFIER
8 +-------------------------------
9 | {length}
10 +-------------------------------
11 |   +---------------------------
12 |   | SERVICE_DISCRIMINATOR
13 |   +---------------------------
14 |   | COMPONENT_TYPE_TAG
15 |   +---------------------------
16 |   | {length}
17 |   +---------------------------
18 |   |   +-----------------------
19 |   |   | INVOKE_IDENTIFIER_TAG (0x2)
20 |   |   +-----------------------
21 |   |   | {length}              (0x1)
22 |   |   +-----------------------
23 |   |   | {value}               (odd integer 0-127)
24 |   |   +-----------------------
25 |   |   +-----------------------
26 |   |   | OPERATION_VALUE_TAG   (0x2)
27 |   |   +-----------------------
28 |   |   | {length}              (0x1)
29 |   |   +-----------------------
30 |   |   | {value}
31 |   |   +-----------------------
32 |   |   +-----------------------
33 |   |   | ASN.1 data
34 +---+---+-----------------------
35 #endif
36
37 enum {
38         SUPPLEMENTARY_SERVICE   = 0x91,
39 } SERVICE_DISCRIMINATOR;
40
41 enum {
42         INVOKE                                  = 0xa1,
43         RETURN_RESULT                   = 0xa2,
44         RETURN_ERROR                    = 0xa3,
45         REJECT                                  = 0xa4,
46 } COMPONENT_TYPE_TAG;
47
48 enum {
49         INVOKE_IDENTIFIER               = 0x02,
50         LINKED_IDENTIFIER               = 0x80,
51         NULL_IDENTIFIER                 = 0x05,
52 } INVOKE_IDENTIFIER_TAG;
53
54 enum {
55         OPERATION_VALUE                 = 0x02,
56 } OPERATION_VALUE_TAG;
57
58 enum {
59         VALUE_QUERY                     = 0x8c,
60         SET_VALUE                               = 0x8d,
61         REQUEST_FEATURE                 = 0x8f,
62         ABORT                                   = 0xbe,
63         REDIRECT_CALL                   = 0xce,
64         CALLING_PARTY_TO_HOLD   = 0xcf,
65         CALLING_PARTY_FROM_HOLD = 0x50,
66         DROP_TARGET_PARTY               = 0xd1,
67         USER_DATA_TRANSFER              = 0xd3,
68         APP_SPECIFIC_STATUS     = 0xd2,
69
70         /* not from document */
71         CALL_DEFLECT                    = 0x0d,
72         AOC                                     = 0x22,
73 } OPERATION_CODE;
74
75 enum {
76         Q931_IE_TAG                     = 0x40,
77 } ARGUMENT_TAG;
78
79 #ifdef FACILITY_DEBUG
80 #define FAC_DUMP(fac,len,bc) fac_dump(fac,len,bc)
81 #include <ctype.h>
82 static void fac_dump (__u8 *facility, unsigned int fac_len, struct misdn_bchannel *bc)
83 {
84         int i;
85         cb_log(0, bc->port, "    --- facility dump start. length:%d\n", fac_len);
86         for (i = 0; i < fac_len; ++i)
87                 if (isprint(facility[i]))
88                         cb_log(0, bc->port, "    --- %d: %04p (char:%c)\n", i, facility[i], facility[i]);
89                 else
90                         cb_log(0, bc->port, "    --- %d: %04p\n", i, facility[i]);
91         cb_log(0, bc->port, "    --- facility dump end\n");
92 }
93 #else
94 #define FAC_DUMP(fac,len,bc)
95 #endif
96
97 /*
98 ** Facility Encoding
99 */
100
101 static int enc_fac_calldeflect (__u8 *dest, char *number, int pres)
102 {
103         __u8 *body_len,
104                  *p = dest,
105                  *seq1, *seq2;
106
107         *p++ = SUPPLEMENTARY_SERVICE;
108         *p++ = INVOKE;
109
110         body_len = p++;
111
112         p += _enc_int(p, 0x1 /* some odd integer in (0..127) */, INVOKE_IDENTIFIER);
113         p += _enc_int(p, CALL_DEFLECT, OPERATION_VALUE);
114         p += enc_sequence_start(p, &seq1);
115           p += enc_sequence_start(p, &seq2);
116             p += _enc_num_string(p, number, strlen(number), ASN1_TAG_CONTEXT_SPECIFIC);
117           p += enc_sequence_end(p, seq2);
118           p += enc_bool(p, pres);
119     p += enc_sequence_end(p, seq1);
120         
121         *body_len = p - &body_len[1];
122         
123         return p - dest;
124 }
125
126 static void enc_ie_facility (__u8 **ntmode, msg_t *msg, __u8 *facility, int facility_len, struct misdn_bchannel *bc)
127 {
128         __u8 *ie_fac;
129         
130         Q931_info_t *qi;
131
132         ie_fac = msg_put(msg, facility_len + 2);
133         if (bc->nt) {
134                 *ntmode = ie_fac + 1;
135         } else {
136                 qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
137                 qi->QI_ELEMENT(facility) = ie_fac - (__u8 *)qi - sizeof(Q931_info_t);
138         }
139
140         ie_fac[0] = IE_FACILITY;
141         ie_fac[1] = facility_len;
142         memcpy(ie_fac + 2, facility, facility_len);
143
144         FAC_DUMP(ie_fac, facility_len + 2, bc);
145 }
146
147 void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type,  union facility fac, struct misdn_bchannel *bc)
148 {
149         __u8 facility[256];
150         int len;
151
152         switch (type) {
153         case FACILITY_CALLDEFLECT:
154                 len = enc_fac_calldeflect(facility, fac.calldeflect_nr, 1);
155                 enc_ie_facility(ntmsg, msg, facility, len, bc);
156                 break;
157         case FACILITY_CENTREX:
158         case FACILITY_NONE:
159                 break;
160         }
161 }
162
163 /*
164 ** Facility Decoding
165 */
166
167 static int dec_fac_calldeflect (__u8 *p, int len, struct misdn_bchannel *bc)
168 {
169         __u8 *end = p + len;
170         int offset,
171                 pres;
172
173         if ((offset = dec_sequence(p, end)) < 0)
174                 return -1;
175         p += offset;
176
177         if ((offset = dec_sequence(p, end)) < 0)
178                 return -1;
179         p += offset;
180         
181         if ((offset = dec_num_string(p, end, bc->fac.calldeflect_nr)) < 0)
182                 return -1;
183         p += offset;
184
185         if ((offset = dec_bool(p, end, &pres)) < 0)
186                 return -1;
187
188         cb_log(0, 0, "CALLDEFLECT: dest:%s pres:%s (not implemented yet)\n", bc->fac.calldeflect_nr, pres ? "yes" : "no");
189         bc->fac_type = FACILITY_CALLDEFLECT;
190
191         return 0;
192 }
193
194 void fac_dec (__u8 *p, Q931_info_t *qi, enum facility_type *type,  union facility *fac, struct misdn_bchannel *bc)
195 {
196         int len,
197                 offset,
198                 inner_len,
199                 invoke_id,
200                 op_tag,
201                 op_val;
202         __u8 *end,
203                                   *begin = p;
204
205         if (!bc->nt) {
206                 if (qi->QI_ELEMENT(facility))
207                         p = (__u8 *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
208                 else
209                         p = NULL;
210         }
211         if (!p)
212                 return;
213
214         offset = dec_len (p, &len);
215         if (offset < 0) {
216                 cb_log(0, bc->port, "Could not decode FACILITY: dec_len failed!\n");
217                 return;
218         }
219         p += offset;
220         end = p + len;
221
222         FAC_DUMP(p, len, bc);
223
224         if (len < 3 || p[0] != SUPPLEMENTARY_SERVICE || p[1] != INVOKE) {
225                 cb_log(0, bc->port, "Could not decode FACILITY: invalid or not supported!\n");
226                 return;
227         }
228         p += 2;
229
230         offset = dec_len (p, &inner_len);
231         if (offset < 0) {
232                 cb_log(0, bc->port, "Could not decode FACILITY: failed parsing inner length!\n");
233                 return;
234         }
235         p += offset;
236
237         offset = dec_int (p, end, &invoke_id);
238         if (offset < 0) {
239                 cb_log(0, bc->port, "Could not decode FACILITY: failed parsing invoke identifier!\n");
240                 return;
241         }
242         p += offset;
243
244         offset = _dec_int (p, end, &op_val, &op_tag);
245         if (offset < 0) {
246                 cb_log(0, bc->port, "Could not decode FACILITY: failed parsing operation value!\n");
247                 return;
248         }
249         p += offset;
250
251         if (op_tag != OPERATION_VALUE || offset != 3) {
252                 cb_log(0, bc->port, "Could not decode FACILITY: operation value tag 0x%x unknown!\n", op_tag);
253                 return;
254         }
255
256         switch (op_val) {
257         case CALL_DEFLECT:
258                 cb_log(0, bc->port, "FACILITY: Call Deflect\n");
259                 dec_fac_calldeflect(p, len - (p - begin) + 1, bc);
260                 break;
261         case AOC:
262                 cb_log(0, bc->port, "FACILITY: AOC\n");
263                 break;
264         default:
265                 cb_log(0, bc->port, "FACILITY unknown: operation value 0x%x, ignoring ...\n", op_val);
266         }
267 }