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