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