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