Use INET_ADDRLEN (bug #1956) (from airport!)
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Inter-Asterisk eXchange
5  * 
6  * Copyright (C) 2003, Digium
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <string.h>
17 #include <netinet/in.h>
18 #include <asterisk/frame.h>
19 #include <asterisk/utils.h>
20 #include <arpa/inet.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "iax2.h"
25 #include "iax2-parser.h"
26
27
28 static int frames = 0;
29 static int iframes = 0;
30 static int oframes = 0;
31
32 static void internaloutput(const char *str)
33 {
34         printf(str);
35 }
36
37 static void internalerror(const char *str)
38 {
39         fprintf(stderr, "WARNING: %s", str);
40 }
41
42 static void (*outputf)(const char *str) = internaloutput;
43 static void (*errorf)(const char *str) = internalerror;
44
45 static void dump_addr(char *output, int maxlen, void *value, int len)
46 {
47         struct sockaddr_in sin;
48         char iabuf[INET_ADDRSTRLEN];
49         if (len == (int)sizeof(sin)) {
50                 memcpy(&sin, value, len);
51                 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
52         } else {
53                 snprintf(output, maxlen, "Invalid Address");
54         }
55 }
56
57 static void dump_string(char *output, int maxlen, void *value, int len)
58 {
59         maxlen--;
60         if (maxlen > len)
61                 maxlen = len;
62         strncpy(output,value, maxlen);
63         output[maxlen] = '\0';
64 }
65
66 static void dump_int(char *output, int maxlen, void *value, int len)
67 {
68         if (len == (int)sizeof(unsigned int))
69                 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
70         else
71                 snprintf(output, maxlen, "Invalid INT");
72 }
73
74 static void dump_short(char *output, int maxlen, void *value, int len)
75 {
76         if (len == (int)sizeof(unsigned short))
77                 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
78         else
79                 snprintf(output, maxlen, "Invalid SHORT");
80 }
81
82 static void dump_byte(char *output, int maxlen, void *value, int len)
83 {
84         if (len == (int)sizeof(unsigned char))
85                 snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
86         else
87                 snprintf(output, maxlen, "Invalid BYTE");
88 }
89
90 static struct iax2_ie {
91         int ie;
92         char *name;
93         void (*dump)(char *output, int maxlen, void *value, int len);
94 } ies[] = {
95         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
96         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
97         { IAX_IE_CALLING_ANI, "ANI", dump_string },
98         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
99         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
100         { IAX_IE_USERNAME, "USERNAME", dump_string },
101         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
102         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
103         { IAX_IE_FORMAT, "FORMAT", dump_int },
104         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
105         { IAX_IE_VERSION, "VERSION", dump_short },
106         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
107         { IAX_IE_DNID, "DNID", dump_string },
108         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
109         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
110         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
111         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
112         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
113         { IAX_IE_REFRESH, "REFRESH", dump_short },
114         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
115         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
116         { IAX_IE_CAUSE, "CAUSE", dump_string },
117         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
118         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
119         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
120         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
121         { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
122         { IAX_IE_PROVISIONING, "PROVISIONING" },
123         { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
124         { IAX_IE_DATETIME, "DATE TIME", dump_int },
125         { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
126         { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
127         { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
128         { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
129         { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
130         { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
131 };
132
133 const char *iax_ie2str(int ie)
134 {
135         int x;
136         for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
137                 if (ies[x].ie == ie)
138                         return ies[x].name;
139         }
140         return "Unknown IE";
141 }
142
143 static void dump_ies(unsigned char *iedata, int len)
144 {
145         int ielen;
146         int ie;
147         int x;
148         int found;
149         char interp[80];
150         char tmp[256];
151         if (len < 2)
152                 return;
153         while(len > 2) {
154                 ie = iedata[0];
155                 ielen = iedata[1];
156                 if (ielen + 2> len) {
157                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
158                         outputf(tmp);
159                         return;
160                 }
161                 found = 0;
162                 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
163                         if (ies[x].ie == ie) {
164                                 if (ies[x].dump) {
165                                         ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
166                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
167                                         outputf(tmp);
168                                 } else {
169                                         if (ielen)
170                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
171                                         else
172                                                 strcpy(interp, "Present");
173                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
174                                         outputf(tmp);
175                                 }
176                                 found++;
177                         }
178                 }
179                 if (!found) {
180                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
181                         outputf(tmp);
182                 }
183                 iedata += (2 + ielen);
184                 len -= (2 + ielen);
185         }
186         outputf("\n");
187 }
188
189 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
190 {
191         char *frames[] = {
192                 "(0?)",
193                 "DTMF   ",
194                 "VOICE  ",
195                 "VIDEO  ",
196                 "CONTROL",
197                 "NULL   ",
198                 "IAX    ",
199                 "TEXT   ",
200                 "IMAGE  " };
201         char *iaxs[] = {
202                 "(0?)",
203                 "NEW    ",
204                 "PING   ",
205                 "PONG   ",
206                 "ACK    ",
207                 "HANGUP ",
208                 "REJECT ",
209                 "ACCEPT ",
210                 "AUTHREQ",
211                 "AUTHREP",
212                 "INVAL  ",
213                 "LAGRQ  ",
214                 "LAGRP  ",
215                 "REGREQ ",
216                 "REGAUTH",
217                 "REGACK ",
218                 "REGREJ ",
219                 "REGREL ",
220                 "VNAK   ",
221                 "DPREQ  ",
222                 "DPREP  ",
223                 "DIAL   ",
224                 "TXREQ  ",
225                 "TXCNT  ",
226                 "TXACC  ",
227                 "TXREADY",
228                 "TXREL  ",
229                 "TXREJ  ",
230                 "QUELCH ",
231                 "UNQULCH",
232                 "POKE",
233                 "PAGE",
234                 "MWI",
235                 "UNSUPPORTED",
236                 "TRANSFER",
237                 "PROVISION",
238                 "FWDOWNLD",
239                 "FWDATA"
240         };
241         char *cmds[] = {
242                 "(0?)",
243                 "HANGUP ",
244                 "RING   ",
245                 "RINGING",
246                 "ANSWER ",
247                 "BUSY   ",
248                 "TKOFFHK ",
249                 "OFFHOOK" };
250         struct ast_iax2_full_hdr *fh;
251         char retries[20];
252         char class2[20];
253         char subclass2[20];
254         char *class;
255         char *subclass;
256         char tmp[256];
257         char iabuf[INET_ADDRSTRLEN];
258         if (f) {
259                 fh = f->data;
260                 snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
261         } else {
262                 fh = fhi;
263                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
264                         strcpy(retries, "Yes");
265                 else
266                         strcpy(retries, "No");
267         }
268         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
269                 /* Don't mess with mini-frames */
270                 return;
271         }
272         if (fh->type > (int)sizeof(frames)/(int)sizeof(char *)) {
273                 snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
274                 class = class2;
275         } else {
276                 class = frames[(int)fh->type];
277         }
278         if (fh->type == AST_FRAME_DTMF) {
279                 sprintf(subclass2, "%c", fh->csub);
280                 subclass = subclass2;
281         } else if (fh->type == AST_FRAME_IAX) {
282                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
283                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
284                         subclass = subclass2;
285                 } else {
286                         subclass = iaxs[(int)fh->csub];
287                 }
288         } else if (fh->type == AST_FRAME_CONTROL) {
289                 if (fh->csub > (int)sizeof(cmds)/(int)sizeof(char *)) {
290                         snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
291                         subclass = subclass2;
292                 } else {
293                         subclass = cmds[(int)fh->csub];
294                 }
295         } else {
296                 snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
297                 subclass = subclass2;
298         }
299 snprintf(tmp, (int)sizeof(tmp), 
300 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
301         (rx ? "Rx" : "Tx"),
302         retries, fh->oseqno, fh->iseqno, class, subclass);
303         outputf(tmp);
304 snprintf(tmp, (int)sizeof(tmp), 
305 "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
306         (unsigned long)ntohl(fh->ts),
307         ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
308                 ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
309         outputf(tmp);
310         if (fh->type == AST_FRAME_IAX)
311                 dump_ies(fh->iedata, datalen);
312 }
313
314 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
315 {
316         char tmp[256];
317         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
318                 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);
319                 errorf(tmp);
320                 return -1;
321         }
322         ied->buf[ied->pos++] = ie;
323         ied->buf[ied->pos++] = datalen;
324         memcpy(ied->buf + ied->pos, data, datalen);
325         ied->pos += datalen;
326         return 0;
327 }
328
329 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
330 {
331         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
332 }
333
334 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
335 {
336         unsigned int newval;
337         newval = htonl(value);
338         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
339 }
340
341 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
342 {
343         unsigned short newval;
344         newval = htons(value);
345         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
346 }
347
348 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
349 {
350         return iax_ie_append_raw(ied, ie, str, strlen(str));
351 }
352
353 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
354 {
355         return iax_ie_append_raw(ied, ie, &dat, 1);
356 }
357
358 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
359 {
360         return iax_ie_append_raw(ied, ie, NULL, 0);
361 }
362
363 void iax_set_output(void (*func)(const char *))
364 {
365         outputf = func;
366 }
367
368 void iax_set_error(void (*func)(const char *))
369 {
370         errorf = func;
371 }
372
373 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
374 {
375         /* Parse data into information elements */
376         int len;
377         int ie;
378         char tmp[256];
379         memset(ies, 0, (int)sizeof(struct iax_ies));
380         ies->msgcount = -1;
381         ies->firmwarever = -1;
382         while(datalen >= 2) {
383                 ie = data[0];
384                 len = data[1];
385                 if (len > datalen - 2) {
386                         errorf("Information element length exceeds message size\n");
387                         return -1;
388                 }
389                 switch(ie) {
390                 case IAX_IE_CALLED_NUMBER:
391                         ies->called_number = data + 2;
392                         break;
393                 case IAX_IE_CALLING_NUMBER:
394                         ies->calling_number = data + 2;
395                         break;
396                 case IAX_IE_CALLING_ANI:
397                         ies->calling_ani = data + 2;
398                         break;
399                 case IAX_IE_CALLING_NAME:
400                         ies->calling_name = data + 2;
401                         break;
402                 case IAX_IE_CALLED_CONTEXT:
403                         ies->called_context = data + 2;
404                         break;
405                 case IAX_IE_USERNAME:
406                         ies->username = data + 2;
407                         break;
408                 case IAX_IE_PASSWORD:
409                         ies->password = data + 2;
410                         break;
411                 case IAX_IE_CAPABILITY:
412                         if (len != (int)sizeof(unsigned int)) {
413                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
414                                 errorf(tmp);
415                         } else
416                                 ies->capability = ntohl(*((unsigned int *)(data + 2)));
417                         break;
418                 case IAX_IE_FORMAT:
419                         if (len != (int)sizeof(unsigned int)) {
420                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
421                                 errorf(tmp);
422                         } else
423                                 ies->format = ntohl(*((unsigned int *)(data + 2)));
424                         break;
425                 case IAX_IE_LANGUAGE:
426                         ies->language = data + 2;
427                         break;
428                 case IAX_IE_VERSION:
429                         if (len != (int)sizeof(unsigned short)) {
430                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
431                                 errorf(tmp);
432                         } else
433                                 ies->version = ntohs(*((unsigned short *)(data + 2)));
434                         break;
435                 case IAX_IE_ADSICPE:
436                         if (len != (int)sizeof(unsigned short)) {
437                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
438                                 errorf(tmp);
439                         } else
440                                 ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
441                         break;
442                 case IAX_IE_DNID:
443                         ies->dnid = data + 2;
444                         break;
445                 case IAX_IE_RDNIS:
446                         ies->rdnis = data + 2;
447                         break;
448                 case IAX_IE_AUTHMETHODS:
449                         if (len != (int)sizeof(unsigned short))  {
450                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
451                                 errorf(tmp);
452                         } else
453                                 ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
454                         break;
455                 case IAX_IE_CHALLENGE:
456                         ies->challenge = data + 2;
457                         break;
458                 case IAX_IE_MD5_RESULT:
459                         ies->md5_result = data + 2;
460                         break;
461                 case IAX_IE_RSA_RESULT:
462                         ies->rsa_result = data + 2;
463                         break;
464                 case IAX_IE_APPARENT_ADDR:
465                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
466                         break;
467                 case IAX_IE_REFRESH:
468                         if (len != (int)sizeof(unsigned short)) {
469                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
470                                 errorf(tmp);
471                         } else
472                                 ies->refresh = ntohs(*((unsigned short *)(data + 2)));
473                         break;
474                 case IAX_IE_DPSTATUS:
475                         if (len != (int)sizeof(unsigned short)) {
476                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
477                                 errorf(tmp);
478                         } else
479                                 ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
480                         break;
481                 case IAX_IE_CALLNO:
482                         if (len != (int)sizeof(unsigned short)) {
483                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
484                                 errorf(tmp);
485                         } else
486                                 ies->callno = ntohs(*((unsigned short *)(data + 2)));
487                         break;
488                 case IAX_IE_CAUSE:
489                         ies->cause = data + 2;
490                         break;
491                 case IAX_IE_IAX_UNKNOWN:
492                         if (len == 1)
493                                 ies->iax_unknown = data[2];
494                         else {
495                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
496                                 errorf(tmp);
497                         }
498                         break;
499                 case IAX_IE_MSGCOUNT:
500                         if (len != (int)sizeof(unsigned short)) {
501                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
502                                 errorf(tmp);
503                         } else
504                                 ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
505                         break;
506                 case IAX_IE_AUTOANSWER:
507                         ies->autoanswer = 1;
508                         break;
509                 case IAX_IE_MUSICONHOLD:
510                         ies->musiconhold = 1;
511                         break;
512                 case IAX_IE_TRANSFERID:
513                         if (len != (int)sizeof(unsigned int)) {
514                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
515                                 errorf(tmp);
516                         } else
517                                 ies->transferid = ntohl(*((unsigned int *)(data + 2)));
518                         break;
519                 case IAX_IE_DATETIME:
520                         if (len != (int)sizeof(unsigned int)) {
521                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
522                                 errorf(tmp);
523                         } else
524                                 ies->datetime = ntohl(*((unsigned int *)(data + 2)));
525                         break;
526                 case IAX_IE_FIRMWAREVER:
527                         if (len != (int)sizeof(unsigned short)) {
528                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
529                                 errorf(tmp);
530                         } else
531                                 ies->firmwarever = ntohs(*((unsigned short *)(data + 2)));      
532                         break;
533                 case IAX_IE_DEVICETYPE:
534                         ies->devicetype = data + 2;
535                         break;
536                 case IAX_IE_SERVICEIDENT:
537                         ies->serviceident = data + 2;
538                         break;
539                 case IAX_IE_FWBLOCKDESC:
540                         if (len != (int)sizeof(unsigned int)) {
541                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
542                                 errorf(tmp);
543                         } else
544                                 ies->fwdesc = ntohl(*((unsigned int *)(data + 2)));
545                         break;
546                 case IAX_IE_FWBLOCKDATA:
547                         ies->fwdata = data + 2;
548                         ies->fwdatalen = len;
549                         break;
550                 case IAX_IE_PROVVER:
551                         if (len != (int)sizeof(unsigned int)) {
552                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
553                                 errorf(tmp);
554                         } else
555                                 ies->provver = ntohl(*((unsigned int *)(data + 2)));
556                         break;
557                 default:
558                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
559                         outputf(tmp);
560                 }
561                 /* Overwrite information element with 0, to null terminate previous portion */
562                 data[0] = 0;
563                 datalen -= (len + 2);
564                 data += (len + 2);
565         }
566         /* Null-terminate last field */
567         *data = '\0';
568         if (datalen) {
569                 errorf("Invalid information element contents, strange boundary\n");
570                 return -1;
571         }
572         return 0;
573 }
574
575 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
576 {
577         fr->af.frametype = f->frametype;
578         fr->af.subclass = f->subclass;
579         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
580         fr->af.datalen = f->datalen;
581         fr->af.samples = f->samples;
582         fr->af.offset = AST_FRIENDLY_OFFSET;
583         fr->af.src = f->src;
584         fr->af.delivery.tv_sec = 0;
585         fr->af.delivery.tv_usec = 0;
586         fr->af.data = fr->afdata;
587         if (fr->af.datalen) 
588                 memcpy(fr->af.data, f->data, fr->af.datalen);
589 }
590
591 struct iax_frame *iax_frame_new(int direction, int datalen)
592 {
593         struct iax_frame *fr;
594         fr = malloc((int)sizeof(struct iax_frame) + datalen);
595         if (fr) {
596                 fr->direction = direction;
597                 fr->retrans = -1;
598                 frames++;
599                 if (fr->direction == DIRECTION_INGRESS)
600                         iframes++;
601                 else
602                         oframes++;
603         }
604         return fr;
605 }
606
607 void iax_frame_free(struct iax_frame *fr)
608 {
609         /* Note: does not remove from scheduler! */
610         if (fr->direction == DIRECTION_INGRESS)
611                 iframes--;
612         else if (fr->direction == DIRECTION_OUTGRESS)
613                 oframes--;
614         else {
615                 errorf("Attempt to double free frame detected\n");
616                 return;
617         }
618         fr->direction = 0;
619         free(fr);
620         frames--;
621 }
622
623 int iax_get_frames(void) { return frames; }
624 int iax_get_iframes(void) { return iframes; }
625 int iax_get_oframes(void) { return oframes; }