Merge experimental codec preferences for IAX2 (bug #2971)
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Inter-Asterisk eXchange
5  * 
6  * Copyright (C) 2003-2004, Digium
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <string.h>
17 #include <netinet/in.h>
18 #include <asterisk/frame.h>
19 #include <asterisk/utils.h>
20 #include <arpa/inet.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "iax2.h"
25 #include "iax2-parser.h"
26 #include "iax2-provision.h"
27
28
29 static int frames = 0;
30 static int iframes = 0;
31 static int oframes = 0;
32
33 #ifdef SOLARIS
34 static unsigned int get_uint32(unsigned char *p)
35 {
36   return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
37 }
38
39 static unsigned short get_uint16(unsigned char *p)
40 {
41   return (p[0] << 8) | p[1] ;
42 }
43
44 #else
45 #define get_uint32(p) (*((unsigned int *)(p)))
46 #define get_uint16(p) (*((unsigned short *)(p)))
47 #endif
48
49 static void internaloutput(const char *str)
50 {
51         fputs(str, stdout);
52 }
53
54 static void internalerror(const char *str)
55 {
56         fprintf(stderr, "WARNING: %s", str);
57 }
58
59 static void (*outputf)(const char *str) = internaloutput;
60 static void (*errorf)(const char *str) = internalerror;
61
62 static void dump_addr(char *output, int maxlen, void *value, int len)
63 {
64         struct sockaddr_in sin;
65         char iabuf[INET_ADDRSTRLEN];
66         if (len == (int)sizeof(sin)) {
67                 memcpy(&sin, value, len);
68                 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
69         } else {
70                 snprintf(output, maxlen, "Invalid Address");
71         }
72 }
73
74 static void dump_string(char *output, int maxlen, void *value, int len)
75 {
76         maxlen--;
77         if (maxlen > len)
78                 maxlen = len;
79         strncpy(output,value, maxlen);
80         output[maxlen] = '\0';
81 }
82
83 static void dump_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 };
232
233 static struct iax2_ie prov_ies[] = {
234         { PROV_IE_USEDHCP, "USEDHCP" },
235         { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
236         { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
237         { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
238         { PROV_IE_PORTNO, "BINDPORT", dump_short },
239         { PROV_IE_USER, "USERNAME", dump_string },
240         { PROV_IE_PASS, "PASSWORD", dump_string },
241         { PROV_IE_LANG, "LANGUAGE", dump_string },
242         { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
243         { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
244         { PROV_IE_FORMAT, "FORMAT", dump_int },
245         { PROV_IE_AESKEY, "AESKEY" },
246         { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
247         { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
248         { PROV_IE_NEWAESKEY, "NEWAESKEY" },
249         { PROV_IE_PROVVER, "PROV VERSION", dump_int },
250         { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
251 };
252
253 const char *iax_ie2str(int ie)
254 {
255         int x;
256         for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
257                 if (ies[x].ie == ie)
258                         return ies[x].name;
259         }
260         return "Unknown IE";
261 }
262
263
264 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
265 {
266         int ielen;
267         int ie;
268         int x;
269         int found;
270         char interp[80];
271         char tmp[256];
272         if (len < 2)
273                 return;
274         strcpy(output, "\n"); 
275         maxlen -= strlen(output); output += strlen(output);
276         while(len > 2) {
277                 ie = iedata[0];
278                 ielen = iedata[1];
279                 if (ielen + 2> len) {
280                         snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
281                         strncpy(output, tmp, maxlen - 1);
282                         maxlen -= strlen(output); output += strlen(output);
283                         return;
284                 }
285                 found = 0;
286                 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
287                         if (prov_ies[x].ie == ie) {
288                                 if (prov_ies[x].dump) {
289                                         prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
290                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
291                                         strncpy(output, tmp, maxlen - 1);
292                                         maxlen -= strlen(output); output += strlen(output);
293                                 } else {
294                                         if (ielen)
295                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
296                                         else
297                                                 strcpy(interp, "Present");
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                                 }
302                                 found++;
303                         }
304                 }
305                 if (!found) {
306                         snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
307                         strncpy(output, tmp, maxlen - 1);
308                         maxlen -= strlen(output); output += strlen(output);
309                 }
310                 iedata += (2 + ielen);
311                 len -= (2 + ielen);
312         }
313 }
314
315 static void dump_ies(unsigned char *iedata, int len)
316 {
317         int ielen;
318         int ie;
319         int x;
320         int found;
321         char interp[1024];
322         char tmp[1024];
323         if (len < 2)
324                 return;
325         while(len > 2) {
326                 ie = iedata[0];
327                 ielen = iedata[1];
328                 if (ielen + 2> len) {
329                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
330                         outputf(tmp);
331                         return;
332                 }
333                 found = 0;
334                 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
335                         if (ies[x].ie == ie) {
336                                 if (ies[x].dump) {
337                                         ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
338                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
339                                         outputf(tmp);
340                                 } else {
341                                         if (ielen)
342                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
343                                         else
344                                                 strcpy(interp, "Present");
345                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
346                                         outputf(tmp);
347                                 }
348                                 found++;
349                         }
350                 }
351                 if (!found) {
352                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
353                         outputf(tmp);
354                 }
355                 iedata += (2 + ielen);
356                 len -= (2 + ielen);
357         }
358         outputf("\n");
359 }
360
361 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
362 {
363         char *frames[] = {
364                 "(0?)",
365                 "DTMF   ",
366                 "VOICE  ",
367                 "VIDEO  ",
368                 "CONTROL",
369                 "NULL   ",
370                 "IAX    ",
371                 "TEXT   ",
372                 "IMAGE  " };
373         char *iaxs[] = {
374                 "(0?)",
375                 "NEW    ",
376                 "PING   ",
377                 "PONG   ",
378                 "ACK    ",
379                 "HANGUP ",
380                 "REJECT ",
381                 "ACCEPT ",
382                 "AUTHREQ",
383                 "AUTHREP",
384                 "INVAL  ",
385                 "LAGRQ  ",
386                 "LAGRP  ",
387                 "REGREQ ",
388                 "REGAUTH",
389                 "REGACK ",
390                 "REGREJ ",
391                 "REGREL ",
392                 "VNAK   ",
393                 "DPREQ  ",
394                 "DPREP  ",
395                 "DIAL   ",
396                 "TXREQ  ",
397                 "TXCNT  ",
398                 "TXACC  ",
399                 "TXREADY",
400                 "TXREL  ",
401                 "TXREJ  ",
402                 "QUELCH ",
403                 "UNQULCH",
404                 "POKE",
405                 "PAGE",
406                 "MWI",
407                 "UNSUPPORTED",
408                 "TRANSFER",
409                 "PROVISION",
410                 "FWDOWNLD",
411                 "FWDATA"
412         };
413         char *cmds[] = {
414                 "(0?)",
415                 "HANGUP ",
416                 "RING   ",
417                 "RINGING",
418                 "ANSWER ",
419                 "BUSY   ",
420                 "TKOFFHK ",
421                 "OFFHOOK" };
422         struct ast_iax2_full_hdr *fh;
423         char retries[20];
424         char class2[20];
425         char subclass2[20];
426         char *class;
427         char *subclass;
428         char tmp[256];
429         char iabuf[INET_ADDRSTRLEN];
430         if (f) {
431                 fh = f->data;
432                 snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
433         } else {
434                 fh = fhi;
435                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
436                         strcpy(retries, "Yes");
437                 else
438                         strcpy(retries, " No");
439         }
440         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
441                 /* Don't mess with mini-frames */
442                 return;
443         }
444         if (fh->type > (int)sizeof(frames)/(int)sizeof(frames[0])) {
445                 snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
446                 class = class2;
447         } else {
448                 class = frames[(int)fh->type];
449         }
450         if (fh->type == AST_FRAME_DTMF) {
451                 sprintf(subclass2, "%c", fh->csub);
452                 subclass = subclass2;
453         } else if (fh->type == AST_FRAME_IAX) {
454                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
455                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
456                         subclass = subclass2;
457                 } else {
458                         subclass = iaxs[(int)fh->csub];
459                 }
460         } else if (fh->type == AST_FRAME_CONTROL) {
461                 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
462                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
463                         subclass = subclass2;
464                 } else {
465                         subclass = cmds[(int)fh->csub];
466                 }
467         } else {
468                 snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
469                 subclass = subclass2;
470         }
471 snprintf(tmp, (int)sizeof(tmp), 
472 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
473         (rx ? "Rx" : "Tx"),
474         retries, fh->oseqno, fh->iseqno, class, subclass);
475         outputf(tmp);
476 snprintf(tmp, (int)sizeof(tmp), 
477 "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
478         (unsigned long)ntohl(fh->ts),
479         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
480                 ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
481         outputf(tmp);
482         if (fh->type == AST_FRAME_IAX)
483                 dump_ies(fh->iedata, datalen);
484 }
485
486 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
487 {
488         char tmp[256];
489         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
490                 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);
491                 errorf(tmp);
492                 return -1;
493         }
494         ied->buf[ied->pos++] = ie;
495         ied->buf[ied->pos++] = datalen;
496         memcpy(ied->buf + ied->pos, data, datalen);
497         ied->pos += datalen;
498         return 0;
499 }
500
501 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
502 {
503         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
504 }
505
506 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
507 {
508         unsigned int newval;
509         newval = htonl(value);
510         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
511 }
512
513 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
514 {
515         unsigned short newval;
516         newval = htons(value);
517         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
518 }
519
520 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
521 {
522         return iax_ie_append_raw(ied, ie, str, strlen(str));
523 }
524
525 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
526 {
527         return iax_ie_append_raw(ied, ie, &dat, 1);
528 }
529
530 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
531 {
532         return iax_ie_append_raw(ied, ie, NULL, 0);
533 }
534
535 void iax_set_output(void (*func)(const char *))
536 {
537         outputf = func;
538 }
539
540 void iax_set_error(void (*func)(const char *))
541 {
542         errorf = func;
543 }
544
545 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
546 {
547         /* Parse data into information elements */
548         int len;
549         int ie;
550         char tmp[256];
551         memset(ies, 0, (int)sizeof(struct iax_ies));
552         ies->msgcount = -1;
553         ies->firmwarever = -1;
554         ies->calling_ton = -1;
555         ies->calling_tns = -1;
556         ies->calling_pres = -1;
557         ies->samprate = IAX_RATE_8KHZ;
558         while(datalen >= 2) {
559                 ie = data[0];
560                 len = data[1];
561                 if (len > datalen - 2) {
562                         errorf("Information element length exceeds message size\n");
563                         return -1;
564                 }
565                 switch(ie) {
566                 case IAX_IE_CALLED_NUMBER:
567                         ies->called_number = data + 2;
568                         break;
569                 case IAX_IE_CALLING_NUMBER:
570                         ies->calling_number = data + 2;
571                         break;
572                 case IAX_IE_CALLING_ANI:
573                         ies->calling_ani = data + 2;
574                         break;
575                 case IAX_IE_CALLING_NAME:
576                         ies->calling_name = data + 2;
577                         break;
578                 case IAX_IE_CALLED_CONTEXT:
579                         ies->called_context = data + 2;
580                         break;
581                 case IAX_IE_USERNAME:
582                         ies->username = data + 2;
583                         break;
584                 case IAX_IE_PASSWORD:
585                         ies->password = data + 2;
586                         break;
587                 case IAX_IE_CODEC_PREFS:
588                         ies->codec_prefs = data + 2;
589                         break;
590                 case IAX_IE_CAPABILITY:
591                         if (len != (int)sizeof(unsigned int)) {
592                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
593                                 errorf(tmp);
594                         } else
595                                 ies->capability = ntohl(get_uint32(data + 2));
596                         break;
597                 case IAX_IE_FORMAT:
598                         if (len != (int)sizeof(unsigned int)) {
599                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
600                                 errorf(tmp);
601                         } else
602                                 ies->format = ntohl(get_uint32(data + 2));
603                         break;
604                 case IAX_IE_LANGUAGE:
605                         ies->language = data + 2;
606                         break;
607                 case IAX_IE_VERSION:
608                         if (len != (int)sizeof(unsigned short)) {
609                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
610                                 errorf(tmp);
611                         } else
612                                 ies->version = ntohs(get_uint16(data + 2));
613                         break;
614                 case IAX_IE_ADSICPE:
615                         if (len != (int)sizeof(unsigned short)) {
616                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
617                                 errorf(tmp);
618                         } else
619                                 ies->adsicpe = ntohs(get_uint16(data + 2));
620                         break;
621                 case IAX_IE_SAMPLINGRATE:
622                         if (len != (int)sizeof(unsigned short)) {
623                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
624                                 errorf(tmp);
625                         } else
626                                 ies->samprate = ntohs(get_uint16(data + 2));
627                         break;
628                 case IAX_IE_DNID:
629                         ies->dnid = data + 2;
630                         break;
631                 case IAX_IE_RDNIS:
632                         ies->rdnis = data + 2;
633                         break;
634                 case IAX_IE_AUTHMETHODS:
635                         if (len != (int)sizeof(unsigned short))  {
636                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
637                                 errorf(tmp);
638                         } else
639                                 ies->authmethods = ntohs(get_uint16(data + 2));
640                         break;
641                 case IAX_IE_ENCRYPTION:
642                         if (len != (int)sizeof(unsigned short))  {
643                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
644                                 errorf(tmp);
645                         } else
646                                 ies->encmethods = ntohs(get_uint16(data + 2));
647                         break;
648                 case IAX_IE_CHALLENGE:
649                         ies->challenge = data + 2;
650                         break;
651                 case IAX_IE_MD5_RESULT:
652                         ies->md5_result = data + 2;
653                         break;
654                 case IAX_IE_RSA_RESULT:
655                         ies->rsa_result = data + 2;
656                         break;
657                 case IAX_IE_APPARENT_ADDR:
658                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
659                         break;
660                 case IAX_IE_REFRESH:
661                         if (len != (int)sizeof(unsigned short)) {
662                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
663                                 errorf(tmp);
664                         } else
665                                 ies->refresh = ntohs(get_uint16(data + 2));
666                         break;
667                 case IAX_IE_DPSTATUS:
668                         if (len != (int)sizeof(unsigned short)) {
669                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
670                                 errorf(tmp);
671                         } else
672                                 ies->dpstatus = ntohs(get_uint16(data + 2));
673                         break;
674                 case IAX_IE_CALLNO:
675                         if (len != (int)sizeof(unsigned short)) {
676                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
677                                 errorf(tmp);
678                         } else
679                                 ies->callno = ntohs(get_uint16(data + 2));
680                         break;
681                 case IAX_IE_CAUSE:
682                         ies->cause = data + 2;
683                         break;
684                 case IAX_IE_CAUSECODE:
685                         if (len != 1) {
686                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
687                                 errorf(tmp);
688                         } else {
689                                 ies->causecode = data[2];
690                         }
691                         break;
692                 case IAX_IE_IAX_UNKNOWN:
693                         if (len == 1)
694                                 ies->iax_unknown = data[2];
695                         else {
696                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
697                                 errorf(tmp);
698                         }
699                         break;
700                 case IAX_IE_MSGCOUNT:
701                         if (len != (int)sizeof(unsigned short)) {
702                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
703                                 errorf(tmp);
704                         } else
705                                 ies->msgcount = ntohs(get_uint16(data + 2));    
706                         break;
707                 case IAX_IE_AUTOANSWER:
708                         ies->autoanswer = 1;
709                         break;
710                 case IAX_IE_MUSICONHOLD:
711                         ies->musiconhold = 1;
712                         break;
713                 case IAX_IE_TRANSFERID:
714                         if (len != (int)sizeof(unsigned int)) {
715                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
716                                 errorf(tmp);
717                         } else
718                                 ies->transferid = ntohl(get_uint32(data + 2));
719                         break;
720                 case IAX_IE_DATETIME:
721                         if (len != (int)sizeof(unsigned int)) {
722                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
723                                 errorf(tmp);
724                         } else
725                                 ies->datetime = ntohl(get_uint32(data + 2));
726                         break;
727                 case IAX_IE_FIRMWAREVER:
728                         if (len != (int)sizeof(unsigned short)) {
729                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
730                                 errorf(tmp);
731                         } else
732                                 ies->firmwarever = ntohs(get_uint16(data + 2)); 
733                         break;
734                 case IAX_IE_DEVICETYPE:
735                         ies->devicetype = data + 2;
736                         break;
737                 case IAX_IE_SERVICEIDENT:
738                         ies->serviceident = data + 2;
739                         break;
740                 case IAX_IE_FWBLOCKDESC:
741                         if (len != (int)sizeof(unsigned int)) {
742                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
743                                 errorf(tmp);
744                         } else
745                                 ies->fwdesc = ntohl(get_uint32(data + 2));
746                         break;
747                 case IAX_IE_FWBLOCKDATA:
748                         ies->fwdata = data + 2;
749                         ies->fwdatalen = len;
750                         break;
751                 case IAX_IE_ENCKEY:
752                         ies->enckey = data + 2;
753                         ies->enckeylen = len;
754                         break;
755                 case IAX_IE_PROVVER:
756                         if (len != (int)sizeof(unsigned int)) {
757                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
758                                 errorf(tmp);
759                         } else {
760                                 ies->provverpres = 1;
761                                 ies->provver = ntohl(get_uint32(data + 2));
762                         }
763                         break;
764                 case IAX_IE_CALLINGPRES:
765                         if (len == 1)
766                                 ies->calling_pres = data[2];
767                         else {
768                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
769                                 errorf(tmp);
770                         }
771                         break;
772                 case IAX_IE_CALLINGTON:
773                         if (len == 1)
774                                 ies->calling_ton = data[2];
775                         else {
776                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
777                                 errorf(tmp);
778                         }
779                         break;
780                 case IAX_IE_CALLINGTNS:
781                         if (len != (int)sizeof(unsigned short)) {
782                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
783                                 errorf(tmp);
784                         } else
785                                 ies->calling_tns = ntohs(get_uint16(data + 2)); 
786                         break;
787                 default:
788                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
789                         outputf(tmp);
790                 }
791                 /* Overwrite information element with 0, to null terminate previous portion */
792                 data[0] = 0;
793                 datalen -= (len + 2);
794                 data += (len + 2);
795         }
796         /* Null-terminate last field */
797         *data = '\0';
798         if (datalen) {
799                 errorf("Invalid information element contents, strange boundary\n");
800                 return -1;
801         }
802         return 0;
803 }
804
805 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
806 {
807         fr->af.frametype = f->frametype;
808         fr->af.subclass = f->subclass;
809         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
810         fr->af.datalen = f->datalen;
811         fr->af.samples = f->samples;
812         fr->af.offset = AST_FRIENDLY_OFFSET;
813         fr->af.src = f->src;
814         fr->af.delivery.tv_sec = 0;
815         fr->af.delivery.tv_usec = 0;
816         fr->af.data = fr->afdata;
817         if (fr->af.datalen) 
818                 memcpy(fr->af.data, f->data, fr->af.datalen);
819 }
820
821 struct iax_frame *iax_frame_new(int direction, int datalen)
822 {
823         struct iax_frame *fr;
824         fr = malloc((int)sizeof(struct iax_frame) + datalen);
825         if (fr) {
826                 fr->direction = direction;
827                 fr->retrans = -1;
828                 frames++;
829                 if (fr->direction == DIRECTION_INGRESS)
830                         iframes++;
831                 else
832                         oframes++;
833         }
834         return fr;
835 }
836
837 void iax_frame_free(struct iax_frame *fr)
838 {
839         /* Note: does not remove from scheduler! */
840         if (fr->direction == DIRECTION_INGRESS)
841                 iframes--;
842         else if (fr->direction == DIRECTION_OUTGRESS)
843                 oframes--;
844         else {
845                 errorf("Attempt to double free frame detected\n");
846                 return;
847         }
848         fr->direction = 0;
849         free(fr);
850         frames--;
851 }
852
853 int iax_get_frames(void) { return frames; }
854 int iax_get_iframes(void) { return iframes; }
855 int iax_get_oframes(void) { return oframes; }