Fix queue URL passing (bug #3543)
[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                 "HTML   ",
380                 "CNG    " };
381         char *iaxs[] = {
382                 "(0?)",
383                 "NEW    ",
384                 "PING   ",
385                 "PONG   ",
386                 "ACK    ",
387                 "HANGUP ",
388                 "REJECT ",
389                 "ACCEPT ",
390                 "AUTHREQ",
391                 "AUTHREP",
392                 "INVAL  ",
393                 "LAGRQ  ",
394                 "LAGRP  ",
395                 "REGREQ ",
396                 "REGAUTH",
397                 "REGACK ",
398                 "REGREJ ",
399                 "REGREL ",
400                 "VNAK   ",
401                 "DPREQ  ",
402                 "DPREP  ",
403                 "DIAL   ",
404                 "TXREQ  ",
405                 "TXCNT  ",
406                 "TXACC  ",
407                 "TXREADY",
408                 "TXREL  ",
409                 "TXREJ  ",
410                 "QUELCH ",
411                 "UNQULCH",
412                 "POKE",
413                 "PAGE",
414                 "MWI",
415                 "UNSUPPORTED",
416                 "TRANSFER",
417                 "PROVISION",
418                 "FWDOWNLD",
419                 "FWDATA"
420         };
421         char *cmds[] = {
422                 "(0?)",
423                 "HANGUP ",
424                 "RING   ",
425                 "RINGING",
426                 "ANSWER ",
427                 "BUSY   ",
428                 "TKOFFHK ",
429                 "OFFHOOK" };
430         struct ast_iax2_full_hdr *fh;
431         char retries[20];
432         char class2[20];
433         char subclass2[20];
434         char *class;
435         char *subclass;
436         char tmp[256];
437         char iabuf[INET_ADDRSTRLEN];
438         if (f) {
439                 fh = f->data;
440                 snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
441         } else {
442                 fh = fhi;
443                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
444                         strcpy(retries, "Yes");
445                 else
446                         strcpy(retries, " No");
447         }
448         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
449                 /* Don't mess with mini-frames */
450                 return;
451         }
452         if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
453                 snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
454                 class = class2;
455         } else {
456                 class = frames[(int)fh->type];
457         }
458         if (fh->type == AST_FRAME_DTMF) {
459                 sprintf(subclass2, "%c", fh->csub);
460                 subclass = subclass2;
461         } else if (fh->type == AST_FRAME_IAX) {
462                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
463                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
464                         subclass = subclass2;
465                 } else {
466                         subclass = iaxs[(int)fh->csub];
467                 }
468         } else if (fh->type == AST_FRAME_CONTROL) {
469                 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
470                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
471                         subclass = subclass2;
472                 } else {
473                         subclass = cmds[(int)fh->csub];
474                 }
475         } else {
476                 snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
477                 subclass = subclass2;
478         }
479 snprintf(tmp, (int)sizeof(tmp), 
480 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
481         (rx ? "Rx" : "Tx"),
482         retries, fh->oseqno, fh->iseqno, class, subclass);
483         outputf(tmp);
484 snprintf(tmp, (int)sizeof(tmp), 
485 "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
486         (unsigned long)ntohl(fh->ts),
487         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
488                 ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
489         outputf(tmp);
490         if (fh->type == AST_FRAME_IAX)
491                 dump_ies(fh->iedata, datalen);
492 }
493
494 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
495 {
496         char tmp[256];
497         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
498                 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);
499                 errorf(tmp);
500                 return -1;
501         }
502         ied->buf[ied->pos++] = ie;
503         ied->buf[ied->pos++] = datalen;
504         memcpy(ied->buf + ied->pos, data, datalen);
505         ied->pos += datalen;
506         return 0;
507 }
508
509 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
510 {
511         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
512 }
513
514 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
515 {
516         unsigned int newval;
517         newval = htonl(value);
518         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
519 }
520
521 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
522 {
523         unsigned short newval;
524         newval = htons(value);
525         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
526 }
527
528 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
529 {
530         return iax_ie_append_raw(ied, ie, str, strlen(str));
531 }
532
533 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
534 {
535         return iax_ie_append_raw(ied, ie, &dat, 1);
536 }
537
538 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
539 {
540         return iax_ie_append_raw(ied, ie, NULL, 0);
541 }
542
543 void iax_set_output(void (*func)(const char *))
544 {
545         outputf = func;
546 }
547
548 void iax_set_error(void (*func)(const char *))
549 {
550         errorf = func;
551 }
552
553 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
554 {
555         /* Parse data into information elements */
556         int len;
557         int ie;
558         char tmp[256];
559         memset(ies, 0, (int)sizeof(struct iax_ies));
560         ies->msgcount = -1;
561         ies->firmwarever = -1;
562         ies->calling_ton = -1;
563         ies->calling_tns = -1;
564         ies->calling_pres = -1;
565         ies->samprate = IAX_RATE_8KHZ;
566         while(datalen >= 2) {
567                 ie = data[0];
568                 len = data[1];
569                 if (len > datalen - 2) {
570                         errorf("Information element length exceeds message size\n");
571                         return -1;
572                 }
573                 switch(ie) {
574                 case IAX_IE_CALLED_NUMBER:
575                         ies->called_number = data + 2;
576                         break;
577                 case IAX_IE_CALLING_NUMBER:
578                         ies->calling_number = data + 2;
579                         break;
580                 case IAX_IE_CALLING_ANI:
581                         ies->calling_ani = data + 2;
582                         break;
583                 case IAX_IE_CALLING_NAME:
584                         ies->calling_name = data + 2;
585                         break;
586                 case IAX_IE_CALLED_CONTEXT:
587                         ies->called_context = data + 2;
588                         break;
589                 case IAX_IE_USERNAME:
590                         ies->username = data + 2;
591                         break;
592                 case IAX_IE_PASSWORD:
593                         ies->password = data + 2;
594                         break;
595                 case IAX_IE_CODEC_PREFS:
596                         ies->codec_prefs = data + 2;
597                         break;
598                 case IAX_IE_CAPABILITY:
599                         if (len != (int)sizeof(unsigned int)) {
600                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
601                                 errorf(tmp);
602                         } else
603                                 ies->capability = ntohl(get_uint32(data + 2));
604                         break;
605                 case IAX_IE_FORMAT:
606                         if (len != (int)sizeof(unsigned int)) {
607                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
608                                 errorf(tmp);
609                         } else
610                                 ies->format = ntohl(get_uint32(data + 2));
611                         break;
612                 case IAX_IE_LANGUAGE:
613                         ies->language = data + 2;
614                         break;
615                 case IAX_IE_VERSION:
616                         if (len != (int)sizeof(unsigned short)) {
617                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
618                                 errorf(tmp);
619                         } else
620                                 ies->version = ntohs(get_uint16(data + 2));
621                         break;
622                 case IAX_IE_ADSICPE:
623                         if (len != (int)sizeof(unsigned short)) {
624                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
625                                 errorf(tmp);
626                         } else
627                                 ies->adsicpe = ntohs(get_uint16(data + 2));
628                         break;
629                 case IAX_IE_SAMPLINGRATE:
630                         if (len != (int)sizeof(unsigned short)) {
631                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
632                                 errorf(tmp);
633                         } else
634                                 ies->samprate = ntohs(get_uint16(data + 2));
635                         break;
636                 case IAX_IE_DNID:
637                         ies->dnid = data + 2;
638                         break;
639                 case IAX_IE_RDNIS:
640                         ies->rdnis = data + 2;
641                         break;
642                 case IAX_IE_AUTHMETHODS:
643                         if (len != (int)sizeof(unsigned short))  {
644                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
645                                 errorf(tmp);
646                         } else
647                                 ies->authmethods = ntohs(get_uint16(data + 2));
648                         break;
649                 case IAX_IE_ENCRYPTION:
650                         if (len != (int)sizeof(unsigned short))  {
651                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
652                                 errorf(tmp);
653                         } else
654                                 ies->encmethods = ntohs(get_uint16(data + 2));
655                         break;
656                 case IAX_IE_CHALLENGE:
657                         ies->challenge = data + 2;
658                         break;
659                 case IAX_IE_MD5_RESULT:
660                         ies->md5_result = data + 2;
661                         break;
662                 case IAX_IE_RSA_RESULT:
663                         ies->rsa_result = data + 2;
664                         break;
665                 case IAX_IE_APPARENT_ADDR:
666                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
667                         break;
668                 case IAX_IE_REFRESH:
669                         if (len != (int)sizeof(unsigned short)) {
670                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
671                                 errorf(tmp);
672                         } else
673                                 ies->refresh = ntohs(get_uint16(data + 2));
674                         break;
675                 case IAX_IE_DPSTATUS:
676                         if (len != (int)sizeof(unsigned short)) {
677                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
678                                 errorf(tmp);
679                         } else
680                                 ies->dpstatus = ntohs(get_uint16(data + 2));
681                         break;
682                 case IAX_IE_CALLNO:
683                         if (len != (int)sizeof(unsigned short)) {
684                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
685                                 errorf(tmp);
686                         } else
687                                 ies->callno = ntohs(get_uint16(data + 2));
688                         break;
689                 case IAX_IE_CAUSE:
690                         ies->cause = data + 2;
691                         break;
692                 case IAX_IE_CAUSECODE:
693                         if (len != 1) {
694                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
695                                 errorf(tmp);
696                         } else {
697                                 ies->causecode = data[2];
698                         }
699                         break;
700                 case IAX_IE_IAX_UNKNOWN:
701                         if (len == 1)
702                                 ies->iax_unknown = data[2];
703                         else {
704                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
705                                 errorf(tmp);
706                         }
707                         break;
708                 case IAX_IE_MSGCOUNT:
709                         if (len != (int)sizeof(unsigned short)) {
710                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
711                                 errorf(tmp);
712                         } else
713                                 ies->msgcount = ntohs(get_uint16(data + 2));    
714                         break;
715                 case IAX_IE_AUTOANSWER:
716                         ies->autoanswer = 1;
717                         break;
718                 case IAX_IE_MUSICONHOLD:
719                         ies->musiconhold = 1;
720                         break;
721                 case IAX_IE_TRANSFERID:
722                         if (len != (int)sizeof(unsigned int)) {
723                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
724                                 errorf(tmp);
725                         } else
726                                 ies->transferid = ntohl(get_uint32(data + 2));
727                         break;
728                 case IAX_IE_DATETIME:
729                         if (len != (int)sizeof(unsigned int)) {
730                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
731                                 errorf(tmp);
732                         } else
733                                 ies->datetime = ntohl(get_uint32(data + 2));
734                         break;
735                 case IAX_IE_FIRMWAREVER:
736                         if (len != (int)sizeof(unsigned short)) {
737                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
738                                 errorf(tmp);
739                         } else
740                                 ies->firmwarever = ntohs(get_uint16(data + 2)); 
741                         break;
742                 case IAX_IE_DEVICETYPE:
743                         ies->devicetype = data + 2;
744                         break;
745                 case IAX_IE_SERVICEIDENT:
746                         ies->serviceident = data + 2;
747                         break;
748                 case IAX_IE_FWBLOCKDESC:
749                         if (len != (int)sizeof(unsigned int)) {
750                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
751                                 errorf(tmp);
752                         } else
753                                 ies->fwdesc = ntohl(get_uint32(data + 2));
754                         break;
755                 case IAX_IE_FWBLOCKDATA:
756                         ies->fwdata = data + 2;
757                         ies->fwdatalen = len;
758                         break;
759                 case IAX_IE_ENCKEY:
760                         ies->enckey = data + 2;
761                         ies->enckeylen = len;
762                         break;
763                 case IAX_IE_PROVVER:
764                         if (len != (int)sizeof(unsigned int)) {
765                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
766                                 errorf(tmp);
767                         } else {
768                                 ies->provverpres = 1;
769                                 ies->provver = ntohl(get_uint32(data + 2));
770                         }
771                         break;
772                 case IAX_IE_CALLINGPRES:
773                         if (len == 1)
774                                 ies->calling_pres = data[2];
775                         else {
776                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
777                                 errorf(tmp);
778                         }
779                         break;
780                 case IAX_IE_CALLINGTON:
781                         if (len == 1)
782                                 ies->calling_ton = data[2];
783                         else {
784                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
785                                 errorf(tmp);
786                         }
787                         break;
788                 case IAX_IE_CALLINGTNS:
789                         if (len != (int)sizeof(unsigned short)) {
790                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
791                                 errorf(tmp);
792                         } else
793                                 ies->calling_tns = ntohs(get_uint16(data + 2)); 
794                         break;
795                case IAX_IE_RR_JITTER:
796                        if (len != (int)sizeof(unsigned int)) {
797                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
798                                errorf(tmp);
799                        } else {
800                                ies->rr_jitter = ntohl(get_uint32(data + 2));
801                        }
802                        break;
803                case IAX_IE_RR_LOSS:
804                        if (len != (int)sizeof(unsigned int)) {
805                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
806                                errorf(tmp);
807                        } else {
808                                ies->rr_loss = ntohl(get_uint32(data + 2));
809                        }
810                        break;
811                case IAX_IE_RR_PKTS:
812                        if (len != (int)sizeof(unsigned int)) {
813                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
814                                errorf(tmp);
815                        } else {
816                                ies->rr_pkts = ntohl(get_uint32(data + 2));
817                        }
818                        break;
819                case IAX_IE_RR_DELAY:
820                        if (len != (int)sizeof(unsigned short)) {
821                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
822                         errorf(tmp);
823                        } else {
824                                ies->rr_delay = ntohs(get_uint16(data + 2));
825                        }
826                        break;
827                 case IAX_IE_RR_DROPPED:
828                         if (len != (int)sizeof(unsigned int)) {
829                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
830                                 errorf(tmp);
831                         } else {
832                                 ies->rr_dropped = ntohl(get_uint32(data + 2));
833                         }
834                         break;
835                 case IAX_IE_RR_OOO:
836                         if (len != (int)sizeof(unsigned int)) {
837                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
838                                 errorf(tmp);
839                         } else {
840                                 ies->rr_ooo = ntohl(get_uint32(data + 2));
841                         }
842                         break;
843                 default:
844                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
845                         outputf(tmp);
846                 }
847                 /* Overwrite information element with 0, to null terminate previous portion */
848                 data[0] = 0;
849                 datalen -= (len + 2);
850                 data += (len + 2);
851         }
852         /* Null-terminate last field */
853         *data = '\0';
854         if (datalen) {
855                 errorf("Invalid information element contents, strange boundary\n");
856                 return -1;
857         }
858         return 0;
859 }
860
861 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
862 {
863         fr->af.frametype = f->frametype;
864         fr->af.subclass = f->subclass;
865         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
866         fr->af.datalen = f->datalen;
867         fr->af.samples = f->samples;
868         fr->af.offset = AST_FRIENDLY_OFFSET;
869         fr->af.src = f->src;
870         fr->af.delivery.tv_sec = 0;
871         fr->af.delivery.tv_usec = 0;
872         fr->af.data = fr->afdata;
873         if (fr->af.datalen) 
874                 memcpy(fr->af.data, f->data, fr->af.datalen);
875 }
876
877 struct iax_frame *iax_frame_new(int direction, int datalen)
878 {
879         struct iax_frame *fr;
880         fr = malloc((int)sizeof(struct iax_frame) + datalen);
881         if (fr) {
882                 fr->direction = direction;
883                 fr->retrans = -1;
884                 frames++;
885                 if (fr->direction == DIRECTION_INGRESS)
886                         iframes++;
887                 else
888                         oframes++;
889         }
890         return fr;
891 }
892
893 void iax_frame_free(struct iax_frame *fr)
894 {
895         /* Note: does not remove from scheduler! */
896         if (fr->direction == DIRECTION_INGRESS)
897                 iframes--;
898         else if (fr->direction == DIRECTION_OUTGRESS)
899                 oframes--;
900         else {
901                 errorf("Attempt to double free frame detected\n");
902                 return;
903         }
904         fr->direction = 0;
905         free(fr);
906         frames--;
907 }
908
909 int iax_get_frames(void) { return frames; }
910 int iax_get_iframes(void) { return iframes; }
911 int iax_get_oframes(void) { return oframes; }