2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Inter-Asterisk eXchange
6 * Copyright (C) 2003, Digium
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <asterisk/frame.h>
18 #include <arpa/inet.h>
23 #include "iax2-parser.h"
26 static int frames = 0;
27 static int iframes = 0;
28 static int oframes = 0;
30 static void internaloutput(const char *str)
35 static void internalerror(const char *str)
37 fprintf(stderr, "WARNING: %s", str);
40 static void (*outputf)(const char *str) = internaloutput;
41 static void (*errorf)(const char *str) = internalerror;
43 static void dump_addr(char *output, int maxlen, void *value, int len)
45 struct sockaddr_in sin;
46 if (len == sizeof(sin)) {
47 memcpy(&sin, value, len);
48 snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
50 snprintf(output, maxlen, "Invalid Address");
54 static void dump_string(char *output, int maxlen, void *value, int len)
59 strncpy(output,value, maxlen);
60 output[maxlen] = '\0';
63 static void dump_int(char *output, int maxlen, void *value, int len)
65 if (len == sizeof(unsigned int))
66 snprintf(output, maxlen, "%d", ntohl(*((unsigned int *)value)));
68 snprintf(output, maxlen, "Invalid INT");
71 static void dump_short(char *output, int maxlen, void *value, int len)
73 if (len == sizeof(unsigned short))
74 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
76 snprintf(output, maxlen, "Invalid SHORT");
79 static void dump_byte(char *output, int maxlen, void *value, int len)
81 if (len == sizeof(unsigned char))
82 snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
84 snprintf(output, maxlen, "Invalid BYTE");
87 static struct iax2_ie {
90 void (*dump)(char *output, int maxlen, void *value, int len);
92 { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
93 { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
94 { IAX_IE_CALLING_NUMBER, "ANI", dump_string },
95 { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
96 { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
97 { IAX_IE_USERNAME, "USERNAME", dump_string },
98 { IAX_IE_PASSWORD, "PASSWORD", dump_string },
99 { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
100 { IAX_IE_FORMAT, "FORMAT", dump_int },
101 { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
102 { IAX_IE_VERSION, "VERSION", dump_short },
103 { IAX_IE_ADSICPE, "ADSICPE", dump_short },
104 { IAX_IE_DNID, "DNID", dump_string },
105 { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
106 { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
107 { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
108 { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
109 { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
110 { IAX_IE_REFRESH, "REFRESH", dump_short },
111 { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
112 { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
113 { IAX_IE_CAUSE, "CAUSE", dump_string },
114 { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
115 { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
116 { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
117 { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
120 const char *iax_ie2str(int ie)
123 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
130 static void dump_ies(unsigned char *iedata, int len)
143 if (ielen + 2> len) {
144 snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
149 for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
150 if (ies[x].ie == ie) {
152 ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
153 snprintf(tmp, sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
156 snprintf(tmp, sizeof(tmp), " %-15.15s : Present\n", ies[x].name);
163 snprintf(tmp, sizeof(tmp), " Unknown IE %03d : Present\n", ie);
166 iedata += (2 + ielen);
172 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
229 struct ast_iax2_full_hdr *fh;
238 snprintf(retries, sizeof(retries), "%03d", f->retries);
241 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
242 strcpy(retries, "Yes");
244 strcpy(retries, "No");
246 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
247 /* Don't mess with mini-frames */
250 if (fh->type > sizeof(frames)/sizeof(char *)) {
251 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
254 class = frames[(int)fh->type];
256 if (fh->type == AST_FRAME_DTMF) {
257 sprintf(subclass2, "%c", fh->csub);
258 subclass = subclass2;
259 } else if (fh->type == AST_FRAME_IAX) {
260 if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
261 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
262 subclass = subclass2;
264 subclass = iaxs[(int)fh->csub];
266 } else if (fh->type == AST_FRAME_CONTROL) {
267 if (fh->csub > sizeof(cmds)/sizeof(char *)) {
268 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
269 subclass = subclass2;
271 subclass = cmds[(int)fh->csub];
274 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
275 subclass = subclass2;
277 snprintf(tmp, sizeof(tmp),
278 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
280 retries, fh->oseqno, fh->iseqno, class, subclass);
282 snprintf(tmp, sizeof(tmp),
283 " Timestamp: %05dms SCall: %5.5d DCall: %5.5d [%s:%d]\n",
285 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
286 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
288 if (fh->type == AST_FRAME_IAX)
289 dump_ies(fh->iedata, datalen);
292 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
295 if (datalen > (sizeof(ied->buf) - ied->pos)) {
296 snprintf(tmp, sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, sizeof(ied->buf) - ied->pos);
300 ied->buf[ied->pos++] = ie;
301 ied->buf[ied->pos++] = datalen;
302 memcpy(ied->buf + ied->pos, data, datalen);
307 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
309 return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
312 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
315 newval = htonl(value);
316 return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
319 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
321 unsigned short newval;
322 newval = htons(value);
323 return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
326 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
328 return iax_ie_append_raw(ied, ie, str, strlen(str));
331 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
333 return iax_ie_append_raw(ied, ie, &dat, 1);
336 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
338 return iax_ie_append_raw(ied, ie, NULL, 0);
341 void iax_set_output(void (*func)(const char *))
346 void iax_set_error(void (*func)(const char *))
351 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
353 /* Parse data into information elements */
357 memset(ies, 0, sizeof(struct iax_ies));
359 while(datalen >= 2) {
362 if (len > datalen - 2) {
363 errorf("Information element length exceeds message size\n");
367 case IAX_IE_CALLED_NUMBER:
368 ies->called_number = data + 2;
370 case IAX_IE_CALLING_NUMBER:
371 ies->calling_number = data + 2;
373 case IAX_IE_CALLING_ANI:
374 ies->calling_ani = data + 2;
376 case IAX_IE_CALLING_NAME:
377 ies->calling_name = data + 2;
379 case IAX_IE_CALLED_CONTEXT:
380 ies->called_context = data + 2;
382 case IAX_IE_USERNAME:
383 ies->username = data + 2;
385 case IAX_IE_PASSWORD:
386 ies->password = data + 2;
388 case IAX_IE_CAPABILITY:
389 if (len != sizeof(unsigned int)) {
390 snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
393 ies->capability = ntohl(*((unsigned int *)(data + 2)));
396 if (len != sizeof(unsigned int)) {
397 snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
400 ies->format = ntohl(*((unsigned int *)(data + 2)));
402 case IAX_IE_LANGUAGE:
403 ies->language = data + 2;
406 if (len != sizeof(unsigned short)) {
407 snprintf(tmp, sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
410 ies->version = ntohs(*((unsigned short *)(data + 2)));
413 if (len != sizeof(unsigned short)) {
414 snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
417 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
420 ies->dnid = data + 2;
422 case IAX_IE_AUTHMETHODS:
423 if (len != sizeof(unsigned short)) {
424 snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
427 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
429 case IAX_IE_CHALLENGE:
430 ies->challenge = data + 2;
432 case IAX_IE_MD5_RESULT:
433 ies->md5_result = data + 2;
435 case IAX_IE_RSA_RESULT:
436 ies->rsa_result = data + 2;
438 case IAX_IE_APPARENT_ADDR:
439 ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
442 if (len != sizeof(unsigned short)) {
443 snprintf(tmp, sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
446 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
448 case IAX_IE_DPSTATUS:
449 if (len != sizeof(unsigned short)) {
450 snprintf(tmp, sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
453 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
456 if (len != sizeof(unsigned short)) {
457 snprintf(tmp, sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
460 ies->callno = ntohs(*((unsigned short *)(data + 2)));
463 ies->cause = data + 2;
465 case IAX_IE_IAX_UNKNOWN:
467 ies->iax_unknown = data[2];
469 snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
473 case IAX_IE_MSGCOUNT:
474 if (len != sizeof(unsigned short)) {
475 snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
478 ies->msgcount = ntohs(*((unsigned short *)(data + 2)));
480 case IAX_IE_AUTOANSWER:
483 case IAX_IE_MUSICONHOLD:
484 ies->musiconhold = 1;
486 case IAX_IE_TRANSFERID:
487 if (len != sizeof(unsigned int)) {
488 snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
491 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
494 snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
497 /* Overwrite information element with 0, to null terminate previous portion */
499 datalen -= (len + 2);
502 /* Null-terminate last field */
505 errorf("Invalid information element contents, strange boundary\n");
511 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
513 fr->af.frametype = f->frametype;
514 fr->af.subclass = f->subclass;
515 fr->af.mallocd = 0; /* Our frame is static relative to the container */
516 fr->af.datalen = f->datalen;
517 fr->af.samples = f->samples;
518 fr->af.offset = AST_FRIENDLY_OFFSET;
520 fr->af.data = fr->afdata;
522 memcpy(fr->af.data, f->data, fr->af.datalen);
525 struct iax_frame *iax_frame_new(int direction, int datalen)
527 struct iax_frame *fr;
528 fr = malloc(sizeof(struct iax_frame) + datalen);
530 fr->direction = direction;
533 if (fr->direction == DIRECTION_INGRESS)
541 void iax_frame_free(struct iax_frame *fr)
543 /* Note: does not remove from scheduler! */
544 if (fr->direction == DIRECTION_INGRESS)
546 else if (fr->direction == DIRECTION_OUTGRESS)
549 errorf("Attempt to double free frame detected\n");
557 int iax_get_frames(void) { return frames; }
558 int iax_get_iframes(void) { return iframes; }
559 int iax_get_oframes(void) { return oframes; }