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