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