67341fc5e609f5c1f946df08a50bb7f5c945de50
[asterisk/asterisk.git] / channels / iax2-parser.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Implementation of Inter-Asterisk eXchange Protocol, v 2
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <string.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38
39 #include "asterisk/frame.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/unaligned.h"
42 #include "asterisk/lock.h"
43
44 #include "iax2.h"
45 #include "iax2-parser.h"
46 #include "iax2-provision.h"
47
48 static int frames = 0;
49 static int iframes = 0;
50 static int oframes = 0;
51
52 static void internaloutput(const char *str)
53 {
54         fputs(str, stdout);
55 }
56
57 static void internalerror(const char *str)
58 {
59         fprintf(stderr, "WARNING: %s", str);
60 }
61
62 static void (*outputf)(const char *str) = internaloutput;
63 static void (*errorf)(const char *str) = internalerror;
64
65 static void dump_addr(char *output, int maxlen, void *value, int len)
66 {
67         struct sockaddr_in sin;
68         if (len == (int)sizeof(sin)) {
69                 memcpy(&sin, value, len);
70                 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
71         } else {
72                 snprintf(output, maxlen, "Invalid Address");
73         }
74 }
75
76 static void dump_string(char *output, int maxlen, void *value, int len)
77 {
78         maxlen--;
79         if (maxlen > len)
80                 maxlen = len;
81         strncpy(output, value, maxlen);
82         output[maxlen] = '\0';
83 }
84
85 static void dump_prefs(char *output, int maxlen, void *value, int len)
86 {
87         struct ast_codec_pref pref;
88         int total_len = 0;
89
90         maxlen--;
91         total_len = maxlen;
92
93         if (maxlen > len)
94                 maxlen = len;
95
96         strncpy(output, value, maxlen);
97         output[maxlen] = '\0';
98         
99         ast_codec_pref_convert(&pref, output, total_len, 0);
100         memset(output,0,total_len);
101         ast_codec_pref_string(&pref, output, total_len);
102 }
103
104 static void dump_int(char *output, int maxlen, void *value, int len)
105 {
106         if (len == (int)sizeof(unsigned int))
107                 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
108         else
109                 ast_copy_string(output, "Invalid INT", maxlen); 
110 }
111
112 static void dump_short(char *output, int maxlen, void *value, int len)
113 {
114         if (len == (int)sizeof(unsigned short))
115                 snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
116         else
117                 ast_copy_string(output, "Invalid SHORT", maxlen);
118 }
119
120 static void dump_byte(char *output, int maxlen, void *value, int len)
121 {
122         if (len == (int)sizeof(unsigned char))
123                 snprintf(output, maxlen, "%d", *((unsigned char *)value));
124         else
125                 ast_copy_string(output, "Invalid BYTE", maxlen);
126 }
127
128 static void dump_datetime(char *output, int maxlen, void *value, int len)
129 {
130         struct tm tm;
131         unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
132         if (len == (int)sizeof(unsigned int)) {
133                 tm.tm_sec  = (val & 0x1f) << 1;
134                 tm.tm_min  = (val >> 5) & 0x3f;
135                 tm.tm_hour = (val >> 11) & 0x1f;
136                 tm.tm_mday = (val >> 16) & 0x1f;
137                 tm.tm_mon  = ((val >> 21) & 0x0f) - 1;
138                 tm.tm_year = ((val >> 25) & 0x7f) + 100;
139                 strftime(output, maxlen, "%Y-%m-%d  %T", &tm); 
140         } else
141                 ast_copy_string(output, "Invalid DATETIME format!", maxlen);
142 }
143
144 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
145 {
146         struct sockaddr_in sin;
147         if (len == (int)sizeof(unsigned int)) {
148                 memcpy(&sin.sin_addr, value, len);
149                 snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
150         } else
151                 ast_copy_string(output, "Invalid IPADDR", maxlen);
152 }
153
154
155 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
156 {
157         char buf[256] = "";
158         if (len == (int)sizeof(unsigned int))
159                 snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
160                         iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
161         else
162                 ast_copy_string(output, "Invalid INT", maxlen);
163 }
164
165 static void dump_samprate(char *output, int maxlen, void *value, int len)
166 {
167         char tmp[256]="";
168         int sr;
169         if (len == (int)sizeof(unsigned short)) {
170                 sr = ntohs(*((unsigned short *)value));
171                 if (sr & IAX_RATE_8KHZ)
172                         strcat(tmp, ",8khz");
173                 if (sr & IAX_RATE_11KHZ)
174                         strcat(tmp, ",11.025khz");
175                 if (sr & IAX_RATE_16KHZ)
176                         strcat(tmp, ",16khz");
177                 if (sr & IAX_RATE_22KHZ)
178                         strcat(tmp, ",22.05khz");
179                 if (sr & IAX_RATE_44KHZ)
180                         strcat(tmp, ",44.1khz");
181                 if (sr & IAX_RATE_48KHZ)
182                         strcat(tmp, ",48khz");
183                 if (strlen(tmp))
184                         ast_copy_string(output, &tmp[1], maxlen);
185                 else
186                         ast_copy_string(output, "None Specified!\n", maxlen);
187         } else
188                 ast_copy_string(output, "Invalid SHORT", maxlen);
189
190 }
191
192 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
193 static void dump_prov(char *output, int maxlen, void *value, int len)
194 {
195         dump_prov_ies(output, maxlen, value, len);
196 }
197
198 static struct iax2_ie {
199         int ie;
200         char *name;
201         void (*dump)(char *output, int maxlen, void *value, int len);
202 } ies[] = {
203         { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
204         { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
205         { IAX_IE_CALLING_ANI, "ANI", dump_string },
206         { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
207         { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
208         { IAX_IE_USERNAME, "USERNAME", dump_string },
209         { IAX_IE_PASSWORD, "PASSWORD", dump_string },
210         { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
211         { IAX_IE_FORMAT, "FORMAT", dump_int },
212         { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
213         { IAX_IE_VERSION, "VERSION", dump_short },
214         { IAX_IE_ADSICPE, "ADSICPE", dump_short },
215         { IAX_IE_DNID, "DNID", dump_string },
216         { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
217         { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
218         { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
219         { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
220         { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
221         { IAX_IE_REFRESH, "REFRESH", dump_short },
222         { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
223         { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
224         { IAX_IE_CAUSE, "CAUSE", dump_string },
225         { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
226         { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
227         { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
228         { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
229         { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
230         { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
231         { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
232         { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
233         { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
234         { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
235         { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
236         { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
237         { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
238         { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
239         { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
240         { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
241         { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
242         { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
243         { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
244         { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
245         { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
246         { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
247         { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
248         { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
249         { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
250         { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
251         { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
252         { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
253 };
254
255 static struct iax2_ie prov_ies[] = {
256         { PROV_IE_USEDHCP, "USEDHCP" },
257         { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
258         { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
259         { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
260         { PROV_IE_PORTNO, "BINDPORT", dump_short },
261         { PROV_IE_USER, "USERNAME", dump_string },
262         { PROV_IE_PASS, "PASSWORD", dump_string },
263         { PROV_IE_LANG, "LANGUAGE", dump_string },
264         { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
265         { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
266         { PROV_IE_FORMAT, "FORMAT", dump_int },
267         { PROV_IE_AESKEY, "AESKEY" },
268         { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
269         { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
270         { PROV_IE_NEWAESKEY, "NEWAESKEY" },
271         { PROV_IE_PROVVER, "PROV VERSION", dump_int },
272         { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
273 };
274
275 const char *iax_ie2str(int ie)
276 {
277         int x;
278         for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
279                 if (ies[x].ie == ie)
280                         return ies[x].name;
281         }
282         return "Unknown IE";
283 }
284
285
286 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
287 {
288         int ielen;
289         int ie;
290         int x;
291         int found;
292         char interp[80];
293         char tmp[256];
294         if (len < 2)
295                 return;
296         strcpy(output, "\n"); 
297         maxlen -= strlen(output); output += strlen(output);
298         while(len > 2) {
299                 ie = iedata[0];
300                 ielen = iedata[1];
301                 if (ielen + 2> len) {
302                         snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
303                         ast_copy_string(output, tmp, maxlen);
304                         maxlen -= strlen(output);
305                         output += strlen(output);
306                         return;
307                 }
308                 found = 0;
309                 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
310                         if (prov_ies[x].ie == ie) {
311                                 if (prov_ies[x].dump) {
312                                         prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
313                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
314                                         ast_copy_string(output, tmp, maxlen);
315                                         maxlen -= strlen(output); output += strlen(output);
316                                 } else {
317                                         if (ielen)
318                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
319                                         else
320                                                 strcpy(interp, "Present");
321                                         snprintf(tmp, (int)sizeof(tmp), "       %-15.15s : %s\n", prov_ies[x].name, interp);
322                                         ast_copy_string(output, tmp, maxlen);
323                                         maxlen -= strlen(output); output += strlen(output);
324                                 }
325                                 found++;
326                         }
327                 }
328                 if (!found) {
329                         snprintf(tmp, (int)sizeof(tmp), "       Unknown Prov IE %03d  : Present\n", ie);
330                         ast_copy_string(output, tmp, maxlen);
331                         maxlen -= strlen(output); output += strlen(output);
332                 }
333                 iedata += (2 + ielen);
334                 len -= (2 + ielen);
335         }
336 }
337
338 static void dump_ies(unsigned char *iedata, int len)
339 {
340         int ielen;
341         int ie;
342         int x;
343         int found;
344         char interp[1024];
345         char tmp[1024];
346         if (len < 2)
347                 return;
348         while(len > 2) {
349                 ie = iedata[0];
350                 ielen = iedata[1];
351                 if (ielen + 2> len) {
352                         snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
353                         outputf(tmp);
354                         return;
355                 }
356                 found = 0;
357                 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
358                         if (ies[x].ie == ie) {
359                                 if (ies[x].dump) {
360                                         ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
361                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
362                                         outputf(tmp);
363                                 } else {
364                                         if (ielen)
365                                                 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
366                                         else
367                                                 strcpy(interp, "Present");
368                                         snprintf(tmp, (int)sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
369                                         outputf(tmp);
370                                 }
371                                 found++;
372                         }
373                 }
374                 if (!found) {
375                         snprintf(tmp, (int)sizeof(tmp), "   Unknown IE %03d  : Present\n", ie);
376                         outputf(tmp);
377                 }
378                 iedata += (2 + ielen);
379                 len -= (2 + ielen);
380         }
381         outputf("\n");
382 }
383
384 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
385 {
386         const char *frames[] = {
387                 "(0?)",
388                 "DTMF   ",
389                 "VOICE  ",
390                 "VIDEO  ",
391                 "CONTROL",
392                 "NULL   ",
393                 "IAX    ",
394                 "TEXT   ",
395                 "IMAGE  ",
396                 "HTML   ",
397                 "CNG    " };
398         const char *iaxs[] = {
399                 "(0?)",
400                 "NEW    ",
401                 "PING   ",
402                 "PONG   ",
403                 "ACK    ",
404                 "HANGUP ",
405                 "REJECT ",
406                 "ACCEPT ",
407                 "AUTHREQ",
408                 "AUTHREP",
409                 "INVAL  ",
410                 "LAGRQ  ",
411                 "LAGRP  ",
412                 "REGREQ ",
413                 "REGAUTH",
414                 "REGACK ",
415                 "REGREJ ",
416                 "REGREL ",
417                 "VNAK   ",
418                 "DPREQ  ",
419                 "DPREP  ",
420                 "DIAL   ",
421                 "TXREQ  ",
422                 "TXCNT  ",
423                 "TXACC  ",
424                 "TXREADY",
425                 "TXREL  ",
426                 "TXREJ  ",
427                 "QUELCH ",
428                 "UNQULCH",
429                 "POKE   ",
430                 "PAGE   ",
431                 "MWI    ",
432                 "UNSPRTD",
433                 "TRANSFR",
434                 "PROVISN",
435                 "FWDWNLD",
436                 "FWDATA "
437         };
438         const char *cmds[] = {
439                 "(0?)",
440                 "HANGUP ",
441                 "RING   ",
442                 "RINGING",
443                 "ANSWER ",
444                 "BUSY   ",
445                 "TKOFFHK",
446                 "OFFHOOK",
447                 "CONGSTN",
448                 "FLASH  ",
449                 "WINK   ",
450                 "OPTION ",
451                 "RDKEY  ",
452                 "RDUNKEY",
453                 "PROGRES",
454                 "PROCDNG",
455                 "HOLD   ",
456                 "UNHOLD ",
457                 "VIDUPDT", };
458         struct ast_iax2_full_hdr *fh;
459         char retries[20];
460         char class2[20];
461         char subclass2[20];
462         const char *class;
463         const char *subclass;
464         char *dir;
465         char tmp[512];
466
467         switch(rx) {
468         case 0:
469                 dir = "Tx";
470                 break;
471         case 2:
472                 dir = "TE";
473                 break;
474         case 3:
475                 dir = "RD";
476                 break;
477         default:
478                 dir = "Rx";
479                 break;
480         }
481         if (f) {
482                 fh = f->data;
483                 snprintf(retries, sizeof(retries), "%03d", f->retries);
484         } else {
485                 fh = fhi;
486                 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
487                         strcpy(retries, "Yes");
488                 else
489                         strcpy(retries, " No");
490         }
491         if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
492                 /* Don't mess with mini-frames */
493                 return;
494         }
495         if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
496                 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
497                 class = class2;
498         } else {
499                 class = frames[(int)fh->type];
500         }
501         if (fh->type == AST_FRAME_DTMF) {
502                 sprintf(subclass2, "%c", fh->csub);
503                 subclass = subclass2;
504         } else if (fh->type == AST_FRAME_IAX) {
505                 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
506                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
507                         subclass = subclass2;
508                 } else {
509                         subclass = iaxs[(int)fh->csub];
510                 }
511         } else if (fh->type == AST_FRAME_CONTROL) {
512                 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
513                         snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
514                         subclass = subclass2;
515                 } else {
516                         subclass = cmds[(int)fh->csub];
517                 }
518         } else {
519                 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
520                 subclass = subclass2;
521         }
522         snprintf(tmp, sizeof(tmp), 
523                  "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
524                  dir,
525                  retries, fh->oseqno, fh->iseqno, class, subclass);
526         outputf(tmp);
527         snprintf(tmp, sizeof(tmp), 
528                  "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
529                  (unsigned long)ntohl(fh->ts),
530                  ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
531                  ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
532         outputf(tmp);
533         if (fh->type == AST_FRAME_IAX)
534                 dump_ies(fh->iedata, datalen);
535 }
536
537 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
538 {
539         char tmp[256];
540         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
541                 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);
542                 errorf(tmp);
543                 return -1;
544         }
545         ied->buf[ied->pos++] = ie;
546         ied->buf[ied->pos++] = datalen;
547         memcpy(ied->buf + ied->pos, data, datalen);
548         ied->pos += datalen;
549         return 0;
550 }
551
552 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
553 {
554         return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
555 }
556
557 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value) 
558 {
559         unsigned int newval;
560         newval = htonl(value);
561         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
562 }
563
564 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value) 
565 {
566         unsigned short newval;
567         newval = htons(value);
568         return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
569 }
570
571 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
572 {
573         return iax_ie_append_raw(ied, ie, str, strlen(str));
574 }
575
576 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
577 {
578         return iax_ie_append_raw(ied, ie, &dat, 1);
579 }
580
581 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie) 
582 {
583         return iax_ie_append_raw(ied, ie, NULL, 0);
584 }
585
586 void iax_set_output(void (*func)(const char *))
587 {
588         outputf = func;
589 }
590
591 void iax_set_error(void (*func)(const char *))
592 {
593         errorf = func;
594 }
595
596 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
597 {
598         /* Parse data into information elements */
599         int len;
600         int ie;
601         char tmp[256];
602         memset(ies, 0, (int)sizeof(struct iax_ies));
603         ies->msgcount = -1;
604         ies->firmwarever = -1;
605         ies->calling_ton = -1;
606         ies->calling_tns = -1;
607         ies->calling_pres = -1;
608         ies->samprate = IAX_RATE_8KHZ;
609         while(datalen >= 2) {
610                 ie = data[0];
611                 len = data[1];
612                 if (len > datalen - 2) {
613                         errorf("Information element length exceeds message size\n");
614                         return -1;
615                 }
616                 switch(ie) {
617                 case IAX_IE_CALLED_NUMBER:
618                         ies->called_number = (char *)data + 2;
619                         break;
620                 case IAX_IE_CALLING_NUMBER:
621                         ies->calling_number = (char *)data + 2;
622                         break;
623                 case IAX_IE_CALLING_ANI:
624                         ies->calling_ani = (char *)data + 2;
625                         break;
626                 case IAX_IE_CALLING_NAME:
627                         ies->calling_name = (char *)data + 2;
628                         break;
629                 case IAX_IE_CALLED_CONTEXT:
630                         ies->called_context = (char *)data + 2;
631                         break;
632                 case IAX_IE_USERNAME:
633                         ies->username = (char *)data + 2;
634                         break;
635                 case IAX_IE_PASSWORD:
636                         ies->password = (char *)data + 2;
637                         break;
638                 case IAX_IE_CODEC_PREFS:
639                         ies->codec_prefs = (char *)data + 2;
640                         break;
641                 case IAX_IE_CAPABILITY:
642                         if (len != (int)sizeof(unsigned int)) {
643                                 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
644                                 errorf(tmp);
645                         } else
646                                 ies->capability = ntohl(get_unaligned_uint32(data + 2));
647                         break;
648                 case IAX_IE_FORMAT:
649                         if (len != (int)sizeof(unsigned int)) {
650                                 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
651                                 errorf(tmp);
652                         } else
653                                 ies->format = ntohl(get_unaligned_uint32(data + 2));
654                         break;
655                 case IAX_IE_LANGUAGE:
656                         ies->language = (char *)data + 2;
657                         break;
658                 case IAX_IE_VERSION:
659                         if (len != (int)sizeof(unsigned short)) {
660                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
661                                 errorf(tmp);
662                         } else
663                                 ies->version = ntohs(get_unaligned_uint16(data + 2));
664                         break;
665                 case IAX_IE_ADSICPE:
666                         if (len != (int)sizeof(unsigned short)) {
667                                 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
668                                 errorf(tmp);
669                         } else
670                                 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
671                         break;
672                 case IAX_IE_SAMPLINGRATE:
673                         if (len != (int)sizeof(unsigned short)) {
674                                 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
675                                 errorf(tmp);
676                         } else
677                                 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
678                         break;
679                 case IAX_IE_DNID:
680                         ies->dnid = (char *)data + 2;
681                         break;
682                 case IAX_IE_RDNIS:
683                         ies->rdnis = (char *)data + 2;
684                         break;
685                 case IAX_IE_AUTHMETHODS:
686                         if (len != (int)sizeof(unsigned short))  {
687                                 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
688                                 errorf(tmp);
689                         } else
690                                 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
691                         break;
692                 case IAX_IE_ENCRYPTION:
693                         if (len != (int)sizeof(unsigned short))  {
694                                 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
695                                 errorf(tmp);
696                         } else
697                                 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
698                         break;
699                 case IAX_IE_CHALLENGE:
700                         ies->challenge = (char *)data + 2;
701                         break;
702                 case IAX_IE_MD5_RESULT:
703                         ies->md5_result = (char *)data + 2;
704                         break;
705                 case IAX_IE_RSA_RESULT:
706                         ies->rsa_result = (char *)data + 2;
707                         break;
708                 case IAX_IE_APPARENT_ADDR:
709                         ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
710                         break;
711                 case IAX_IE_REFRESH:
712                         if (len != (int)sizeof(unsigned short)) {
713                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
714                                 errorf(tmp);
715                         } else
716                                 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
717                         break;
718                 case IAX_IE_DPSTATUS:
719                         if (len != (int)sizeof(unsigned short)) {
720                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
721                                 errorf(tmp);
722                         } else
723                                 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
724                         break;
725                 case IAX_IE_CALLNO:
726                         if (len != (int)sizeof(unsigned short)) {
727                                 snprintf(tmp, (int)sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
728                                 errorf(tmp);
729                         } else
730                                 ies->callno = ntohs(get_unaligned_uint16(data + 2));
731                         break;
732                 case IAX_IE_CAUSE:
733                         ies->cause = (char *)data + 2;
734                         break;
735                 case IAX_IE_CAUSECODE:
736                         if (len != 1) {
737                                 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
738                                 errorf(tmp);
739                         } else {
740                                 ies->causecode = data[2];
741                         }
742                         break;
743                 case IAX_IE_IAX_UNKNOWN:
744                         if (len == 1)
745                                 ies->iax_unknown = data[2];
746                         else {
747                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
748                                 errorf(tmp);
749                         }
750                         break;
751                 case IAX_IE_MSGCOUNT:
752                         if (len != (int)sizeof(unsigned short)) {
753                                 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
754                                 errorf(tmp);
755                         } else
756                                 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));  
757                         break;
758                 case IAX_IE_AUTOANSWER:
759                         ies->autoanswer = 1;
760                         break;
761                 case IAX_IE_MUSICONHOLD:
762                         ies->musiconhold = 1;
763                         break;
764                 case IAX_IE_TRANSFERID:
765                         if (len != (int)sizeof(unsigned int)) {
766                                 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
767                                 errorf(tmp);
768                         } else
769                                 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
770                         break;
771                 case IAX_IE_DATETIME:
772                         if (len != (int)sizeof(unsigned int)) {
773                                 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
774                                 errorf(tmp);
775                         } else
776                                 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
777                         break;
778                 case IAX_IE_FIRMWAREVER:
779                         if (len != (int)sizeof(unsigned short)) {
780                                 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
781                                 errorf(tmp);
782                         } else
783                                 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));       
784                         break;
785                 case IAX_IE_DEVICETYPE:
786                         ies->devicetype = (char *)data + 2;
787                         break;
788                 case IAX_IE_SERVICEIDENT:
789                         ies->serviceident = (char *)data + 2;
790                         break;
791                 case IAX_IE_FWBLOCKDESC:
792                         if (len != (int)sizeof(unsigned int)) {
793                                 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
794                                 errorf(tmp);
795                         } else
796                                 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
797                         break;
798                 case IAX_IE_FWBLOCKDATA:
799                         ies->fwdata = data + 2;
800                         ies->fwdatalen = len;
801                         break;
802                 case IAX_IE_ENCKEY:
803                         ies->enckey = data + 2;
804                         ies->enckeylen = len;
805                         break;
806                 case IAX_IE_PROVVER:
807                         if (len != (int)sizeof(unsigned int)) {
808                                 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
809                                 errorf(tmp);
810                         } else {
811                                 ies->provverpres = 1;
812                                 ies->provver = ntohl(get_unaligned_uint32(data + 2));
813                         }
814                         break;
815                 case IAX_IE_CALLINGPRES:
816                         if (len == 1)
817                                 ies->calling_pres = data[2];
818                         else {
819                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
820                                 errorf(tmp);
821                         }
822                         break;
823                 case IAX_IE_CALLINGTON:
824                         if (len == 1)
825                                 ies->calling_ton = data[2];
826                         else {
827                                 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
828                                 errorf(tmp);
829                         }
830                         break;
831                 case IAX_IE_CALLINGTNS:
832                         if (len != (int)sizeof(unsigned short)) {
833                                 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
834                                 errorf(tmp);
835                         } else
836                                 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));       
837                         break;
838                case IAX_IE_RR_JITTER:
839                        if (len != (int)sizeof(unsigned int)) {
840                                snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
841                                errorf(tmp);
842                        } else {
843                                ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
844                        }
845                        break;
846                case IAX_IE_RR_LOSS:
847                        if (len != (int)sizeof(unsigned int)) {
848                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
849                                errorf(tmp);
850                        } else {
851                                ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
852                        }
853                        break;
854                case IAX_IE_RR_PKTS:
855                        if (len != (int)sizeof(unsigned int)) {
856                                snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
857                                errorf(tmp);
858                        } else {
859                                ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
860                        }
861                        break;
862                case IAX_IE_RR_DELAY:
863                        if (len != (int)sizeof(unsigned short)) {
864                                snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
865                         errorf(tmp);
866                        } else {
867                                ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
868                        }
869                        break;
870                 case IAX_IE_RR_DROPPED:
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);
873                                 errorf(tmp);
874                         } else {
875                                 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
876                         }
877                         break;
878                 case IAX_IE_RR_OOO:
879                         if (len != (int)sizeof(unsigned int)) {
880                                 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
881                                 errorf(tmp);
882                         } else {
883                                 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
884                         }
885                         break;
886                 default:
887                         snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
888                         outputf(tmp);
889                 }
890                 /* Overwrite information element with 0, to null terminate previous portion */
891                 data[0] = 0;
892                 datalen -= (len + 2);
893                 data += (len + 2);
894         }
895         /* Null-terminate last field */
896         *data = '\0';
897         if (datalen) {
898                 errorf("Invalid information element contents, strange boundary\n");
899                 return -1;
900         }
901         return 0;
902 }
903
904 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
905 {
906         fr->af.frametype = f->frametype;
907         fr->af.subclass = f->subclass;
908         fr->af.mallocd = 0;                             /* Our frame is static relative to the container */
909         fr->af.datalen = f->datalen;
910         fr->af.samples = f->samples;
911         fr->af.offset = AST_FRIENDLY_OFFSET;
912         fr->af.src = f->src;
913         fr->af.delivery.tv_sec = 0;
914         fr->af.delivery.tv_usec = 0;
915         fr->af.data = fr->afdata;
916         if (fr->af.datalen) {
917 #if __BYTE_ORDER == __LITTLE_ENDIAN
918                 /* We need to byte-swap slinear samples from network byte order */
919                 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
920                         ast_swapcopy_samples(fr->af.data, f->data, fr->af.samples);
921                 } else
922 #endif
923                 memcpy(fr->af.data, f->data, fr->af.datalen);
924         }
925 }
926
927 struct iax_frame *iax_frame_new(int direction, int datalen)
928 {
929         struct iax_frame *fr;
930         fr = malloc((int)sizeof(struct iax_frame) + datalen);
931         if (fr) {
932                 fr->direction = direction;
933                 fr->retrans = -1;
934                 ast_atomic_fetchadd_int(&frames, 1);
935                 if (fr->direction == DIRECTION_INGRESS)
936                         ast_atomic_fetchadd_int(&iframes, 1);
937                 else
938                         ast_atomic_fetchadd_int(&oframes, 1);
939         }
940         return fr;
941 }
942
943 void iax_frame_free(struct iax_frame *fr)
944 {
945         /* Note: does not remove from scheduler! */
946         if (fr->direction == DIRECTION_INGRESS)
947                 ast_atomic_fetchadd_int(&iframes, -1);
948         else if (fr->direction == DIRECTION_OUTGRESS)
949                 ast_atomic_fetchadd_int(&oframes, -1);
950         else {
951                 errorf("Attempt to double free frame detected\n");
952                 return;
953         }
954         fr->direction = 0;
955         free(fr);
956         ast_atomic_fetchadd_int(&frames, -1);
957 }
958
959 int iax_get_frames(void) { return frames; }
960 int iax_get_iframes(void) { return iframes; }
961 int iax_get_oframes(void) { return oframes; }