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