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