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.
21 * \brief Implementation of Inter-Asterisk eXchange Protocol, v 2
23 * \author Mark Spencer <markster@digium.com>
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"
42 #include "iax2-parser.h"
43 #include "iax2-provision.h"
45 static int frames
= 0;
46 static int iframes
= 0;
47 static int oframes
= 0;
49 #if !defined(LOW_MEMORY)
50 static void frame_cache_cleanup(void *data
);
52 /*! \brief A per-thread cache of iax_frame structures */
53 AST_THREADSTORAGE_CUSTOM(frame_cache
, NULL
, frame_cache_cleanup
);
55 /*! \brief This is just so iax_frames, a list head struct for holding a list of
56 * iax_frame structures, is defined. */
57 AST_LIST_HEAD_NOLOCK(iax_frame_list
, iax_frame
);
60 struct iax_frame_list list
;
64 #define FRAME_CACHE_MAX_SIZE 20
67 static void internaloutput(const char *str
)
72 static void internalerror(const char *str
)
74 fprintf(stderr
, "WARNING: %s", str
);
77 static void (*outputf
)(const char *str
) = internaloutput
;
78 static void (*errorf
)(const char *str
) = internalerror
;
80 static void dump_addr(char *output
, int maxlen
, void *value
, int len
)
82 struct sockaddr_in sin
;
83 if (len
== (int)sizeof(sin
)) {
84 memcpy(&sin
, value
, len
);
85 snprintf(output
, maxlen
, "IPV4 %s:%d", ast_inet_ntoa(sin
.sin_addr
), ntohs(sin
.sin_port
));
87 ast_copy_string(output
, "Invalid Address", maxlen
);
91 static void dump_string_hex(char *output
, int maxlen
, void *value
, int len
)
95 while (len
-- && (i
+ 1) * 4 < maxlen
) {
96 sprintf(output
+ (4 * i
), "\\x%2.2x", *((unsigned char *)value
+ i
));
101 static void dump_string(char *output
, int maxlen
, void *value
, int len
)
106 strncpy(output
, value
, maxlen
);
107 output
[maxlen
] = '\0';
110 static void dump_prefs(char *output
, int maxlen
, void *value
, int len
)
112 struct ast_codec_pref pref
;
121 strncpy(output
, value
, maxlen
);
122 output
[maxlen
] = '\0';
124 ast_codec_pref_convert(&pref
, output
, total_len
, 0);
125 memset(output
,0,total_len
);
126 ast_codec_pref_string(&pref
, output
, total_len
);
129 static void dump_int(char *output
, int maxlen
, void *value
, int len
)
131 if (len
== (int)sizeof(unsigned int))
132 snprintf(output
, maxlen
, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value
)));
134 ast_copy_string(output
, "Invalid INT", maxlen
);
137 static void dump_short(char *output
, int maxlen
, void *value
, int len
)
139 if (len
== (int)sizeof(unsigned short))
140 snprintf(output
, maxlen
, "%d", ntohs(get_unaligned_uint16(value
)));
142 ast_copy_string(output
, "Invalid SHORT", maxlen
);
145 static void dump_byte(char *output
, int maxlen
, void *value
, int len
)
147 if (len
== (int)sizeof(unsigned char))
148 snprintf(output
, maxlen
, "%d", *((unsigned char *)value
));
150 ast_copy_string(output
, "Invalid BYTE", maxlen
);
153 static void dump_datetime(char *output
, int maxlen
, void *value
, int len
)
156 unsigned long val
= (unsigned long) ntohl(get_unaligned_uint32(value
));
157 if (len
== (int)sizeof(unsigned int)) {
158 tm
.tm_sec
= (val
& 0x1f) << 1;
159 tm
.tm_min
= (val
>> 5) & 0x3f;
160 tm
.tm_hour
= (val
>> 11) & 0x1f;
161 tm
.tm_mday
= (val
>> 16) & 0x1f;
162 tm
.tm_mon
= ((val
>> 21) & 0x0f) - 1;
163 tm
.tm_year
= ((val
>> 25) & 0x7f) + 100;
164 ast_strftime(output
, maxlen
, "%Y-%m-%d %T", &tm
);
166 ast_copy_string(output
, "Invalid DATETIME format!", maxlen
);
169 static void dump_ipaddr(char *output
, int maxlen
, void *value
, int len
)
171 struct sockaddr_in sin
;
172 if (len
== (int)sizeof(unsigned int)) {
173 memcpy(&sin
.sin_addr
, value
, len
);
174 snprintf(output
, maxlen
, "%s", ast_inet_ntoa(sin
.sin_addr
));
176 ast_copy_string(output
, "Invalid IPADDR", maxlen
);
180 static void dump_prov_flags(char *output
, int maxlen
, void *value
, int len
)
183 if (len
== (int)sizeof(unsigned int))
184 snprintf(output
, maxlen
, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value
)),
185 iax_provflags2str(buf
, sizeof(buf
), ntohl(get_unaligned_uint32(value
))));
187 ast_copy_string(output
, "Invalid INT", maxlen
);
190 static void dump_samprate(char *output
, int maxlen
, void *value
, int len
)
194 if (len
== (int)sizeof(unsigned short)) {
195 sr
= ntohs(*((unsigned short *)value
));
196 if (sr
& IAX_RATE_8KHZ
)
197 strcat(tmp
, ",8khz");
198 if (sr
& IAX_RATE_11KHZ
)
199 strcat(tmp
, ",11.025khz");
200 if (sr
& IAX_RATE_16KHZ
)
201 strcat(tmp
, ",16khz");
202 if (sr
& IAX_RATE_22KHZ
)
203 strcat(tmp
, ",22.05khz");
204 if (sr
& IAX_RATE_44KHZ
)
205 strcat(tmp
, ",44.1khz");
206 if (sr
& IAX_RATE_48KHZ
)
207 strcat(tmp
, ",48khz");
209 ast_copy_string(output
, &tmp
[1], maxlen
);
211 ast_copy_string(output
, "None Specified!\n", maxlen
);
213 ast_copy_string(output
, "Invalid SHORT", maxlen
);
217 static void dump_prov_ies(char *output
, int maxlen
, unsigned char *iedata
, int len
);
218 static void dump_prov(char *output
, int maxlen
, void *value
, int len
)
220 dump_prov_ies(output
, maxlen
, value
, len
);
223 static struct iax2_ie
{
226 void (*dump
)(char *output
, int maxlen
, void *value
, int len
);
228 { IAX_IE_CALLED_NUMBER
, "CALLED NUMBER", dump_string
},
229 { IAX_IE_CALLING_NUMBER
, "CALLING NUMBER", dump_string
},
230 { IAX_IE_CALLING_ANI
, "ANI", dump_string
},
231 { IAX_IE_CALLING_NAME
, "CALLING NAME", dump_string
},
232 { IAX_IE_CALLED_CONTEXT
, "CALLED CONTEXT", dump_string
},
233 { IAX_IE_USERNAME
, "USERNAME", dump_string
},
234 { IAX_IE_PASSWORD
, "PASSWORD", dump_string
},
235 { IAX_IE_CAPABILITY
, "CAPABILITY", dump_int
},
236 { IAX_IE_FORMAT
, "FORMAT", dump_int
},
237 { IAX_IE_LANGUAGE
, "LANGUAGE", dump_string
},
238 { IAX_IE_VERSION
, "VERSION", dump_short
},
239 { IAX_IE_ADSICPE
, "ADSICPE", dump_short
},
240 { IAX_IE_DNID
, "DNID", dump_string
},
241 { IAX_IE_AUTHMETHODS
, "AUTHMETHODS", dump_short
},
242 { IAX_IE_CHALLENGE
, "CHALLENGE", dump_string_hex
},
243 { IAX_IE_MD5_RESULT
, "MD5 RESULT", dump_string
},
244 { IAX_IE_RSA_RESULT
, "RSA RESULT", dump_string
},
245 { IAX_IE_APPARENT_ADDR
, "APPARENT ADDRESS", dump_addr
},
246 { IAX_IE_REFRESH
, "REFRESH", dump_short
},
247 { IAX_IE_DPSTATUS
, "DIALPLAN STATUS", dump_short
},
248 { IAX_IE_CALLNO
, "CALL NUMBER", dump_short
},
249 { IAX_IE_CAUSE
, "CAUSE", dump_string
},
250 { IAX_IE_IAX_UNKNOWN
, "UNKNOWN IAX CMD", dump_byte
},
251 { IAX_IE_MSGCOUNT
, "MESSAGE COUNT", dump_short
},
252 { IAX_IE_AUTOANSWER
, "AUTO ANSWER REQ" },
253 { IAX_IE_TRANSFERID
, "TRANSFER ID", dump_int
},
254 { IAX_IE_RDNIS
, "REFERRING DNIS", dump_string
},
255 { IAX_IE_PROVISIONING
, "PROVISIONING", dump_prov
},
256 { IAX_IE_AESPROVISIONING
, "AES PROVISIONG" },
257 { IAX_IE_DATETIME
, "DATE TIME", dump_datetime
},
258 { IAX_IE_DEVICETYPE
, "DEVICE TYPE", dump_string
},
259 { IAX_IE_SERVICEIDENT
, "SERVICE IDENT", dump_string
},
260 { IAX_IE_FIRMWAREVER
, "FIRMWARE VER", dump_short
},
261 { IAX_IE_FWBLOCKDESC
, "FW BLOCK DESC", dump_int
},
262 { IAX_IE_FWBLOCKDATA
, "FW BLOCK DATA" },
263 { IAX_IE_PROVVER
, "PROVISIONG VER", dump_int
},
264 { IAX_IE_CALLINGPRES
, "CALLING PRESNTN", dump_byte
},
265 { IAX_IE_CALLINGTON
, "CALLING TYPEOFNUM", dump_byte
},
266 { IAX_IE_CALLINGTNS
, "CALLING TRANSITNET", dump_short
},
267 { IAX_IE_SAMPLINGRATE
, "SAMPLINGRATE", dump_samprate
},
268 { IAX_IE_CAUSECODE
, "CAUSE CODE", dump_byte
},
269 { IAX_IE_ENCRYPTION
, "ENCRYPTION", dump_short
},
270 { IAX_IE_ENCKEY
, "ENCRYPTION KEY" },
271 { IAX_IE_CODEC_PREFS
, "CODEC_PREFS", dump_prefs
},
272 { IAX_IE_RR_JITTER
, "RR_JITTER", dump_int
},
273 { IAX_IE_RR_LOSS
, "RR_LOSS", dump_int
},
274 { IAX_IE_RR_PKTS
, "RR_PKTS", dump_int
},
275 { IAX_IE_RR_DELAY
, "RR_DELAY", dump_short
},
276 { IAX_IE_RR_DROPPED
, "RR_DROPPED", dump_int
},
277 { IAX_IE_RR_OOO
, "RR_OUTOFORDER", dump_int
},
278 { IAX_IE_VARIABLE
, "VARIABLE", dump_string
},
279 { IAX_IE_OSPTOKEN
, "OSPTOKEN" },
282 static struct iax2_ie prov_ies
[] = {
283 { PROV_IE_USEDHCP
, "USEDHCP" },
284 { PROV_IE_IPADDR
, "IPADDR", dump_ipaddr
},
285 { PROV_IE_SUBNET
, "SUBNET", dump_ipaddr
},
286 { PROV_IE_GATEWAY
, "GATEWAY", dump_ipaddr
},
287 { PROV_IE_PORTNO
, "BINDPORT", dump_short
},
288 { PROV_IE_USER
, "USERNAME", dump_string
},
289 { PROV_IE_PASS
, "PASSWORD", dump_string
},
290 { PROV_IE_LANG
, "LANGUAGE", dump_string
},
291 { PROV_IE_TOS
, "TYPEOFSERVICE", dump_byte
},
292 { PROV_IE_FLAGS
, "FLAGS", dump_prov_flags
},
293 { PROV_IE_FORMAT
, "FORMAT", dump_int
},
294 { PROV_IE_AESKEY
, "AESKEY" },
295 { PROV_IE_SERVERIP
, "SERVERIP", dump_ipaddr
},
296 { PROV_IE_SERVERPORT
, "SERVERPORT", dump_short
},
297 { PROV_IE_NEWAESKEY
, "NEWAESKEY" },
298 { PROV_IE_PROVVER
, "PROV VERSION", dump_int
},
299 { PROV_IE_ALTSERVER
, "ALTSERVERIP", dump_ipaddr
},
302 const char *iax_ie2str(int ie
)
305 for (x
= 0; x
< ARRAY_LEN(infoelts
); x
++) {
306 if (infoelts
[x
].ie
== ie
)
307 return infoelts
[x
].name
;
313 static void dump_prov_ies(char *output
, int maxlen
, unsigned char *iedata
, int len
)
323 strcpy(output
, "\n");
324 maxlen
-= strlen(output
); output
+= strlen(output
);
328 if (ielen
+ 2> len
) {
329 snprintf(tmp
, (int)sizeof(tmp
), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen
+ 2, len
);
330 ast_copy_string(output
, tmp
, maxlen
);
331 maxlen
-= strlen(output
);
332 output
+= strlen(output
);
336 for (x
=0;x
<(int)sizeof(prov_ies
) / (int)sizeof(prov_ies
[0]); x
++) {
337 if (prov_ies
[x
].ie
== ie
) {
338 if (prov_ies
[x
].dump
) {
339 prov_ies
[x
].dump(interp
, (int)sizeof(interp
), iedata
+ 2, ielen
);
340 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", prov_ies
[x
].name
, interp
);
341 ast_copy_string(output
, tmp
, maxlen
);
342 maxlen
-= strlen(output
); output
+= strlen(output
);
345 snprintf(interp
, (int)sizeof(interp
), "%d bytes", ielen
);
347 strcpy(interp
, "Present");
348 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", prov_ies
[x
].name
, interp
);
349 ast_copy_string(output
, tmp
, maxlen
);
350 maxlen
-= strlen(output
); output
+= strlen(output
);
356 snprintf(tmp
, (int)sizeof(tmp
), " Unknown Prov IE %03d : Present\n", ie
);
357 ast_copy_string(output
, tmp
, maxlen
);
358 maxlen
-= strlen(output
); output
+= strlen(output
);
360 iedata
+= (2 + ielen
);
365 static void dump_ies(unsigned char *iedata
, int len
)
378 if (ielen
+ 2> len
) {
379 snprintf(tmp
, (int)sizeof(tmp
), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen
+ 2, len
);
384 for (x
= 0; x
< ARRAY_LEN(infoelts
); x
++) {
385 if (infoelts
[x
].ie
== ie
) {
386 if (infoelts
[x
].dump
) {
387 infoelts
[x
].dump(interp
, (int)sizeof(interp
), iedata
+ 2, ielen
);
388 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", infoelts
[x
].name
, interp
);
392 snprintf(interp
, (int)sizeof(interp
), "%d bytes", ielen
);
394 strcpy(interp
, "Present");
395 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", infoelts
[x
].name
, interp
);
402 snprintf(tmp
, (int)sizeof(tmp
), " Unknown IE %03d : Present\n", ie
);
405 iedata
+= (2 + ielen
);
411 void iax_showframe(struct iax_frame
*f
, struct ast_iax2_full_hdr
*fhi
, int rx
, struct sockaddr_in
*sin
, int datalen
)
413 const char *framelist
[] = {
428 const char *iaxs
[] = {
469 const char *cmds
[] = {
489 struct ast_iax2_full_hdr
*fh
;
494 const char *subclass
;
514 snprintf(retries
, sizeof(retries
), "%03d", f
->retries
);
517 if (ntohs(fh
->dcallno
) & IAX_FLAG_RETRANS
)
518 strcpy(retries
, "Yes");
520 strcpy(retries
, " No");
522 if (!(ntohs(fh
->scallno
) & IAX_FLAG_FULL
)) {
523 /* Don't mess with mini-frames */
526 if (fh
->type
>= ARRAY_LEN(framelist
)) {
527 snprintf(class2
, sizeof(class2
), "(%d?)", fh
->type
);
530 class = framelist
[(int)fh
->type
];
532 if (fh
->type
== AST_FRAME_DTMF_BEGIN
|| fh
->type
== AST_FRAME_DTMF_END
) {
533 sprintf(subclass2
, "%c", fh
->csub
);
534 subclass
= subclass2
;
535 } else if (fh
->type
== AST_FRAME_IAX
) {
536 if (fh
->csub
>= (int)sizeof(iaxs
)/(int)sizeof(iaxs
[0])) {
537 snprintf(subclass2
, sizeof(subclass2
), "(%d?)", fh
->csub
);
538 subclass
= subclass2
;
540 subclass
= iaxs
[(int)fh
->csub
];
542 } else if (fh
->type
== AST_FRAME_CONTROL
) {
543 if (fh
->csub
>= (int)sizeof(cmds
)/(int)sizeof(cmds
[0])) {
544 snprintf(subclass2
, sizeof(subclass2
), "(%d?)", fh
->csub
);
545 subclass
= subclass2
;
547 subclass
= cmds
[(int)fh
->csub
];
550 snprintf(subclass2
, sizeof(subclass2
), "%d", fh
->csub
);
551 subclass
= subclass2
;
553 snprintf(tmp
, sizeof(tmp
),
554 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
556 retries
, fh
->oseqno
, fh
->iseqno
, class, subclass
);
558 snprintf(tmp
, sizeof(tmp
),
559 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
560 (unsigned long)ntohl(fh
->ts
),
561 ntohs(fh
->scallno
) & ~IAX_FLAG_FULL
, ntohs(fh
->dcallno
) & ~IAX_FLAG_RETRANS
,
562 ast_inet_ntoa(sin
->sin_addr
), ntohs(sin
->sin_port
));
564 if (fh
->type
== AST_FRAME_IAX
)
565 dump_ies(fh
->iedata
, datalen
);
568 int iax_ie_append_raw(struct iax_ie_data
*ied
, unsigned char ie
, const void *data
, int datalen
)
571 if (datalen
> ((int)sizeof(ied
->buf
) - ied
->pos
)) {
572 snprintf(tmp
, (int)sizeof(tmp
), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie
), ie
, datalen
, (int)sizeof(ied
->buf
) - ied
->pos
);
576 ied
->buf
[ied
->pos
++] = ie
;
577 ied
->buf
[ied
->pos
++] = datalen
;
578 memcpy(ied
->buf
+ ied
->pos
, data
, datalen
);
583 int iax_ie_append_addr(struct iax_ie_data
*ied
, unsigned char ie
, const struct sockaddr_in
*sin
)
585 return iax_ie_append_raw(ied
, ie
, sin
, (int)sizeof(struct sockaddr_in
));
588 int iax_ie_append_int(struct iax_ie_data
*ied
, unsigned char ie
, unsigned int value
)
591 newval
= htonl(value
);
592 return iax_ie_append_raw(ied
, ie
, &newval
, (int)sizeof(newval
));
595 int iax_ie_append_short(struct iax_ie_data
*ied
, unsigned char ie
, unsigned short value
)
597 unsigned short newval
;
598 newval
= htons(value
);
599 return iax_ie_append_raw(ied
, ie
, &newval
, (int)sizeof(newval
));
602 int iax_ie_append_str(struct iax_ie_data
*ied
, unsigned char ie
, const char *str
)
604 return iax_ie_append_raw(ied
, ie
, str
, strlen(str
));
607 int iax_ie_append_byte(struct iax_ie_data
*ied
, unsigned char ie
, unsigned char dat
)
609 return iax_ie_append_raw(ied
, ie
, &dat
, 1);
612 int iax_ie_append(struct iax_ie_data
*ied
, unsigned char ie
)
614 return iax_ie_append_raw(ied
, ie
, NULL
, 0);
617 void iax_set_output(void (*func
)(const char *))
622 void iax_set_error(void (*func
)(const char *))
627 int iax_parse_ies(struct iax_ies
*ies
, unsigned char *data
, int datalen
)
629 /* Parse data into information elements */
632 char tmp
[256], *tmp2
;
633 struct ast_variable
*var
, *var2
, *prev
;
635 memset(ies
, 0, (int)sizeof(struct iax_ies
));
637 ies
->firmwarever
= -1;
638 ies
->calling_ton
= -1;
639 ies
->calling_tns
= -1;
640 ies
->calling_pres
= -1;
641 ies
->samprate
= IAX_RATE_8KHZ
;
642 while(datalen
>= 2) {
645 if (len
> datalen
- 2) {
646 errorf("Information element length exceeds message size\n");
650 case IAX_IE_CALLED_NUMBER
:
651 ies
->called_number
= (char *)data
+ 2;
653 case IAX_IE_CALLING_NUMBER
:
654 ies
->calling_number
= (char *)data
+ 2;
656 case IAX_IE_CALLING_ANI
:
657 ies
->calling_ani
= (char *)data
+ 2;
659 case IAX_IE_CALLING_NAME
:
660 ies
->calling_name
= (char *)data
+ 2;
662 case IAX_IE_CALLED_CONTEXT
:
663 ies
->called_context
= (char *)data
+ 2;
665 case IAX_IE_USERNAME
:
666 ies
->username
= (char *)data
+ 2;
668 case IAX_IE_PASSWORD
:
669 ies
->password
= (char *)data
+ 2;
671 case IAX_IE_CODEC_PREFS
:
672 ies
->codec_prefs
= (char *)data
+ 2;
674 case IAX_IE_CAPABILITY
:
675 if (len
!= (int)sizeof(unsigned int)) {
676 snprintf(tmp
, (int)sizeof(tmp
), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
679 ies
->capability
= ntohl(get_unaligned_uint32(data
+ 2));
682 if (len
!= (int)sizeof(unsigned int)) {
683 snprintf(tmp
, (int)sizeof(tmp
), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
686 ies
->format
= ntohl(get_unaligned_uint32(data
+ 2));
688 case IAX_IE_LANGUAGE
:
689 ies
->language
= (char *)data
+ 2;
692 if (len
!= (int)sizeof(unsigned short)) {
693 snprintf(tmp
, (int)sizeof(tmp
), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
696 ies
->version
= ntohs(get_unaligned_uint16(data
+ 2));
699 if (len
!= (int)sizeof(unsigned short)) {
700 snprintf(tmp
, (int)sizeof(tmp
), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
703 ies
->adsicpe
= ntohs(get_unaligned_uint16(data
+ 2));
705 case IAX_IE_SAMPLINGRATE
:
706 if (len
!= (int)sizeof(unsigned short)) {
707 snprintf(tmp
, (int)sizeof(tmp
), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
710 ies
->samprate
= ntohs(get_unaligned_uint16(data
+ 2));
713 ies
->dnid
= (char *)data
+ 2;
716 ies
->rdnis
= (char *)data
+ 2;
718 case IAX_IE_AUTHMETHODS
:
719 if (len
!= (int)sizeof(unsigned short)) {
720 snprintf(tmp
, (int)sizeof(tmp
), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
723 ies
->authmethods
= ntohs(get_unaligned_uint16(data
+ 2));
725 case IAX_IE_ENCRYPTION
:
726 if (len
!= (int)sizeof(unsigned short)) {
727 snprintf(tmp
, (int)sizeof(tmp
), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
730 ies
->encmethods
= ntohs(get_unaligned_uint16(data
+ 2));
732 case IAX_IE_CHALLENGE
:
733 ies
->challenge
= (char *)data
+ 2;
735 case IAX_IE_MD5_RESULT
:
736 ies
->md5_result
= (char *)data
+ 2;
738 case IAX_IE_RSA_RESULT
:
739 ies
->rsa_result
= (char *)data
+ 2;
741 case IAX_IE_APPARENT_ADDR
:
742 ies
->apparent_addr
= ((struct sockaddr_in
*)(data
+ 2));
745 if (len
!= (int)sizeof(unsigned short)) {
746 snprintf(tmp
, (int)sizeof(tmp
), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
749 ies
->refresh
= ntohs(get_unaligned_uint16(data
+ 2));
751 case IAX_IE_DPSTATUS
:
752 if (len
!= (int)sizeof(unsigned short)) {
753 snprintf(tmp
, (int)sizeof(tmp
), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
756 ies
->dpstatus
= ntohs(get_unaligned_uint16(data
+ 2));
759 if (len
!= (int)sizeof(unsigned short)) {
760 snprintf(tmp
, (int)sizeof(tmp
), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
763 ies
->callno
= ntohs(get_unaligned_uint16(data
+ 2));
766 ies
->cause
= (char *)data
+ 2;
768 case IAX_IE_CAUSECODE
:
770 snprintf(tmp
, (int)sizeof(tmp
), "Expecting causecode to be single byte but was %d\n", len
);
773 ies
->causecode
= data
[2];
776 case IAX_IE_IAX_UNKNOWN
:
778 ies
->iax_unknown
= data
[2];
780 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte Unknown command, but was %d long\n", len
);
784 case IAX_IE_MSGCOUNT
:
785 if (len
!= (int)sizeof(unsigned short)) {
786 snprintf(tmp
, (int)sizeof(tmp
), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
789 ies
->msgcount
= ntohs(get_unaligned_uint16(data
+ 2));
791 case IAX_IE_AUTOANSWER
:
794 case IAX_IE_MUSICONHOLD
:
795 ies
->musiconhold
= 1;
797 case IAX_IE_TRANSFERID
:
798 if (len
!= (int)sizeof(unsigned int)) {
799 snprintf(tmp
, (int)sizeof(tmp
), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
802 ies
->transferid
= ntohl(get_unaligned_uint32(data
+ 2));
804 case IAX_IE_DATETIME
:
805 if (len
!= (int)sizeof(unsigned int)) {
806 snprintf(tmp
, (int)sizeof(tmp
), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
809 ies
->datetime
= ntohl(get_unaligned_uint32(data
+ 2));
811 case IAX_IE_FIRMWAREVER
:
812 if (len
!= (int)sizeof(unsigned short)) {
813 snprintf(tmp
, (int)sizeof(tmp
), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
816 ies
->firmwarever
= ntohs(get_unaligned_uint16(data
+ 2));
818 case IAX_IE_DEVICETYPE
:
819 ies
->devicetype
= (char *)data
+ 2;
821 case IAX_IE_SERVICEIDENT
:
822 ies
->serviceident
= (char *)data
+ 2;
824 case IAX_IE_FWBLOCKDESC
:
825 if (len
!= (int)sizeof(unsigned int)) {
826 snprintf(tmp
, (int)sizeof(tmp
), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
829 ies
->fwdesc
= ntohl(get_unaligned_uint32(data
+ 2));
831 case IAX_IE_FWBLOCKDATA
:
832 ies
->fwdata
= data
+ 2;
833 ies
->fwdatalen
= len
;
836 ies
->enckey
= data
+ 2;
837 ies
->enckeylen
= len
;
840 if (len
!= (int)sizeof(unsigned int)) {
841 snprintf(tmp
, (int)sizeof(tmp
), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
844 ies
->provverpres
= 1;
845 ies
->provver
= ntohl(get_unaligned_uint32(data
+ 2));
848 case IAX_IE_CALLINGPRES
:
850 ies
->calling_pres
= data
[2];
852 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte callingpres, but was %d long\n", len
);
856 case IAX_IE_CALLINGTON
:
858 ies
->calling_ton
= data
[2];
860 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte callington, but was %d long\n", len
);
864 case IAX_IE_CALLINGTNS
:
865 if (len
!= (int)sizeof(unsigned short)) {
866 snprintf(tmp
, (int)sizeof(tmp
), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
869 ies
->calling_tns
= ntohs(get_unaligned_uint16(data
+ 2));
871 case IAX_IE_RR_JITTER
:
872 if (len
!= (int)sizeof(unsigned int)) {
873 snprintf(tmp
, (int)sizeof(tmp
), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
876 ies
->rr_jitter
= ntohl(get_unaligned_uint32(data
+ 2));
880 if (len
!= (int)sizeof(unsigned int)) {
881 snprintf(tmp
, (int)sizeof(tmp
), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
884 ies
->rr_loss
= ntohl(get_unaligned_uint32(data
+ 2));
888 if (len
!= (int)sizeof(unsigned int)) {
889 snprintf(tmp
, (int)sizeof(tmp
), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
892 ies
->rr_pkts
= ntohl(get_unaligned_uint32(data
+ 2));
895 case IAX_IE_RR_DELAY
:
896 if (len
!= (int)sizeof(unsigned short)) {
897 snprintf(tmp
, (int)sizeof(tmp
), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
900 ies
->rr_delay
= ntohs(get_unaligned_uint16(data
+ 2));
903 case IAX_IE_RR_DROPPED
:
904 if (len
!= (int)sizeof(unsigned int)) {
905 snprintf(tmp
, (int)sizeof(tmp
), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
908 ies
->rr_dropped
= ntohl(get_unaligned_uint32(data
+ 2));
912 if (len
!= (int)sizeof(unsigned int)) {
913 snprintf(tmp
, (int)sizeof(tmp
), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
916 ies
->rr_ooo
= ntohl(get_unaligned_uint32(data
+ 2));
919 case IAX_IE_VARIABLE
:
920 ast_copy_string(tmp
, (char *)data
+ 2, len
+ 1);
921 tmp2
= strchr(tmp
, '=');
926 /* Existing variable or new variable? */
927 for (var2
= ies
->vars
, prev
= NULL
; var2
; prev
= var2
, var2
= var2
->next
) {
928 if (strcmp(tmp
, var2
->name
) == 0) {
929 int length
= strlen(var2
->value
) + strlen(tmp2
) + 1;
930 char *tmp3
= alloca(length
);
931 snprintf(tmp3
, length
, "%s%s", var2
->value
, tmp2
);
932 var
= ast_variable_new(tmp
, tmp3
, var2
->file
);
933 var
->next
= var2
->next
;
943 var
= ast_variable_new(tmp
, tmp2
, "");
944 var
->next
= ies
->vars
;
948 case IAX_IE_OSPTOKEN
:
949 if ((count
= data
[2]) < IAX_MAX_OSPBLOCK_NUM
) {
950 ies
->osptokenblock
[count
] = (char *)data
+ 2 + 1;
951 ies
->ospblocklength
[count
] = len
- 1;
953 snprintf(tmp
, (int)sizeof(tmp
), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM
- 1, count
);
958 snprintf(tmp
, (int)sizeof(tmp
), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie
), ie
, len
);
961 /* Overwrite information element with 0, to null terminate previous portion */
963 datalen
-= (len
+ 2);
966 /* Null-terminate last field */
969 errorf("Invalid information element contents, strange boundary\n");
975 void iax_frame_wrap(struct iax_frame
*fr
, struct ast_frame
*f
)
977 fr
->af
.frametype
= f
->frametype
;
978 fr
->af
.subclass
= f
->subclass
;
979 fr
->af
.mallocd
= 0; /* Our frame is static relative to the container */
980 fr
->af
.datalen
= f
->datalen
;
981 fr
->af
.samples
= f
->samples
;
982 fr
->af
.offset
= AST_FRIENDLY_OFFSET
;
984 fr
->af
.delivery
.tv_sec
= 0;
985 fr
->af
.delivery
.tv_usec
= 0;
986 fr
->af
.data
.ptr
= fr
->afdata
;
988 if (fr
->af
.datalen
) {
989 size_t copy_len
= fr
->af
.datalen
;
990 if (copy_len
> fr
->afdatalen
) {
991 ast_log(LOG_ERROR
, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
992 (int) fr
->afdatalen
, (int) fr
->af
.datalen
);
993 copy_len
= fr
->afdatalen
;
995 #if __BYTE_ORDER == __LITTLE_ENDIAN
996 /* We need to byte-swap slinear samples from network byte order */
997 if ((fr
->af
.frametype
== AST_FRAME_VOICE
) && (fr
->af
.subclass
== AST_FORMAT_SLINEAR
)) {
998 /* 2 bytes / sample for SLINEAR */
999 ast_swapcopy_samples(fr
->af
.data
.ptr
, f
->data
.ptr
, copy_len
/ 2);
1002 memcpy(fr
->af
.data
.ptr
, f
->data
.ptr
, copy_len
);
1006 struct iax_frame
*iax_frame_new(int direction
, int datalen
, unsigned int cacheable
)
1008 struct iax_frame
*fr
= NULL
;
1010 #if !defined(LOW_MEMORY)
1011 struct iax_frames
*iax_frames
= NULL
;
1012 struct iax_frame
*smallest
= NULL
;
1014 /* Attempt to get a frame from this thread's cache */
1015 if ((iax_frames
= ast_threadstorage_get(&frame_cache
, sizeof(*iax_frames
)))) {
1016 smallest
= AST_LIST_FIRST(&iax_frames
->list
);
1017 AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames
->list
, fr
, list
) {
1018 if (fr
->afdatalen
>= datalen
) {
1019 size_t afdatalen
= fr
->afdatalen
;
1020 AST_LIST_REMOVE_CURRENT(list
);
1022 memset(fr
, 0, sizeof(*fr
));
1023 fr
->afdatalen
= afdatalen
;
1025 } else if (smallest
->afdatalen
> fr
->afdatalen
) {
1029 AST_LIST_TRAVERSE_SAFE_END
;
1032 if (iax_frames
->size
>= FRAME_CACHE_MAX_SIZE
&& smallest
) {
1033 /* Make useless cache into something more useful */
1034 AST_LIST_REMOVE(&iax_frames
->list
, smallest
, list
);
1035 if (!(fr
= ast_realloc(smallest
, sizeof(*fr
) + datalen
))) {
1036 AST_LIST_INSERT_TAIL(&iax_frames
->list
, smallest
, list
);
1039 } else if (!(fr
= ast_calloc_cache(1, sizeof(*fr
) + datalen
)))
1041 fr
->afdatalen
= datalen
;
1044 if (!(fr
= ast_calloc(1, sizeof(*fr
) + datalen
)))
1046 fr
->afdatalen
= datalen
;
1050 fr
->direction
= direction
;
1052 fr
->cacheable
= cacheable
;
1054 if (fr
->direction
== DIRECTION_INGRESS
)
1055 ast_atomic_fetchadd_int(&iframes
, 1);
1057 ast_atomic_fetchadd_int(&oframes
, 1);
1059 ast_atomic_fetchadd_int(&frames
, 1);
1064 void iax_frame_free(struct iax_frame
*fr
)
1066 #if !defined(LOW_MEMORY)
1067 struct iax_frames
*iax_frames
= NULL
;
1070 /* Note: does not remove from scheduler! */
1071 if (fr
->direction
== DIRECTION_INGRESS
)
1072 ast_atomic_fetchadd_int(&iframes
, -1);
1073 else if (fr
->direction
== DIRECTION_OUTGRESS
)
1074 ast_atomic_fetchadd_int(&oframes
, -1);
1076 errorf("Attempt to double free frame detected\n");
1079 ast_atomic_fetchadd_int(&frames
, -1);
1081 #if !defined(LOW_MEMORY)
1082 if (!fr
->cacheable
|| !(iax_frames
= ast_threadstorage_get(&frame_cache
, sizeof(*iax_frames
)))) {
1087 if (iax_frames
->size
< FRAME_CACHE_MAX_SIZE
) {
1089 /* Pseudo-sort: keep smaller frames at the top of the list. This should
1090 * increase the chance that we pick the smallest applicable frame for use. */
1091 if (AST_LIST_FIRST(&iax_frames
->list
) && AST_LIST_FIRST(&iax_frames
->list
)->afdatalen
< fr
->afdatalen
) {
1092 AST_LIST_INSERT_TAIL(&iax_frames
->list
, fr
, list
);
1094 AST_LIST_INSERT_HEAD(&iax_frames
->list
, fr
, list
);
1103 #if !defined(LOW_MEMORY)
1104 static void frame_cache_cleanup(void *data
)
1106 struct iax_frames
*framelist
= data
;
1107 struct iax_frame
*current
;
1109 while ((current
= AST_LIST_REMOVE_HEAD(&framelist
->list
, list
)))
1112 ast_free(framelist
);
1116 int iax_get_frames(void) { return frames
; }
1117 int iax_get_iframes(void) { return iframes
; }
1118 int iax_get_oframes(void) { return oframes
; }