use double-quotes instead of angle-brackets for non-system include files (bug #4058)
[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 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
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 "asterisk/utils.h"
20 #include "asterisk/unaligned.h"
21 #include <arpa/inet.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include "iax2.h"
26 #include "iax2-parser.h"
27 #include "iax2-provision.h"
28
29
30 static int frames = 0;
31 static int iframes = 0;
32 static int oframes = 0;
33
34 static void internaloutput(const char *str)
35 {
36         fputs(str, stdout);
37 }
38
39 static void internalerror(const char *str)
40 {
41         fprintf(stderr, "WARNING: %s", str);
42 }
43
44 static void (*outputf)(const char *str) = internaloutput;
45 static void (*errorf)(const char *str) = internalerror;
46
47 static void dump_addr(char *output, int maxlen, void *value, int len)
48 {
49         struct sockaddr_in sin;
50         char iabuf[INET_ADDRSTRLEN];
51         if (len == (int)sizeof(sin)) {
52                 memcpy(&sin, value, len);
53                 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
54         } else {
55                 snprintf(output, maxlen, "Invalid Address");
56         }
57 }
58
59 static void dump_string(char *output, int maxlen, void *value, int len)
60 {
61         maxlen--;
62         if (maxlen > len)
63                 maxlen = len;
64         strncpy(output,value, maxlen);
65         output[maxlen] = '\0';
66 }
67
68 static void dump_prefs(char *output, int maxlen, void *value, int len)
69 {
70         struct ast_codec_pref pref;
71         int total_len = 0;
72
73         maxlen--;
74         total_len = maxlen;
75
76         if (maxlen > len)
77                 maxlen = len;
78
79         strncpy(output,value, maxlen);
80         output[maxlen] = '\0';
81         
82         ast_codec_pref_convert(&pref, output, total_len, 0);
83         memset(output,0,total_len);
84         ast_codec_pref_string(&pref, output, total_len);
85 }
86
87 static void dump_int(char *output, int maxlen, void *value, int len)
88 {
89         if (len == (int)sizeof(unsigned int))
90                 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
91         else
92                 snprintf(output, maxlen, "Invalid INT");
93 }
94
95 static void dump_short(char *output, int maxlen, void *value, int len)
96 {
97         if (len == (int)sizeof(unsigned short))
98                 snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
99         else
100                 snprintf(output, maxlen, "Invalid SHORT");
101 }
102
103 static void dump_byte(char *output, int maxlen, void *value, int len)
104 {
105         if (len == (int)sizeof(unsigned char))
106                 snprintf(output, maxlen, "%d", *((unsigned char *)value));
107         else
108                 snprintf(output, maxlen, "Invalid BYTE");
109 }
110
111 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
112 {
113         struct sockaddr_in sin;
114         char iabuf[INET_ADDRSTRLEN];
115         if (len == (int)sizeof(unsigned int)) {
116                 memcpy(&sin.sin_addr, value, len);
117                 ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr);
118                 snprintf(output, maxlen, "%s", iabuf);
119         } else
120                 snprintf(output, maxlen, "Invalid IPADDR");
121 }
122
123
124 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
125 {
126         char buf[256] = "";
127         if (len == (int)sizeof(unsigned int))
128                 snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
129                         iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
130         else
131                 snprintf(output, maxlen, "Invalid INT");
132 }
133
134 static void dump_samprate(char *output, int maxlen, void *value, int len)
135 {
136         char tmp[256]="";
137         int sr;
138         if (len == (int)sizeof(unsigned short)) {
139                 sr = ntohs(*((unsigned short *)value));
140                 if (sr & IAX_RATE_8KHZ)
141                         strcat(tmp, ",8khz");
142                 if (sr & IAX_RATE_11KHZ)
143                         strcat(tmp, ",11.025khz");
144                 if (sr & IAX_RATE_16KHZ)
145                         strcat(tmp, ",16khz");
146                 if (sr & IAX_RATE_22KHZ)
147                         strcat(tmp, ",22.05khz");
148                 if (sr & IAX_RATE_44KHZ)
149                         strcat(tmp, ",44.1khz");
150                 if (sr & IAX_RATE_48KHZ)
151                         strcat(tmp, ",48khz");
152                 if (strlen(tmp))
153                         strncpy(output, &tmp[1], maxlen - 1);
154                 else
155                         strncpy(output, "None specified!\n", maxlen - 1);
156         } else
157                 snprintf(output, maxlen, "Invalid SHORT");
158
159 }
160
161 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
162 static void dump_prov(char *output, int maxlen, void *value, int len)
163 {
164         dump_prov_ies(output, maxlen, value, len);
165 }
166
167 static struct iax2_ie {
168         int ie;
169         char *name;
170         void (*dump)(char *output, int maxlen, void *value, int len);
171 } ies[] = {
172         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
173         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
174         { IAX_IE_CALLING_ANI, "ANI", dump_string },
175         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
176         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
177         { IAX_IE_USERNAME, "USERNAME", dump_string },
178         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
179         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
180         { IAX_IE_FORMAT, "FORMAT", dump_int },
181         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
182         { IAX_IE_VERSION, "VERSION", dump_short },
183         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
184         { IAX_IE_DNID, "DNID", dump_string },
185         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
186         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
187         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
188         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
189         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
190         { IAX_IE_REFRESH, "REFRESH", dump_short },
191         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
192         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
193         { IAX_IE_CAUSE, "CAUSE", dump_string },
194         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
195         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
196         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
197         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
198         { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
199         { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
200         { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
201         { IAX_IE_DATETIME, "DATE TIME", dump_int },
202         { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
203         { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
204         { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
205         { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
206         { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
207         { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
208         { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
209         { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
210         { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
211         { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
212         { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
213         { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
214         { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
215         { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
216         { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
217         { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
218         { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
219         { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
220         { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
221         { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
222 };
223
224 static struct iax2_ie prov_ies[] = {
225         { PROV_IE_USEDHCP, "USEDHCP" },
226         { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
227         { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
228         { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
229         { PROV_IE_PORTNO, "BINDPORT", dump_short },
230         { PROV_IE_USER, "USERNAME", dump_string },
231         { PROV_IE_PASS, "PASSWORD", dump_string },
232         { PROV_IE_LANG, "LANGUAGE", dump_string },
233         { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
234         { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
235         { PROV_IE_FORMAT, "FORMAT", dump_int },
236         { PROV_IE_AESKEY, "AESKEY" },
237         { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
238         { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
239         { PROV_IE_NEWAESKEY, "NEWAESKEY" },
240         { PROV_IE_PROVVER, "PROV VERSION", dump_int },
241         { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
242 };
243
244 const char *iax_ie2str(int ie)
245 {
246         int x;
247         for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
248                 if (ies[x].ie == ie)
249                         return ies[x].name;
250         }
251         return "Unknown IE";
252 }
253
254
255 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
256 {
257         int ielen;
258         int ie;
259         int x;
260         int found;
261         char interp[80];
262         char tmp[256];
263         if (len < 2)
264                 return;
265         strcpy(output, "\n"); 
266         maxlen -= strlen(output); output += strlen(output);
267         while(len > 2) {
268                 ie = iedata[0];
269                 ielen = iedata[1];
270                 if (ielen + 2> len) {
271                         snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
272                         strncpy(output, tmp, maxlen - 1);
273                         maxlen -= strlen(output); output += strlen(output);
274                         return;
275                 }
276                 found = 0;
277                 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
278                         if (prov_ies[x].ie == ie) {
279                                 if (prov_ies[x].dump) {
280                                         prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
281                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
282                                         strncpy(output, tmp, maxlen - 1);
283                                         maxlen -= strlen(output); output += strlen(output);
284                                 } else {
285                                         if (ielen)
286                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
287                                         else
288                                                 strcpy(interp, "Present");
289                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
290                                         strncpy(output, tmp, maxlen - 1);
291                                         maxlen -= strlen(output); output += strlen(output);
292                                 }
293                                 found++;
294                         }
295                 }
296                 if (!found) {
297                         snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
298                         strncpy(output, tmp, maxlen - 1);
299                         maxlen -= strlen(output); output += strlen(output);
300                 }
301                 iedata += (2 + ielen);
302                 len -= (2 + ielen);
303         }
304 }
305
306 static void dump_ies(unsigned char *iedata, int len)
307 {
308         int ielen;
309         int ie;
310         int x;
311         int found;
312         char interp[1024];
313         char tmp[1024];
314         if (len < 2)
315                 return;
316         while(len > 2) {
317                 ie = iedata[0];
318                 ielen = iedata[1];
319                 if (ielen + 2> len) {
320                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
321                         outputf(tmp);
322                         return;
323                 }
324                 found = 0;
325                 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
326                         if (ies[x].ie == ie) {
327                                 if (ies[x].dump) {
328                                         ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
329                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
330                                         outputf(tmp);
331                                 } else {
332                                         if (ielen)
333                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
334                                         else
335                                                 strcpy(interp, "Present");
336                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
337                                         outputf(tmp);
338                                 }
339                                 found++;
340                         }
341                 }
342                 if (!found) {
343                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
344                         outputf(tmp);
345                 }
346                 iedata += (2 + ielen);
347                 len -= (2 + ielen);
348         }
349         outputf("\n");
350 }
351
352 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
353 {
354         char *frames[] = {
355                 "(0?)",
356                 "DTMF   ",
357                 "VOICE  ",
358                 "VIDEO  ",
359                 "CONTROL",
360                 "NULL   ",
361                 "IAX    ",
362                 "TEXT   ",
363                 "IMAGE  ",
364                 "HTML   ",
365                 "CNG    " };
366         char *iaxs[] = {
367                 "(0?)",
368                 "NEW    ",
369                 "PING   ",
370                 "PONG   ",
371                 "ACK    ",
372                 "HANGUP ",
373                 "REJECT ",
374                 "ACCEPT ",
375                 "AUTHREQ",
376                 "AUTHREP",
377                 "INVAL  ",
378                 "LAGRQ  ",
379                 "LAGRP  ",
380                 "REGREQ ",
381                 "REGAUTH",
382                 "REGACK ",
383                 "REGREJ ",
384                 "REGREL ",
385                 "VNAK   ",
386                 "DPREQ  ",
387                 "DPREP  ",
388                 "DIAL   ",
389                 "TXREQ  ",
390                 "TXCNT  ",
391                 "TXACC  ",
392                 "TXREADY",
393                 "TXREL  ",
394                 "TXREJ  ",
395                 "QUELCH ",
396                 "UNQULCH",
397                 "POKE",
398                 "PAGE",
399                 "MWI",
400                 "UNSUPPORTED",
401                 "TRANSFER",
402                 "PROVISION",
403                 "FWDOWNLD",
404                 "FWDATA"
405         };
406         char *cmds[] = {
407                 "(0?)",
408                 "HANGUP ",
409                 "RING   ",
410                 "RINGING",
411                 "ANSWER ",
412                 "BUSY   ",
413                 "TKOFFHK ",
414                 "OFFHOOK" };
415         struct ast_iax2_full_hdr *fh;
416         char retries[20];
417         char class2[20];
418         char subclass2[20];
419         char *class;
420         char *subclass;
421         char tmp[256];
422         char iabuf[INET_ADDRSTRLEN];
423         if (f) {
424                 fh = f->data;
425                 snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
426         } else {
427                 fh = fhi;
428                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
429                         strcpy(retries, "Yes");
430                 else
431                         strcpy(retries, " No");
432         }
433         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
434                 /* Don't mess with mini-frames */
435                 return;
436         }
437         if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
438                 snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
439                 class = class2;
440         } else {
441                 class = frames[(int)fh->type];
442         }
443         if (fh->type == AST_FRAME_DTMF) {
444                 sprintf(subclass2, "%c", fh->csub);
445                 subclass = subclass2;
446         } else if (fh->type == AST_FRAME_IAX) {
447                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
448                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
449                         subclass = subclass2;
450                 } else {
451                         subclass = iaxs[(int)fh->csub];
452                 }
453         } else if (fh->type == AST_FRAME_CONTROL) {
454                 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
455                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
456                         subclass = subclass2;
457                 } else {
458                         subclass = cmds[(int)fh->csub];
459                 }
460         } else {
461                 snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
462                 subclass = subclass2;
463         }
464 snprintf(tmp, (int)sizeof(tmp), 
465 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
466         (rx ? "Rx" : "Tx"),
467         retries, fh->oseqno, fh->iseqno, class, subclass);
468         outputf(tmp);
469 snprintf(tmp, (int)sizeof(tmp), 
470 "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
471         (unsigned long)ntohl(fh->ts),
472         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
473                 ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
474         outputf(tmp);
475         if (fh->type == AST_FRAME_IAX)
476                 dump_ies(fh->iedata, datalen);
477 }
478
479 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
480 {
481         char tmp[256];
482         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
483                 snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
484                 errorf(tmp);
485                 return -1;
486         }
487         ied->buf[ied->pos++] = ie;
488         ied->buf[ied->pos++] = datalen;
489         memcpy(ied->buf + ied->pos, data, datalen);
490         ied->pos += datalen;
491         return 0;
492 }
493
494 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
495 {
496         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
497 }
498
499 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
500 {
501         unsigned int newval;
502         newval = htonl(value);
503         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
504 }
505
506 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
507 {
508         unsigned short newval;
509         newval = htons(value);
510         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
511 }
512
513 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
514 {
515         return iax_ie_append_raw(ied, ie, str, strlen(str));
516 }
517
518 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
519 {
520         return iax_ie_append_raw(ied, ie, &dat, 1);
521 }
522
523 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
524 {
525         return iax_ie_append_raw(ied, ie, NULL, 0);
526 }
527
528 void iax_set_output(void (*func)(const char *))
529 {
530         outputf = func;
531 }
532
533 void iax_set_error(void (*func)(const char *))
534 {
535         errorf = func;
536 }
537
538 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
539 {
540         /* Parse data into information elements */
541         int len;
542         int ie;
543         char tmp[256];
544         memset(ies, 0, (int)sizeof(struct iax_ies));
545         ies->msgcount = -1;
546         ies->firmwarever = -1;
547         ies->calling_ton = -1;
548         ies->calling_tns = -1;
549         ies->calling_pres = -1;
550         ies->samprate = IAX_RATE_8KHZ;
551         while(datalen >= 2) {
552                 ie = data[0];
553                 len = data[1];
554                 if (len > datalen - 2) {
555                         errorf("Information element length exceeds message size\n");
556                         return -1;
557                 }
558                 switch(ie) {
559                 case IAX_IE_CALLED_NUMBER:
560                         ies->called_number = data + 2;
561                         break;
562                 case IAX_IE_CALLING_NUMBER:
563                         ies->calling_number = data + 2;
564                         break;
565                 case IAX_IE_CALLING_ANI:
566                         ies->calling_ani = data + 2;
567                         break;
568                 case IAX_IE_CALLING_NAME:
569                         ies->calling_name = data + 2;
570                         break;
571                 case IAX_IE_CALLED_CONTEXT:
572                         ies->called_context = data + 2;
573                         break;
574                 case IAX_IE_USERNAME:
575                         ies->username = data + 2;
576                         break;
577                 case IAX_IE_PASSWORD:
578                         ies->password = data + 2;
579                         break;
580                 case IAX_IE_CODEC_PREFS:
581                         ies->codec_prefs = data + 2;
582                         break;
583                 case IAX_IE_CAPABILITY:
584                         if (len != (int)sizeof(unsigned int)) {
585                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
586                                 errorf(tmp);
587                         } else
588                                 ies->capability = ntohl(get_unaligned_uint32(data + 2));
589                         break;
590                 case IAX_IE_FORMAT:
591                         if (len != (int)sizeof(unsigned int)) {
592                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
593                                 errorf(tmp);
594                         } else
595                                 ies->format = ntohl(get_unaligned_uint32(data + 2));
596                         break;
597                 case IAX_IE_LANGUAGE:
598                         ies->language = data + 2;
599                         break;
600                 case IAX_IE_VERSION:
601                         if (len != (int)sizeof(unsigned short)) {
602                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
603                                 errorf(tmp);
604                         } else
605                                 ies->version = ntohs(get_unaligned_uint16(data + 2));
606                         break;
607                 case IAX_IE_ADSICPE:
608                         if (len != (int)sizeof(unsigned short)) {
609                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
610                                 errorf(tmp);
611                         } else
612                                 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
613                         break;
614                 case IAX_IE_SAMPLINGRATE:
615                         if (len != (int)sizeof(unsigned short)) {
616                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
617                                 errorf(tmp);
618                         } else
619                                 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
620                         break;
621                 case IAX_IE_DNID:
622                         ies->dnid = data + 2;
623                         break;
624                 case IAX_IE_RDNIS:
625                         ies->rdnis = data + 2;
626                         break;
627                 case IAX_IE_AUTHMETHODS:
628                         if (len != (int)sizeof(unsigned short))  {
629                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
630                                 errorf(tmp);
631                         } else
632                                 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
633                         break;
634                 case IAX_IE_ENCRYPTION:
635                         if (len != (int)sizeof(unsigned short))  {
636                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
637                                 errorf(tmp);
638                         } else
639                                 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
640                         break;
641                 case IAX_IE_CHALLENGE:
642                         ies->challenge = data + 2;
643                         break;
644                 case IAX_IE_MD5_RESULT:
645                         ies->md5_result = data + 2;
646                         break;
647                 case IAX_IE_RSA_RESULT:
648                         ies->rsa_result = data + 2;
649                         break;
650                 case IAX_IE_APPARENT_ADDR:
651                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
652                         break;
653                 case IAX_IE_REFRESH:
654                         if (len != (int)sizeof(unsigned short)) {
655                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
656                                 errorf(tmp);
657                         } else
658                                 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
659                         break;
660                 case IAX_IE_DPSTATUS:
661                         if (len != (int)sizeof(unsigned short)) {
662                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
663                                 errorf(tmp);
664                         } else
665                                 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
666                         break;
667                 case IAX_IE_CALLNO:
668                         if (len != (int)sizeof(unsigned short)) {
669                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
670                                 errorf(tmp);
671                         } else
672                                 ies->callno = ntohs(get_unaligned_uint16(data + 2));
673                         break;
674                 case IAX_IE_CAUSE:
675                         ies->cause = data + 2;
676                         break;
677                 case IAX_IE_CAUSECODE:
678                         if (len != 1) {
679                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
680                                 errorf(tmp);
681                         } else {
682                                 ies->causecode = data[2];
683                         }
684                         break;
685                 case IAX_IE_IAX_UNKNOWN:
686                         if (len == 1)
687                                 ies->iax_unknown = data[2];
688                         else {
689                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
690                                 errorf(tmp);
691                         }
692                         break;
693                 case IAX_IE_MSGCOUNT:
694                         if (len != (int)sizeof(unsigned short)) {
695                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
696                                 errorf(tmp);
697                         } else
698                                 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));  
699                         break;
700                 case IAX_IE_AUTOANSWER:
701                         ies->autoanswer = 1;
702                         break;
703                 case IAX_IE_MUSICONHOLD:
704                         ies->musiconhold = 1;
705                         break;
706                 case IAX_IE_TRANSFERID:
707                         if (len != (int)sizeof(unsigned int)) {
708                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
709                                 errorf(tmp);
710                         } else
711                                 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
712                         break;
713                 case IAX_IE_DATETIME:
714                         if (len != (int)sizeof(unsigned int)) {
715                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
716                                 errorf(tmp);
717                         } else
718                                 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
719                         break;
720                 case IAX_IE_FIRMWAREVER:
721                         if (len != (int)sizeof(unsigned short)) {
722                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
723                                 errorf(tmp);
724                         } else
725                                 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));       
726                         break;
727                 case IAX_IE_DEVICETYPE:
728                         ies->devicetype = data + 2;
729                         break;
730                 case IAX_IE_SERVICEIDENT:
731                         ies->serviceident = data + 2;
732                         break;
733                 case IAX_IE_FWBLOCKDESC:
734                         if (len != (int)sizeof(unsigned int)) {
735                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
736                                 errorf(tmp);
737                         } else
738                                 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
739                         break;
740                 case IAX_IE_FWBLOCKDATA:
741                         ies->fwdata = data + 2;
742                         ies->fwdatalen = len;
743                         break;
744                 case IAX_IE_ENCKEY:
745                         ies->enckey = data + 2;
746                         ies->enckeylen = len;
747                         break;
748                 case IAX_IE_PROVVER:
749                         if (len != (int)sizeof(unsigned int)) {
750                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
751                                 errorf(tmp);
752                         } else {
753                                 ies->provverpres = 1;
754                                 ies->provver = ntohl(get_unaligned_uint32(data + 2));
755                         }
756                         break;
757                 case IAX_IE_CALLINGPRES:
758                         if (len == 1)
759                                 ies->calling_pres = data[2];
760                         else {
761                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
762                                 errorf(tmp);
763                         }
764                         break;
765                 case IAX_IE_CALLINGTON:
766                         if (len == 1)
767                                 ies->calling_ton = data[2];
768                         else {
769                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
770                                 errorf(tmp);
771                         }
772                         break;
773                 case IAX_IE_CALLINGTNS:
774                         if (len != (int)sizeof(unsigned short)) {
775                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
776                                 errorf(tmp);
777                         } else
778                                 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));       
779                         break;
780                case IAX_IE_RR_JITTER:
781                        if (len != (int)sizeof(unsigned int)) {
782                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
783                                errorf(tmp);
784                        } else {
785                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
786                        }
787                        break;
788                case IAX_IE_RR_LOSS:
789                        if (len != (int)sizeof(unsigned int)) {
790                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
791                                errorf(tmp);
792                        } else {
793                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
794                        }
795                        break;
796                case IAX_IE_RR_PKTS:
797                        if (len != (int)sizeof(unsigned int)) {
798                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
799                                errorf(tmp);
800                        } else {
801                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
802                        }
803                        break;
804                case IAX_IE_RR_DELAY:
805                        if (len != (int)sizeof(unsigned short)) {
806                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
807                         errorf(tmp);
808                        } else {
809                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
810                        }
811                        break;
812                 case IAX_IE_RR_DROPPED:
813                         if (len != (int)sizeof(unsigned int)) {
814                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
815                                 errorf(tmp);
816                         } else {
817                                 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
818                         }
819                         break;
820                 case IAX_IE_RR_OOO:
821                         if (len != (int)sizeof(unsigned int)) {
822                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
823                                 errorf(tmp);
824                         } else {
825                                 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
826                         }
827                         break;
828                 default:
829                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
830                         outputf(tmp);
831                 }
832                 /* Overwrite information element with 0, to null terminate previous portion */
833                 data[0] = 0;
834                 datalen -= (len + 2);
835                 data += (len + 2);
836         }
837         /* Null-terminate last field */
838         *data = '\0';
839         if (datalen) {
840                 errorf("Invalid information element contents, strange boundary\n");
841                 return -1;
842         }
843         return 0;
844 }
845
846 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
847 {
848         fr->af.frametype = f->frametype;
849         fr->af.subclass = f->subclass;
850         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
851         fr->af.datalen = f->datalen;
852         fr->af.samples = f->samples;
853         fr->af.offset = AST_FRIENDLY_OFFSET;
854         fr->af.src = f->src;
855         fr->af.delivery.tv_sec = 0;
856         fr->af.delivery.tv_usec = 0;
857         fr->af.data = fr->afdata;
858         if (fr->af.datalen) {
859 #if __BYTE_ORDER == __LITTLE_ENDIAN
860                 /* We need to byte-swap slinear samples from network byte order */
861                 if (fr->af.subclass == AST_FORMAT_SLINEAR) {
862                         ast_swapcopy_samples(fr->af.data, f->data, fr->af.samples);
863                 } else
864 #endif
865                 memcpy(fr->af.data, f->data, fr->af.datalen);
866         }
867 }
868
869 struct iax_frame *iax_frame_new(int direction, int datalen)
870 {
871         struct iax_frame *fr;
872         fr = malloc((int)sizeof(struct iax_frame) + datalen);
873         if (fr) {
874                 fr->direction = direction;
875                 fr->retrans = -1;
876                 frames++;
877                 if (fr->direction == DIRECTION_INGRESS)
878                         iframes++;
879                 else
880                         oframes++;
881         }
882         return fr;
883 }
884
885 void iax_frame_free(struct iax_frame *fr)
886 {
887         /* Note: does not remove from scheduler! */
888         if (fr->direction == DIRECTION_INGRESS)
889                 iframes--;
890         else if (fr->direction == DIRECTION_OUTGRESS)
891                 oframes--;
892         else {
893                 errorf("Attempt to double free frame detected\n");
894                 return;
895         }
896         fr->direction = 0;
897         free(fr);
898         frames--;
899 }
900
901 int iax_get_frames(void) { return frames; }
902 int iax_get_iframes(void) { return iframes; }
903 int iax_get_oframes(void) { return oframes; }