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