00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00029
00030 #include <sys/types.h>
00031 #include <sys/socket.h>
00032 #include <string.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 #include <unistd.h>
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038
00039 #include "asterisk/frame.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/unaligned.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/lock.h"
00044 #include "asterisk/threadstorage.h"
00045
00046 #include "iax2.h"
00047 #include "iax2-parser.h"
00048 #include "iax2-provision.h"
00049
00050 static int frames = 0;
00051 static int iframes = 0;
00052 static int oframes = 0;
00053
00054 #if !defined(LOW_MEMORY)
00055 static void frame_cache_cleanup(void *data);
00056
00057
00058 AST_THREADSTORAGE_CUSTOM(frame_cache, frame_cache_init, frame_cache_cleanup);
00059
00060
00061
00062 AST_LIST_HEAD_NOLOCK(iax_frames, iax_frame);
00063 #endif
00064
00065 static void internaloutput(const char *str)
00066 {
00067 fputs(str, stdout);
00068 }
00069
00070 static void internalerror(const char *str)
00071 {
00072 fprintf(stderr, "WARNING: %s", str);
00073 }
00074
00075 static void (*outputf)(const char *str) = internaloutput;
00076 static void (*errorf)(const char *str) = internalerror;
00077
00078 static void dump_addr(char *output, int maxlen, void *value, int len)
00079 {
00080 struct sockaddr_in sin;
00081 if (len == (int)sizeof(sin)) {
00082 memcpy(&sin, value, len);
00083 snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
00084 } else {
00085 snprintf(output, maxlen, "Invalid Address");
00086 }
00087 }
00088
00089 static void dump_string(char *output, int maxlen, void *value, int len)
00090 {
00091 maxlen--;
00092 if (maxlen > len)
00093 maxlen = len;
00094 strncpy(output, value, maxlen);
00095 output[maxlen] = '\0';
00096 }
00097
00098 static void dump_prefs(char *output, int maxlen, void *value, int len)
00099 {
00100 struct ast_codec_pref pref;
00101 int total_len = 0;
00102
00103 maxlen--;
00104 total_len = maxlen;
00105
00106 if (maxlen > len)
00107 maxlen = len;
00108
00109 strncpy(output, value, maxlen);
00110 output[maxlen] = '\0';
00111
00112 ast_codec_pref_convert(&pref, output, total_len, 0);
00113 memset(output,0,total_len);
00114 ast_codec_pref_string(&pref, output, total_len);
00115 }
00116
00117 static void dump_int(char *output, int maxlen, void *value, int len)
00118 {
00119 if (len == (int)sizeof(unsigned int))
00120 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
00121 else
00122 ast_copy_string(output, "Invalid INT", maxlen);
00123 }
00124
00125 static void dump_short(char *output, int maxlen, void *value, int len)
00126 {
00127 if (len == (int)sizeof(unsigned short))
00128 snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
00129 else
00130 ast_copy_string(output, "Invalid SHORT", maxlen);
00131 }
00132
00133 static void dump_byte(char *output, int maxlen, void *value, int len)
00134 {
00135 if (len == (int)sizeof(unsigned char))
00136 snprintf(output, maxlen, "%d", *((unsigned char *)value));
00137 else
00138 ast_copy_string(output, "Invalid BYTE", maxlen);
00139 }
00140
00141 static void dump_datetime(char *output, int maxlen, void *value, int len)
00142 {
00143 struct tm tm;
00144 unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
00145 if (len == (int)sizeof(unsigned int)) {
00146 tm.tm_sec = (val & 0x1f) << 1;
00147 tm.tm_min = (val >> 5) & 0x3f;
00148 tm.tm_hour = (val >> 11) & 0x1f;
00149 tm.tm_mday = (val >> 16) & 0x1f;
00150 tm.tm_mon = ((val >> 21) & 0x0f) - 1;
00151 tm.tm_year = ((val >> 25) & 0x7f) + 100;
00152 strftime(output, maxlen, "%Y-%m-%d %T", &tm);
00153 } else
00154 ast_copy_string(output, "Invalid DATETIME format!", maxlen);
00155 }
00156
00157 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
00158 {
00159 struct sockaddr_in sin;
00160 if (len == (int)sizeof(unsigned int)) {
00161 memcpy(&sin.sin_addr, value, len);
00162 snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
00163 } else
00164 ast_copy_string(output, "Invalid IPADDR", maxlen);
00165 }
00166
00167
00168 static void dump_prov_flags(char *output, int maxlen, void *value, int len)
00169 {
00170 char buf[256] = "";
00171 if (len == (int)sizeof(unsigned int))
00172 snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
00173 iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
00174 else
00175 ast_copy_string(output, "Invalid INT", maxlen);
00176 }
00177
00178 static void dump_samprate(char *output, int maxlen, void *value, int len)
00179 {
00180 char tmp[256]="";
00181 int sr;
00182 if (len == (int)sizeof(unsigned short)) {
00183 sr = ntohs(*((unsigned short *)value));
00184 if (sr & IAX_RATE_8KHZ)
00185 strcat(tmp, ",8khz");
00186 if (sr & IAX_RATE_11KHZ)
00187 strcat(tmp, ",11.025khz");
00188 if (sr & IAX_RATE_16KHZ)
00189 strcat(tmp, ",16khz");
00190 if (sr & IAX_RATE_22KHZ)
00191 strcat(tmp, ",22.05khz");
00192 if (sr & IAX_RATE_44KHZ)
00193 strcat(tmp, ",44.1khz");
00194 if (sr & IAX_RATE_48KHZ)
00195 strcat(tmp, ",48khz");
00196 if (strlen(tmp))
00197 ast_copy_string(output, &tmp[1], maxlen);
00198 else
00199 ast_copy_string(output, "None Specified!\n", maxlen);
00200 } else
00201 ast_copy_string(output, "Invalid SHORT", maxlen);
00202
00203 }
00204
00205 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
00206 static void dump_prov(char *output, int maxlen, void *value, int len)
00207 {
00208 dump_prov_ies(output, maxlen, value, len);
00209 }
00210
00211 static struct iax2_ie {
00212 int ie;
00213 char *name;
00214 void (*dump)(char *output, int maxlen, void *value, int len);
00215 } ies[] = {
00216 { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
00217 { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
00218 { IAX_IE_CALLING_ANI, "ANI", dump_string },
00219 { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
00220 { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
00221 { IAX_IE_USERNAME, "USERNAME", dump_string },
00222 { IAX_IE_PASSWORD, "PASSWORD", dump_string },
00223 { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
00224 { IAX_IE_FORMAT, "FORMAT", dump_int },
00225 { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
00226 { IAX_IE_VERSION, "VERSION", dump_short },
00227 { IAX_IE_ADSICPE, "ADSICPE", dump_short },
00228 { IAX_IE_DNID, "DNID", dump_string },
00229 { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
00230 { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
00231 { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
00232 { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
00233 { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
00234 { IAX_IE_REFRESH, "REFRESH", dump_short },
00235 { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
00236 { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
00237 { IAX_IE_CAUSE, "CAUSE", dump_string },
00238 { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
00239 { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
00240 { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
00241 { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
00242 { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
00243 { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
00244 { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
00245 { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
00246 { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
00247 { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
00248 { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
00249 { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
00250 { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
00251 { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
00252 { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
00253 { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
00254 { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
00255 { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
00256 { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
00257 { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
00258 { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
00259 { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
00260 { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
00261 { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
00262 { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
00263 { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
00264 { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
00265 { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
00266 { IAX_IE_VARIABLE, "VARIABLE", dump_string },
00267 };
00268
00269 static struct iax2_ie prov_ies[] = {
00270 { PROV_IE_USEDHCP, "USEDHCP" },
00271 { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
00272 { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
00273 { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
00274 { PROV_IE_PORTNO, "BINDPORT", dump_short },
00275 { PROV_IE_USER, "USERNAME", dump_string },
00276 { PROV_IE_PASS, "PASSWORD", dump_string },
00277 { PROV_IE_LANG, "LANGUAGE", dump_string },
00278 { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
00279 { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
00280 { PROV_IE_FORMAT, "FORMAT", dump_int },
00281 { PROV_IE_AESKEY, "AESKEY" },
00282 { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
00283 { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
00284 { PROV_IE_NEWAESKEY, "NEWAESKEY" },
00285 { PROV_IE_PROVVER, "PROV VERSION", dump_int },
00286 { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
00287 };
00288
00289 const char *iax_ie2str(int ie)
00290 {
00291 int x;
00292 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00293 if (ies[x].ie == ie)
00294 return ies[x].name;
00295 }
00296 return "Unknown IE";
00297 }
00298
00299
00300 static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
00301 {
00302 int ielen;
00303 int ie;
00304 int x;
00305 int found;
00306 char interp[80];
00307 char tmp[256];
00308 if (len < 2)
00309 return;
00310 strcpy(output, "\n");
00311 maxlen -= strlen(output); output += strlen(output);
00312 while(len > 2) {
00313 ie = iedata[0];
00314 ielen = iedata[1];
00315 if (ielen + 2> len) {
00316 snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
00317 ast_copy_string(output, tmp, maxlen);
00318 maxlen -= strlen(output);
00319 output += strlen(output);
00320 return;
00321 }
00322 found = 0;
00323 for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
00324 if (prov_ies[x].ie == ie) {
00325 if (prov_ies[x].dump) {
00326 prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00327 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
00328 ast_copy_string(output, tmp, maxlen);
00329 maxlen -= strlen(output); output += strlen(output);
00330 } else {
00331 if (ielen)
00332 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00333 else
00334 strcpy(interp, "Present");
00335 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
00336 ast_copy_string(output, tmp, maxlen);
00337 maxlen -= strlen(output); output += strlen(output);
00338 }
00339 found++;
00340 }
00341 }
00342 if (!found) {
00343 snprintf(tmp, (int)sizeof(tmp), " Unknown Prov IE %03d : Present\n", ie);
00344 ast_copy_string(output, tmp, maxlen);
00345 maxlen -= strlen(output); output += strlen(output);
00346 }
00347 iedata += (2 + ielen);
00348 len -= (2 + ielen);
00349 }
00350 }
00351
00352 static void dump_ies(unsigned char *iedata, int len)
00353 {
00354 int ielen;
00355 int ie;
00356 int x;
00357 int found;
00358 char interp[1024];
00359 char tmp[1024];
00360 if (len < 2)
00361 return;
00362 while(len > 2) {
00363 ie = iedata[0];
00364 ielen = iedata[1];
00365 if (ielen + 2> len) {
00366 snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
00367 outputf(tmp);
00368 return;
00369 }
00370 found = 0;
00371 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00372 if (ies[x].ie == ie) {
00373 if (ies[x].dump) {
00374 ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00375 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
00376 outputf(tmp);
00377 } else {
00378 if (ielen)
00379 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00380 else
00381 strcpy(interp, "Present");
00382 snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
00383 outputf(tmp);
00384 }
00385 found++;
00386 }
00387 }
00388 if (!found) {
00389 snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
00390 outputf(tmp);
00391 }
00392 iedata += (2 + ielen);
00393 len -= (2 + ielen);
00394 }
00395 outputf("\n");
00396 }
00397
00398 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00399 {
00400 const char *frames[] = {
00401 "(0?)",
00402 "DTMF_E ",
00403 "VOICE ",
00404 "VIDEO ",
00405 "CONTROL",
00406 "NULL ",
00407 "IAX ",
00408 "TEXT ",
00409 "IMAGE ",
00410 "HTML ",
00411 "CNG ",
00412 "MODEM ",
00413 "DTMF_B ",
00414 };
00415 const char *iaxs[] = {
00416 "(0?)",
00417 "NEW ",
00418 "PING ",
00419 "PONG ",
00420 "ACK ",
00421 "HANGUP ",
00422 "REJECT ",
00423 "ACCEPT ",
00424 "AUTHREQ",
00425 "AUTHREP",
00426 "INVAL ",
00427 "LAGRQ ",
00428 "LAGRP ",
00429 "REGREQ ",
00430 "REGAUTH",
00431 "REGACK ",
00432 "REGREJ ",
00433 "REGREL ",
00434 "VNAK ",
00435 "DPREQ ",
00436 "DPREP ",
00437 "DIAL ",
00438 "TXREQ ",
00439 "TXCNT ",
00440 "TXACC ",
00441 "TXREADY",
00442 "TXREL ",
00443 "TXREJ ",
00444 "QUELCH ",
00445 "UNQULCH",
00446 "POKE ",
00447 "PAGE ",
00448 "MWI ",
00449 "UNSPRTD",
00450 "TRANSFR",
00451 "PROVISN",
00452 "FWDWNLD",
00453 "FWDATA "
00454 };
00455 const char *cmds[] = {
00456 "(0?)",
00457 "HANGUP ",
00458 "RING ",
00459 "RINGING",
00460 "ANSWER ",
00461 "BUSY ",
00462 "TKOFFHK",
00463 "OFFHOOK",
00464 "CONGSTN",
00465 "FLASH ",
00466 "WINK ",
00467 "OPTION ",
00468 "RDKEY ",
00469 "RDUNKEY",
00470 "PROGRES",
00471 "PROCDNG",
00472 "HOLD ",
00473 "UNHOLD ",
00474 "VIDUPDT", };
00475 struct ast_iax2_full_hdr *fh;
00476 char retries[20];
00477 char class2[20];
00478 char subclass2[20];
00479 const char *class;
00480 const char *subclass;
00481 char *dir;
00482 char tmp[512];
00483
00484 switch(rx) {
00485 case 0:
00486 dir = "Tx";
00487 break;
00488 case 2:
00489 dir = "TE";
00490 break;
00491 case 3:
00492 dir = "RD";
00493 break;
00494 default:
00495 dir = "Rx";
00496 break;
00497 }
00498 if (f) {
00499 fh = f->data;
00500 snprintf(retries, sizeof(retries), "%03d", f->retries);
00501 } else {
00502 fh = fhi;
00503 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
00504 strcpy(retries, "Yes");
00505 else
00506 strcpy(retries, " No");
00507 }
00508 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
00509
00510 return;
00511 }
00512 if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
00513 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
00514 class = class2;
00515 } else {
00516 class = frames[(int)fh->type];
00517 }
00518 if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
00519 sprintf(subclass2, "%c", fh->csub);
00520 subclass = subclass2;
00521 } else if (fh->type == AST_FRAME_IAX) {
00522 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
00523 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00524 subclass = subclass2;
00525 } else {
00526 subclass = iaxs[(int)fh->csub];
00527 }
00528 } else if (fh->type == AST_FRAME_CONTROL) {
00529 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
00530 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00531 subclass = subclass2;
00532 } else {
00533 subclass = cmds[(int)fh->csub];
00534 }
00535 } else {
00536 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
00537 subclass = subclass2;
00538 }
00539 snprintf(tmp, sizeof(tmp),
00540 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
00541 dir,
00542 retries, fh->oseqno, fh->iseqno, class, subclass);
00543 outputf(tmp);
00544 snprintf(tmp, sizeof(tmp),
00545 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
00546 (unsigned long)ntohl(fh->ts),
00547 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
00548 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
00549 outputf(tmp);
00550 if (fh->type == AST_FRAME_IAX)
00551 dump_ies(fh->iedata, datalen);
00552 }
00553
00554 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
00555 {
00556 char tmp[256];
00557 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00558 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);
00559 errorf(tmp);
00560 return -1;
00561 }
00562 ied->buf[ied->pos++] = ie;
00563 ied->buf[ied->pos++] = datalen;
00564 memcpy(ied->buf + ied->pos, data, datalen);
00565 ied->pos += datalen;
00566 return 0;
00567 }
00568
00569 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
00570 {
00571 return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00572 }
00573
00574 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
00575 {
00576 unsigned int newval;
00577 newval = htonl(value);
00578 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00579 }
00580
00581 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
00582 {
00583 unsigned short newval;
00584 newval = htons(value);
00585 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00586 }
00587
00588 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
00589 {
00590 return iax_ie_append_raw(ied, ie, str, strlen(str));
00591 }
00592
00593 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
00594 {
00595 return iax_ie_append_raw(ied, ie, &dat, 1);
00596 }
00597
00598 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
00599 {
00600 return iax_ie_append_raw(ied, ie, NULL, 0);
00601 }
00602
00603 void iax_set_output(void (*func)(const char *))
00604 {
00605 outputf = func;
00606 }
00607
00608 void iax_set_error(void (*func)(const char *))
00609 {
00610 errorf = func;
00611 }
00612
00613 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
00614 {
00615
00616 int len;
00617 int ie;
00618 char tmp[256], *tmp2;
00619 struct ast_variable *var;
00620 memset(ies, 0, (int)sizeof(struct iax_ies));
00621 ies->msgcount = -1;
00622 ies->firmwarever = -1;
00623 ies->calling_ton = -1;
00624 ies->calling_tns = -1;
00625 ies->calling_pres = -1;
00626 ies->samprate = IAX_RATE_8KHZ;
00627 while(datalen >= 2) {
00628 ie = data[0];
00629 len = data[1];
00630 if (len > datalen - 2) {
00631 errorf("Information element length exceeds message size\n");
00632 return -1;
00633 }
00634 switch(ie) {
00635 case IAX_IE_CALLED_NUMBER:
00636 ies->called_number = (char *)data + 2;
00637 break;
00638 case IAX_IE_CALLING_NUMBER:
00639 ies->calling_number = (char *)data + 2;
00640 break;
00641 case IAX_IE_CALLING_ANI:
00642 ies->calling_ani = (char *)data + 2;
00643 break;
00644 case IAX_IE_CALLING_NAME:
00645 ies->calling_name = (char *)data + 2;
00646 break;
00647 case IAX_IE_CALLED_CONTEXT:
00648 ies->called_context = (char *)data + 2;
00649 break;
00650 case IAX_IE_USERNAME:
00651 ies->username = (char *)data + 2;
00652 break;
00653 case IAX_IE_PASSWORD:
00654 ies->password = (char *)data + 2;
00655 break;
00656 case IAX_IE_CODEC_PREFS:
00657 ies->codec_prefs = (char *)data + 2;
00658 break;
00659 case IAX_IE_CAPABILITY:
00660 if (len != (int)sizeof(unsigned int)) {
00661 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00662 errorf(tmp);
00663 } else
00664 ies->capability = ntohl(get_unaligned_uint32(data + 2));
00665 break;
00666 case IAX_IE_FORMAT:
00667 if (len != (int)sizeof(unsigned int)) {
00668 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00669 errorf(tmp);
00670 } else
00671 ies->format = ntohl(get_unaligned_uint32(data + 2));
00672 break;
00673 case IAX_IE_LANGUAGE:
00674 ies->language = (char *)data + 2;
00675 break;
00676 case IAX_IE_VERSION:
00677 if (len != (int)sizeof(unsigned short)) {
00678 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00679 errorf(tmp);
00680 } else
00681 ies->version = ntohs(get_unaligned_uint16(data + 2));
00682 break;
00683 case IAX_IE_ADSICPE:
00684 if (len != (int)sizeof(unsigned short)) {
00685 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00686 errorf(tmp);
00687 } else
00688 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
00689 break;
00690 case IAX_IE_SAMPLINGRATE:
00691 if (len != (int)sizeof(unsigned short)) {
00692 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00693 errorf(tmp);
00694 } else
00695 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
00696 break;
00697 case IAX_IE_DNID:
00698 ies->dnid = (char *)data + 2;
00699 break;
00700 case IAX_IE_RDNIS:
00701 ies->rdnis = (char *)data + 2;
00702 break;
00703 case IAX_IE_AUTHMETHODS:
00704 if (len != (int)sizeof(unsigned short)) {
00705 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00706 errorf(tmp);
00707 } else
00708 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
00709 break;
00710 case IAX_IE_ENCRYPTION:
00711 if (len != (int)sizeof(unsigned short)) {
00712 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00713 errorf(tmp);
00714 } else
00715 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
00716 break;
00717 case IAX_IE_CHALLENGE:
00718 ies->challenge = (char *)data + 2;
00719 break;
00720 case IAX_IE_MD5_RESULT:
00721 ies->md5_result = (char *)data + 2;
00722 break;
00723 case IAX_IE_RSA_RESULT:
00724 ies->rsa_result = (char *)data + 2;
00725 break;
00726 case IAX_IE_APPARENT_ADDR:
00727 ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
00728 break;
00729 case IAX_IE_REFRESH:
00730 if (len != (int)sizeof(unsigned short)) {
00731 snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00732 errorf(tmp);
00733 } else
00734 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
00735 break;
00736 case IAX_IE_DPSTATUS:
00737 if (len != (int)sizeof(unsigned short)) {
00738 snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00739 errorf(tmp);
00740 } else
00741 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
00742 break;
00743 case IAX_IE_CALLNO:
00744 if (len != (int)sizeof(unsigned short)) {
00745 snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00746 errorf(tmp);
00747 } else
00748 ies->callno = ntohs(get_unaligned_uint16(data + 2));
00749 break;
00750 case IAX_IE_CAUSE:
00751 ies->cause = (char *)data + 2;
00752 break;
00753 case IAX_IE_CAUSECODE:
00754 if (len != 1) {
00755 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
00756 errorf(tmp);
00757 } else {
00758 ies->causecode = data[2];
00759 }
00760 break;
00761 case IAX_IE_IAX_UNKNOWN:
00762 if (len == 1)
00763 ies->iax_unknown = data[2];
00764 else {
00765 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00766 errorf(tmp);
00767 }
00768 break;
00769 case IAX_IE_MSGCOUNT:
00770 if (len != (int)sizeof(unsigned short)) {
00771 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00772 errorf(tmp);
00773 } else
00774 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));
00775 break;
00776 case IAX_IE_AUTOANSWER:
00777 ies->autoanswer = 1;
00778 break;
00779 case IAX_IE_MUSICONHOLD:
00780 ies->musiconhold = 1;
00781 break;
00782 case IAX_IE_TRANSFERID:
00783 if (len != (int)sizeof(unsigned int)) {
00784 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00785 errorf(tmp);
00786 } else
00787 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
00788 break;
00789 case IAX_IE_DATETIME:
00790 if (len != (int)sizeof(unsigned int)) {
00791 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00792 errorf(tmp);
00793 } else
00794 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
00795 break;
00796 case IAX_IE_FIRMWAREVER:
00797 if (len != (int)sizeof(unsigned short)) {
00798 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00799 errorf(tmp);
00800 } else
00801 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));
00802 break;
00803 case IAX_IE_DEVICETYPE:
00804 ies->devicetype = (char *)data + 2;
00805 break;
00806 case IAX_IE_SERVICEIDENT:
00807 ies->serviceident = (char *)data + 2;
00808 break;
00809 case IAX_IE_FWBLOCKDESC:
00810 if (len != (int)sizeof(unsigned int)) {
00811 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00812 errorf(tmp);
00813 } else
00814 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
00815 break;
00816 case IAX_IE_FWBLOCKDATA:
00817 ies->fwdata = data + 2;
00818 ies->fwdatalen = len;
00819 break;
00820 case IAX_IE_ENCKEY:
00821 ies->enckey = data + 2;
00822 ies->enckeylen = len;
00823 break;
00824 case IAX_IE_PROVVER:
00825 if (len != (int)sizeof(unsigned int)) {
00826 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00827 errorf(tmp);
00828 } else {
00829 ies->provverpres = 1;
00830 ies->provver = ntohl(get_unaligned_uint32(data + 2));
00831 }
00832 break;
00833 case IAX_IE_CALLINGPRES:
00834 if (len == 1)
00835 ies->calling_pres = data[2];
00836 else {
00837 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
00838 errorf(tmp);
00839 }
00840 break;
00841 case IAX_IE_CALLINGTON:
00842 if (len == 1)
00843 ies->calling_ton = data[2];
00844 else {
00845 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
00846 errorf(tmp);
00847 }
00848 break;
00849 case IAX_IE_CALLINGTNS:
00850 if (len != (int)sizeof(unsigned short)) {
00851 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00852 errorf(tmp);
00853 } else
00854 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));
00855 break;
00856 case IAX_IE_RR_JITTER:
00857 if (len != (int)sizeof(unsigned int)) {
00858 snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00859 errorf(tmp);
00860 } else {
00861 ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
00862 }
00863 break;
00864 case IAX_IE_RR_LOSS:
00865 if (len != (int)sizeof(unsigned int)) {
00866 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00867 errorf(tmp);
00868 } else {
00869 ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
00870 }
00871 break;
00872 case IAX_IE_RR_PKTS:
00873 if (len != (int)sizeof(unsigned int)) {
00874 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00875 errorf(tmp);
00876 } else {
00877 ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
00878 }
00879 break;
00880 case IAX_IE_RR_DELAY:
00881 if (len != (int)sizeof(unsigned short)) {
00882 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00883 errorf(tmp);
00884 } else {
00885 ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
00886 }
00887 break;
00888 case IAX_IE_RR_DROPPED:
00889 if (len != (int)sizeof(unsigned int)) {
00890 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00891 errorf(tmp);
00892 } else {
00893 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
00894 }
00895 break;
00896 case IAX_IE_RR_OOO:
00897 if (len != (int)sizeof(unsigned int)) {
00898 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00899 errorf(tmp);
00900 } else {
00901 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
00902 }
00903 break;
00904 case IAX_IE_VARIABLE:
00905 ast_copy_string(tmp, (char *)data + 2, len + 1);
00906 tmp2 = strchr(tmp, '=');
00907 if (tmp2)
00908 *tmp2++ = '\0';
00909 else
00910 tmp2 = "";
00911 var = ast_variable_new(tmp, tmp2);
00912 var->next = ies->vars;
00913 ies->vars = var;
00914 break;
00915 default:
00916 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
00917 outputf(tmp);
00918 }
00919
00920 data[0] = 0;
00921 datalen -= (len + 2);
00922 data += (len + 2);
00923 }
00924
00925 *data = '\0';
00926 if (datalen) {
00927 errorf("Invalid information element contents, strange boundary\n");
00928 return -1;
00929 }
00930 return 0;
00931 }
00932
00933 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
00934 {
00935 fr->af.frametype = f->frametype;
00936 fr->af.subclass = f->subclass;
00937 fr->af.mallocd = 0;
00938 fr->af.datalen = f->datalen;
00939 fr->af.samples = f->samples;
00940 fr->af.offset = AST_FRIENDLY_OFFSET;
00941 fr->af.src = f->src;
00942 fr->af.delivery.tv_sec = 0;
00943 fr->af.delivery.tv_usec = 0;
00944 fr->af.data = fr->afdata;
00945 fr->af.len = f->len;
00946 if (fr->af.datalen) {
00947 #if __BYTE_ORDER == __LITTLE_ENDIAN
00948
00949 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
00950 ast_swapcopy_samples(fr->af.data, f->data, fr->af.samples);
00951 } else
00952 #endif
00953 memcpy(fr->af.data, f->data, fr->af.datalen);
00954 }
00955 }
00956
00957 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
00958 {
00959 struct iax_frame *fr = NULL;
00960
00961 #if !defined(LOW_MEMORY)
00962 struct iax_frames *iax_frames;
00963
00964
00965 if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
00966 AST_LIST_TRAVERSE_SAFE_BEGIN(iax_frames, fr, list) {
00967 if (fr->mallocd_datalen >= datalen) {
00968 size_t mallocd_datalen = fr->mallocd_datalen;
00969 AST_LIST_REMOVE_CURRENT(iax_frames, list);
00970 memset(fr, 0, sizeof(*fr));
00971 fr->mallocd_datalen = mallocd_datalen;
00972 break;
00973 }
00974 }
00975 AST_LIST_TRAVERSE_SAFE_END
00976 }
00977 if (!fr) {
00978 if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
00979 return NULL;
00980 fr->mallocd_datalen = datalen;
00981 }
00982 #else
00983 if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
00984 return NULL;
00985 fr->mallocd_datalen = datalen;
00986 #endif
00987
00988
00989 fr->direction = direction;
00990 fr->retrans = -1;
00991 fr->cacheable = cacheable;
00992
00993 if (fr->direction == DIRECTION_INGRESS)
00994 ast_atomic_fetchadd_int(&iframes, 1);
00995 else
00996 ast_atomic_fetchadd_int(&oframes, 1);
00997
00998 ast_atomic_fetchadd_int(&frames, 1);
00999
01000 return fr;
01001 }
01002
01003 void iax_frame_free(struct iax_frame *fr)
01004 {
01005 #if !defined(LOW_MEMORY)
01006 struct iax_frames *iax_frames;
01007 #endif
01008
01009
01010 if (fr->direction == DIRECTION_INGRESS)
01011 ast_atomic_fetchadd_int(&iframes, -1);
01012 else if (fr->direction == DIRECTION_OUTGRESS)
01013 ast_atomic_fetchadd_int(&oframes, -1);
01014 else {
01015 errorf("Attempt to double free frame detected\n");
01016 return;
01017 }
01018 ast_atomic_fetchadd_int(&frames, -1);
01019
01020 #if !defined(LOW_MEMORY)
01021 if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01022 free(fr);
01023 return;
01024 }
01025
01026 fr->direction = 0;
01027 AST_LIST_INSERT_HEAD(iax_frames, fr, list);
01028 #else
01029 free(fr);
01030 #endif
01031 }
01032
01033 #if !defined(LOW_MEMORY)
01034 static void frame_cache_cleanup(void *data)
01035 {
01036 struct iax_frames *frames = data;
01037 struct iax_frame *cur;
01038
01039 while ((cur = AST_LIST_REMOVE_HEAD(frames, list)))
01040 free(cur);
01041
01042 free(frames);
01043 }
01044 #endif
01045
01046 int iax_get_frames(void) { return frames; }
01047 int iax_get_iframes(void) { return iframes; }
01048 int iax_get_oframes(void) { return oframes; }