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