Tell the IAX2 parser about more control frame types.
[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 const 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                 "T38    ",
578                 "SRCUPDT",
579                 "TXFER  ",
580                 "CNLINE ",
581                 "REDIR  ",
582         };
583         struct ast_iax2_full_hdr *fh;
584         char retries[20];
585         char class2[20];
586         char subclass2[20];
587         const char *class;
588         const char *subclass;
589         char *dir;
590         char tmp[512];
591
592         switch(rx) {
593         case 0:
594                 dir = "Tx";
595                 break;
596         case 2:
597                 dir = "TE";
598                 break;
599         case 3:
600                 dir = "RD";
601                 break;
602         default:
603                 dir = "Rx";
604                 break;
605         }
606         if (f) {
607                 fh = f->data;
608                 snprintf(retries, sizeof(retries), "%03d", f->retries);
609         } else {
610                 fh = fhi;
611                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
612                         strcpy(retries, "Yes");
613                 else
614                         strcpy(retries, " No");
615         }
616         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
617                 /* Don't mess with mini-frames */
618                 return;
619         }
620         if (fh->type >= ARRAY_LEN(framelist)) {
621                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
622                 class = class2;
623         } else {
624                 class = framelist[(int)fh->type];
625         }
626         if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
627                 sprintf(subclass2, "%c", fh->csub);
628                 subclass = subclass2;
629         } else if (fh->type == AST_FRAME_IAX) {
630                         iax_frame_subclass2str((int)fh->csub, subclass2, sizeof(subclass2));
631                         subclass = subclass2;
632         } else if (fh->type == AST_FRAME_CONTROL) {
633                 if (fh->csub >= ARRAY_LEN(cmds)) {
634                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
635                         subclass = subclass2;
636                 } else {
637                         subclass = cmds[(int)fh->csub];
638                 }
639         } else {
640                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
641                 subclass = subclass2;
642         }
643         snprintf(tmp, sizeof(tmp), 
644                  "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
645                  dir,
646                  retries, fh->oseqno, fh->iseqno, class, subclass);
647         outputf(tmp);
648         snprintf(tmp, sizeof(tmp), 
649                  "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
650                  (unsigned long)ntohl(fh->ts),
651                  ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
652                  ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
653         outputf(tmp);
654         if (fh->type == AST_FRAME_IAX)
655                 dump_ies(fh->iedata, datalen);
656 }
657
658 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
659 {
660         char tmp[256];
661         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
662                 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);
663                 errorf(tmp);
664                 return -1;
665         }
666         ied->buf[ied->pos++] = ie;
667         ied->buf[ied->pos++] = datalen;
668         memcpy(ied->buf + ied->pos, data, datalen);
669         ied->pos += datalen;
670         return 0;
671 }
672
673 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
674 {
675         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
676 }
677
678 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
679 {
680         unsigned int newval;
681         newval = htonl(value);
682         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
683 }
684
685 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
686 {
687         unsigned short newval;
688         newval = htons(value);
689         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
690 }
691
692 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
693 {
694         return iax_ie_append_raw(ied, ie, str, strlen(str));
695 }
696
697 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
698 {
699         return iax_ie_append_raw(ied, ie, &dat, 1);
700 }
701
702 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
703 {
704         return iax_ie_append_raw(ied, ie, NULL, 0);
705 }
706
707 void iax_set_output(void (*func)(const char *))
708 {
709         outputf = func;
710 }
711
712 void iax_set_error(void (*func)(const char *))
713 {
714         errorf = func;
715 }
716
717 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
718 {
719         /* Parse data into information elements */
720         int len;
721         int ie;
722         char tmp[256], *tmp2;
723         struct ast_variable *var, *var2, *prev;
724         unsigned int count;
725         memset(ies, 0, (int)sizeof(struct iax_ies));
726         ies->msgcount = -1;
727         ies->firmwarever = -1;
728         ies->calling_ton = -1;
729         ies->calling_tns = -1;
730         ies->calling_pres = -1;
731         ies->samprate = IAX_RATE_8KHZ;
732         while(datalen >= 2) {
733                 ie = data[0];
734                 len = data[1];
735                 if (len > datalen - 2) {
736                         errorf("Information element length exceeds message size\n");
737                         return -1;
738                 }
739                 switch(ie) {
740                 case IAX_IE_CALLED_NUMBER:
741                         ies->called_number = (char *)data + 2;
742                         break;
743                 case IAX_IE_CALLING_NUMBER:
744                         ies->calling_number = (char *)data + 2;
745                         break;
746                 case IAX_IE_CALLING_ANI:
747                         ies->calling_ani = (char *)data + 2;
748                         break;
749                 case IAX_IE_CALLING_NAME:
750                         ies->calling_name = (char *)data + 2;
751                         break;
752                 case IAX_IE_CALLED_CONTEXT:
753                         ies->called_context = (char *)data + 2;
754                         break;
755                 case IAX_IE_USERNAME:
756                         ies->username = (char *)data + 2;
757                         break;
758                 case IAX_IE_PASSWORD:
759                         ies->password = (char *)data + 2;
760                         break;
761                 case IAX_IE_CODEC_PREFS:
762                         ies->codec_prefs = (char *)data + 2;
763                         break;
764                 case IAX_IE_CAPABILITY:
765                         if (len != (int)sizeof(unsigned int)) {
766                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
767                                 errorf(tmp);
768                         } else
769                                 ies->capability = ntohl(get_unaligned_uint32(data + 2));
770                         break;
771                 case IAX_IE_FORMAT:
772                         if (len != (int)sizeof(unsigned int)) {
773                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
774                                 errorf(tmp);
775                         } else
776                                 ies->format = ntohl(get_unaligned_uint32(data + 2));
777                         break;
778                 case IAX_IE_LANGUAGE:
779                         ies->language = (char *)data + 2;
780                         break;
781                 case IAX_IE_VERSION:
782                         if (len != (int)sizeof(unsigned short)) {
783                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
784                                 errorf(tmp);
785                         } else
786                                 ies->version = ntohs(get_unaligned_uint16(data + 2));
787                         break;
788                 case IAX_IE_ADSICPE:
789                         if (len != (int)sizeof(unsigned short)) {
790                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
791                                 errorf(tmp);
792                         } else
793                                 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
794                         break;
795                 case IAX_IE_SAMPLINGRATE:
796                         if (len != (int)sizeof(unsigned short)) {
797                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
798                                 errorf(tmp);
799                         } else
800                                 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
801                         break;
802                 case IAX_IE_DNID:
803                         ies->dnid = (char *)data + 2;
804                         break;
805                 case IAX_IE_RDNIS:
806                         ies->rdnis = (char *)data + 2;
807                         break;
808                 case IAX_IE_AUTHMETHODS:
809                         if (len != (int)sizeof(unsigned short))  {
810                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
811                                 errorf(tmp);
812                         } else
813                                 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
814                         break;
815                 case IAX_IE_ENCRYPTION:
816                         if (len != (int)sizeof(unsigned short))  {
817                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
818                                 errorf(tmp);
819                         } else
820                                 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
821                         break;
822                 case IAX_IE_CHALLENGE:
823                         ies->challenge = (char *)data + 2;
824                         break;
825                 case IAX_IE_MD5_RESULT:
826                         ies->md5_result = (char *)data + 2;
827                         break;
828                 case IAX_IE_RSA_RESULT:
829                         ies->rsa_result = (char *)data + 2;
830                         break;
831                 case IAX_IE_APPARENT_ADDR:
832                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
833                         break;
834                 case IAX_IE_REFRESH:
835                         if (len != (int)sizeof(unsigned short)) {
836                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
837                                 errorf(tmp);
838                         } else
839                                 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
840                         break;
841                 case IAX_IE_DPSTATUS:
842                         if (len != (int)sizeof(unsigned short)) {
843                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
844                                 errorf(tmp);
845                         } else
846                                 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
847                         break;
848                 case IAX_IE_CALLNO:
849                         if (len != (int)sizeof(unsigned short)) {
850                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
851                                 errorf(tmp);
852                         } else
853                                 ies->callno = ntohs(get_unaligned_uint16(data + 2));
854                         break;
855                 case IAX_IE_CAUSE:
856                         ies->cause = (char *)data + 2;
857                         break;
858                 case IAX_IE_CAUSECODE:
859                         if (len != 1) {
860                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
861                                 errorf(tmp);
862                         } else {
863                                 ies->causecode = data[2];
864                         }
865                         break;
866                 case IAX_IE_IAX_UNKNOWN:
867                         if (len == 1)
868                                 ies->iax_unknown = data[2];
869                         else {
870                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
871                                 errorf(tmp);
872                         }
873                         break;
874                 case IAX_IE_MSGCOUNT:
875                         if (len != (int)sizeof(unsigned short)) {
876                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
877                                 errorf(tmp);
878                         } else
879                                 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));  
880                         break;
881                 case IAX_IE_AUTOANSWER:
882                         ies->autoanswer = 1;
883                         break;
884                 case IAX_IE_MUSICONHOLD:
885                         ies->musiconhold = 1;
886                         break;
887                 case IAX_IE_TRANSFERID:
888                         if (len != (int)sizeof(unsigned int)) {
889                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
890                                 errorf(tmp);
891                         } else
892                                 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
893                         break;
894                 case IAX_IE_DATETIME:
895                         if (len != (int)sizeof(unsigned int)) {
896                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
897                                 errorf(tmp);
898                         } else
899                                 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
900                         break;
901                 case IAX_IE_FIRMWAREVER:
902                         if (len != (int)sizeof(unsigned short)) {
903                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
904                                 errorf(tmp);
905                         } else
906                                 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));       
907                         break;
908                 case IAX_IE_DEVICETYPE:
909                         ies->devicetype = (char *)data + 2;
910                         break;
911                 case IAX_IE_SERVICEIDENT:
912                         ies->serviceident = (char *)data + 2;
913                         break;
914                 case IAX_IE_FWBLOCKDESC:
915                         if (len != (int)sizeof(unsigned int)) {
916                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
917                                 errorf(tmp);
918                         } else
919                                 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
920                         break;
921                 case IAX_IE_FWBLOCKDATA:
922                         ies->fwdata = data + 2;
923                         ies->fwdatalen = len;
924                         break;
925                 case IAX_IE_ENCKEY:
926                         ies->enckey = data + 2;
927                         ies->enckeylen = len;
928                         break;
929                 case IAX_IE_PROVVER:
930                         if (len != (int)sizeof(unsigned int)) {
931                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
932                                 errorf(tmp);
933                         } else {
934                                 ies->provverpres = 1;
935                                 ies->provver = ntohl(get_unaligned_uint32(data + 2));
936                         }
937                         break;
938                 case IAX_IE_CALLINGPRES:
939                         if (len == 1)
940                                 ies->calling_pres = data[2];
941                         else {
942                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
943                                 errorf(tmp);
944                         }
945                         break;
946                 case IAX_IE_CALLINGTON:
947                         if (len == 1)
948                                 ies->calling_ton = data[2];
949                         else {
950                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
951                                 errorf(tmp);
952                         }
953                         break;
954                 case IAX_IE_CALLINGTNS:
955                         if (len != (int)sizeof(unsigned short)) {
956                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
957                                 errorf(tmp);
958                         } else
959                                 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));       
960                         break;
961                case IAX_IE_RR_JITTER:
962                        if (len != (int)sizeof(unsigned int)) {
963                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
964                                errorf(tmp);
965                        } else {
966                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
967                        }
968                        break;
969                case IAX_IE_RR_LOSS:
970                        if (len != (int)sizeof(unsigned int)) {
971                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
972                                errorf(tmp);
973                        } else {
974                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
975                        }
976                        break;
977                case IAX_IE_RR_PKTS:
978                        if (len != (int)sizeof(unsigned int)) {
979                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
980                                errorf(tmp);
981                        } else {
982                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
983                        }
984                        break;
985                case IAX_IE_RR_DELAY:
986                        if (len != (int)sizeof(unsigned short)) {
987                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
988                         errorf(tmp);
989                        } else {
990                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
991                        }
992                        break;
993                 case IAX_IE_RR_DROPPED:
994                         if (len != (int)sizeof(unsigned int)) {
995                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
996                                 errorf(tmp);
997                         } else {
998                                 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
999                         }
1000                         break;
1001                 case IAX_IE_RR_OOO:
1002                         if (len != (int)sizeof(unsigned int)) {
1003                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
1004                                 errorf(tmp);
1005                         } else {
1006                                 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
1007                         }
1008                         break;
1009                 case IAX_IE_VARIABLE:
1010                         ast_copy_string(tmp, (char *)data + 2, len + 1);
1011                         tmp2 = strchr(tmp, '=');
1012                         if (tmp2)
1013                                 *tmp2++ = '\0';
1014                         else
1015                                 tmp2 = "";
1016                         {
1017                                 struct ast_str *str = ast_str_create(16);
1018                                 /* Existing variable or new variable? */
1019                                 for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
1020                                         if (strcmp(tmp, var2->name) == 0) {
1021                                                 ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
1022                                                 var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
1023                                                 var->next = var2->next;
1024                                                 if (prev) {
1025                                                         prev->next = var;
1026                                                 } else {
1027                                                         ies->vars = var;
1028                                                 }
1029                                                 snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
1030                                                 errorf(tmp);
1031                                                 ast_free(var2);
1032                                                 break;
1033                                         }
1034                                 }
1035                                 ast_free(str);
1036                         }
1037
1038                         if (!var2) {
1039                                 var = ast_variable_new(tmp, tmp2, "");
1040                                 snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
1041                                 errorf(tmp);
1042                                 var->next = ies->vars;
1043                                 ies->vars = var;
1044                         }
1045                         break;
1046                 case IAX_IE_OSPTOKEN:
1047                         if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
1048                                 ies->osptokenblock[count] = (char *)data + 2 + 1;
1049                                 ies->ospblocklength[count] = len - 1;
1050                         } else {
1051                                 snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
1052                                 errorf(tmp);
1053                         }
1054                         break;
1055                 default:
1056                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
1057                         outputf(tmp);
1058                 }
1059                 /* Overwrite information element with 0, to null terminate previous portion */
1060                 data[0] = 0;
1061                 datalen -= (len + 2);
1062                 data += (len + 2);
1063         }
1064         /* Null-terminate last field */
1065         *data = '\0';
1066         if (datalen) {
1067                 errorf("Invalid information element contents, strange boundary\n");
1068                 return -1;
1069         }
1070         return 0;
1071 }
1072
1073 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
1074 {
1075         fr->af.frametype = f->frametype;
1076         fr->af.subclass = f->subclass;
1077         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
1078         fr->af.datalen = f->datalen;
1079         fr->af.samples = f->samples;
1080         fr->af.offset = AST_FRIENDLY_OFFSET;
1081         fr->af.src = f->src;
1082         fr->af.delivery.tv_sec = 0;
1083         fr->af.delivery.tv_usec = 0;
1084         fr->af.data.ptr = fr->afdata;
1085         fr->af.len = f->len;
1086         if (fr->af.datalen) {
1087                 size_t copy_len = fr->af.datalen;
1088                 if (copy_len > fr->afdatalen) {
1089                         ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
1090                                 (int) fr->afdatalen, (int) fr->af.datalen);
1091                         copy_len = fr->afdatalen;
1092                 }
1093 #if __BYTE_ORDER == __LITTLE_ENDIAN
1094                 /* We need to byte-swap slinear samples from network byte order */
1095                 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
1096                         /* 2 bytes / sample for SLINEAR */
1097                         ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
1098                 } else
1099 #endif
1100                         memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
1101         }
1102 }
1103
1104 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
1105 {
1106         struct iax_frame *fr = NULL;
1107
1108 #if !defined(LOW_MEMORY)
1109         struct iax_frames *iax_frames = NULL;
1110         struct iax_frame *smallest = NULL;
1111
1112         /* Attempt to get a frame from this thread's cache */
1113         if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1114                 smallest = AST_LIST_FIRST(&iax_frames->list);
1115                 AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
1116                         if (fr->afdatalen >= datalen) {
1117                                 size_t afdatalen = fr->afdatalen;
1118                                 AST_LIST_REMOVE_CURRENT(list);
1119                                 iax_frames->size--;
1120                                 memset(fr, 0, sizeof(*fr));
1121                                 fr->afdatalen = afdatalen;
1122                                 break;
1123                         } else if (smallest->afdatalen > fr->afdatalen) {
1124                                 smallest = fr;
1125                         }
1126                 }
1127                 AST_LIST_TRAVERSE_SAFE_END;
1128         }
1129         if (!fr) {
1130                 if (iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) {
1131                         /* Make useless cache into something more useful */
1132                         AST_LIST_REMOVE(&iax_frames->list, smallest, list);
1133                         if (!(fr = ast_realloc(smallest, sizeof(*fr) + datalen))) {
1134                                 AST_LIST_INSERT_TAIL(&iax_frames->list, smallest, list);
1135                                 return NULL;
1136                         }
1137                 } else if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
1138                         return NULL;
1139                 fr->afdatalen = datalen;
1140         }
1141 #else
1142         if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
1143                 return NULL;
1144         fr->afdatalen = datalen;
1145 #endif
1146
1147
1148         fr->direction = direction;
1149         fr->retrans = -1;
1150         fr->cacheable = cacheable;
1151         
1152         if (fr->direction == DIRECTION_INGRESS)
1153                 ast_atomic_fetchadd_int(&iframes, 1);
1154         else
1155                 ast_atomic_fetchadd_int(&oframes, 1);
1156         
1157         ast_atomic_fetchadd_int(&frames, 1);
1158
1159         return fr;
1160 }
1161
1162 void iax_frame_free(struct iax_frame *fr)
1163 {
1164 #if !defined(LOW_MEMORY)
1165         struct iax_frames *iax_frames = NULL;
1166 #endif
1167
1168         /* Note: does not remove from scheduler! */
1169         if (fr->direction == DIRECTION_INGRESS)
1170                 ast_atomic_fetchadd_int(&iframes, -1);
1171         else if (fr->direction == DIRECTION_OUTGRESS)
1172                 ast_atomic_fetchadd_int(&oframes, -1);
1173         else {
1174                 errorf("Attempt to double free frame detected\n");
1175                 return;
1176         }
1177         ast_atomic_fetchadd_int(&frames, -1);
1178
1179 #if !defined(LOW_MEMORY)
1180         if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1181                 ast_free(fr);
1182                 return;
1183         }
1184
1185         if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
1186                 fr->direction = 0;
1187                 /* Pseudo-sort: keep smaller frames at the top of the list. This should
1188                  * increase the chance that we pick the smallest applicable frame for use. */
1189                 if (AST_LIST_FIRST(&iax_frames->list) && AST_LIST_FIRST(&iax_frames->list)->afdatalen < fr->afdatalen) {
1190                         AST_LIST_INSERT_TAIL(&iax_frames->list, fr, list);
1191                 } else {
1192                         AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
1193                 }
1194                 iax_frames->size++;
1195                 return;
1196         }
1197 #endif
1198         ast_free(fr);
1199 }
1200
1201 #if !defined(LOW_MEMORY)
1202 static void frame_cache_cleanup(void *data)
1203 {
1204         struct iax_frames *framelist = data;
1205         struct iax_frame *current;
1206
1207         while ((current = AST_LIST_REMOVE_HEAD(&framelist->list, list)))
1208                 ast_free(current);
1209
1210         ast_free(framelist);
1211 }
1212 #endif
1213
1214 int iax_get_frames(void) { return frames; }
1215 int iax_get_iframes(void) { return iframes; }
1216 int iax_get_oframes(void) { return oframes; }