Optionally display the value of several variables within the Status command.
[asterisk-bristuff.git] / channels / iax2-parser.c
bloba86bf74284850fe4eb6bb68fce67892d0cff85f8
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_frames, iax_frame);
58 #endif
60 static void internaloutput(const char *str)
62 fputs(str, stdout);
65 static void internalerror(const char *str)
67 fprintf(stderr, "WARNING: %s", str);
70 static void (*outputf)(const char *str) = internaloutput;
71 static void (*errorf)(const char *str) = internalerror;
73 static void dump_addr(char *output, int maxlen, void *value, int len)
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);
84 static void dump_string(char *output, int maxlen, void *value, int len)
86 maxlen--;
87 if (maxlen > len)
88 maxlen = len;
89 strncpy(output, value, maxlen);
90 output[maxlen] = '\0';
93 static void dump_prefs(char *output, int maxlen, void *value, int len)
95 struct ast_codec_pref pref;
96 int total_len = 0;
98 maxlen--;
99 total_len = maxlen;
101 if (maxlen > len)
102 maxlen = len;
104 strncpy(output, value, maxlen);
105 output[maxlen] = '\0';
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);
112 static void dump_int(char *output, int maxlen, void *value, int len)
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);
120 static void dump_short(char *output, int maxlen, void *value, int len)
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);
128 static void dump_byte(char *output, int maxlen, void *value, int len)
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);
136 static void dump_datetime(char *output, int maxlen, void *value, int len)
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);
152 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
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);
163 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
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);
173 static void dump_samprate(char *output, int maxlen, void *value, int len)
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);
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)
203 dump_prov_ies(output, maxlen, value, len);
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" },
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 },
285 const char *iax_ie2str(int ie)
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;
292 return "Unknown IE";
296 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
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;
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);
335 found++;
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);
343 iedata += (2 + ielen);
344 len -= (2 + ielen);
348 static void dump_ies(unsigned char *iedata, int len)
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;
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);
381 found++;
384 if (!found) {
385 snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
386 outputf(tmp);
388 iedata += (2 + ielen);
389 len -= (2 + ielen);
391 outputf("\n");
394 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
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 ",
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"
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];
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;
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");
505 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
506 /* Don't mess with mini-frames */
507 return;
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];
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];
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];
532 } else {
533 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
534 subclass = subclass2;
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);
551 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
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;
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;
566 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
568 return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
571 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
573 unsigned int newval;
574 newval = htonl(value);
575 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
578 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
580 unsigned short newval;
581 newval = htons(value);
582 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
585 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
587 return iax_ie_append_raw(ied, ie, str, strlen(str));
590 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
592 return iax_ie_append_raw(ied, ie, &dat, 1);
595 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
597 return iax_ie_append_raw(ied, ie, NULL, 0);
600 void iax_set_output(void (*func)(const char *))
602 outputf = func;
605 void iax_set_error(void (*func)(const char *))
607 errorf = func;
610 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
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;
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];
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);
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));
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);
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);
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));
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));
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));
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));
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));
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));
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;
925 if (!var2) {
926 var = ast_variable_new(tmp, tmp2, "");
927 var->next = ies->vars;
928 ies->vars = var;
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);
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);
944 /* Overwrite information element with 0, to null terminate previous portion */
945 data[0] = 0;
946 datalen -= (len + 2);
947 data += (len + 2);
949 /* Null-terminate last field */
950 *data = '\0';
951 if (datalen) {
952 errorf("Invalid information element contents, strange boundary\n");
953 return -1;
955 return 0;
958 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
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;
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);
989 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
991 struct iax_frame *fr = NULL;
993 #if !defined(LOW_MEMORY)
994 struct iax_frames *iax_frames = NULL;
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;
1007 AST_LIST_TRAVERSE_SAFE_END;
1009 if (!fr) {
1010 if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
1011 return NULL;
1012 fr->afdatalen = datalen;
1014 #else
1015 if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
1016 return NULL;
1017 fr->afdatalen = datalen;
1018 #endif
1021 fr->direction = direction;
1022 fr->retrans = -1;
1023 fr->cacheable = cacheable;
1025 if (fr->direction == DIRECTION_INGRESS)
1026 ast_atomic_fetchadd_int(&iframes, 1);
1027 else
1028 ast_atomic_fetchadd_int(&oframes, 1);
1030 ast_atomic_fetchadd_int(&frames, 1);
1032 return fr;
1035 void iax_frame_free(struct iax_frame *fr)
1037 #if !defined(LOW_MEMORY)
1038 struct iax_frames *iax_frames = NULL;
1039 #endif
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;
1050 ast_atomic_fetchadd_int(&frames, -1);
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;
1058 fr->direction = 0;
1059 AST_LIST_INSERT_HEAD(iax_frames, fr, list);
1060 #else
1061 ast_free(fr);
1062 #endif
1065 #if !defined(LOW_MEMORY)
1066 static void frame_cache_cleanup(void *data)
1068 struct iax_frames *frames = data;
1069 struct iax_frame *cur;
1071 while ((cur = AST_LIST_REMOVE_HEAD(frames, list)))
1072 ast_free(cur);
1074 ast_free(frames);
1076 #endif
1078 int iax_get_frames(void) { return frames; }
1079 int iax_get_iframes(void) { return iframes; }
1080 int iax_get_oframes(void) { return oframes; }