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