Add placeholder for provisioning info
[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 };
122
123 const char *iax_ie2str(int ie)
124 {
125         int x;
126         for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
127                 if (ies[x].ie == ie)
128                         return ies[x].name;
129         }
130         return "Unknown IE";
131 }
132
133 static void dump_ies(unsigned char *iedata, int len)
134 {
135         int ielen;
136         int ie;
137         int x;
138         int found;
139         char interp[80];
140         char tmp[256];
141         if (len < 2)
142                 return;
143         while(len > 2) {
144                 ie = iedata[0];
145                 ielen = iedata[1];
146                 if (ielen + 2> len) {
147                         snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
148                         outputf(tmp);
149                         return;
150                 }
151                 found = 0;
152                 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
153                         if (ies[x].ie == ie) {
154                                 if (ies[x].dump) {
155                                         ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
156                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
157                                         outputf(tmp);
158                                 } else {
159                                         snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
160                                         outputf(tmp);
161                                 }
162                                 found++;
163                         }
164                 }
165                 if (!found) {
166                         snprintf(tmp, sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
167                         outputf(tmp);
168                 }
169                 iedata += (2 + ielen);
170                 len -= (2 + ielen);
171         }
172         outputf("\n");
173 }
174
175 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
176 {
177         char *frames[] = {
178                 "(0?)",
179                 "DTMF   ",
180                 "VOICE  ",
181                 "VIDEO  ",
182                 "CONTROL",
183                 "NULL   ",
184                 "IAX    ",
185                 "TEXT   ",
186                 "IMAGE  " };
187         char *iaxs[] = {
188                 "(0?)",
189                 "NEW    ",
190                 "PING   ",
191                 "PONG   ",
192                 "ACK    ",
193                 "HANGUP ",
194                 "REJECT ",
195                 "ACCEPT ",
196                 "AUTHREQ",
197                 "AUTHREP",
198                 "INVAL  ",
199                 "LAGRQ  ",
200                 "LAGRP  ",
201                 "REGREQ ",
202                 "REGAUTH",
203                 "REGACK ",
204                 "REGREJ ",
205                 "REGREL ",
206                 "VNAK   ",
207                 "DPREQ  ",
208                 "DPREP  ",
209                 "DIAL   ",
210                 "TXREQ  ",
211                 "TXCNT  ",
212                 "TXACC  ",
213                 "TXREADY",
214                 "TXREL  ",
215                 "TXREJ  ",
216                 "QUELCH ",
217                 "UNQULCH",
218                 "POKE",
219                 "PAGE",
220                 "MWI",
221                 "UNSUPPORTED",
222                 "TRANSFER",
223                 "PROVISION",
224         };
225         char *cmds[] = {
226                 "(0?)",
227                 "HANGUP ",
228                 "RING   ",
229                 "RINGING",
230                 "ANSWER ",
231                 "BUSY   ",
232                 "TKOFFHK ",
233                 "OFFHOOK" };
234         struct ast_iax2_full_hdr *fh;
235         char retries[20];
236         char class2[20];
237         char subclass2[20];
238         char *class;
239         char *subclass;
240         char tmp[256];
241         if (f) {
242                 fh = f->data;
243                 snprintf(retries, sizeof(retries), "%03d", f->retries);
244         } else {
245                 fh = fhi;
246                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
247                         strcpy(retries, "Yes");
248                 else
249                         strcpy(retries, "No");
250         }
251         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
252                 /* Don't mess with mini-frames */
253                 return;
254         }
255         if (fh->type > sizeof(frames)/sizeof(char *)) {
256                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
257                 class = class2;
258         } else {
259                 class = frames[(int)fh->type];
260         }
261         if (fh->type == AST_FRAME_DTMF) {
262                 sprintf(subclass2, "%c", fh->csub);
263                 subclass = subclass2;
264         } else if (fh->type == AST_FRAME_IAX) {
265                 if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
266                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
267                         subclass = subclass2;
268                 } else {
269                         subclass = iaxs[(int)fh->csub];
270                 }
271         } else if (fh->type == AST_FRAME_CONTROL) {
272                 if (fh->csub > sizeof(cmds)/sizeof(char *)) {
273                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
274                         subclass = subclass2;
275                 } else {
276                         subclass = cmds[(int)fh->csub];
277                 }
278         } else {
279                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
280                 subclass = subclass2;
281         }
282 snprintf(tmp, sizeof(tmp), 
283 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
284         (rx ? "Rx" : "Tx"),
285         retries, fh->oseqno, fh->iseqno, class, subclass);
286         outputf(tmp);
287 snprintf(tmp, sizeof(tmp), 
288 "   Timestamp: %05dms  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
289         ntohl(fh->ts),
290         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
291                 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
292         outputf(tmp);
293         if (fh->type == AST_FRAME_IAX)
294                 dump_ies(fh->iedata, datalen);
295 }
296
297 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
298 {
299         char tmp[256];
300         if (datalen > (sizeof(ied->buf) - ied->pos)) {
301                 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);
302                 errorf(tmp);
303                 return -1;
304         }
305         ied->buf[ied->pos++] = ie;
306         ied->buf[ied->pos++] = datalen;
307         memcpy(ied->buf + ied->pos, data, datalen);
308         ied->pos += datalen;
309         return 0;
310 }
311
312 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
313 {
314         return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
315 }
316
317 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
318 {
319         unsigned int newval;
320         newval = htonl(value);
321         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
322 }
323
324 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
325 {
326         unsigned short newval;
327         newval = htons(value);
328         return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
329 }
330
331 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
332 {
333         return iax_ie_append_raw(ied, ie, str, strlen(str));
334 }
335
336 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
337 {
338         return iax_ie_append_raw(ied, ie, &dat, 1);
339 }
340
341 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
342 {
343         return iax_ie_append_raw(ied, ie, NULL, 0);
344 }
345
346 void iax_set_output(void (*func)(const char *))
347 {
348         outputf = func;
349 }
350
351 void iax_set_error(void (*func)(const char *))
352 {
353         errorf = func;
354 }
355
356 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
357 {
358         /* Parse data into information elements */
359         int len;
360         int ie;
361         char tmp[256];
362         memset(ies, 0, sizeof(struct iax_ies));
363         ies->msgcount = -1;
364         while(datalen >= 2) {
365                 ie = data[0];
366                 len = data[1];
367                 if (len > datalen - 2) {
368                         errorf("Information element length exceeds message size\n");
369                         return -1;
370                 }
371                 switch(ie) {
372                 case IAX_IE_CALLED_NUMBER:
373                         ies->called_number = data + 2;
374                         break;
375                 case IAX_IE_CALLING_NUMBER:
376                         ies->calling_number = data + 2;
377                         break;
378                 case IAX_IE_CALLING_ANI:
379                         ies->calling_ani = data + 2;
380                         break;
381                 case IAX_IE_CALLING_NAME:
382                         ies->calling_name = data + 2;
383                         break;
384                 case IAX_IE_CALLED_CONTEXT:
385                         ies->called_context = data + 2;
386                         break;
387                 case IAX_IE_USERNAME:
388                         ies->username = data + 2;
389                         break;
390                 case IAX_IE_PASSWORD:
391                         ies->password = data + 2;
392                         break;
393                 case IAX_IE_CAPABILITY:
394                         if (len != sizeof(unsigned int)) {
395                                 snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
396                                 errorf(tmp);
397                         } else
398                                 ies->capability = ntohl(*((unsigned int *)(data + 2)));
399                         break;
400                 case IAX_IE_FORMAT:
401                         if (len != sizeof(unsigned int)) {
402                                 snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
403                                 errorf(tmp);
404                         } else
405                                 ies->format = ntohl(*((unsigned int *)(data + 2)));
406                         break;
407                 case IAX_IE_LANGUAGE:
408                         ies->language = data + 2;
409                         break;
410                 case IAX_IE_VERSION:
411                         if (len != sizeof(unsigned short)) {
412                                 snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
413                                 errorf(tmp);
414                         } else
415                                 ies->version = ntohs(*((unsigned short *)(data + 2)));
416                         break;
417                 case IAX_IE_ADSICPE:
418                         if (len != sizeof(unsigned short)) {
419                                 snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
420                                 errorf(tmp);
421                         } else
422                                 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
423                         break;
424                 case IAX_IE_DNID:
425                         ies->dnid = data + 2;
426                         break;
427                 case IAX_IE_RDNIS:
428                         ies->rdnis = data + 2;
429                         break;
430                 case IAX_IE_AUTHMETHODS:
431                         if (len != sizeof(unsigned short))  {
432                                 snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
433                                 errorf(tmp);
434                         } else
435                                 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
436                         break;
437                 case IAX_IE_CHALLENGE:
438                         ies->challenge = data + 2;
439                         break;
440                 case IAX_IE_MD5_RESULT:
441                         ies->md5_result = data + 2;
442                         break;
443                 case IAX_IE_RSA_RESULT:
444                         ies->rsa_result = data + 2;
445                         break;
446                 case IAX_IE_APPARENT_ADDR:
447                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
448                         break;
449                 case IAX_IE_REFRESH:
450                         if (len != sizeof(unsigned short)) {
451                                 snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
452                                 errorf(tmp);
453                         } else
454                                 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
455                         break;
456                 case IAX_IE_DPSTATUS:
457                         if (len != sizeof(unsigned short)) {
458                                 snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
459                                 errorf(tmp);
460                         } else
461                                 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
462                         break;
463                 case IAX_IE_CALLNO:
464                         if (len != sizeof(unsigned short)) {
465                                 snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
466                                 errorf(tmp);
467                         } else
468                                 ies->callno = ntohs(*((unsigned short *)(data + 2)));
469                         break;
470                 case IAX_IE_CAUSE:
471                         ies->cause = data + 2;
472                         break;
473                 case IAX_IE_IAX_UNKNOWN:
474                         if (len == 1)
475                                 ies->iax_unknown = data[2];
476                         else {
477                                 snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
478                                 errorf(tmp);
479                         }
480                         break;
481                 case IAX_IE_MSGCOUNT:
482                         if (len != sizeof(unsigned short)) {
483                                 snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
484                                 errorf(tmp);
485                         } else
486                                 ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
487                         break;
488                 case IAX_IE_AUTOANSWER:
489                         ies->autoanswer = 1;
490                         break;
491                 case IAX_IE_MUSICONHOLD:
492                         ies->musiconhold = 1;
493                         break;
494                 case IAX_IE_TRANSFERID:
495                         if (len != sizeof(unsigned int)) {
496                                 snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
497                                 errorf(tmp);
498                         } else
499                                 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
500                         break;
501                 default:
502                         snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
503                         errorf(tmp);
504                 }
505                 /* Overwrite information element with 0, to null terminate previous portion */
506                 data[0] = 0;
507                 datalen -= (len + 2);
508                 data += (len + 2);
509         }
510         /* Null-terminate last field */
511         *data = '\0';
512         if (datalen) {
513                 errorf("Invalid information element contents, strange boundary\n");
514                 return -1;
515         }
516         return 0;
517 }
518
519 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
520 {
521         fr->af.frametype = f->frametype;
522         fr->af.subclass = f->subclass;
523         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
524         fr->af.datalen = f->datalen;
525         fr->af.samples = f->samples;
526         fr->af.offset = AST_FRIENDLY_OFFSET;
527         fr->af.src = f->src;
528         fr->af.data = fr->afdata;
529         if (fr->af.datalen) 
530                 memcpy(fr->af.data, f->data, fr->af.datalen);
531 }
532
533 struct iax_frame *iax_frame_new(int direction, int datalen)
534 {
535         struct iax_frame *fr;
536         fr = malloc(sizeof(struct iax_frame) + datalen);
537         if (fr) {
538                 fr->direction = direction;
539                 fr->retrans = -1;
540                 frames++;
541                 if (fr->direction == DIRECTION_INGRESS)
542                         iframes++;
543                 else
544                         oframes++;
545         }
546         return fr;
547 }
548
549 void iax_frame_free(struct iax_frame *fr)
550 {
551         /* Note: does not remove from scheduler! */
552         if (fr->direction == DIRECTION_INGRESS)
553                 iframes--;
554         else if (fr->direction == DIRECTION_OUTGRESS)
555                 oframes--;
556         else {
557                 errorf("Attempt to double free frame detected\n");
558                 return;
559         }
560         fr->direction = 0;
561         free(fr);
562         frames--;
563 }
564
565 int iax_get_frames(void) { return frames; }
566 int iax_get_iframes(void) { return iframes; }
567 int iax_get_oframes(void) { return oframes; }