I thought I was going to be able to leave 1.4 alone, but that was not the case.
[asterisk-bristuff.git] / channels / iax2-parser.c
blobf9c3714dbe36fb09ad200fe783a35cce6a04ac08
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_frames, iax_frame);
62 #endif
64 static void internaloutput(const char *str)
66 fputs(str, stdout);
69 static void internalerror(const char *str)
71 fprintf(stderr, "WARNING: %s", str);
74 static void (*outputf)(const char *str) = internaloutput;
75 static void (*errorf)(const char *str) = internalerror;
77 static void dump_addr(char *output, int maxlen, void *value, int len)
79 struct sockaddr_in sin;
80 if (len == (int)sizeof(sin)) {
81 memcpy(&sin, value, len);
82 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
83 } else {
84 snprintf(output, maxlen, "Invalid Address");
88 static void dump_string(char *output, int maxlen, void *value, int len)
90 maxlen--;
91 if (maxlen > len)
92 maxlen = len;
93 strncpy(output, value, maxlen);
94 output[maxlen] = '\0';
97 static void dump_prefs(char *output, int maxlen, void *value, int len)
99 struct ast_codec_pref pref;
100 int total_len = 0;
102 maxlen--;
103 total_len = maxlen;
105 if (maxlen > len)
106 maxlen = len;
108 strncpy(output, value, maxlen);
109 output[maxlen] = '\0';
111 ast_codec_pref_convert(&pref, output, total_len, 0);
112 memset(output,0,total_len);
113 ast_codec_pref_string(&pref, output, total_len);
116 static void dump_int(char *output, int maxlen, void *value, int len)
118 if (len == (int)sizeof(unsigned int))
119 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
120 else
121 ast_copy_string(output, "Invalid INT", maxlen);
124 static void dump_short(char *output, int maxlen, void *value, int len)
126 if (len == (int)sizeof(unsigned short))
127 snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
128 else
129 ast_copy_string(output, "Invalid SHORT", maxlen);
132 static void dump_byte(char *output, int maxlen, void *value, int len)
134 if (len == (int)sizeof(unsigned char))
135 snprintf(output, maxlen, "%d", *((unsigned char *)value));
136 else
137 ast_copy_string(output, "Invalid BYTE", maxlen);
140 static void dump_datetime(char *output, int maxlen, void *value, int len)
142 struct tm tm;
143 unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
144 if (len == (int)sizeof(unsigned int)) {
145 tm.tm_sec = (val & 0x1f) << 1;
146 tm.tm_min = (val >> 5) & 0x3f;
147 tm.tm_hour = (val >> 11) & 0x1f;
148 tm.tm_mday = (val >> 16) & 0x1f;
149 tm.tm_mon = ((val >> 21) & 0x0f) - 1;
150 tm.tm_year = ((val >> 25) & 0x7f) + 100;
151 strftime(output, maxlen, "%Y-%m-%d %T", &tm);
152 } else
153 ast_copy_string(output, "Invalid DATETIME format!", maxlen);
156 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
158 struct sockaddr_in sin;
159 if (len == (int)sizeof(unsigned int)) {
160 memcpy(&sin.sin_addr, value, len);
161 snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
162 } else
163 ast_copy_string(output, "Invalid IPADDR", maxlen);
167 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
169 char buf[256] = "";
170 if (len == (int)sizeof(unsigned int))
171 snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
172 iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
173 else
174 ast_copy_string(output, "Invalid INT", maxlen);
177 static void dump_samprate(char *output, int maxlen, void *value, int len)
179 char tmp[256]="";
180 int sr;
181 if (len == (int)sizeof(unsigned short)) {
182 sr = ntohs(*((unsigned short *)value));
183 if (sr & IAX_RATE_8KHZ)
184 strcat(tmp, ",8khz");
185 if (sr & IAX_RATE_11KHZ)
186 strcat(tmp, ",11.025khz");
187 if (sr & IAX_RATE_16KHZ)
188 strcat(tmp, ",16khz");
189 if (sr & IAX_RATE_22KHZ)
190 strcat(tmp, ",22.05khz");
191 if (sr & IAX_RATE_44KHZ)
192 strcat(tmp, ",44.1khz");
193 if (sr & IAX_RATE_48KHZ)
194 strcat(tmp, ",48khz");
195 if (strlen(tmp))
196 ast_copy_string(output, &tmp[1], maxlen);
197 else
198 ast_copy_string(output, "None Specified!\n", maxlen);
199 } else
200 ast_copy_string(output, "Invalid SHORT", maxlen);
204 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
205 static void dump_prov(char *output, int maxlen, void *value, int len)
207 dump_prov_ies(output, maxlen, value, len);
210 static struct iax2_ie {
211 int ie;
212 char *name;
213 void (*dump)(char *output, int maxlen, void *value, int len);
214 } ies[] = {
215 { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
216 { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
217 { IAX_IE_CALLING_ANI, "ANI", dump_string },
218 { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
219 { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
220 { IAX_IE_USERNAME, "USERNAME", dump_string },
221 { IAX_IE_PASSWORD, "PASSWORD", dump_string },
222 { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
223 { IAX_IE_FORMAT, "FORMAT", dump_int },
224 { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
225 { IAX_IE_VERSION, "VERSION", dump_short },
226 { IAX_IE_ADSICPE, "ADSICPE", dump_short },
227 { IAX_IE_DNID, "DNID", dump_string },
228 { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
229 { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
230 { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
231 { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
232 { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
233 { IAX_IE_REFRESH, "REFRESH", dump_short },
234 { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
235 { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
236 { IAX_IE_CAUSE, "CAUSE", dump_string },
237 { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
238 { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
239 { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
240 { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
241 { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
242 { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
243 { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
244 { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
245 { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
246 { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
247 { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
248 { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
249 { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
250 { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
251 { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
252 { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
253 { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
254 { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
255 { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
256 { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
257 { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
258 { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
259 { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
260 { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
261 { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
262 { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
263 { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
264 { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
267 static struct iax2_ie prov_ies[] = {
268 { PROV_IE_USEDHCP, "USEDHCP" },
269 { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
270 { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
271 { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
272 { PROV_IE_PORTNO, "BINDPORT", dump_short },
273 { PROV_IE_USER, "USERNAME", dump_string },
274 { PROV_IE_PASS, "PASSWORD", dump_string },
275 { PROV_IE_LANG, "LANGUAGE", dump_string },
276 { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
277 { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
278 { PROV_IE_FORMAT, "FORMAT", dump_int },
279 { PROV_IE_AESKEY, "AESKEY" },
280 { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
281 { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
282 { PROV_IE_NEWAESKEY, "NEWAESKEY" },
283 { PROV_IE_PROVVER, "PROV VERSION", dump_int },
284 { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
287 const char *iax_ie2str(int ie)
289 int x;
290 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
291 if (ies[x].ie == ie)
292 return ies[x].name;
294 return "Unknown IE";
298 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
300 int ielen;
301 int ie;
302 int x;
303 int found;
304 char interp[80];
305 char tmp[256];
306 if (len < 2)
307 return;
308 strcpy(output, "\n");
309 maxlen -= strlen(output); output += strlen(output);
310 while(len > 2) {
311 ie = iedata[0];
312 ielen = iedata[1];
313 if (ielen + 2> len) {
314 snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
315 ast_copy_string(output, tmp, maxlen);
316 maxlen -= strlen(output);
317 output += strlen(output);
318 return;
320 found = 0;
321 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
322 if (prov_ies[x].ie == ie) {
323 if (prov_ies[x].dump) {
324 prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
325 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
326 ast_copy_string(output, tmp, maxlen);
327 maxlen -= strlen(output); output += strlen(output);
328 } else {
329 if (ielen)
330 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
331 else
332 strcpy(interp, "Present");
333 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
334 ast_copy_string(output, tmp, maxlen);
335 maxlen -= strlen(output); output += strlen(output);
337 found++;
340 if (!found) {
341 snprintf(tmp, (int)sizeof(tmp), " Unknown Prov IE %03d : Present\n", ie);
342 ast_copy_string(output, tmp, maxlen);
343 maxlen -= strlen(output); output += strlen(output);
345 iedata += (2 + ielen);
346 len -= (2 + ielen);
350 static void dump_ies(unsigned char *iedata, int len)
352 int ielen;
353 int ie;
354 int x;
355 int found;
356 char interp[1024];
357 char tmp[1024];
358 if (len < 2)
359 return;
360 while(len > 2) {
361 ie = iedata[0];
362 ielen = iedata[1];
363 if (ielen + 2> len) {
364 snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
365 outputf(tmp);
366 return;
368 found = 0;
369 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
370 if (ies[x].ie == ie) {
371 if (ies[x].dump) {
372 ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
373 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
374 outputf(tmp);
375 } else {
376 if (ielen)
377 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
378 else
379 strcpy(interp, "Present");
380 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
381 outputf(tmp);
383 found++;
386 if (!found) {
387 snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
388 outputf(tmp);
390 iedata += (2 + ielen);
391 len -= (2 + ielen);
393 outputf("\n");
396 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
398 const char *frames[] = {
399 "(0?)",
400 "DTMF_E ",
401 "VOICE ",
402 "VIDEO ",
403 "CONTROL",
404 "NULL ",
405 "IAX ",
406 "TEXT ",
407 "IMAGE ",
408 "HTML ",
409 "CNG ",
410 "MODEM ",
411 "DTMF_B ",
413 const char *iaxs[] = {
414 "(0?)",
415 "NEW ",
416 "PING ",
417 "PONG ",
418 "ACK ",
419 "HANGUP ",
420 "REJECT ",
421 "ACCEPT ",
422 "AUTHREQ",
423 "AUTHREP",
424 "INVAL ",
425 "LAGRQ ",
426 "LAGRP ",
427 "REGREQ ",
428 "REGAUTH",
429 "REGACK ",
430 "REGREJ ",
431 "REGREL ",
432 "VNAK ",
433 "DPREQ ",
434 "DPREP ",
435 "DIAL ",
436 "TXREQ ",
437 "TXCNT ",
438 "TXACC ",
439 "TXREADY",
440 "TXREL ",
441 "TXREJ ",
442 "QUELCH ",
443 "UNQULCH",
444 "POKE ",
445 "PAGE ",
446 "MWI ",
447 "UNSPRTD",
448 "TRANSFR",
449 "PROVISN",
450 "FWDWNLD",
451 "FWDATA ",
452 "TXMEDIA"
454 const char *cmds[] = {
455 "(0?)",
456 "HANGUP ",
457 "RING ",
458 "RINGING",
459 "ANSWER ",
460 "BUSY ",
461 "TKOFFHK",
462 "OFFHOOK",
463 "CONGSTN",
464 "FLASH ",
465 "WINK ",
466 "OPTION ",
467 "RDKEY ",
468 "RDUNKEY",
469 "PROGRES",
470 "PROCDNG",
471 "HOLD ",
472 "UNHOLD ",
473 "VIDUPDT", };
474 struct ast_iax2_full_hdr *fh;
475 char retries[20];
476 char class2[20];
477 char subclass2[20];
478 const char *class;
479 const char *subclass;
480 char *dir;
481 char tmp[512];
483 switch(rx) {
484 case 0:
485 dir = "Tx";
486 break;
487 case 2:
488 dir = "TE";
489 break;
490 case 3:
491 dir = "RD";
492 break;
493 default:
494 dir = "Rx";
495 break;
497 if (f) {
498 fh = f->data;
499 snprintf(retries, sizeof(retries), "%03d", f->retries);
500 } else {
501 fh = fhi;
502 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
503 strcpy(retries, "Yes");
504 else
505 strcpy(retries, " No");
507 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
508 /* Don't mess with mini-frames */
509 return;
511 if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
512 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
513 class = class2;
514 } else {
515 class = frames[(int)fh->type];
517 if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
518 sprintf(subclass2, "%c", fh->csub);
519 subclass = subclass2;
520 } else if (fh->type == AST_FRAME_IAX) {
521 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
522 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
523 subclass = subclass2;
524 } else {
525 subclass = iaxs[(int)fh->csub];
527 } else if (fh->type == AST_FRAME_CONTROL) {
528 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
529 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
530 subclass = subclass2;
531 } else {
532 subclass = cmds[(int)fh->csub];
534 } else {
535 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
536 subclass = subclass2;
538 snprintf(tmp, sizeof(tmp),
539 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
540 dir,
541 retries, fh->oseqno, fh->iseqno, class, subclass);
542 outputf(tmp);
543 snprintf(tmp, sizeof(tmp),
544 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
545 (unsigned long)ntohl(fh->ts),
546 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
547 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
548 outputf(tmp);
549 if (fh->type == AST_FRAME_IAX)
550 dump_ies(fh->iedata, datalen);
553 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
555 char tmp[256];
556 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
557 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);
558 errorf(tmp);
559 return -1;
561 ied->buf[ied->pos++] = ie;
562 ied->buf[ied->pos++] = datalen;
563 memcpy(ied->buf + ied->pos, data, datalen);
564 ied->pos += datalen;
565 return 0;
568 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
570 return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
573 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
575 unsigned int newval;
576 newval = htonl(value);
577 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
580 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
582 unsigned short newval;
583 newval = htons(value);
584 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
587 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
589 return iax_ie_append_raw(ied, ie, str, strlen(str));
592 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
594 return iax_ie_append_raw(ied, ie, &dat, 1);
597 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
599 return iax_ie_append_raw(ied, ie, NULL, 0);
602 void iax_set_output(void (*func)(const char *))
604 outputf = func;
607 void iax_set_error(void (*func)(const char *))
609 errorf = func;
612 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
614 /* Parse data into information elements */
615 int len;
616 int ie;
617 char tmp[256];
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 default:
903 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
904 outputf(tmp);
906 /* Overwrite information element with 0, to null terminate previous portion */
907 data[0] = 0;
908 datalen -= (len + 2);
909 data += (len + 2);
911 /* Null-terminate last field */
912 *data = '\0';
913 if (datalen) {
914 errorf("Invalid information element contents, strange boundary\n");
915 return -1;
917 return 0;
920 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
922 fr->af.frametype = f->frametype;
923 fr->af.subclass = f->subclass;
924 fr->af.mallocd = 0; /* Our frame is static relative to the container */
925 fr->af.datalen = f->datalen;
926 fr->af.samples = f->samples;
927 fr->af.offset = AST_FRIENDLY_OFFSET;
928 fr->af.src = f->src;
929 fr->af.delivery.tv_sec = 0;
930 fr->af.delivery.tv_usec = 0;
931 fr->af.data = fr->afdata;
932 fr->af.len = f->len;
933 if (fr->af.datalen) {
934 size_t copy_len = fr->af.datalen;
935 if (copy_len > fr->afdatalen) {
936 ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
937 (int) fr->afdatalen, (int) fr->af.datalen);
938 copy_len = fr->afdatalen;
940 #if __BYTE_ORDER == __LITTLE_ENDIAN
941 /* We need to byte-swap slinear samples from network byte order */
942 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
943 /* 2 bytes / sample for SLINEAR */
944 ast_swapcopy_samples(fr->af.data, f->data, copy_len / 2);
945 } else
946 #endif
947 memcpy(fr->af.data, f->data, copy_len);
951 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
953 struct iax_frame *fr = NULL;
955 #if !defined(LOW_MEMORY)
956 struct iax_frames *iax_frames;
958 /* Attempt to get a frame from this thread's cache */
959 if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
960 AST_LIST_TRAVERSE_SAFE_BEGIN(iax_frames, fr, list) {
961 if (fr->afdatalen >= datalen) {
962 size_t afdatalen = fr->afdatalen;
963 AST_LIST_REMOVE_CURRENT(iax_frames, list);
964 memset(fr, 0, sizeof(*fr));
965 fr->afdatalen = afdatalen;
966 break;
969 AST_LIST_TRAVERSE_SAFE_END
971 if (!fr) {
972 if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
973 return NULL;
974 fr->afdatalen = datalen;
976 #else
977 if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
978 return NULL;
979 fr->afdatalen = datalen;
980 #endif
983 fr->direction = direction;
984 fr->retrans = -1;
985 fr->cacheable = cacheable;
987 if (fr->direction == DIRECTION_INGRESS)
988 ast_atomic_fetchadd_int(&iframes, 1);
989 else
990 ast_atomic_fetchadd_int(&oframes, 1);
992 ast_atomic_fetchadd_int(&frames, 1);
994 return fr;
997 void iax_frame_free(struct iax_frame *fr)
999 #if !defined(LOW_MEMORY)
1000 struct iax_frames *iax_frames;
1001 #endif
1003 /* Note: does not remove from scheduler! */
1004 if (fr->direction == DIRECTION_INGRESS)
1005 ast_atomic_fetchadd_int(&iframes, -1);
1006 else if (fr->direction == DIRECTION_OUTGRESS)
1007 ast_atomic_fetchadd_int(&oframes, -1);
1008 else {
1009 errorf("Attempt to double free frame detected\n");
1010 return;
1012 ast_atomic_fetchadd_int(&frames, -1);
1014 #if !defined(LOW_MEMORY)
1015 if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
1016 free(fr);
1017 return;
1020 fr->direction = 0;
1021 AST_LIST_INSERT_HEAD(iax_frames, fr, list);
1022 #else
1023 free(fr);
1024 #endif
1027 #if !defined(LOW_MEMORY)
1028 static void frame_cache_cleanup(void *data)
1030 struct iax_frames *frames = data;
1031 struct iax_frame *cur;
1033 while ((cur = AST_LIST_REMOVE_HEAD(frames, list)))
1034 free(cur);
1036 free(frames);
1038 #endif
1040 int iax_get_frames(void) { return frames; }
1041 int iax_get_iframes(void) { return iframes; }
1042 int iax_get_oframes(void) { return oframes; }