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