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