Finish provisioning placeholder
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Inter-Asterisk eXchange
5  * 
6  * Copyright (C) 2003, Digium
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <string.h>
17 #include <netinet/in.h>
18 #include <asterisk/frame.h>
19 #include <arpa/inet.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "iax2.h"
24 #include "iax2-parser.h"
25
26
27 static int frames = 0;
28 static int iframes = 0;
29 static int oframes = 0;
30
31 static void internaloutput(const char *str)
32 {
33         printf(str);
34 }
35
36 static void internalerror(const char *str)
37 {
38         fprintf(stderr, "WARNING: %s", str);
39 }
40
41 static void (*outputf)(const char *str) = internaloutput;
42 static void (*errorf)(const char *str) = internalerror;
43
44 static void dump_addr(char *output, int maxlen, void *value, int len)
45 {
46         struct sockaddr_in sin;
47         if (len == sizeof(sin)) {
48                 memcpy(&sin, value, len);
49                 snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
50         } else {
51                 snprintf(output, maxlen, "Invalid Address");
52         }
53 }
54
55 static void dump_string(char *output, int maxlen, void *value, int len)
56 {
57         maxlen--;
58         if (maxlen > len)
59                 maxlen = len;
60         strncpy(output,value, maxlen);
61         output[maxlen] = '\0';
62 }
63
64 static void dump_int(char *output, int maxlen, void *value, int len)
65 {
66         if (len == sizeof(unsigned int))
67                 snprintf(output, maxlen, "%d", ntohl(*((unsigned int *)value)));
68         else
69                 snprintf(output, maxlen, "Invalid INT");
70 }
71
72 static void dump_short(char *output, int maxlen, void *value, int len)
73 {
74         if (len == sizeof(unsigned short))
75                 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
76         else
77                 snprintf(output, maxlen, "Invalid SHORT");
78 }
79
80 static void dump_byte(char *output, int maxlen, void *value, int len)
81 {
82         if (len == sizeof(unsigned char))
83                 snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
84         else
85                 snprintf(output, maxlen, "Invalid BYTE");
86 }
87
88 static struct iax2_ie {
89         int ie;
90         char *name;
91         void (*dump)(char *output, int maxlen, void *value, int len);
92 } ies[] = {
93         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
94         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
95         { IAX_IE_CALLING_ANI, "ANI", dump_string },
96         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
97         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
98         { IAX_IE_USERNAME, "USERNAME", dump_string },
99         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
100         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
101         { IAX_IE_FORMAT, "FORMAT", dump_int },
102         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
103         { IAX_IE_VERSION, "VERSION", dump_short },
104         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
105         { IAX_IE_DNID, "DNID", dump_string },
106         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
107         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
108         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
109         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
110         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
111         { IAX_IE_REFRESH, "REFRESH", dump_short },
112         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
113         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
114         { IAX_IE_CAUSE, "CAUSE", dump_string },
115         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
116         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
117         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
118         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
119         { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
120         { IAX_IE_PROVISIONING, "PROVISIONING" },
121         { IAX_IE_AESPROVISIONING, "AES PROVISIONING" },
122 };
123
124 const char *iax_ie2str(int ie)
125 {
126         int x;
127         for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
128                 if (ies[x].ie == ie)
129                         return ies[x].name;
130         }
131         return "Unknown IE";
132 }
133
134 static void dump_ies(unsigned char *iedata, int len)
135 {
136         int ielen;
137         int ie;
138         int x;
139         int found;
140         char interp[80];
141         char tmp[256];
142         if (len < 2)
143                 return;
144         while(len > 2) {
145                 ie = iedata[0];
146                 ielen = iedata[1];
147                 if (ielen + 2> len) {
148                         snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
149                         outputf(tmp);
150                         return;
151                 }
152                 found = 0;
153                 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
154                         if (ies[x].ie == ie) {
155                                 if (ies[x].dump) {
156                                         ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
157                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
158                                         outputf(tmp);
159                                 } else {
160                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
161                                         outputf(tmp);
162                                 }
163                                 found++;
164                         }
165                 }
166                 if (!found) {
167                         snprintf(tmp, sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
168                         outputf(tmp);
169                 }
170                 iedata += (2 + ielen);
171                 len -= (2 + ielen);
172         }
173         outputf("\n");
174 }
175
176 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
177 {
178         char *frames[] = {
179                 "(0?)",
180                 "DTMF   ",
181                 "VOICE  ",
182                 "VIDEO  ",
183                 "CONTROL",
184                 "NULL   ",
185                 "IAX    ",
186                 "TEXT   ",
187                 "IMAGE  " };
188         char *iaxs[] = {
189                 "(0?)",
190                 "NEW    ",
191                 "PING   ",
192                 "PONG   ",
193                 "ACK    ",
194                 "HANGUP ",
195                 "REJECT ",
196                 "ACCEPT ",
197                 "AUTHREQ",
198                 "AUTHREP",
199                 "INVAL  ",
200                 "LAGRQ  ",
201                 "LAGRP  ",
202                 "REGREQ ",
203                 "REGAUTH",
204                 "REGACK ",
205                 "REGREJ ",
206                 "REGREL ",
207                 "VNAK   ",
208                 "DPREQ  ",
209                 "DPREP  ",
210                 "DIAL   ",
211                 "TXREQ  ",
212                 "TXCNT  ",
213                 "TXACC  ",
214                 "TXREADY",
215                 "TXREL  ",
216                 "TXREJ  ",
217                 "QUELCH ",
218                 "UNQULCH",
219                 "POKE",
220                 "PAGE",
221                 "MWI",
222                 "UNSUPPORTED",
223                 "TRANSFER",
224                 "PROVISION",
225         };
226         char *cmds[] = {
227                 "(0?)",
228                 "HANGUP ",
229                 "RING   ",
230                 "RINGING",
231                 "ANSWER ",
232                 "BUSY   ",
233                 "TKOFFHK ",
234                 "OFFHOOK" };
235         struct ast_iax2_full_hdr *fh;
236         char retries[20];
237         char class2[20];
238         char subclass2[20];
239         char *class;
240         char *subclass;
241         char tmp[256];
242         if (f) {
243                 fh = f->data;
244                 snprintf(retries, sizeof(retries), "%03d", f->retries);
245         } else {
246                 fh = fhi;
247                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
248                         strcpy(retries, "Yes");
249                 else
250                         strcpy(retries, "No");
251         }
252         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
253                 /* Don't mess with mini-frames */
254                 return;
255         }
256         if (fh->type > sizeof(frames)/sizeof(char *)) {
257                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
258                 class = class2;
259         } else {
260                 class = frames[(int)fh->type];
261         }
262         if (fh->type == AST_FRAME_DTMF) {
263                 sprintf(subclass2, "%c", fh->csub);
264                 subclass = subclass2;
265         } else if (fh->type == AST_FRAME_IAX) {
266                 if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
267                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
268                         subclass = subclass2;
269                 } else {
270                         subclass = iaxs[(int)fh->csub];
271                 }
272         } else if (fh->type == AST_FRAME_CONTROL) {
273                 if (fh->csub > sizeof(cmds)/sizeof(char *)) {
274                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
275                         subclass = subclass2;
276                 } else {
277                         subclass = cmds[(int)fh->csub];
278                 }
279         } else {
280                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
281                 subclass = subclass2;
282         }
283 snprintf(tmp, sizeof(tmp), 
284 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
285         (rx ? "Rx" : "Tx"),
286         retries, fh->oseqno, fh->iseqno, class, subclass);
287         outputf(tmp);
288 snprintf(tmp, sizeof(tmp), 
289 "   Timestamp: %05dms  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
290         ntohl(fh->ts),
291         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
292                 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
293         outputf(tmp);
294         if (fh->type == AST_FRAME_IAX)
295                 dump_ies(fh->iedata, datalen);
296 }
297
298 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
299 {
300         char tmp[256];
301         if (datalen > (sizeof(ied->buf) - ied->pos)) {
302                 snprintf(tmp, sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, sizeof(ied->buf) - ied->pos);
303                 errorf(tmp);
304                 return -1;
305         }
306         ied->buf[ied->pos++] = ie;
307         ied->buf[ied->pos++] = datalen;
308         memcpy(ied->buf + ied->pos, data, datalen);
309         ied->pos += datalen;
310         return 0;
311 }
312
313 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
314 {
315         return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
316 }
317
318 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
319 {
320         unsigned int newval;
321         newval = htonl(value);
322         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
323 }
324
325 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
326 {
327         unsigned short newval;
328         newval = htons(value);
329         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
330 }
331
332 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
333 {
334         return iax_ie_append_raw(ied, ie, str, strlen(str));
335 }
336
337 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
338 {
339         return iax_ie_append_raw(ied, ie, &dat, 1);
340 }
341
342 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
343 {
344         return iax_ie_append_raw(ied, ie, NULL, 0);
345 }
346
347 void iax_set_output(void (*func)(const char *))
348 {
349         outputf = func;
350 }
351
352 void iax_set_error(void (*func)(const char *))
353 {
354         errorf = func;
355 }
356
357 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
358 {
359         /* Parse data into information elements */
360         int len;
361         int ie;
362         char tmp[256];
363         memset(ies, 0, sizeof(struct iax_ies));
364         ies->msgcount = -1;
365         while(datalen >= 2) {
366                 ie = data[0];
367                 len = data[1];
368                 if (len > datalen - 2) {
369                         errorf("Information element length exceeds message size\n");
370                         return -1;
371                 }
372                 switch(ie) {
373                 case IAX_IE_CALLED_NUMBER:
374                         ies->called_number = data + 2;
375                         break;
376                 case IAX_IE_CALLING_NUMBER:
377                         ies->calling_number = data + 2;
378                         break;
379                 case IAX_IE_CALLING_ANI:
380                         ies->calling_ani = data + 2;
381                         break;
382                 case IAX_IE_CALLING_NAME:
383                         ies->calling_name = data + 2;
384                         break;
385                 case IAX_IE_CALLED_CONTEXT:
386                         ies->called_context = data + 2;
387                         break;
388                 case IAX_IE_USERNAME:
389                         ies->username = data + 2;
390                         break;
391                 case IAX_IE_PASSWORD:
392                         ies->password = data + 2;
393                         break;
394                 case IAX_IE_CAPABILITY:
395                         if (len != sizeof(unsigned int)) {
396                                 snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
397                                 errorf(tmp);
398                         } else
399                                 ies->capability = ntohl(*((unsigned int *)(data + 2)));
400                         break;
401                 case IAX_IE_FORMAT:
402                         if (len != sizeof(unsigned int)) {
403                                 snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
404                                 errorf(tmp);
405                         } else
406                                 ies->format = ntohl(*((unsigned int *)(data + 2)));
407                         break;
408                 case IAX_IE_LANGUAGE:
409                         ies->language = data + 2;
410                         break;
411                 case IAX_IE_VERSION:
412                         if (len != sizeof(unsigned short)) {
413                                 snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
414                                 errorf(tmp);
415                         } else
416                                 ies->version = ntohs(*((unsigned short *)(data + 2)));
417                         break;
418                 case IAX_IE_ADSICPE:
419                         if (len != sizeof(unsigned short)) {
420                                 snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
421                                 errorf(tmp);
422                         } else
423                                 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
424                         break;
425                 case IAX_IE_DNID:
426                         ies->dnid = data + 2;
427                         break;
428                 case IAX_IE_RDNIS:
429                         ies->rdnis = data + 2;
430                         break;
431                 case IAX_IE_AUTHMETHODS:
432                         if (len != sizeof(unsigned short))  {
433                                 snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
434                                 errorf(tmp);
435                         } else
436                                 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
437                         break;
438                 case IAX_IE_CHALLENGE:
439                         ies->challenge = data + 2;
440                         break;
441                 case IAX_IE_MD5_RESULT:
442                         ies->md5_result = data + 2;
443                         break;
444                 case IAX_IE_RSA_RESULT:
445                         ies->rsa_result = data + 2;
446                         break;
447                 case IAX_IE_APPARENT_ADDR:
448                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
449                         break;
450                 case IAX_IE_REFRESH:
451                         if (len != sizeof(unsigned short)) {
452                                 snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
453                                 errorf(tmp);
454                         } else
455                                 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
456                         break;
457                 case IAX_IE_DPSTATUS:
458                         if (len != sizeof(unsigned short)) {
459                                 snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
460                                 errorf(tmp);
461                         } else
462                                 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
463                         break;
464                 case IAX_IE_CALLNO:
465                         if (len != sizeof(unsigned short)) {
466                                 snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
467                                 errorf(tmp);
468                         } else
469                                 ies->callno = ntohs(*((unsigned short *)(data + 2)));
470                         break;
471                 case IAX_IE_CAUSE:
472                         ies->cause = data + 2;
473                         break;
474                 case IAX_IE_IAX_UNKNOWN:
475                         if (len == 1)
476                                 ies->iax_unknown = data[2];
477                         else {
478                                 snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
479                                 errorf(tmp);
480                         }
481                         break;
482                 case IAX_IE_MSGCOUNT:
483                         if (len != sizeof(unsigned short)) {
484                                 snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
485                                 errorf(tmp);
486                         } else
487                                 ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
488                         break;
489                 case IAX_IE_AUTOANSWER:
490                         ies->autoanswer = 1;
491                         break;
492                 case IAX_IE_MUSICONHOLD:
493                         ies->musiconhold = 1;
494                         break;
495                 case IAX_IE_TRANSFERID:
496                         if (len != sizeof(unsigned int)) {
497                                 snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
498                                 errorf(tmp);
499                         } else
500                                 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
501                         break;
502                 default:
503                         snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
504                         errorf(tmp);
505                 }
506                 /* Overwrite information element with 0, to null terminate previous portion */
507                 data[0] = 0;
508                 datalen -= (len + 2);
509                 data += (len + 2);
510         }
511         /* Null-terminate last field */
512         *data = '\0';
513         if (datalen) {
514                 errorf("Invalid information element contents, strange boundary\n");
515                 return -1;
516         }
517         return 0;
518 }
519
520 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
521 {
522         fr->af.frametype = f->frametype;
523         fr->af.subclass = f->subclass;
524         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
525         fr->af.datalen = f->datalen;
526         fr->af.samples = f->samples;
527         fr->af.offset = AST_FRIENDLY_OFFSET;
528         fr->af.src = f->src;
529         fr->af.data = fr->afdata;
530         if (fr->af.datalen) 
531                 memcpy(fr->af.data, f->data, fr->af.datalen);
532 }
533
534 struct iax_frame *iax_frame_new(int direction, int datalen)
535 {
536         struct iax_frame *fr;
537         fr = malloc(sizeof(struct iax_frame) + datalen);
538         if (fr) {
539                 fr->direction = direction;
540                 fr->retrans = -1;
541                 frames++;
542                 if (fr->direction == DIRECTION_INGRESS)
543                         iframes++;
544                 else
545                         oframes++;
546         }
547         return fr;
548 }
549
550 void iax_frame_free(struct iax_frame *fr)
551 {
552         /* Note: does not remove from scheduler! */
553         if (fr->direction == DIRECTION_INGRESS)
554                 iframes--;
555         else if (fr->direction == DIRECTION_OUTGRESS)
556                 oframes--;
557         else {
558                 errorf("Attempt to double free frame detected\n");
559                 return;
560         }
561         fr->direction = 0;
562         free(fr);
563         frames--;
564 }
565
566 int iax_get_frames(void) { return frames; }
567 int iax_get_iframes(void) { return iframes; }
568 int iax_get_oframes(void) { return oframes; }