Add iax2 parsing for TNS/TON/PRES
[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 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         { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
162         { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
163         { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
164 };
165
166 static struct iax2_ie prov_ies[] = {
167         { PROV_IE_USEDHCP, "USEDHCP" },
168         { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
169         { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
170         { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
171         { PROV_IE_PORTNO, "BINDPORT", dump_short },
172         { PROV_IE_USER, "USERNAME", dump_string },
173         { PROV_IE_PASS, "PASSWORD", dump_string },
174         { PROV_IE_LANG, "LANGUAGE", dump_string },
175         { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
176         { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
177         { PROV_IE_FORMAT, "FORMAT", dump_int },
178         { PROV_IE_AESKEY, "AESKEY" },
179         { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
180         { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
181         { PROV_IE_NEWAESKEY, "NEWAESKEY" },
182         { PROV_IE_PROVVER, "PROV VERSION", dump_int },
183         { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
184 };
185
186 const char *iax_ie2str(int ie)
187 {
188         int x;
189         for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
190                 if (ies[x].ie == ie)
191                         return ies[x].name;
192         }
193         return "Unknown IE";
194 }
195
196
197 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
198 {
199         int ielen;
200         int ie;
201         int x;
202         int found;
203         char interp[80];
204         char tmp[256];
205         if (len < 2)
206                 return;
207         strcpy(output, "\n"); 
208         maxlen -= strlen(output); output += strlen(output);
209         while(len > 2) {
210                 ie = iedata[0];
211                 ielen = iedata[1];
212                 if (ielen + 2> len) {
213                         snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
214                         strncpy(output, tmp, maxlen - 1);
215                         maxlen -= strlen(output); output += strlen(output);
216                         return;
217                 }
218                 found = 0;
219                 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
220                         if (prov_ies[x].ie == ie) {
221                                 if (prov_ies[x].dump) {
222                                         prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
223                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
224                                         strncpy(output, tmp, maxlen - 1);
225                                         maxlen -= strlen(output); output += strlen(output);
226                                 } else {
227                                         if (ielen)
228                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
229                                         else
230                                                 strcpy(interp, "Present");
231                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
232                                         strncpy(output, tmp, maxlen - 1);
233                                         maxlen -= strlen(output); output += strlen(output);
234                                 }
235                                 found++;
236                         }
237                 }
238                 if (!found) {
239                         snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
240                         strncpy(output, tmp, maxlen - 1);
241                         maxlen -= strlen(output); output += strlen(output);
242                 }
243                 iedata += (2 + ielen);
244                 len -= (2 + ielen);
245         }
246 }
247
248 static void dump_ies(unsigned char *iedata, int len)
249 {
250         int ielen;
251         int ie;
252         int x;
253         int found;
254         char interp[1024];
255         char tmp[1024];
256         if (len < 2)
257                 return;
258         while(len > 2) {
259                 ie = iedata[0];
260                 ielen = iedata[1];
261                 if (ielen + 2> len) {
262                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
263                         outputf(tmp);
264                         return;
265                 }
266                 found = 0;
267                 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
268                         if (ies[x].ie == ie) {
269                                 if (ies[x].dump) {
270                                         ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
271                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
272                                         outputf(tmp);
273                                 } else {
274                                         if (ielen)
275                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
276                                         else
277                                                 strcpy(interp, "Present");
278                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
279                                         outputf(tmp);
280                                 }
281                                 found++;
282                         }
283                 }
284                 if (!found) {
285                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
286                         outputf(tmp);
287                 }
288                 iedata += (2 + ielen);
289                 len -= (2 + ielen);
290         }
291         outputf("\n");
292 }
293
294 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
295 {
296         char *frames[] = {
297                 "(0?)",
298                 "DTMF   ",
299                 "VOICE  ",
300                 "VIDEO  ",
301                 "CONTROL",
302                 "NULL   ",
303                 "IAX    ",
304                 "TEXT   ",
305                 "IMAGE  " };
306         char *iaxs[] = {
307                 "(0?)",
308                 "NEW    ",
309                 "PING   ",
310                 "PONG   ",
311                 "ACK    ",
312                 "HANGUP ",
313                 "REJECT ",
314                 "ACCEPT ",
315                 "AUTHREQ",
316                 "AUTHREP",
317                 "INVAL  ",
318                 "LAGRQ  ",
319                 "LAGRP  ",
320                 "REGREQ ",
321                 "REGAUTH",
322                 "REGACK ",
323                 "REGREJ ",
324                 "REGREL ",
325                 "VNAK   ",
326                 "DPREQ  ",
327                 "DPREP  ",
328                 "DIAL   ",
329                 "TXREQ  ",
330                 "TXCNT  ",
331                 "TXACC  ",
332                 "TXREADY",
333                 "TXREL  ",
334                 "TXREJ  ",
335                 "QUELCH ",
336                 "UNQULCH",
337                 "POKE",
338                 "PAGE",
339                 "MWI",
340                 "UNSUPPORTED",
341                 "TRANSFER",
342                 "PROVISION",
343                 "FWDOWNLD",
344                 "FWDATA"
345         };
346         char *cmds[] = {
347                 "(0?)",
348                 "HANGUP ",
349                 "RING   ",
350                 "RINGING",
351                 "ANSWER ",
352                 "BUSY   ",
353                 "TKOFFHK ",
354                 "OFFHOOK" };
355         struct ast_iax2_full_hdr *fh;
356         char retries[20];
357         char class2[20];
358         char subclass2[20];
359         char *class;
360         char *subclass;
361         char tmp[256];
362         char iabuf[INET_ADDRSTRLEN];
363         if (f) {
364                 fh = f->data;
365                 snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
366         } else {
367                 fh = fhi;
368                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
369                         strcpy(retries, "Yes");
370                 else
371                         strcpy(retries, " No");
372         }
373         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
374                 /* Don't mess with mini-frames */
375                 return;
376         }
377         if (fh->type > (int)sizeof(frames)/(int)sizeof(char *)) {
378                 snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
379                 class = class2;
380         } else {
381                 class = frames[(int)fh->type];
382         }
383         if (fh->type == AST_FRAME_DTMF) {
384                 sprintf(subclass2, "%c", fh->csub);
385                 subclass = subclass2;
386         } else if (fh->type == AST_FRAME_IAX) {
387                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
388                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
389                         subclass = subclass2;
390                 } else {
391                         subclass = iaxs[(int)fh->csub];
392                 }
393         } else if (fh->type == AST_FRAME_CONTROL) {
394                 if (fh->csub > (int)sizeof(cmds)/(int)sizeof(char *)) {
395                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
396                         subclass = subclass2;
397                 } else {
398                         subclass = cmds[(int)fh->csub];
399                 }
400         } else {
401                 snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
402                 subclass = subclass2;
403         }
404 snprintf(tmp, (int)sizeof(tmp), 
405 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
406         (rx ? "Rx" : "Tx"),
407         retries, fh->oseqno, fh->iseqno, class, subclass);
408         outputf(tmp);
409 snprintf(tmp, (int)sizeof(tmp), 
410 "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
411         (unsigned long)ntohl(fh->ts),
412         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
413                 ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
414         outputf(tmp);
415         if (fh->type == AST_FRAME_IAX)
416                 dump_ies(fh->iedata, datalen);
417 }
418
419 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
420 {
421         char tmp[256];
422         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
423                 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);
424                 errorf(tmp);
425                 return -1;
426         }
427         ied->buf[ied->pos++] = ie;
428         ied->buf[ied->pos++] = datalen;
429         memcpy(ied->buf + ied->pos, data, datalen);
430         ied->pos += datalen;
431         return 0;
432 }
433
434 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
435 {
436         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
437 }
438
439 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
440 {
441         unsigned int newval;
442         newval = htonl(value);
443         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
444 }
445
446 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
447 {
448         unsigned short newval;
449         newval = htons(value);
450         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
451 }
452
453 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
454 {
455         return iax_ie_append_raw(ied, ie, str, strlen(str));
456 }
457
458 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
459 {
460         return iax_ie_append_raw(ied, ie, &dat, 1);
461 }
462
463 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
464 {
465         return iax_ie_append_raw(ied, ie, NULL, 0);
466 }
467
468 void iax_set_output(void (*func)(const char *))
469 {
470         outputf = func;
471 }
472
473 void iax_set_error(void (*func)(const char *))
474 {
475         errorf = func;
476 }
477
478 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
479 {
480         /* Parse data into information elements */
481         int len;
482         int ie;
483         char tmp[256];
484         memset(ies, 0, (int)sizeof(struct iax_ies));
485         ies->msgcount = -1;
486         ies->firmwarever = -1;
487         ies->calling_ton = -1;
488         ies->calling_tns = -1;
489         ies->calling_pres = -1;
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 = data + 2;
500                         break;
501                 case IAX_IE_CALLING_NUMBER:
502                         ies->calling_number = data + 2;
503                         break;
504                 case IAX_IE_CALLING_ANI:
505                         ies->calling_ani = data + 2;
506                         break;
507                 case IAX_IE_CALLING_NAME:
508                         ies->calling_name = data + 2;
509                         break;
510                 case IAX_IE_CALLED_CONTEXT:
511                         ies->called_context = data + 2;
512                         break;
513                 case IAX_IE_USERNAME:
514                         ies->username = data + 2;
515                         break;
516                 case IAX_IE_PASSWORD:
517                         ies->password = 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(*((unsigned int *)(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(*((unsigned int *)(data + 2)));
532                         break;
533                 case IAX_IE_LANGUAGE:
534                         ies->language = data + 2;
535                         break;
536                 case IAX_IE_VERSION:
537                         if (len != (int)sizeof(unsigned short)) {
538                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
539                                 errorf(tmp);
540                         } else
541                                 ies->version = ntohs(*((unsigned short *)(data + 2)));
542                         break;
543                 case IAX_IE_ADSICPE:
544                         if (len != (int)sizeof(unsigned short)) {
545                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
546                                 errorf(tmp);
547                         } else
548                                 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
549                         break;
550                 case IAX_IE_DNID:
551                         ies->dnid = data + 2;
552                         break;
553                 case IAX_IE_RDNIS:
554                         ies->rdnis = data + 2;
555                         break;
556                 case IAX_IE_AUTHMETHODS:
557                         if (len != (int)sizeof(unsigned short))  {
558                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
559                                 errorf(tmp);
560                         } else
561                                 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
562                         break;
563                 case IAX_IE_CHALLENGE:
564                         ies->challenge = data + 2;
565                         break;
566                 case IAX_IE_MD5_RESULT:
567                         ies->md5_result = data + 2;
568                         break;
569                 case IAX_IE_RSA_RESULT:
570                         ies->rsa_result = data + 2;
571                         break;
572                 case IAX_IE_APPARENT_ADDR:
573                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
574                         break;
575                 case IAX_IE_REFRESH:
576                         if (len != (int)sizeof(unsigned short)) {
577                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
578                                 errorf(tmp);
579                         } else
580                                 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
581                         break;
582                 case IAX_IE_DPSTATUS:
583                         if (len != (int)sizeof(unsigned short)) {
584                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
585                                 errorf(tmp);
586                         } else
587                                 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
588                         break;
589                 case IAX_IE_CALLNO:
590                         if (len != (int)sizeof(unsigned short)) {
591                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
592                                 errorf(tmp);
593                         } else
594                                 ies->callno = ntohs(*((unsigned short *)(data + 2)));
595                         break;
596                 case IAX_IE_CAUSE:
597                         ies->cause = data + 2;
598                         break;
599                 case IAX_IE_IAX_UNKNOWN:
600                         if (len == 1)
601                                 ies->iax_unknown = data[2];
602                         else {
603                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
604                                 errorf(tmp);
605                         }
606                         break;
607                 case IAX_IE_MSGCOUNT:
608                         if (len != (int)sizeof(unsigned short)) {
609                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
610                                 errorf(tmp);
611                         } else
612                                 ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
613                         break;
614                 case IAX_IE_AUTOANSWER:
615                         ies->autoanswer = 1;
616                         break;
617                 case IAX_IE_MUSICONHOLD:
618                         ies->musiconhold = 1;
619                         break;
620                 case IAX_IE_TRANSFERID:
621                         if (len != (int)sizeof(unsigned int)) {
622                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
623                                 errorf(tmp);
624                         } else
625                                 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
626                         break;
627                 case IAX_IE_DATETIME:
628                         if (len != (int)sizeof(unsigned int)) {
629                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
630                                 errorf(tmp);
631                         } else
632                                 ies->datetime = ntohl(*((unsigned int *)(data + 2)));
633                         break;
634                 case IAX_IE_FIRMWAREVER:
635                         if (len != (int)sizeof(unsigned short)) {
636                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
637                                 errorf(tmp);
638                         } else
639                                 ies->firmwarever = ntohs(*((unsigned short *)(data + 2)));      
640                         break;
641                 case IAX_IE_DEVICETYPE:
642                         ies->devicetype = data + 2;
643                         break;
644                 case IAX_IE_SERVICEIDENT:
645                         ies->serviceident = data + 2;
646                         break;
647                 case IAX_IE_FWBLOCKDESC:
648                         if (len != (int)sizeof(unsigned int)) {
649                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
650                                 errorf(tmp);
651                         } else
652                                 ies->fwdesc = ntohl(*((unsigned int *)(data + 2)));
653                         break;
654                 case IAX_IE_FWBLOCKDATA:
655                         ies->fwdata = data + 2;
656                         ies->fwdatalen = len;
657                         break;
658                 case IAX_IE_PROVVER:
659                         if (len != (int)sizeof(unsigned int)) {
660                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
661                                 errorf(tmp);
662                         } else {
663                                 ies->provverpres = 1;
664                                 ies->provver = ntohl(*((unsigned int *)(data + 2)));
665                         }
666                         break;
667                 case IAX_IE_CALLINGPRES:
668                         if (len == 1)
669                                 ies->calling_pres = data[2];
670                         else {
671                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
672                                 errorf(tmp);
673                         }
674                         break;
675                 case IAX_IE_CALLINGTON:
676                         if (len == 1)
677                                 ies->calling_ton = data[2];
678                         else {
679                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
680                                 errorf(tmp);
681                         }
682                         break;
683                 case IAX_IE_CALLINGTNS:
684                         if (len != (int)sizeof(unsigned short)) {
685                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
686                                 errorf(tmp);
687                         } else
688                                 ies->calling_tns = ntohs(*((unsigned short *)(data + 2)));      
689                         break;
690                 default:
691                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
692                         outputf(tmp);
693                 }
694                 /* Overwrite information element with 0, to null terminate previous portion */
695                 data[0] = 0;
696                 datalen -= (len + 2);
697                 data += (len + 2);
698         }
699         /* Null-terminate last field */
700         *data = '\0';
701         if (datalen) {
702                 errorf("Invalid information element contents, strange boundary\n");
703                 return -1;
704         }
705         return 0;
706 }
707
708 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
709 {
710         fr->af.frametype = f->frametype;
711         fr->af.subclass = f->subclass;
712         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
713         fr->af.datalen = f->datalen;
714         fr->af.samples = f->samples;
715         fr->af.offset = AST_FRIENDLY_OFFSET;
716         fr->af.src = f->src;
717         fr->af.delivery.tv_sec = 0;
718         fr->af.delivery.tv_usec = 0;
719         fr->af.data = fr->afdata;
720         if (fr->af.datalen) 
721                 memcpy(fr->af.data, f->data, fr->af.datalen);
722 }
723
724 struct iax_frame *iax_frame_new(int direction, int datalen)
725 {
726         struct iax_frame *fr;
727         fr = malloc((int)sizeof(struct iax_frame) + datalen);
728         if (fr) {
729                 fr->direction = direction;
730                 fr->retrans = -1;
731                 frames++;
732                 if (fr->direction == DIRECTION_INGRESS)
733                         iframes++;
734                 else
735                         oframes++;
736         }
737         return fr;
738 }
739
740 void iax_frame_free(struct iax_frame *fr)
741 {
742         /* Note: does not remove from scheduler! */
743         if (fr->direction == DIRECTION_INGRESS)
744                 iframes--;
745         else if (fr->direction == DIRECTION_OUTGRESS)
746                 oframes--;
747         else {
748                 errorf("Attempt to double free frame detected\n");
749                 return;
750         }
751         fr->direction = 0;
752         free(fr);
753         frames--;
754 }
755
756 int iax_get_frames(void) { return frames; }
757 int iax_get_iframes(void) { return iframes; }
758 int iax_get_oframes(void) { return oframes; }