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