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