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