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