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