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_frames
, iax_frame
);
60 static void internaloutput(const char *str
)
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
));
80 ast_copy_string(output
, "Invalid Address", maxlen
);
84 static void dump_string(char *output
, int maxlen
, void *value
, int 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
;
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
)));
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
)));
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
));
133 ast_copy_string(output
, "Invalid BYTE", maxlen
);
136 static void dump_datetime(char *output
, int maxlen
, void *value
, int len
)
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
);
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
));
159 ast_copy_string(output
, "Invalid IPADDR", maxlen
);
163 static void dump_prov_flags(char *output
, int maxlen
, void *value
, int len
)
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
))));
170 ast_copy_string(output
, "Invalid INT", maxlen
);
173 static void dump_samprate(char *output
, int maxlen
, void *value
, int len
)
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");
192 ast_copy_string(output
, &tmp
[1], maxlen
);
194 ast_copy_string(output
, "None Specified!\n", maxlen
);
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
{
209 void (*dump
)(char *output
, int maxlen
, void *value
, int len
);
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
)
288 for (x
=0;x
<(int)sizeof(ies
) / (int)sizeof(ies
[0]); x
++) {
296 static void dump_prov_ies(char *output
, int maxlen
, unsigned char *iedata
, int len
)
306 strcpy(output
, "\n");
307 maxlen
-= strlen(output
); output
+= strlen(output
);
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
);
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
);
328 snprintf(interp
, (int)sizeof(interp
), "%d bytes", ielen
);
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
);
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
);
348 static void dump_ies(unsigned char *iedata
, int len
)
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
);
367 for (x
=0;x
<(int)sizeof(ies
) / (int)sizeof(ies
[0]); x
++) {
368 if (ies
[x
].ie
== ie
) {
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
);
375 snprintf(interp
, (int)sizeof(interp
), "%d bytes", ielen
);
377 strcpy(interp
, "Present");
378 snprintf(tmp
, (int)sizeof(tmp
), " %-15.15s : %s\n", ies
[x
].name
, interp
);
385 snprintf(tmp
, (int)sizeof(tmp
), " Unknown IE %03d : Present\n", ie
);
388 iedata
+= (2 + ielen
);
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
[] = {
411 const char *iaxs
[] = {
452 const char *cmds
[] = {
472 struct ast_iax2_full_hdr
*fh
;
477 const char *subclass
;
497 snprintf(retries
, sizeof(retries
), "%03d", f
->retries
);
500 if (ntohs(fh
->dcallno
) & IAX_FLAG_RETRANS
)
501 strcpy(retries
, "Yes");
503 strcpy(retries
, " No");
505 if (!(ntohs(fh
->scallno
) & IAX_FLAG_FULL
)) {
506 /* Don't mess with mini-frames */
509 if (fh
->type
>= (int)sizeof(frames
)/(int)sizeof(frames
[0])) {
510 snprintf(class2
, sizeof(class2
), "(%d?)", fh
->type
);
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
;
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
;
530 subclass
= cmds
[(int)fh
->csub
];
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",
539 retries
, fh
->oseqno
, fh
->iseqno
, class, subclass
);
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
));
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
)
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
);
559 ied
->buf
[ied
->pos
++] = ie
;
560 ied
->buf
[ied
->pos
++] = datalen
;
561 memcpy(ied
->buf
+ ied
->pos
, data
, datalen
);
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
)
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 *))
605 void iax_set_error(void (*func
)(const char *))
610 int iax_parse_ies(struct iax_ies
*ies
, unsigned char *data
, int datalen
)
612 /* Parse data into information elements */
615 char tmp
[256], *tmp2
;
616 struct ast_variable
*var
, *var2
, *prev
;
618 memset(ies
, 0, (int)sizeof(struct iax_ies
));
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) {
628 if (len
> datalen
- 2) {
629 errorf("Information element length exceeds message size\n");
633 case IAX_IE_CALLED_NUMBER
:
634 ies
->called_number
= (char *)data
+ 2;
636 case IAX_IE_CALLING_NUMBER
:
637 ies
->calling_number
= (char *)data
+ 2;
639 case IAX_IE_CALLING_ANI
:
640 ies
->calling_ani
= (char *)data
+ 2;
642 case IAX_IE_CALLING_NAME
:
643 ies
->calling_name
= (char *)data
+ 2;
645 case IAX_IE_CALLED_CONTEXT
:
646 ies
->called_context
= (char *)data
+ 2;
648 case IAX_IE_USERNAME
:
649 ies
->username
= (char *)data
+ 2;
651 case IAX_IE_PASSWORD
:
652 ies
->password
= (char *)data
+ 2;
654 case IAX_IE_CODEC_PREFS
:
655 ies
->codec_prefs
= (char *)data
+ 2;
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
);
662 ies
->capability
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
669 ies
->format
= ntohl(get_unaligned_uint32(data
+ 2));
671 case IAX_IE_LANGUAGE
:
672 ies
->language
= (char *)data
+ 2;
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
);
679 ies
->version
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
686 ies
->adsicpe
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
693 ies
->samprate
= ntohs(get_unaligned_uint16(data
+ 2));
696 ies
->dnid
= (char *)data
+ 2;
699 ies
->rdnis
= (char *)data
+ 2;
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
);
706 ies
->authmethods
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
713 ies
->encmethods
= ntohs(get_unaligned_uint16(data
+ 2));
715 case IAX_IE_CHALLENGE
:
716 ies
->challenge
= (char *)data
+ 2;
718 case IAX_IE_MD5_RESULT
:
719 ies
->md5_result
= (char *)data
+ 2;
721 case IAX_IE_RSA_RESULT
:
722 ies
->rsa_result
= (char *)data
+ 2;
724 case IAX_IE_APPARENT_ADDR
:
725 ies
->apparent_addr
= ((struct sockaddr_in
*)(data
+ 2));
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
);
732 ies
->refresh
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
739 ies
->dpstatus
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
746 ies
->callno
= ntohs(get_unaligned_uint16(data
+ 2));
749 ies
->cause
= (char *)data
+ 2;
751 case IAX_IE_CAUSECODE
:
753 snprintf(tmp
, (int)sizeof(tmp
), "Expecting causecode to be single byte but was %d\n", len
);
756 ies
->causecode
= data
[2];
759 case IAX_IE_IAX_UNKNOWN
:
761 ies
->iax_unknown
= data
[2];
763 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte Unknown command, but was %d long\n", len
);
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
);
772 ies
->msgcount
= ntohs(get_unaligned_uint16(data
+ 2));
774 case IAX_IE_AUTOANSWER
:
777 case IAX_IE_MUSICONHOLD
:
778 ies
->musiconhold
= 1;
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
);
785 ies
->transferid
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
792 ies
->datetime
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
799 ies
->firmwarever
= ntohs(get_unaligned_uint16(data
+ 2));
801 case IAX_IE_DEVICETYPE
:
802 ies
->devicetype
= (char *)data
+ 2;
804 case IAX_IE_SERVICEIDENT
:
805 ies
->serviceident
= (char *)data
+ 2;
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
);
812 ies
->fwdesc
= ntohl(get_unaligned_uint32(data
+ 2));
814 case IAX_IE_FWBLOCKDATA
:
815 ies
->fwdata
= data
+ 2;
816 ies
->fwdatalen
= len
;
819 ies
->enckey
= data
+ 2;
820 ies
->enckeylen
= len
;
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
);
827 ies
->provverpres
= 1;
828 ies
->provver
= ntohl(get_unaligned_uint32(data
+ 2));
831 case IAX_IE_CALLINGPRES
:
833 ies
->calling_pres
= data
[2];
835 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte callingpres, but was %d long\n", len
);
839 case IAX_IE_CALLINGTON
:
841 ies
->calling_ton
= data
[2];
843 snprintf(tmp
, (int)sizeof(tmp
), "Expected single byte callington, but was %d long\n", len
);
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
);
852 ies
->calling_tns
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
859 ies
->rr_jitter
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
867 ies
->rr_loss
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
875 ies
->rr_pkts
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
883 ies
->rr_delay
= ntohs(get_unaligned_uint16(data
+ 2));
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
);
891 ies
->rr_dropped
= ntohl(get_unaligned_uint32(data
+ 2));
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
);
899 ies
->rr_ooo
= ntohl(get_unaligned_uint32(data
+ 2));
902 case IAX_IE_VARIABLE
:
903 ast_copy_string(tmp
, (char *)data
+ 2, len
+ 1);
904 tmp2
= strchr(tmp
, '=');
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
;
926 var
= ast_variable_new(tmp
, tmp2
, "");
927 var
->next
= ies
->vars
;
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;
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
);
941 snprintf(tmp
, (int)sizeof(tmp
), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie
), ie
, len
);
944 /* Overwrite information element with 0, to null terminate previous portion */
946 datalen
-= (len
+ 2);
949 /* Null-terminate last field */
952 errorf("Invalid information element contents, strange boundary\n");
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
;
967 fr
->af
.delivery
.tv_sec
= 0;
968 fr
->af
.delivery
.tv_usec
= 0;
969 fr
->af
.data
= fr
->afdata
;
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);
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
;
1007 AST_LIST_TRAVERSE_SAFE_END
;
1010 if (!(fr
= ast_calloc_cache(1, sizeof(*fr
) + datalen
)))
1012 fr
->afdatalen
= datalen
;
1015 if (!(fr
= ast_calloc(1, sizeof(*fr
) + datalen
)))
1017 fr
->afdatalen
= datalen
;
1021 fr
->direction
= direction
;
1023 fr
->cacheable
= cacheable
;
1025 if (fr
->direction
== DIRECTION_INGRESS
)
1026 ast_atomic_fetchadd_int(&iframes
, 1);
1028 ast_atomic_fetchadd_int(&oframes
, 1);
1030 ast_atomic_fetchadd_int(&frames
, 1);
1035 void iax_frame_free(struct iax_frame
*fr
)
1037 #if !defined(LOW_MEMORY)
1038 struct iax_frames
*iax_frames
= NULL
;
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);
1047 errorf("Attempt to double free frame detected\n");
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
)))) {
1059 AST_LIST_INSERT_HEAD(iax_frames
, fr
, list
);
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
)))
1078 int iax_get_frames(void) { return frames
; }
1079 int iax_get_iframes(void) { return iframes
; }
1080 int iax_get_oframes(void) { return oframes
; }