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/types.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.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"
46 #include "iax2-parser.h"
47 #include "iax2-provision.h"
49 static int frames
= 0;
50 static int iframes
= 0;
51 static int oframes
= 0;
53 #if !defined(LOW_MEMORY)
54 static void frame_cache_cleanup(void *data
);
56 /*! \brief A per-thread cache of iax_frame structures */
57 AST_THREADSTORAGE_CUSTOM(frame_cache
, frame_cache_init
, frame_cache_cleanup
);
59 /*! \brief This is just so iax_frames, a list head struct for holding a list of
60 * iax_frame structures, is defined. */
61 AST_LIST_HEAD_NOLOCK(iax_frame_list
, iax_frame
);
64 struct iax_frame_list list
;
68 #define FRAME_CACHE_MAX_SIZE 20
71 static void internaloutput(const char *str
)
76 static void internalerror(const char *str
)
78 fprintf(stderr
, "WARNING: %s", str
);
81 static void (*outputf
)(const char *str
) = internaloutput
;
82 static void (*errorf
)(const char *str
) = internalerror
;
84 static void dump_addr(char *output
, int maxlen
, void *value
, int len
)
86 struct sockaddr_in sin
;
87 if (len
== (int)sizeof(sin
)) {
88 memcpy(&sin
, value
, len
);
89 snprintf(output
, maxlen
, "IPV4 %s:%d", ast_inet_ntoa(sin
.sin_addr
), ntohs(sin
.sin_port
));
91 snprintf(output
, maxlen
, "Invalid Address");
95 static void dump_string(char *output
, int maxlen
, void *value
, int len
)
100 strncpy(output
, value
, maxlen
);
101 output
[maxlen
] = '\0';
104 static void dump_prefs(char *output
, int maxlen
, void *value
, int len
)
106 struct ast_codec_pref pref
;
115 strncpy(output
, value
, maxlen
);
116 output
[maxlen
] = '\0';
118 ast_codec_pref_convert(&pref
, output
, total_len
, 0);
119 memset(output
,0,total_len
);
120 ast_codec_pref_string(&pref
, output
, total_len
);
123 static void dump_int(char *output
, int maxlen
, void *value
, int len
)
125 if (len
== (int)sizeof(unsigned int))
126 snprintf(output
, maxlen
, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value
)));
128 ast_copy_string(output
, "Invalid INT", maxlen
);
131 static void dump_short(char *output
, int maxlen
, void *value
, int len
)
133 if (len
== (int)sizeof(unsigned short))
134 snprintf(output
, maxlen
, "%d", ntohs(get_unaligned_uint16(value
)));
136 ast_copy_string(output
, "Invalid SHORT", maxlen
);
139 static void dump_byte(char *output
, int maxlen
, void *value
, int len
)
141 if (len
== (int)sizeof(unsigned char))
142 snprintf(output
, maxlen
, "%d", *((unsigned char *)value
));
144 ast_copy_string(output
, "Invalid BYTE", maxlen
);
147 static void dump_datetime(char *output
, int maxlen
, void *value
, int len
)
150 unsigned long val
= (unsigned long) ntohl(get_unaligned_uint32(value
));
151 if (len
== (int)sizeof(unsigned int)) {
152 tm
.tm_sec
= (val
& 0x1f) << 1;
153 tm
.tm_min
= (val
>> 5) & 0x3f;
154 tm
.tm_hour
= (val
>> 11) & 0x1f;
155 tm
.tm_mday
= (val
>> 16) & 0x1f;
156 tm
.tm_mon
= ((val
>> 21) & 0x0f) - 1;
157 tm
.tm_year
= ((val
>> 25) & 0x7f) + 100;
158 strftime(output
, maxlen
, "%Y-%m-%d %T", &tm
);
160 ast_copy_string(output
, "Invalid DATETIME format!", maxlen
);
163 static void dump_ipaddr(char *output
, int maxlen
, void *value
, int len
)
165 struct sockaddr_in sin
;
166 if (len
== (int)sizeof(unsigned int)) {
167 memcpy(&sin
.sin_addr
, value
, len
);
168 snprintf(output
, maxlen
, "%s", ast_inet_ntoa(sin
.sin_addr
));
170 ast_copy_string(output
, "Invalid IPADDR", maxlen
);
174 static void dump_prov_flags(char *output
, int maxlen
, void *value
, int len
)
177 if (len
== (int)sizeof(unsigned int))
178 snprintf(output
, maxlen
, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value
)),
179 iax_provflags2str(buf
, sizeof(buf
), ntohl(get_unaligned_uint32(value
))));
181 ast_copy_string(output
, "Invalid INT", maxlen
);
184 static void dump_samprate(char *output
, int maxlen
, void *value
, int len
)
188 if (len
== (int)sizeof(unsigned short)) {
189 sr
= ntohs(*((unsigned short *)value
));
190 if (sr
& IAX_RATE_8KHZ
)
191 strcat(tmp
, ",8khz");
192 if (sr
& IAX_RATE_11KHZ
)
193 strcat(tmp
, ",11.025khz");
194 if (sr
& IAX_RATE_16KHZ
)
195 strcat(tmp
, ",16khz");
196 if (sr
& IAX_RATE_22KHZ
)
197 strcat(tmp
, ",22.05khz");
198 if (sr
& IAX_RATE_44KHZ
)
199 strcat(tmp
, ",44.1khz");
200 if (sr
& IAX_RATE_48KHZ
)
201 strcat(tmp
, ",48khz");
203 ast_copy_string(output
, &tmp
[1], maxlen
);
205 ast_copy_string(output
, "None Specified!\n", maxlen
);
207 ast_copy_string(output
, "Invalid SHORT", maxlen
);
211 static void dump_prov_ies(char *output
, int maxlen
, unsigned char *iedata
, int len
);
212 static void dump_prov(char *output
, int maxlen
, void *value
, int len
)
214 dump_prov_ies(output
, maxlen
, value
, len
);
217 static struct iax2_ie
{
220 void (*dump
)(char *output
, int maxlen
, void *value
, int len
);
222 { IAX_IE_CALLED_NUMBER
, "CALLED NUMBER", dump_string
},
223 { IAX_IE_CALLING_NUMBER
, "CALLING NUMBER", dump_string
},
224 { IAX_IE_CALLING_ANI
, "ANI", dump_string
},
225 { IAX_IE_CALLING_NAME
, "CALLING NAME", dump_string
},
226 { IAX_IE_CALLED_CONTEXT
, "CALLED CONTEXT", dump_string
},
227 { IAX_IE_USERNAME
, "USERNAME", dump_string
},
228 { IAX_IE_PASSWORD
, "PASSWORD", dump_string
},
229 { IAX_IE_CAPABILITY
, "CAPABILITY", dump_int
},
230 { IAX_IE_FORMAT
, "FORMAT", dump_int
},
231 { IAX_IE_LANGUAGE
, "LANGUAGE", dump_string
},
232 { IAX_IE_VERSION
, "VERSION", dump_short
},
233 { IAX_IE_ADSICPE
, "ADSICPE", dump_short
},
234 { IAX_IE_DNID
, "DNID", dump_string
},
235 { IAX_IE_AUTHMETHODS
, "AUTHMETHODS", dump_short
},
236 { IAX_IE_CHALLENGE
, "CHALLENGE", dump_string
},
237 { IAX_IE_MD5_RESULT
, "MD5 RESULT", dump_string
},
238 { IAX_IE_RSA_RESULT
, "RSA RESULT", dump_string
},
239 { IAX_IE_APPARENT_ADDR
, "APPARENT ADDRESS", dump_addr
},
240 { IAX_IE_REFRESH
, "REFRESH", dump_short
},
241 { IAX_IE_DPSTATUS
, "DIALPLAN STATUS", dump_short
},
242 { IAX_IE_CALLNO
, "CALL NUMBER", dump_short
},
243 { IAX_IE_CAUSE
, "CAUSE", dump_string
},
244 { IAX_IE_IAX_UNKNOWN
, "UNKNOWN IAX CMD", dump_byte
},
245 { IAX_IE_MSGCOUNT
, "MESSAGE COUNT", dump_short
},
246 { IAX_IE_AUTOANSWER
, "AUTO ANSWER REQ" },
247 { IAX_IE_TRANSFERID
, "TRANSFER ID", dump_int
},
248 { IAX_IE_RDNIS
, "REFERRING DNIS", dump_string
},
249 { IAX_IE_PROVISIONING
, "PROVISIONING", dump_prov
},
250 { IAX_IE_AESPROVISIONING
, "AES PROVISIONG" },
251 { IAX_IE_DATETIME
, "DATE TIME", dump_datetime
},
252 { IAX_IE_DEVICETYPE
, "DEVICE TYPE", dump_string
},
253 { IAX_IE_SERVICEIDENT
, "SERVICE IDENT", dump_string
},
254 { IAX_IE_FIRMWAREVER
, "FIRMWARE VER", dump_short
},
255 { IAX_IE_FWBLOCKDESC
, "FW BLOCK DESC", dump_int
},
256 { IAX_IE_FWBLOCKDATA
, "FW BLOCK DATA" },
257 { IAX_IE_PROVVER
, "PROVISIONG VER", dump_int
},
258 { IAX_IE_CALLINGPRES
, "CALLING PRESNTN", dump_byte
},
259 { IAX_IE_CALLINGTON
, "CALLING TYPEOFNUM", dump_byte
},
260 { IAX_IE_CALLINGTNS
, "CALLING TRANSITNET", dump_short
},
261 { IAX_IE_SAMPLINGRATE
, "SAMPLINGRATE", dump_samprate
},
262 { IAX_IE_CAUSECODE
, "CAUSE CODE", dump_byte
},
263 { IAX_IE_ENCRYPTION
, "ENCRYPTION", dump_short
},
264 { IAX_IE_ENCKEY
, "ENCRYPTION KEY" },
265 { IAX_IE_CODEC_PREFS
, "CODEC_PREFS", dump_prefs
},
266 { IAX_IE_RR_JITTER
, "RR_JITTER", dump_int
},
267 { IAX_IE_RR_LOSS
, "RR_LOSS", dump_int
},
268 { IAX_IE_RR_PKTS
, "RR_PKTS", dump_int
},
269 { IAX_IE_RR_DELAY
, "RR_DELAY", dump_short
},
270 { IAX_IE_RR_DROPPED
, "RR_DROPPED", dump_int
},
271 { IAX_IE_RR_OOO
, "RR_OUTOFORDER", dump_int
},
274 static struct iax2_ie prov_ies
[] = {
275 { PROV_IE_USEDHCP
, "USEDHCP" },
276 { PROV_IE_IPADDR
, "IPADDR", dump_ipaddr
},
277 { PROV_IE_SUBNET
, "SUBNET", dump_ipaddr
},
278 { PROV_IE_GATEWAY
, "GATEWAY", dump_ipaddr
},
279 { PROV_IE_PORTNO
, "BINDPORT", dump_short
},
280 { PROV_IE_USER
, "USERNAME", dump_string
},
281 { PROV_IE_PASS
, "PASSWORD", dump_string
},
282 { PROV_IE_LANG
, "LANGUAGE", dump_string
},
283 { PROV_IE_TOS
, "TYPEOFSERVICE", dump_byte
},
284 { PROV_IE_FLAGS
, "FLAGS", dump_prov_flags
},
285 { PROV_IE_FORMAT
, "FORMAT", dump_int
},
286 { PROV_IE_AESKEY
, "AESKEY" },
287 { PROV_IE_SERVERIP
, "SERVERIP", dump_ipaddr
},
288 { PROV_IE_SERVERPORT
, "SERVERPORT", dump_short
},
289 { PROV_IE_NEWAESKEY
, "NEWAESKEY" },
290 { PROV_IE_PROVVER
, "PROV VERSION", dump_int
},
291 { PROV_IE_ALTSERVER
, "ALTSERVERIP", dump_ipaddr
},
294 const char *iax_ie2str(int ie
)
297 for (x
=0;x
<(int)sizeof(ies
) / (int)sizeof(ies
[0]); x
++) {
305 static void dump_prov_ies(char *output
, int maxlen
, unsigned char *iedata
, int len
)
315 strcpy(output
, "\n");
316 maxlen
-= strlen(output
); output
+= strlen(output
);
320 if (ielen
+ 2> len
) {
321 snprintf(tmp
, (int)sizeof(tmp
), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen
+ 2, len
);
322 ast_copy_string(output
, tmp
, maxlen
);
323 maxlen
-= strlen(output
);
324 output
+= strlen(output
);
328 for (x
=0;x
<(int)sizeof(prov_ies
) / (int)sizeof(prov_ies
[0]); x
++) {
329 if (prov_ies
[x
].ie
== ie
) {
330 if (prov_ies
[x
].dump
) {
331 prov_ies
[x
].dump(interp
, (int)sizeof(interp
), iedata
+ 2, ielen
);
332 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", prov_ies
[x
].name
, interp
);
333 ast_copy_string(output
, tmp
, maxlen
);
334 maxlen
-= strlen(output
); output
+= strlen(output
);
337 snprintf(interp
, (int)sizeof(interp
), "%d bytes", ielen
);
339 strcpy(interp
, "Present");
340 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", prov_ies
[x
].name
, interp
);
341 ast_copy_string(output
, tmp
, maxlen
);
342 maxlen
-= strlen(output
); output
+= strlen(output
);
348 snprintf(tmp
, (int)sizeof(tmp
), " Unknown Prov IE %03d : Present\n", ie
);
349 ast_copy_string(output
, tmp
, maxlen
);
350 maxlen
-= strlen(output
); output
+= strlen(output
);
352 iedata
+= (2 + ielen
);
357 static void dump_ies(unsigned char *iedata
, int len
)
370 if (ielen
+ 2> len
) {
371 snprintf(tmp
, (int)sizeof(tmp
), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen
+ 2, len
);
376 for (x
=0;x
<(int)sizeof(ies
) / (int)sizeof(ies
[0]); x
++) {
377 if (ies
[x
].ie
== ie
) {
379 ies
[x
].dump(interp
, (int)sizeof(interp
), iedata
+ 2, ielen
);
380 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", ies
[x
].name
, interp
);
384 snprintf(interp
, (int)sizeof(interp
), "%d bytes", ielen
);
386 strcpy(interp
, "Present");
387 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", ies
[x
].name
, interp
);
394 snprintf(tmp
, (int)sizeof(tmp
), " Unknown IE %03d : Present\n", ie
);
397 iedata
+= (2 + ielen
);
403 void iax_showframe(struct iax_frame
*f
, struct ast_iax2_full_hdr
*fhi
, int rx
, struct sockaddr_in
*sin
, int datalen
)
405 const char *frames
[] = {
420 const char *iaxs
[] = {
461 const char *cmds
[] = {
481 struct ast_iax2_full_hdr
*fh
;
486 const char *subclass
;
506 snprintf(retries
, sizeof(retries
), "%03d", f
->retries
);
509 if (ntohs(fh
->dcallno
) & IAX_FLAG_RETRANS
)
510 strcpy(retries
, "Yes");
512 strcpy(retries
, " No");
514 if (!(ntohs(fh
->scallno
) & IAX_FLAG_FULL
)) {
515 /* Don't mess with mini-frames */
518 if (fh
->type
>= (int)sizeof(frames
)/(int)sizeof(frames
[0])) {
519 snprintf(class2
, sizeof(class2
), "(%d?)", fh
->type
);
522 class = frames
[(int)fh
->type
];
524 if (fh
->type
== AST_FRAME_DTMF_BEGIN
|| fh
->type
== AST_FRAME_DTMF_END
) {
525 sprintf(subclass2
, "%c", fh
->csub
);
526 subclass
= subclass2
;
527 } else if (fh
->type
== AST_FRAME_IAX
) {
528 if (fh
->csub
>= (int)sizeof(iaxs
)/(int)sizeof(iaxs
[0])) {
529 snprintf(subclass2
, sizeof(subclass2
), "(%d?)", fh
->csub
);
530 subclass
= subclass2
;
532 subclass
= iaxs
[(int)fh
->csub
];
534 } else if (fh
->type
== AST_FRAME_CONTROL
) {
535 if (fh
->csub
>= (int)sizeof(cmds
)/(int)sizeof(cmds
[0])) {
536 snprintf(subclass2
, sizeof(subclass2
), "(%d?)", fh
->csub
);
537 subclass
= subclass2
;
539 subclass
= cmds
[(int)fh
->csub
];
542 snprintf(subclass2
, sizeof(subclass2
), "%d", fh
->csub
);
543 subclass
= subclass2
;
545 snprintf(tmp
, sizeof(tmp
),
546 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
548 retries
, fh
->oseqno
, fh
->iseqno
, class, subclass
);
550 snprintf(tmp
, sizeof(tmp
),
551 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
552 (unsigned long)ntohl(fh
->ts
),
553 ntohs(fh
->scallno
) & ~IAX_FLAG_FULL
, ntohs(fh
->dcallno
) & ~IAX_FLAG_RETRANS
,
554 ast_inet_ntoa(sin
->sin_addr
), ntohs(sin
->sin_port
));
556 if (fh
->type
== AST_FRAME_IAX
)
557 dump_ies(fh
->iedata
, datalen
);
560 int iax_ie_append_raw(struct iax_ie_data
*ied
, unsigned char ie
, const void *data
, int datalen
)
563 if (datalen
> ((int)sizeof(ied
->buf
) - ied
->pos
)) {
564 snprintf(tmp
, (int)sizeof(tmp
), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie
), ie
, datalen
, (int)sizeof(ied
->buf
) - ied
->pos
);
568 ied
->buf
[ied
->pos
++] = ie
;
569 ied
->buf
[ied
->pos
++] = datalen
;
570 memcpy(ied
->buf
+ ied
->pos
, data
, datalen
);
575 int iax_ie_append_addr(struct iax_ie_data
*ied
, unsigned char ie
, const struct sockaddr_in
*sin
)
577 return iax_ie_append_raw(ied
, ie
, sin
, (int)sizeof(struct sockaddr_in
));
580 int iax_ie_append_int(struct iax_ie_data
*ied
, unsigned char ie
, unsigned int value
)
583 newval
= htonl(value
);
584 return iax_ie_append_raw(ied
, ie
, &newval
, (int)sizeof(newval
));
587 int iax_ie_append_short(struct iax_ie_data
*ied
, unsigned char ie
, unsigned short value
)
589 unsigned short newval
;
590 newval
= htons(value
);
591 return iax_ie_append_raw(ied
, ie
, &newval
, (int)sizeof(newval
));
594 int iax_ie_append_str(struct iax_ie_data
*ied
, unsigned char ie
, const char *str
)
596 return iax_ie_append_raw(ied
, ie
, str
, strlen(str
));
599 int iax_ie_append_byte(struct iax_ie_data
*ied
, unsigned char ie
, unsigned char dat
)
601 return iax_ie_append_raw(ied
, ie
, &dat
, 1);
604 int iax_ie_append(struct iax_ie_data
*ied
, unsigned char ie
)
606 return iax_ie_append_raw(ied
, ie
, NULL
, 0);
609 void iax_set_output(void (*func
)(const char *))
614 void iax_set_error(void (*func
)(const char *))
619 int iax_parse_ies(struct iax_ies
*ies
, unsigned char *data
, int datalen
)
621 /* Parse data into information elements */
625 memset(ies
, 0, (int)sizeof(struct iax_ies
));
627 ies
->firmwarever
= -1;
628 ies
->calling_ton
= -1;
629 ies
->calling_tns
= -1;
630 ies
->calling_pres
= -1;
631 ies
->samprate
= IAX_RATE_8KHZ
;
632 while(datalen
>= 2) {
635 if (len
> datalen
- 2) {
636 errorf("Information element length exceeds message size\n");
640 case IAX_IE_CALLED_NUMBER
:
641 ies
->called_number
= (char *)data
+ 2;
643 case IAX_IE_CALLING_NUMBER
:
644 ies
->calling_number
= (char *)data
+ 2;
646 case IAX_IE_CALLING_ANI
:
647 ies
->calling_ani
= (char *)data
+ 2;
649 case IAX_IE_CALLING_NAME
:
650 ies
->calling_name
= (char *)data
+ 2;
652 case IAX_IE_CALLED_CONTEXT
:
653 ies
->called_context
= (char *)data
+ 2;
655 case IAX_IE_USERNAME
:
656 ies
->username
= (char *)data
+ 2;
658 case IAX_IE_PASSWORD
:
659 ies
->password
= (char *)data
+ 2;
661 case IAX_IE_CODEC_PREFS
:
662 ies
->codec_prefs
= (char *)data
+ 2;
664 case IAX_IE_CAPABILITY
:
665 if (len
!= (int)sizeof(unsigned int)) {
666 snprintf(tmp
, (int)sizeof(tmp
), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
669 ies
->capability
= ntohl(get_unaligned_uint32(data
+ 2));
672 if (len
!= (int)sizeof(unsigned int)) {
673 snprintf(tmp
, (int)sizeof(tmp
), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
676 ies
->format
= ntohl(get_unaligned_uint32(data
+ 2));
678 case IAX_IE_LANGUAGE
:
679 ies
->language
= (char *)data
+ 2;
682 if (len
!= (int)sizeof(unsigned short)) {
683 snprintf(tmp
, (int)sizeof(tmp
), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
686 ies
->version
= ntohs(get_unaligned_uint16(data
+ 2));
689 if (len
!= (int)sizeof(unsigned short)) {
690 snprintf(tmp
, (int)sizeof(tmp
), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
693 ies
->adsicpe
= ntohs(get_unaligned_uint16(data
+ 2));
695 case IAX_IE_SAMPLINGRATE
:
696 if (len
!= (int)sizeof(unsigned short)) {
697 snprintf(tmp
, (int)sizeof(tmp
), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
700 ies
->samprate
= ntohs(get_unaligned_uint16(data
+ 2));
703 ies
->dnid
= (char *)data
+ 2;
706 ies
->rdnis
= (char *)data
+ 2;
708 case IAX_IE_AUTHMETHODS
:
709 if (len
!= (int)sizeof(unsigned short)) {
710 snprintf(tmp
, (int)sizeof(tmp
), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
713 ies
->authmethods
= ntohs(get_unaligned_uint16(data
+ 2));
715 case IAX_IE_ENCRYPTION
:
716 if (len
!= (int)sizeof(unsigned short)) {
717 snprintf(tmp
, (int)sizeof(tmp
), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
720 ies
->encmethods
= ntohs(get_unaligned_uint16(data
+ 2));
722 case IAX_IE_CHALLENGE
:
723 ies
->challenge
= (char *)data
+ 2;
725 case IAX_IE_MD5_RESULT
:
726 ies
->md5_result
= (char *)data
+ 2;
728 case IAX_IE_RSA_RESULT
:
729 ies
->rsa_result
= (char *)data
+ 2;
731 case IAX_IE_APPARENT_ADDR
:
732 ies
->apparent_addr
= ((struct sockaddr_in
*)(data
+ 2));
735 if (len
!= (int)sizeof(unsigned short)) {
736 snprintf(tmp
, (int)sizeof(tmp
), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
739 ies
->refresh
= ntohs(get_unaligned_uint16(data
+ 2));
741 case IAX_IE_DPSTATUS
:
742 if (len
!= (int)sizeof(unsigned short)) {
743 snprintf(tmp
, (int)sizeof(tmp
), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
746 ies
->dpstatus
= ntohs(get_unaligned_uint16(data
+ 2));
749 if (len
!= (int)sizeof(unsigned short)) {
750 snprintf(tmp
, (int)sizeof(tmp
), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
753 ies
->callno
= ntohs(get_unaligned_uint16(data
+ 2));
756 ies
->cause
= (char *)data
+ 2;
758 case IAX_IE_CAUSECODE
:
760 snprintf(tmp
, (int)sizeof(tmp
), "Expecting causecode to be single byte but was %d\n", len
);
763 ies
->causecode
= data
[2];
766 case IAX_IE_IAX_UNKNOWN
:
768 ies
->iax_unknown
= data
[2];
770 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte Unknown command, but was %d long\n", len
);
774 case IAX_IE_MSGCOUNT
:
775 if (len
!= (int)sizeof(unsigned short)) {
776 snprintf(tmp
, (int)sizeof(tmp
), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
779 ies
->msgcount
= ntohs(get_unaligned_uint16(data
+ 2));
781 case IAX_IE_AUTOANSWER
:
784 case IAX_IE_MUSICONHOLD
:
785 ies
->musiconhold
= 1;
787 case IAX_IE_TRANSFERID
:
788 if (len
!= (int)sizeof(unsigned int)) {
789 snprintf(tmp
, (int)sizeof(tmp
), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
792 ies
->transferid
= ntohl(get_unaligned_uint32(data
+ 2));
794 case IAX_IE_DATETIME
:
795 if (len
!= (int)sizeof(unsigned int)) {
796 snprintf(tmp
, (int)sizeof(tmp
), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
799 ies
->datetime
= ntohl(get_unaligned_uint32(data
+ 2));
801 case IAX_IE_FIRMWAREVER
:
802 if (len
!= (int)sizeof(unsigned short)) {
803 snprintf(tmp
, (int)sizeof(tmp
), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
806 ies
->firmwarever
= ntohs(get_unaligned_uint16(data
+ 2));
808 case IAX_IE_DEVICETYPE
:
809 ies
->devicetype
= (char *)data
+ 2;
811 case IAX_IE_SERVICEIDENT
:
812 ies
->serviceident
= (char *)data
+ 2;
814 case IAX_IE_FWBLOCKDESC
:
815 if (len
!= (int)sizeof(unsigned int)) {
816 snprintf(tmp
, (int)sizeof(tmp
), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
819 ies
->fwdesc
= ntohl(get_unaligned_uint32(data
+ 2));
821 case IAX_IE_FWBLOCKDATA
:
822 ies
->fwdata
= data
+ 2;
823 ies
->fwdatalen
= len
;
826 ies
->enckey
= data
+ 2;
827 ies
->enckeylen
= len
;
830 if (len
!= (int)sizeof(unsigned int)) {
831 snprintf(tmp
, (int)sizeof(tmp
), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
834 ies
->provverpres
= 1;
835 ies
->provver
= ntohl(get_unaligned_uint32(data
+ 2));
838 case IAX_IE_CALLINGPRES
:
840 ies
->calling_pres
= data
[2];
842 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte callingpres, but was %d long\n", len
);
846 case IAX_IE_CALLINGTON
:
848 ies
->calling_ton
= data
[2];
850 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte callington, but was %d long\n", len
);
854 case IAX_IE_CALLINGTNS
:
855 if (len
!= (int)sizeof(unsigned short)) {
856 snprintf(tmp
, (int)sizeof(tmp
), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
859 ies
->calling_tns
= ntohs(get_unaligned_uint16(data
+ 2));
861 case IAX_IE_RR_JITTER
:
862 if (len
!= (int)sizeof(unsigned int)) {
863 snprintf(tmp
, (int)sizeof(tmp
), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
866 ies
->rr_jitter
= ntohl(get_unaligned_uint32(data
+ 2));
870 if (len
!= (int)sizeof(unsigned int)) {
871 snprintf(tmp
, (int)sizeof(tmp
), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
874 ies
->rr_loss
= ntohl(get_unaligned_uint32(data
+ 2));
878 if (len
!= (int)sizeof(unsigned int)) {
879 snprintf(tmp
, (int)sizeof(tmp
), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
882 ies
->rr_pkts
= ntohl(get_unaligned_uint32(data
+ 2));
885 case IAX_IE_RR_DELAY
:
886 if (len
!= (int)sizeof(unsigned short)) {
887 snprintf(tmp
, (int)sizeof(tmp
), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len
);
890 ies
->rr_delay
= ntohs(get_unaligned_uint16(data
+ 2));
893 case IAX_IE_RR_DROPPED
:
894 if (len
!= (int)sizeof(unsigned int)) {
895 snprintf(tmp
, (int)sizeof(tmp
), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
898 ies
->rr_dropped
= ntohl(get_unaligned_uint32(data
+ 2));
902 if (len
!= (int)sizeof(unsigned int)) {
903 snprintf(tmp
, (int)sizeof(tmp
), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len
);
906 ies
->rr_ooo
= ntohl(get_unaligned_uint32(data
+ 2));
910 snprintf(tmp
, (int)sizeof(tmp
), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie
), ie
, len
);
913 /* Overwrite information element with 0, to null terminate previous portion */
915 datalen
-= (len
+ 2);
918 /* Null-terminate last field */
921 errorf("Invalid information element contents, strange boundary\n");
927 void iax_frame_wrap(struct iax_frame
*fr
, struct ast_frame
*f
)
929 fr
->af
.frametype
= f
->frametype
;
930 fr
->af
.subclass
= f
->subclass
;
931 fr
->af
.mallocd
= 0; /* Our frame is static relative to the container */
932 fr
->af
.datalen
= f
->datalen
;
933 fr
->af
.samples
= f
->samples
;
934 fr
->af
.offset
= AST_FRIENDLY_OFFSET
;
936 fr
->af
.delivery
.tv_sec
= 0;
937 fr
->af
.delivery
.tv_usec
= 0;
938 fr
->af
.data
= fr
->afdata
;
940 if (fr
->af
.datalen
) {
941 size_t copy_len
= fr
->af
.datalen
;
942 if (copy_len
> fr
->afdatalen
) {
943 ast_log(LOG_ERROR
, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
944 (int) fr
->afdatalen
, (int) fr
->af
.datalen
);
945 copy_len
= fr
->afdatalen
;
947 #if __BYTE_ORDER == __LITTLE_ENDIAN
948 /* We need to byte-swap slinear samples from network byte order */
949 if ((fr
->af
.frametype
== AST_FRAME_VOICE
) && (fr
->af
.subclass
== AST_FORMAT_SLINEAR
)) {
950 /* 2 bytes / sample for SLINEAR */
951 ast_swapcopy_samples(fr
->af
.data
, f
->data
, copy_len
/ 2);
954 memcpy(fr
->af
.data
, f
->data
, copy_len
);
958 struct iax_frame
*iax_frame_new(int direction
, int datalen
, unsigned int cacheable
)
960 struct iax_frame
*fr
= NULL
;
962 #if !defined(LOW_MEMORY)
963 struct iax_frames
*iax_frames
;
965 /* Attempt to get a frame from this thread's cache */
966 if ((iax_frames
= ast_threadstorage_get(&frame_cache
, sizeof(*iax_frames
)))) {
967 AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames
->list
, fr
, list
) {
968 if (fr
->afdatalen
>= datalen
) {
969 size_t afdatalen
= fr
->afdatalen
;
970 AST_LIST_REMOVE_CURRENT(&iax_frames
->list
, list
);
972 memset(fr
, 0, sizeof(*fr
));
973 fr
->afdatalen
= afdatalen
;
977 AST_LIST_TRAVERSE_SAFE_END
980 if (!(fr
= ast_calloc_cache(1, sizeof(*fr
) + datalen
)))
982 fr
->afdatalen
= datalen
;
985 if (!(fr
= ast_calloc(1, sizeof(*fr
) + datalen
)))
987 fr
->afdatalen
= datalen
;
991 fr
->direction
= direction
;
993 fr
->cacheable
= cacheable
;
995 if (fr
->direction
== DIRECTION_INGRESS
)
996 ast_atomic_fetchadd_int(&iframes
, 1);
998 ast_atomic_fetchadd_int(&oframes
, 1);
1000 ast_atomic_fetchadd_int(&frames
, 1);
1005 void iax_frame_free(struct iax_frame
*fr
)
1007 #if !defined(LOW_MEMORY)
1008 struct iax_frames
*iax_frames
;
1011 /* Note: does not remove from scheduler! */
1012 if (fr
->direction
== DIRECTION_INGRESS
)
1013 ast_atomic_fetchadd_int(&iframes
, -1);
1014 else if (fr
->direction
== DIRECTION_OUTGRESS
)
1015 ast_atomic_fetchadd_int(&oframes
, -1);
1017 errorf("Attempt to double free frame detected\n");
1020 ast_atomic_fetchadd_int(&frames
, -1);
1022 #if !defined(LOW_MEMORY)
1023 if (!fr
->cacheable
|| !(iax_frames
= ast_threadstorage_get(&frame_cache
, sizeof(*iax_frames
)))) {
1028 if (iax_frames
->size
< FRAME_CACHE_MAX_SIZE
) {
1030 AST_LIST_INSERT_HEAD(&iax_frames
->list
, fr
, list
);
1038 #if !defined(LOW_MEMORY)
1039 static void frame_cache_cleanup(void *data
)
1041 struct iax_frames
*frames
= data
;
1042 struct iax_frame
*cur
;
1044 while ((cur
= AST_LIST_REMOVE_HEAD(&frames
->list
, list
)))
1051 int iax_get_frames(void) { return frames
; }
1052 int iax_get_iframes(void) { return iframes
; }
1053 int iax_get_oframes(void) { return oframes
; }