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