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