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