2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Inter-Asterisk eXchange
6 * Copyright (C) 2003-2004, Digium
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU Lesser (Library) General Public License
14 #if defined(WIN32) || defined(_WIN32_WCE)
16 #define snprintf _snprintf
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
34 #include "iax2-parser.h"
36 static int frames = 0;
37 static int iframes = 0;
38 static int oframes = 0;
41 static unsigned int get_uint32(unsigned char *p)
43 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
46 static unsigned short get_uint16(unsigned char *p)
48 return (p[0] << 8) | p[1] ;
52 #define get_uint32(p) (*((unsigned int *)(p)))
53 #define get_uint16(p) (*((unsigned short *)(p)))
57 static void internaloutput(const char *str)
62 static void internalerror(const char *str)
64 fprintf(stderr, "WARNING: %s", str);
67 static void (*outputf)(const char *str) = internaloutput;
68 static void (*errorf)(const char *str) = internalerror;
70 static void dump_addr(char *output, int maxlen, void *value, int len)
72 struct sockaddr_in sin;
73 if (len == sizeof(sin)) {
74 memcpy(&sin, value, len);
75 snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
77 snprintf(output, maxlen, "Invalid Address");
81 static void dump_string(char *output, int maxlen, void *value, int len)
86 strncpy(output,(const char *)value, maxlen);
87 output[maxlen] = '\0';
90 static void dump_int(char *output, int maxlen, void *value, int len)
92 if (len == (int)sizeof(unsigned int))
93 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_uint32(value)));
95 snprintf(output, maxlen, "Invalid INT");
98 static void dump_short(char *output, int maxlen, void *value, int len)
100 if (len == (int)sizeof(unsigned short))
101 snprintf(output, maxlen, "%d", ntohs(get_uint16(value)));
103 snprintf(output, maxlen, "Invalid SHORT");
106 static void dump_byte(char *output, int maxlen, void *value, int len)
108 if (len == (int)sizeof(unsigned char))
109 snprintf(output, maxlen, "%d", *((unsigned char *)value));
111 snprintf(output, maxlen, "Invalid BYTE");
114 static void dump_samprate(char *output, int maxlen, void *value, int len)
118 if (len == (int)sizeof(unsigned short)) {
119 sr = ntohs(*((unsigned short *)value));
120 if (sr & IAX_RATE_8KHZ)
121 strcat(tmp, ",8khz");
122 if (sr & IAX_RATE_11KHZ)
123 strcat(tmp, ",11.025khz");
124 if (sr & IAX_RATE_16KHZ)
125 strcat(tmp, ",16khz");
126 if (sr & IAX_RATE_22KHZ)
127 strcat(tmp, ",22.05khz");
128 if (sr & IAX_RATE_44KHZ)
129 strcat(tmp, ",44.1khz");
130 if (sr & IAX_RATE_48KHZ)
131 strcat(tmp, ",48khz");
133 strncpy(output, &tmp[1], maxlen - 1);
135 strncpy(output, "None specified!\n", maxlen - 1);
137 snprintf(output, maxlen, "Invalid SHORT");
141 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
142 static void dump_prov(char *output, int maxlen, void *value, int len)
144 dump_prov_ies(output, maxlen, (unsigned char *)value, len);
147 static struct iax2_ie {
150 void (*dump)(char *output, int maxlen, void *value, int len);
152 { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
153 { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
154 { IAX_IE_CALLING_ANI, "ANI", dump_string },
155 { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
156 { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
157 { IAX_IE_USERNAME, "USERNAME", dump_string },
158 { IAX_IE_PASSWORD, "PASSWORD", dump_string },
159 { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
160 { IAX_IE_FORMAT, "FORMAT", dump_int },
161 { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
162 { IAX_IE_VERSION, "VERSION", dump_short },
163 { IAX_IE_ADSICPE, "ADSICPE", dump_short },
164 { IAX_IE_DNID, "DNID", dump_string },
165 { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
166 { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
167 { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
168 { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
169 { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
170 { IAX_IE_REFRESH, "REFRESH", dump_short },
171 { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
172 { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
173 { IAX_IE_CAUSE, "CAUSE", dump_string },
174 { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
175 { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
176 { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
177 { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
178 { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
179 { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
180 { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
181 { IAX_IE_DATETIME, "DATE TIME", dump_int },
182 { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
183 { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
184 { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
185 { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
186 { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
187 { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
188 { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
189 { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
190 { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
191 { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
192 { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_string },
193 { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
194 { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
195 { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
196 { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
197 { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
198 { IAX_IE_RR_OOO, "RR_OOO", dump_int },
201 const char *iax_ie2str(int ie)
204 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
212 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
220 strcpy(output, "\n");
221 maxlen -= (int)strlen(output); output += strlen(output);
225 if (ielen + 2> len) {
226 snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
227 strncpy(output, tmp, maxlen - 1);
228 maxlen -= (int)strlen(output); output += strlen(output);
233 snprintf(tmp, (int)sizeof(tmp), " Unknown Prov IE %03d : Present\n", ie);
234 strncpy(output, tmp, maxlen - 1);
235 maxlen -= (int)strlen(output); output += strlen(output);
237 iedata += (2 + ielen);
242 static void dump_ies(unsigned char *iedata, int len)
255 if (ielen + 2> len) {
256 snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
261 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
262 if (ies[x].ie == ie) {
264 ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
265 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
269 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
271 strcpy(interp, "Present");
272 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
279 snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
282 iedata += (2 + ielen);
288 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
290 const char *frames[] = {
300 const char *iaxs[] = {
340 const char *cmds[] = {
354 struct ast_iax2_full_hdr *fh;
359 const char *subclass;
363 fh = (struct ast_iax2_full_hdr *)f->data;
364 snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
367 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
368 strcpy(retries, "Yes");
370 strcpy(retries, " No");
372 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
373 /* Don't mess with mini-frames */
376 if (fh->type >= (int)(sizeof(frames)/sizeof(char *))) {
377 snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
380 clas = frames[(int)fh->type];
382 if (fh->type == AST_FRAME_DTMF) {
383 sprintf(subclass2, "%c", fh->csub);
384 subclass = subclass2;
385 } else if (fh->type == AST_FRAME_IAX) {
386 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
387 snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
388 subclass = subclass2;
390 subclass = iaxs[(int)fh->csub];
392 } else if (fh->type == AST_FRAME_CONTROL) {
393 if (fh->csub >= (int)(sizeof(cmds)/sizeof(char *))) {
394 snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
395 subclass = subclass2;
397 subclass = cmds[(int)fh->csub];
400 snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
401 subclass = subclass2;
403 snprintf(tmp, (int)sizeof(tmp),
404 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
406 retries, fh->oseqno, fh->iseqno, clas, subclass);
408 snprintf(tmp, (int)sizeof(tmp),
409 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
410 (unsigned long)ntohl(fh->ts),
411 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
412 inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
414 if (fh->type == AST_FRAME_IAX)
415 dump_ies(fh->iedata, datalen);
418 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
421 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
422 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);
426 ied->buf[ied->pos++] = ie;
427 ied->buf[ied->pos++] = datalen;
428 memcpy(ied->buf + ied->pos, data, datalen);
433 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
435 return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
438 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
441 newval = htonl(value);
442 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
445 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
447 unsigned short newval;
448 newval = htons(value);
449 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
452 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
454 return iax_ie_append_raw(ied, ie, str, (int)strlen(str));
457 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
459 return iax_ie_append_raw(ied, ie, &dat, 1);
462 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
464 return iax_ie_append_raw(ied, ie, NULL, 0);
467 void iax_set_output(void (*func)(const char *))
472 void iax_set_error(void (*func)(const char *))
477 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
479 /* Parse data into information elements */
483 memset(ies, 0, (int)sizeof(struct iax_ies));
485 ies->firmwarever = -1;
486 ies->calling_ton = -1;
487 ies->calling_tns = -1;
488 ies->calling_pres = -1;
489 ies->samprate = IAX_RATE_8KHZ;
490 while(datalen >= 2) {
493 if (len > datalen - 2) {
494 errorf("Information element length exceeds message size\n");
498 case IAX_IE_CALLED_NUMBER:
499 ies->called_number = (char *) data + 2;
501 case IAX_IE_CALLING_NUMBER:
502 ies->calling_number = (char *) data + 2;
504 case IAX_IE_CALLING_ANI:
505 ies->calling_ani = (char *) data + 2;
507 case IAX_IE_CALLING_NAME:
508 ies->calling_name = (char *) data + 2;
510 case IAX_IE_CALLED_CONTEXT:
511 ies->called_context = (char *) data + 2;
513 case IAX_IE_USERNAME:
514 ies->username = (char *) data + 2;
516 case IAX_IE_PASSWORD:
517 ies->password = (char *) data + 2;
519 case IAX_IE_CAPABILITY:
520 if (len != (int)sizeof(unsigned int)) {
521 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
524 ies->capability = ntohl(get_uint32(data + 2));
527 if (len != (int)sizeof(unsigned int)) {
528 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
531 ies->format = ntohl(get_uint32(data + 2));
533 case IAX_IE_LANGUAGE:
534 ies->language = (char *) data + 2;
536 case IAX_IE_CODEC_PREFS:
537 ies->codec_prefs = (char *) data + 2;
540 if (len != (int)sizeof(unsigned short)) {
541 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
544 ies->version = ntohs(get_uint16(data + 2));
547 if (len != (int)sizeof(unsigned short)) {
548 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
551 ies->adsicpe = ntohs(get_uint16(data + 2));
553 case IAX_IE_SAMPLINGRATE:
554 if (len != (int)sizeof(unsigned short)) {
555 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
558 ies->samprate = ntohs(get_uint16(data + 2));
561 ies->dnid = (char *) data + 2;
564 ies->rdnis = (char *) data + 2;
566 case IAX_IE_AUTHMETHODS:
567 if (len != (int)sizeof(unsigned short)) {
568 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
571 ies->authmethods = ntohs(get_uint16(data + 2));
573 case IAX_IE_CHALLENGE:
574 ies->challenge = (char *) data + 2;
576 case IAX_IE_MD5_RESULT:
577 ies->md5_result = (char *) data + 2;
579 case IAX_IE_RSA_RESULT:
580 ies->rsa_result = (char *) data + 2;
582 case IAX_IE_APPARENT_ADDR:
583 ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
586 if (len != (int)sizeof(unsigned short)) {
587 snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
590 ies->refresh = ntohs(get_uint16(data + 2));
592 case IAX_IE_DPSTATUS:
593 if (len != (int)sizeof(unsigned short)) {
594 snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
597 ies->dpstatus = ntohs(get_uint16(data + 2));
600 if (len != (int)sizeof(unsigned short)) {
601 snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
604 ies->callno = ntohs(get_uint16(data + 2));
607 ies->cause = (char *) data + 2;
609 case IAX_IE_CAUSECODE:
611 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
614 ies->causecode = data[2];
617 case IAX_IE_IAX_UNKNOWN:
619 ies->iax_unknown = data[2];
621 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
625 case IAX_IE_MSGCOUNT:
626 if (len != (int)sizeof(unsigned short)) {
627 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
630 ies->msgcount = ntohs(get_uint16(data + 2));
632 case IAX_IE_AUTOANSWER:
635 case IAX_IE_MUSICONHOLD:
636 ies->musiconhold = 1;
638 case IAX_IE_TRANSFERID:
639 if (len != (int)sizeof(unsigned int)) {
640 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
643 ies->transferid = ntohl(get_uint32(data + 2));
645 case IAX_IE_DATETIME:
646 if (len != (int)sizeof(unsigned int)) {
647 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
650 ies->datetime = ntohl(get_uint32(data + 2));
652 case IAX_IE_FIRMWAREVER:
653 if (len != (int)sizeof(unsigned short)) {
654 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
657 ies->firmwarever = ntohs(get_uint16(data + 2));
659 case IAX_IE_DEVICETYPE:
660 ies->devicetype = (char *) data + 2;
662 case IAX_IE_SERVICEIDENT:
663 ies->serviceident = (char *) data + 2;
665 case IAX_IE_FWBLOCKDESC:
666 if (len != (int)sizeof(unsigned int)) {
667 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
670 ies->fwdesc = ntohl(get_uint32(data + 2));
672 case IAX_IE_FWBLOCKDATA:
673 ies->fwdata = data + 2;
674 ies->fwdatalen = len;
677 if (len != (int)sizeof(unsigned int)) {
678 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
681 ies->provverpres = 1;
682 ies->provver = ntohl(get_uint32(data + 2));
685 case IAX_IE_CALLINGPRES:
687 ies->calling_pres = data[2];
689 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
693 case IAX_IE_CALLINGTON:
695 ies->calling_ton = data[2];
697 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
701 case IAX_IE_CALLINGTNS:
702 if (len != (int)sizeof(unsigned short)) {
703 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
706 ies->calling_tns = ntohs(get_uint16(data + 2));
708 case IAX_IE_RR_JITTER:
709 if (len != (int)sizeof(unsigned int)) {
710 snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
713 ies->rr_jitter = ntohl(get_uint32(data + 2));
717 if (len != (int)sizeof(unsigned int)) {
718 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
721 ies->rr_loss = ntohl(get_uint32(data + 2));
725 if (len != (int)sizeof(unsigned int)) {
726 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
729 ies->rr_pkts = ntohl(get_uint32(data + 2));
732 case IAX_IE_RR_DELAY:
733 if (len != (int)sizeof(unsigned short)) {
734 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
737 ies->rr_delay = ntohs(get_uint16(data + 2));
740 case IAX_IE_RR_DROPPED:
741 if (len != (int)sizeof(unsigned int)) {
742 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
745 ies->rr_dropped = ntohl(get_uint32(data + 2));
749 if (len != (int)sizeof(unsigned int)) {
750 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
753 ies->rr_ooo = ntohl(get_uint32(data + 2));
757 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
760 /* Overwrite information element with 0, to null terminate previous portion */
762 datalen -= (len + 2);
765 /* Null-terminate last field */
768 errorf("Invalid information element contents, strange boundary\n");
774 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
776 fr->af.frametype = f->frametype;
777 fr->af.subclass = f->subclass;
778 fr->af.mallocd = 0; /* Our frame is static relative to the container */
779 fr->af.datalen = f->datalen;
780 fr->af.samples = f->samples;
781 fr->af.offset = AST_FRIENDLY_OFFSET;
783 fr->af.data = fr->afdata;
785 memcpy(fr->af.data, f->data, fr->af.datalen);
788 struct iax_frame *iax_frame_new(int direction, int datalen)
790 struct iax_frame *fr;
791 fr = (struct iax_frame *)malloc((int)sizeof(struct iax_frame) + datalen);
793 fr->direction = direction;
796 if (fr->direction == DIRECTION_INGRESS)
804 void iax_frame_free(struct iax_frame *fr)
806 /* Note: does not remove from scheduler! */
807 if (fr->direction == DIRECTION_INGRESS)
809 else if (fr->direction == DIRECTION_OUTGRESS)
812 errorf("Attempt to double free frame detected\n");
820 int iax_get_frames(void) { return frames; }
821 int iax_get_iframes(void) { return iframes; }
822 int iax_get_oframes(void) { return oframes; }