Merged revisions 194557,194685 via svnmerge from
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Implementation of Inter-Asterisk eXchange Protocol, v 2
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33
34 #include "asterisk/frame.h"
35 #include "asterisk/utils.h"
36 #include "asterisk/unaligned.h"
37 #include "asterisk/config.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/threadstorage.h"
40
41 #include "iax2.h"
42 #include "iax2-parser.h"
43 #include "iax2-provision.h"
44
45 static int frames = 0;
46 static int iframes = 0;
47 static int oframes = 0;
48
49 #if !defined(LOW_MEMORY)
50 static void frame_cache_cleanup(void *data);
51
52 /*! \brief A per-thread cache of iax_frame structures */
53 AST_THREADSTORAGE_CUSTOM(frame_cache, NULL, frame_cache_cleanup);
54
55 /*! \brief This is just so iax_frames, a list head struct for holding a list of
56  *  iax_frame structures, is defined. */
57 AST_LIST_HEAD_NOLOCK(iax_frame_list, iax_frame);
58
59 struct iax_frames {
60         struct iax_frame_list list;
61         size_t size;
62 };
63
64 #define FRAME_CACHE_MAX_SIZE    20
65 #endif
66
67 static void internaloutput(const char *str)
68 {
69         fputs(str, stdout);
70 }
71
72 static void internalerror(const char *str)
73 {
74         fprintf(stderr, "WARNING: %s", str);
75 }
76
77 static void (*outputf)(const char *str) = internaloutput;
78 static void (*errorf)(const char *str) = internalerror;
79
80 static void dump_addr(char *output, int maxlen, void *value, int len)
81 {
82         struct sockaddr_in sin;
83         if (len == (int)sizeof(sin)) {
84                 memcpy(&sin, value, len);
85                 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
86         } else {
87                 ast_copy_string(output, "Invalid Address", maxlen);
88         }
89 }
90
91 static void dump_string_hex(char *output, int maxlen, void *value, int len)
92 {
93         int i = 0;
94
95         while (len-- && (i + 1) * 4 < maxlen) {
96                 sprintf(output + (4 * i), "\\x%2.2x", *((unsigned char *)value + i));
97                 i++;
98         }
99 }
100
101 static void dump_string(char *output, int maxlen, void *value, int len)
102 {
103         maxlen--;
104         if (maxlen > len)
105                 maxlen = len;
106         strncpy(output, value, maxlen);
107         output[maxlen] = '\0';
108 }
109
110 static void dump_prefs(char *output, int maxlen, void *value, int len)
111 {
112         struct ast_codec_pref pref;
113         int total_len = 0;
114
115         maxlen--;
116         total_len = maxlen;
117
118         if (maxlen > len)
119                 maxlen = len;
120
121         strncpy(output, value, maxlen);
122         output[maxlen] = '\0';
123         
124         ast_codec_pref_convert(&pref, output, total_len, 0);
125         memset(output,0,total_len);
126         ast_codec_pref_string(&pref, output, total_len);
127 }
128
129 static void dump_int(char *output, int maxlen, void *value, int len)
130 {
131         if (len == (int)sizeof(unsigned int))
132                 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
133         else
134                 ast_copy_string(output, "Invalid INT", maxlen); 
135 }
136
137 static void dump_short(char *output, int maxlen, void *value, int len)
138 {
139         if (len == (int)sizeof(unsigned short))
140                 snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
141         else
142                 ast_copy_string(output, "Invalid SHORT", maxlen);
143 }
144
145 static void dump_byte(char *output, int maxlen, void *value, int len)
146 {
147         if (len == (int)sizeof(unsigned char))
148                 snprintf(output, maxlen, "%d", *((unsigned char *)value));
149         else
150                 ast_copy_string(output, "Invalid BYTE", maxlen);
151 }
152
153 static void dump_datetime(char *output, int maxlen, void *value, int len)
154 {
155         struct ast_tm tm;
156         unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
157         if (len == (int)sizeof(unsigned int)) {
158                 tm.tm_sec  = (val & 0x1f) << 1;
159                 tm.tm_min  = (val >> 5) & 0x3f;
160                 tm.tm_hour = (val >> 11) & 0x1f;
161                 tm.tm_mday = (val >> 16) & 0x1f;
162                 tm.tm_mon  = ((val >> 21) & 0x0f) - 1;
163                 tm.tm_year = ((val >> 25) & 0x7f) + 100;
164                 ast_strftime(output, maxlen, "%Y-%m-%d  %T", &tm); 
165         } else
166                 ast_copy_string(output, "Invalid DATETIME format!", maxlen);
167 }
168
169 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
170 {
171         struct sockaddr_in sin;
172         if (len == (int)sizeof(unsigned int)) {
173                 memcpy(&sin.sin_addr, value, len);
174                 snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
175         } else
176                 ast_copy_string(output, "Invalid IPADDR", maxlen);
177 }
178
179
180 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
181 {
182         char buf[256] = "";
183         if (len == (int)sizeof(unsigned int))
184                 snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
185                         iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
186         else
187                 ast_copy_string(output, "Invalid INT", maxlen);
188 }
189
190 static void dump_samprate(char *output, int maxlen, void *value, int len)
191 {
192         char tmp[256]="";
193         int sr;
194         if (len == (int)sizeof(unsigned short)) {
195                 sr = ntohs(*((unsigned short *)value));
196                 if (sr & IAX_RATE_8KHZ)
197                         strcat(tmp, ",8khz");
198                 if (sr & IAX_RATE_11KHZ)
199                         strcat(tmp, ",11.025khz");
200                 if (sr & IAX_RATE_16KHZ)
201                         strcat(tmp, ",16khz");
202                 if (sr & IAX_RATE_22KHZ)
203                         strcat(tmp, ",22.05khz");
204                 if (sr & IAX_RATE_44KHZ)
205                         strcat(tmp, ",44.1khz");
206                 if (sr & IAX_RATE_48KHZ)
207                         strcat(tmp, ",48khz");
208                 if (strlen(tmp))
209                         ast_copy_string(output, &tmp[1], maxlen);
210                 else
211                         ast_copy_string(output, "None Specified!\n", maxlen);
212         } else
213                 ast_copy_string(output, "Invalid SHORT", maxlen);
214
215 }
216
217 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
218 static void dump_prov(char *output, int maxlen, void *value, int len)
219 {
220         dump_prov_ies(output, maxlen, value, len);
221 }
222
223 static struct iax2_ie {
224         int ie;
225         char *name;
226         void (*dump)(char *output, int maxlen, void *value, int len);
227 } infoelts[] = {
228         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
229         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
230         { IAX_IE_CALLING_ANI, "ANI", dump_string },
231         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
232         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
233         { IAX_IE_USERNAME, "USERNAME", dump_string },
234         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
235         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
236         { IAX_IE_FORMAT, "FORMAT", dump_int },
237         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
238         { IAX_IE_VERSION, "VERSION", dump_short },
239         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
240         { IAX_IE_DNID, "DNID", dump_string },
241         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
242         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string_hex },
243         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
244         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
245         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
246         { IAX_IE_REFRESH, "REFRESH", dump_short },
247         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
248         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
249         { IAX_IE_CAUSE, "CAUSE", dump_string },
250         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
251         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
252         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
253         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
254         { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
255         { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
256         { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
257         { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
258         { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
259         { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
260         { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
261         { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
262         { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
263         { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
264         { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
265         { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
266         { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
267         { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
268         { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
269         { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
270         { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
271         { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
272         { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
273         { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
274         { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
275         { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
276         { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
277         { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
278         { IAX_IE_VARIABLE, "VARIABLE", dump_string },
279         { IAX_IE_OSPTOKEN, "OSPTOKEN" },
280 };
281
282 static struct iax2_ie prov_ies[] = {
283         { PROV_IE_USEDHCP, "USEDHCP" },
284         { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
285         { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
286         { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
287         { PROV_IE_PORTNO, "BINDPORT", dump_short },
288         { PROV_IE_USER, "USERNAME", dump_string },
289         { PROV_IE_PASS, "PASSWORD", dump_string },
290         { PROV_IE_LANG, "LANGUAGE", dump_string },
291         { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
292         { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
293         { PROV_IE_FORMAT, "FORMAT", dump_int },
294         { PROV_IE_AESKEY, "AESKEY" },
295         { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
296         { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
297         { PROV_IE_NEWAESKEY, "NEWAESKEY" },
298         { PROV_IE_PROVVER, "PROV VERSION", dump_int },
299         { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
300 };
301
302 const char *iax_ie2str(int ie)
303 {
304         int x;
305         for (x = 0; x < ARRAY_LEN(infoelts); x++) {
306                 if (infoelts[x].ie == ie)
307                         return infoelts[x].name;
308         }
309         return "Unknown IE";
310 }
311
312
313 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
314 {
315         int ielen;
316         int ie;
317         int x;
318         int found;
319         char interp[80];
320         char tmp[256];
321         if (len < 2)
322                 return;
323         strcpy(output, "\n"); 
324         maxlen -= strlen(output); output += strlen(output);
325         while(len > 2) {
326                 ie = iedata[0];
327                 ielen = iedata[1];
328                 if (ielen + 2> len) {
329                         snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
330                         ast_copy_string(output, tmp, maxlen);
331                         maxlen -= strlen(output);
332                         output += strlen(output);
333                         return;
334                 }
335                 found = 0;
336                 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
337                         if (prov_ies[x].ie == ie) {
338                                 if (prov_ies[x].dump) {
339                                         prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
340                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
341                                         ast_copy_string(output, tmp, maxlen);
342                                         maxlen -= strlen(output); output += strlen(output);
343                                 } else {
344                                         if (ielen)
345                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
346                                         else
347                                                 strcpy(interp, "Present");
348                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
349                                         ast_copy_string(output, tmp, maxlen);
350                                         maxlen -= strlen(output); output += strlen(output);
351                                 }
352                                 found++;
353                         }
354                 }
355                 if (!found) {
356                         snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
357                         ast_copy_string(output, tmp, maxlen);
358                         maxlen -= strlen(output); output += strlen(output);
359                 }
360                 iedata += (2 + ielen);
361                 len -= (2 + ielen);
362         }
363 }
364
365 static void dump_ies(unsigned char *iedata, int len)
366 {
367         int ielen;
368         int ie;
369         int x;
370         int found;
371         char interp[1024];
372         char tmp[1024];
373         if (len < 2)
374                 return;
375         while(len > 2) {
376                 ie = iedata[0];
377                 ielen = iedata[1];
378                 if (ielen + 2> len) {
379                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
380                         outputf(tmp);
381                         return;
382                 }
383                 found = 0;
384                 for (x = 0; x < ARRAY_LEN(infoelts); x++) {
385                         if (infoelts[x].ie == ie) {
386                                 if (infoelts[x].dump) {
387                                         infoelts[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
388                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", infoelts[x].name, interp);
389                                         outputf(tmp);
390                                 } else {
391                                         if (ielen)
392                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
393                                         else
394                                                 strcpy(interp, "Present");
395                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", infoelts[x].name, interp);
396                                         outputf(tmp);
397                                 }
398                                 found++;
399                         }
400                 }
401                 if (!found) {
402                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
403                         outputf(tmp);
404                 }
405                 iedata += (2 + ielen);
406                 len -= (2 + ielen);
407         }
408         outputf("\n");
409 }
410
411 void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len)
412 {
413         const char *cmd = "Unknown";
414
415         /* if an error occurs here during compile, that means a new iax frame subclass
416          * has been added to the iax_frame_subclass enum.  Add the new subclass to the
417          * switch case and make sure to update it with a new string representation. */
418         switch (subclass) {
419         case IAX_COMMAND_NEW:
420                 cmd = "NEW    ";
421                 break;
422         case IAX_COMMAND_PING:
423                 cmd = "PING   ";
424                 break;
425         case IAX_COMMAND_PONG:
426                 cmd = "PONG   ";
427                 break;
428         case IAX_COMMAND_ACK:
429                 cmd = "ACK    ";
430                 break;
431         case IAX_COMMAND_HANGUP:
432                 cmd = "HANGUP ";
433                 break;
434         case IAX_COMMAND_REJECT:
435                 cmd = "REJECT ";
436                 break;
437         case IAX_COMMAND_ACCEPT:
438                 cmd = "ACCEPT ";
439                 break;
440         case IAX_COMMAND_AUTHREQ:
441                 cmd = "AUTHREQ";
442                 break;
443         case IAX_COMMAND_AUTHREP:
444                 cmd = "AUTHREP";
445                 break;
446         case IAX_COMMAND_INVAL:
447                 cmd = "INVAL  ";
448                 break;
449         case IAX_COMMAND_LAGRQ:
450                 cmd = "LAGRQ  ";
451                 break;
452         case IAX_COMMAND_LAGRP:
453                 cmd = "LAGRP  ";
454                 break;
455         case IAX_COMMAND_REGREQ:
456                 cmd = "REGREQ ";
457                 break;
458         case IAX_COMMAND_REGAUTH:
459                 cmd = "REGAUTH";
460                 break;
461         case IAX_COMMAND_REGACK:
462                 cmd = "REGACK ";
463                 break;
464         case IAX_COMMAND_REGREJ:
465                 cmd = "REGREJ ";
466                 break;
467         case IAX_COMMAND_REGREL:
468                 cmd = "REGREL ";
469                 break;
470         case IAX_COMMAND_VNAK:
471                 cmd = "VNAK   ";
472                 break;
473         case IAX_COMMAND_DPREQ:
474                 cmd = "DPREQ  ";
475                 break;
476         case IAX_COMMAND_DPREP:
477                 cmd = "DPREP  ";
478                 break;
479         case IAX_COMMAND_DIAL:
480                 cmd = "DIAL   ";
481                 break;
482         case IAX_COMMAND_TXREQ:
483                 cmd = "TXREQ  ";
484                 break;
485         case IAX_COMMAND_TXCNT:
486                 cmd = "TXCNT  ";
487                 break;
488         case IAX_COMMAND_TXACC:
489                 cmd = "TXACC  ";
490                 break;
491         case IAX_COMMAND_TXREADY:
492                 cmd = "TXREADY";
493                 break;
494         case IAX_COMMAND_TXREL:
495                 cmd = "TXREL  ";
496                 break;
497         case IAX_COMMAND_TXREJ:
498                 cmd = "TXREJ  ";
499                 break;
500         case IAX_COMMAND_QUELCH:
501                 cmd = "QUELCH ";
502                 break;
503         case IAX_COMMAND_UNQUELCH:
504                 cmd = "UNQULCH";
505                 break;
506         case IAX_COMMAND_POKE:
507                 cmd = "POKE   ";
508                 break;
509         case IAX_COMMAND_PAGE:
510                 cmd = "PAGE   ";
511                 break;
512         case IAX_COMMAND_MWI:
513                 cmd = "MWI    ";
514                 break;
515         case IAX_COMMAND_UNSUPPORT:
516                 cmd = "UNSPRTD";
517                 break;
518         case IAX_COMMAND_TRANSFER:
519                 cmd = "TRANSFR";
520                 break;
521         case IAX_COMMAND_PROVISION:
522                 cmd = "PROVISN";
523                 break;
524         case IAX_COMMAND_FWDOWNL:
525                 cmd = "FWDWNLD";
526                 break;
527         case IAX_COMMAND_FWDATA:
528                 cmd = "FWDATA ";
529                 break;
530         case IAX_COMMAND_TXMEDIA:
531                 cmd = "TXMEDIA";
532                 break;
533         case IAX_COMMAND_RTKEY:
534                 cmd = "RTKEY  ";
535                 break;
536         }
537         ast_copy_string(str, cmd, len);
538 }
539
540 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
541 {
542         const char *framelist[] = {
543                 "(0?)",
544                 "DTMF_E ",
545                 "VOICE  ",
546                 "VIDEO  ",
547                 "CONTROL",
548                 "NULL   ",
549                 "IAX    ",
550                 "TEXT   ",
551                 "IMAGE  ",
552                 "HTML   ",
553                 "CNG    ",
554                 "MODEM  ",
555                 "DTMF_B ",
556         };
557         const char *cmds[] = {
558                 "(0?)",
559                 "HANGUP ",
560                 "RING   ",
561                 "RINGING",
562                 "ANSWER ",
563                 "BUSY   ",
564                 "TKOFFHK",
565                 "OFFHOOK",
566                 "CONGSTN",
567                 "FLASH  ",
568                 "WINK   ",
569                 "OPTION ",
570                 "RDKEY  ",
571                 "RDUNKEY",
572                 "PROGRES",
573                 "PROCDNG",
574                 "HOLD   ",
575                 "UNHOLD ",
576                 "VIDUPDT", };
577         struct ast_iax2_full_hdr *fh;
578         char retries[20];
579         char class2[20];
580         char subclass2[20];
581         const char *class;
582         const char *subclass;
583         char *dir;
584         char tmp[512];
585
586         switch(rx) {
587         case 0:
588                 dir = "Tx";
589                 break;
590         case 2:
591                 dir = "TE";
592                 break;
593         case 3:
594                 dir = "RD";
595                 break;
596         default:
597                 dir = "Rx";
598                 break;
599         }
600         if (f) {
601                 fh = f->data;
602                 snprintf(retries, sizeof(retries), "%03d", f->retries);
603         } else {
604                 fh = fhi;
605                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
606                         strcpy(retries, "Yes");
607                 else
608                         strcpy(retries, " No");
609         }
610         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
611                 /* Don't mess with mini-frames */
612                 return;
613         }
614         if (fh->type >= ARRAY_LEN(framelist)) {
615                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
616                 class = class2;
617         } else {
618                 class = framelist[(int)fh->type];
619         }
620         if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
621                 sprintf(subclass2, "%c", fh->csub);
622                 subclass = subclass2;
623         } else if (fh->type == AST_FRAME_IAX) {
624                         iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2));
625                         subclass = subclass2;
626         } else if (fh->type == AST_FRAME_CONTROL) {
627                 if (fh->csub >= ARRAY_LEN(cmds)) {
628                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
629                         subclass = subclass2;
630                 } else {
631                         subclass = cmds[(int)fh->csub];
632                 }
633         } else {
634                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
635                 subclass = subclass2;
636         }
637         snprintf(tmp, sizeof(tmp), 
638                  "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
639                  dir,
640                  retries, fh->oseqno, fh->iseqno, class, subclass);
641         outputf(tmp);
642         snprintf(tmp, sizeof(tmp), 
643                  "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
644                  (unsigned long)ntohl(fh->ts),
645                  ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
646                  ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
647         outputf(tmp);
648         if (fh->type == AST_FRAME_IAX)
649                 dump_ies(fh->iedata, datalen);
650 }
651
652 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
653 {
654         char tmp[256];
655         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
656                 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);
657                 errorf(tmp);
658                 return -1;
659         }
660         ied->buf[ied->pos++] = ie;
661         ied->buf[ied->pos++] = datalen;
662         memcpy(ied->buf + ied->pos, data, datalen);
663         ied->pos += datalen;
664         return 0;
665 }
666
667 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
668 {
669         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
670 }
671
672 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
673 {
674         unsigned int newval;
675         newval = htonl(value);
676         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
677 }
678
679 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
680 {
681         unsigned short newval;
682         newval = htons(value);
683         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
684 }
685
686 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
687 {
688         return iax_ie_append_raw(ied, ie, str, strlen(str));
689 }
690
691 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
692 {
693         return iax_ie_append_raw(ied, ie, &dat, 1);
694 }
695
696 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
697 {
698         return iax_ie_append_raw(ied, ie, NULL, 0);
699 }
700
701 void iax_set_output(void (*func)(const char *))
702 {
703         outputf = func;
704 }
705
706 void iax_set_error(void (*func)(const char *))
707 {
708         errorf = func;
709 }
710
711 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
712 {
713         /* Parse data into information elements */
714         int len;
715         int ie;
716         char tmp[256], *tmp2;
717         struct ast_variable *var, *var2, *prev;
718         unsigned int count;
719         memset(ies, 0, (int)sizeof(struct iax_ies));
720         ies->msgcount = -1;
721         ies->firmwarever = -1;
722         ies->calling_ton = -1;
723         ies->calling_tns = -1;
724         ies->calling_pres = -1;
725         ies->samprate = IAX_RATE_8KHZ;
726         while(datalen >= 2) {
727                 ie = data[0];
728                 len = data[1];
729                 if (len > datalen - 2) {
730                         errorf("Information element length exceeds message size\n");
731                         return -1;
732                 }
733                 switch(ie) {
734                 case IAX_IE_CALLED_NUMBER:
735                         ies->called_number = (char *)data + 2;
736                         break;
737                 case IAX_IE_CALLING_NUMBER:
738                         ies->calling_number = (char *)data + 2;
739                         break;
740                 case IAX_IE_CALLING_ANI:
741                         ies->calling_ani = (char *)data + 2;
742                         break;
743                 case IAX_IE_CALLING_NAME:
744                         ies->calling_name = (char *)data + 2;
745                         break;
746                 case IAX_IE_CALLED_CONTEXT:
747                         ies->called_context = (char *)data + 2;
748                         break;
749                 case IAX_IE_USERNAME:
750                         ies->username = (char *)data + 2;
751                         break;
752                 case IAX_IE_PASSWORD:
753                         ies->password = (char *)data + 2;
754                         break;
755                 case IAX_IE_CODEC_PREFS:
756                         ies->codec_prefs = (char *)data + 2;
757                         break;
758                 case IAX_IE_CAPABILITY:
759                         if (len != (int)sizeof(unsigned int)) {
760                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
761                                 errorf(tmp);
762                         } else
763                                 ies->capability = ntohl(get_unaligned_uint32(data + 2));
764                         break;
765                 case IAX_IE_FORMAT:
766                         if (len != (int)sizeof(unsigned int)) {
767                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
768                                 errorf(tmp);
769                         } else
770                                 ies->format = ntohl(get_unaligned_uint32(data + 2));
771                         break;
772                 case IAX_IE_LANGUAGE:
773                         ies->language = (char *)data + 2;
774                         break;
775                 case IAX_IE_VERSION:
776                         if (len != (int)sizeof(unsigned short)) {
777                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
778                                 errorf(tmp);
779                         } else
780                                 ies->version = ntohs(get_unaligned_uint16(data + 2));
781                         break;
782                 case IAX_IE_ADSICPE:
783                         if (len != (int)sizeof(unsigned short)) {
784                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
785                                 errorf(tmp);
786                         } else
787                                 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
788                         break;
789                 case IAX_IE_SAMPLINGRATE:
790                         if (len != (int)sizeof(unsigned short)) {
791                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
792                                 errorf(tmp);
793                         } else
794                                 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
795                         break;
796                 case IAX_IE_DNID:
797                         ies->dnid = (char *)data + 2;
798                         break;
799                 case IAX_IE_RDNIS:
800                         ies->rdnis = (char *)data + 2;
801                         break;
802                 case IAX_IE_AUTHMETHODS:
803                         if (len != (int)sizeof(unsigned short))  {
804                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
805                                 errorf(tmp);
806                         } else
807                                 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
808                         break;
809                 case IAX_IE_ENCRYPTION:
810                         if (len != (int)sizeof(unsigned short))  {
811                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
812                                 errorf(tmp);
813                         } else
814                                 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
815                         break;
816                 case IAX_IE_CHALLENGE:
817                         ies->challenge = (char *)data + 2;
818                         break;
819                 case IAX_IE_MD5_RESULT:
820                         ies->md5_result = (char *)data + 2;
821                         break;
822                 case IAX_IE_RSA_RESULT:
823                         ies->rsa_result = (char *)data + 2;
824                         break;
825                 case IAX_IE_APPARENT_ADDR:
826                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
827                         break;
828                 case IAX_IE_REFRESH:
829                         if (len != (int)sizeof(unsigned short)) {
830                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
831                                 errorf(tmp);
832                         } else
833                                 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
834                         break;
835                 case IAX_IE_DPSTATUS:
836                         if (len != (int)sizeof(unsigned short)) {
837                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
838                                 errorf(tmp);
839                         } else
840                                 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
841                         break;
842                 case IAX_IE_CALLNO:
843                         if (len != (int)sizeof(unsigned short)) {
844                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
845                                 errorf(tmp);
846                         } else
847                                 ies->callno = ntohs(get_unaligned_uint16(data + 2));
848                         break;
849                 case IAX_IE_CAUSE:
850                         ies->cause = (char *)data + 2;
851                         break;
852                 case IAX_IE_CAUSECODE:
853                         if (len != 1) {
854                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
855                                 errorf(tmp);
856                         } else {
857                                 ies->causecode = data[2];
858                         }
859                         break;
860                 case IAX_IE_IAX_UNKNOWN:
861                         if (len == 1)
862                                 ies->iax_unknown = data[2];
863                         else {
864                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
865                                 errorf(tmp);
866                         }
867                         break;
868                 case IAX_IE_MSGCOUNT:
869                         if (len != (int)sizeof(unsigned short)) {
870                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
871                                 errorf(tmp);
872                         } else
873                                 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));  
874                         break;
875                 case IAX_IE_AUTOANSWER:
876                         ies->autoanswer = 1;
877                         break;
878                 case IAX_IE_MUSICONHOLD:
879                         ies->musiconhold = 1;
880                         break;
881                 case IAX_IE_TRANSFERID:
882                         if (len != (int)sizeof(unsigned int)) {
883                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
884                                 errorf(tmp);
885                         } else
886                                 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
887                         break;
888                 case IAX_IE_DATETIME:
889                         if (len != (int)sizeof(unsigned int)) {
890                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
891                                 errorf(tmp);
892                         } else
893                                 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
894                         break;
895                 case IAX_IE_FIRMWAREVER:
896                         if (len != (int)sizeof(unsigned short)) {
897                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
898                                 errorf(tmp);
899                         } else
900                                 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));       
901                         break;
902                 case IAX_IE_DEVICETYPE:
903                         ies->devicetype = (char *)data + 2;
904                         break;
905                 case IAX_IE_SERVICEIDENT:
906                         ies->serviceident = (char *)data + 2;
907                         break;
908                 case IAX_IE_FWBLOCKDESC:
909                         if (len != (int)sizeof(unsigned int)) {
910                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
911                                 errorf(tmp);
912                         } else
913                                 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
914                         break;
915                 case IAX_IE_FWBLOCKDATA:
916                         ies->fwdata = data + 2;
917                         ies->fwdatalen = len;
918                         break;
919                 case IAX_IE_ENCKEY:
920                         ies->enckey = data + 2;
921                         ies->enckeylen = len;
922                         break;
923                 case IAX_IE_PROVVER:
924                         if (len != (int)sizeof(unsigned int)) {
925                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
926                                 errorf(tmp);
927                         } else {
928                                 ies->provverpres = 1;
929                                 ies->provver = ntohl(get_unaligned_uint32(data + 2));
930                         }
931                         break;
932                 case IAX_IE_CALLINGPRES:
933                         if (len == 1)
934                                 ies->calling_pres = data[2];
935                         else {
936                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
937                                 errorf(tmp);
938                         }
939                         break;
940                 case IAX_IE_CALLINGTON:
941                         if (len == 1)
942                                 ies->calling_ton = data[2];
943                         else {
944                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
945                                 errorf(tmp);
946                         }
947                         break;
948                 case IAX_IE_CALLINGTNS:
949                         if (len != (int)sizeof(unsigned short)) {
950                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
951                                 errorf(tmp);
952                         } else
953                                 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));       
954                         break;
955                case IAX_IE_RR_JITTER:
956                        if (len != (int)sizeof(unsigned int)) {
957                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
958                                errorf(tmp);
959                        } else {
960                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
961                        }
962                        break;
963                case IAX_IE_RR_LOSS:
964                        if (len != (int)sizeof(unsigned int)) {
965                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
966                                errorf(tmp);
967                        } else {
968                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
969                        }
970                        break;
971                case IAX_IE_RR_PKTS:
972                        if (len != (int)sizeof(unsigned int)) {
973                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
974                                errorf(tmp);
975                        } else {
976                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
977                        }
978                        break;
979                case IAX_IE_RR_DELAY:
980                        if (len != (int)sizeof(unsigned short)) {
981                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
982                         errorf(tmp);
983                        } else {
984                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
985                        }
986                        break;
987                 case IAX_IE_RR_DROPPED:
988                         if (len != (int)sizeof(unsigned int)) {
989                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
990                                 errorf(tmp);
991                         } else {
992                                 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
993                         }
994                         break;
995                 case IAX_IE_RR_OOO:
996                         if (len != (int)sizeof(unsigned int)) {
997                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
998                                 errorf(tmp);
999                         } else {
1000                                 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
1001                         }
1002                         break;
1003                 case IAX_IE_VARIABLE:
1004                         ast_copy_string(tmp, (char *)data + 2, len + 1);
1005                         tmp2 = strchr(tmp, '=');
1006                         if (tmp2)
1007                                 *tmp2++ = '\0';
1008                         else
1009                                 tmp2 = "";
1010                         {
1011                                 struct ast_str *str = ast_str_create(16);
1012                                 /* Existing variable or new variable? */
1013                                 for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
1014                                         if (strcmp(tmp, var2->name) == 0) {
1015                                                 ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
1016                                                 var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
1017                                                 var->next = var2->next;
1018                                                 if (prev) {
1019                                                         prev->next = var;
1020                                                 } else {
1021                                                         ies->vars = var;
1022                                                 }
1023                                                 snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
1024                                                 errorf(tmp);
1025                                                 ast_free(var2);
1026                                                 break;
1027                                         }
1028                                 }
1029                                 ast_free(str);
1030                         }
1031
1032                         if (!var2) {
1033                                 var = ast_variable_new(tmp, tmp2, "");
1034                                 snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
1035                                 errorf(tmp);
1036                                 var->next = ies->vars;
1037                                 ies->vars = var;
1038                         }
1039                         break;
1040                 case IAX_IE_OSPTOKEN:
1041                         if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
1042                                 ies->osptokenblock[count] = (char *)data + 2 + 1;
1043                                 ies->ospblocklength[count] = len - 1;
1044                         } else {
1045                                 snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
1046                                 errorf(tmp);
1047                         }
1048                         break;
1049                 default:
1050                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
1051                         outputf(tmp);
1052                 }
1053                 /* Overwrite information element with 0, to null terminate previous portion */
1054                 data[0] = 0;
1055                 datalen -= (len + 2);
1056                 data += (len + 2);
1057         }
1058         /* Null-terminate last field */
1059         *data = '\0';
1060         if (datalen) {
1061                 errorf("Invalid information element contents, strange boundary\n");
1062                 return -1;
1063         }
1064         return 0;
1065 }
1066
1067 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
1068 {
1069         fr->af.frametype = f->frametype;
1070         fr->af.subclass = f->subclass;
1071         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
1072         fr->af.datalen = f->datalen;
1073         fr->af.samples = f->samples;
1074         fr->af.offset = AST_FRIENDLY_OFFSET;
1075         fr->af.src = f->src;
1076         fr->af.delivery.tv_sec = 0;
1077         fr->af.delivery.tv_usec = 0;
1078         fr->af.data.ptr = fr->afdata;
1079         fr->af.len = f->len;
1080         if (fr->af.datalen) {
1081                 size_t copy_len = fr->af.datalen;
1082                 if (copy_len > fr->afdatalen) {
1083                         ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
1084                                 (int) fr->afdatalen, (int) fr->af.datalen);
1085                         copy_len = fr->afdatalen;
1086                 }
1087 #if __BYTE_ORDER == __LITTLE_ENDIAN
1088                 /* We need to byte-swap slinear samples from network byte order */
1089                 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
1090                         /* 2 bytes / sample for SLINEAR */
1091                         ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
1092                 } else
1093 #endif
1094                         memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
1095         }
1096 }
1097
1098 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
1099 {
1100         struct iax_frame *fr = NULL;
1101
1102 #if !defined(LOW_MEMORY)
1103         struct iax_frames *iax_frames = NULL;
1104         struct iax_frame *smallest = NULL;
1105
1106         /* Attempt to get a frame from this thread's cache */
1107         if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1108                 smallest = AST_LIST_FIRST(&iax_frames->list);
1109                 AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
1110                         if (fr->afdatalen >= datalen) {
1111                                 size_t afdatalen = fr->afdatalen;
1112                                 AST_LIST_REMOVE_CURRENT(list);
1113                                 iax_frames->size--;
1114                                 memset(fr, 0, sizeof(*fr));
1115                                 fr->afdatalen = afdatalen;
1116                                 break;
1117                         } else if (smallest->afdatalen > fr->afdatalen) {
1118                                 smallest = fr;
1119                         }
1120                 }
1121                 AST_LIST_TRAVERSE_SAFE_END;
1122         }
1123         if (!fr) {
1124                 if (iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) {
1125                         /* Make useless cache into something more useful */
1126                         AST_LIST_REMOVE(&iax_frames->list, smallest, list);
1127                         if (!(fr = ast_realloc(smallest, sizeof(*fr) + datalen))) {
1128                                 AST_LIST_INSERT_TAIL(&iax_frames->list, smallest, list);
1129                                 return NULL;
1130                         }
1131                 } else if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
1132                         return NULL;
1133                 fr->afdatalen = datalen;
1134         }
1135 #else
1136         if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
1137                 return NULL;
1138         fr->afdatalen = datalen;
1139 #endif
1140
1141
1142         fr->direction = direction;
1143         fr->retrans = -1;
1144         fr->cacheable = cacheable;
1145         
1146         if (fr->direction == DIRECTION_INGRESS)
1147                 ast_atomic_fetchadd_int(&iframes, 1);
1148         else
1149                 ast_atomic_fetchadd_int(&oframes, 1);
1150         
1151         ast_atomic_fetchadd_int(&frames, 1);
1152
1153         return fr;
1154 }
1155
1156 void iax_frame_free(struct iax_frame *fr)
1157 {
1158 #if !defined(LOW_MEMORY)
1159         struct iax_frames *iax_frames = NULL;
1160 #endif
1161
1162         /* Note: does not remove from scheduler! */
1163         if (fr->direction == DIRECTION_INGRESS)
1164                 ast_atomic_fetchadd_int(&iframes, -1);
1165         else if (fr->direction == DIRECTION_OUTGRESS)
1166                 ast_atomic_fetchadd_int(&oframes, -1);
1167         else {
1168                 errorf("Attempt to double free frame detected\n");
1169                 return;
1170         }
1171         ast_atomic_fetchadd_int(&frames, -1);
1172
1173 #if !defined(LOW_MEMORY)
1174         if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1175                 ast_free(fr);
1176                 return;
1177         }
1178
1179         if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
1180                 fr->direction = 0;
1181                 /* Pseudo-sort: keep smaller frames at the top of the list. This should
1182                  * increase the chance that we pick the smallest applicable frame for use. */
1183                 if (AST_LIST_FIRST(&iax_frames->list) && AST_LIST_FIRST(&iax_frames->list)->afdatalen < fr->afdatalen) {
1184                         AST_LIST_INSERT_TAIL(&iax_frames->list, fr, list);
1185                 } else {
1186                         AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
1187                 }
1188                 iax_frames->size++;
1189                 return;
1190         }
1191 #endif
1192         ast_free(fr);
1193 }
1194
1195 #if !defined(LOW_MEMORY)
1196 static void frame_cache_cleanup(void *data)
1197 {
1198         struct iax_frames *framelist = data;
1199         struct iax_frame *current;
1200
1201         while ((current = AST_LIST_REMOVE_HEAD(&framelist->list, list)))
1202                 ast_free(current);
1203
1204         ast_free(framelist);
1205 }
1206 #endif
1207
1208 int iax_get_frames(void) { return frames; }
1209 int iax_get_iframes(void) { return iframes; }
1210 int iax_get_oframes(void) { return oframes; }