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