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: 194685 $")
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 };
00447 if ((copylen > len) || !subclass || (subclass < 0)) {
00448 str[0] = '\0';
00449 } else if (subclass < ARRAY_LEN(iaxs)) {
00450 ast_copy_string(str, iaxs[subclass], len);
00451 } else {
00452 ast_copy_string(str, "Unknown", len);
00453 }
00454 }
00455
00456 void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00457 {
00458 const char *frames[] = {
00459 "(0?)",
00460 "DTMF_E ",
00461 "VOICE ",
00462 "VIDEO ",
00463 "CONTROL",
00464 "NULL ",
00465 "IAX ",
00466 "TEXT ",
00467 "IMAGE ",
00468 "HTML ",
00469 "CNG ",
00470 "MODEM ",
00471 "DTMF_B ",
00472 };
00473 const char *iaxs[] = {
00474 "(0?)",
00475 "NEW ",
00476 "PING ",
00477 "PONG ",
00478 "ACK ",
00479 "HANGUP ",
00480 "REJECT ",
00481 "ACCEPT ",
00482 "AUTHREQ",
00483 "AUTHREP",
00484 "INVAL ",
00485 "LAGRQ ",
00486 "LAGRP ",
00487 "REGREQ ",
00488 "REGAUTH",
00489 "REGACK ",
00490 "REGREJ ",
00491 "REGREL ",
00492 "VNAK ",
00493 "DPREQ ",
00494 "DPREP ",
00495 "DIAL ",
00496 "TXREQ ",
00497 "TXCNT ",
00498 "TXACC ",
00499 "TXREADY",
00500 "TXREL ",
00501 "TXREJ ",
00502 "QUELCH ",
00503 "UNQULCH",
00504 "POKE ",
00505 "PAGE ",
00506 "MWI ",
00507 "UNSPRTD",
00508 "TRANSFR",
00509 "PROVISN",
00510 "FWDWNLD",
00511 "FWDATA ",
00512 "TXMEDIA"
00513 };
00514 const char *cmds[] = {
00515 "(0?)",
00516 "HANGUP ",
00517 "RING ",
00518 "RINGING",
00519 "ANSWER ",
00520 "BUSY ",
00521 "TKOFFHK",
00522 "OFFHOOK",
00523 "CONGSTN",
00524 "FLASH ",
00525 "WINK ",
00526 "OPTION ",
00527 "RDKEY ",
00528 "RDUNKEY",
00529 "PROGRES",
00530 "PROCDNG",
00531 "HOLD ",
00532 "UNHOLD ",
00533 "VIDUPDT", };
00534 struct ast_iax2_full_hdr *fh;
00535 char retries[20];
00536 char class2[20];
00537 char subclass2[20];
00538 const char *class;
00539 const char *subclass;
00540 char *dir;
00541 char tmp[512];
00542
00543 switch(rx) {
00544 case 0:
00545 dir = "Tx";
00546 break;
00547 case 2:
00548 dir = "TE";
00549 break;
00550 case 3:
00551 dir = "RD";
00552 break;
00553 default:
00554 dir = "Rx";
00555 break;
00556 }
00557 if (f) {
00558 fh = f->data;
00559 snprintf(retries, sizeof(retries), "%03d", f->retries);
00560 } else {
00561 fh = fhi;
00562 if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
00563 strcpy(retries, "Yes");
00564 else
00565 strcpy(retries, " No");
00566 }
00567 if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
00568
00569 return;
00570 }
00571 if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
00572 snprintf(class2, sizeof(class2), "(%d?)", fh->type);
00573 class = class2;
00574 } else {
00575 class = frames[(int)fh->type];
00576 }
00577 if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
00578 sprintf(subclass2, "%c", fh->csub);
00579 subclass = subclass2;
00580 } else if (fh->type == AST_FRAME_IAX) {
00581 if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
00582 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00583 subclass = subclass2;
00584 } else {
00585 subclass = iaxs[(int)fh->csub];
00586 }
00587 } else if (fh->type == AST_FRAME_CONTROL) {
00588 if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
00589 snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
00590 subclass = subclass2;
00591 } else {
00592 subclass = cmds[(int)fh->csub];
00593 }
00594 } else {
00595 snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
00596 subclass = subclass2;
00597 }
00598 snprintf(tmp, sizeof(tmp),
00599 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
00600 dir,
00601 retries, fh->oseqno, fh->iseqno, class, subclass);
00602 outputf(tmp);
00603 snprintf(tmp, sizeof(tmp),
00604 " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
00605 (unsigned long)ntohl(fh->ts),
00606 ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
00607 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
00608 outputf(tmp);
00609 if (fh->type == AST_FRAME_IAX)
00610 dump_ies(fh->iedata, datalen);
00611 }
00612
00613 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
00614 {
00615 char tmp[256];
00616 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00617 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);
00618 errorf(tmp);
00619 return -1;
00620 }
00621 ied->buf[ied->pos++] = ie;
00622 ied->buf[ied->pos++] = datalen;
00623 memcpy(ied->buf + ied->pos, data, datalen);
00624 ied->pos += datalen;
00625 return 0;
00626 }
00627
00628 int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
00629 {
00630 return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00631 }
00632
00633 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
00634 {
00635 unsigned int newval;
00636 newval = htonl(value);
00637 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00638 }
00639
00640 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
00641 {
00642 unsigned short newval;
00643 newval = htons(value);
00644 return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00645 }
00646
00647 int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
00648 {
00649 return iax_ie_append_raw(ied, ie, str, strlen(str));
00650 }
00651
00652 int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
00653 {
00654 return iax_ie_append_raw(ied, ie, &dat, 1);
00655 }
00656
00657 int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
00658 {
00659 return iax_ie_append_raw(ied, ie, NULL, 0);
00660 }
00661
00662 void iax_set_output(void (*func)(const char *))
00663 {
00664 outputf = func;
00665 }
00666
00667 void iax_set_error(void (*func)(const char *))
00668 {
00669 errorf = func;
00670 }
00671
00672 int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
00673 {
00674
00675 int len;
00676 int ie;
00677 char tmp[256];
00678 memset(ies, 0, (int)sizeof(struct iax_ies));
00679 ies->msgcount = -1;
00680 ies->firmwarever = -1;
00681 ies->calling_ton = -1;
00682 ies->calling_tns = -1;
00683 ies->calling_pres = -1;
00684 ies->samprate = IAX_RATE_8KHZ;
00685 while(datalen >= 2) {
00686 ie = data[0];
00687 len = data[1];
00688 if (len > datalen - 2) {
00689 errorf("Information element length exceeds message size\n");
00690 return -1;
00691 }
00692 switch(ie) {
00693 case IAX_IE_CALLED_NUMBER:
00694 ies->called_number = (char *)data + 2;
00695 break;
00696 case IAX_IE_CALLING_NUMBER:
00697 ies->calling_number = (char *)data + 2;
00698 break;
00699 case IAX_IE_CALLING_ANI:
00700 ies->calling_ani = (char *)data + 2;
00701 break;
00702 case IAX_IE_CALLING_NAME:
00703 ies->calling_name = (char *)data + 2;
00704 break;
00705 case IAX_IE_CALLED_CONTEXT:
00706 ies->called_context = (char *)data + 2;
00707 break;
00708 case IAX_IE_USERNAME:
00709 ies->username = (char *)data + 2;
00710 break;
00711 case IAX_IE_PASSWORD:
00712 ies->password = (char *)data + 2;
00713 break;
00714 case IAX_IE_CODEC_PREFS:
00715 ies->codec_prefs = (char *)data + 2;
00716 break;
00717 case IAX_IE_CAPABILITY:
00718 if (len != (int)sizeof(unsigned int)) {
00719 snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00720 errorf(tmp);
00721 } else
00722 ies->capability = ntohl(get_unaligned_uint32(data + 2));
00723 break;
00724 case IAX_IE_FORMAT:
00725 if (len != (int)sizeof(unsigned int)) {
00726 snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00727 errorf(tmp);
00728 } else
00729 ies->format = ntohl(get_unaligned_uint32(data + 2));
00730 break;
00731 case IAX_IE_LANGUAGE:
00732 ies->language = (char *)data + 2;
00733 break;
00734 case IAX_IE_VERSION:
00735 if (len != (int)sizeof(unsigned short)) {
00736 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00737 errorf(tmp);
00738 } else
00739 ies->version = ntohs(get_unaligned_uint16(data + 2));
00740 break;
00741 case IAX_IE_ADSICPE:
00742 if (len != (int)sizeof(unsigned short)) {
00743 snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00744 errorf(tmp);
00745 } else
00746 ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
00747 break;
00748 case IAX_IE_SAMPLINGRATE:
00749 if (len != (int)sizeof(unsigned short)) {
00750 snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00751 errorf(tmp);
00752 } else
00753 ies->samprate = ntohs(get_unaligned_uint16(data + 2));
00754 break;
00755 case IAX_IE_DNID:
00756 ies->dnid = (char *)data + 2;
00757 break;
00758 case IAX_IE_RDNIS:
00759 ies->rdnis = (char *)data + 2;
00760 break;
00761 case IAX_IE_AUTHMETHODS:
00762 if (len != (int)sizeof(unsigned short)) {
00763 snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00764 errorf(tmp);
00765 } else
00766 ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
00767 break;
00768 case IAX_IE_ENCRYPTION:
00769 if (len != (int)sizeof(unsigned short)) {
00770 snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00771 errorf(tmp);
00772 } else
00773 ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
00774 break;
00775 case IAX_IE_CHALLENGE:
00776 ies->challenge = (char *)data + 2;
00777 break;
00778 case IAX_IE_MD5_RESULT:
00779 ies->md5_result = (char *)data + 2;
00780 break;
00781 case IAX_IE_RSA_RESULT:
00782 ies->rsa_result = (char *)data + 2;
00783 break;
00784 case IAX_IE_APPARENT_ADDR:
00785 ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
00786 break;
00787 case IAX_IE_REFRESH:
00788 if (len != (int)sizeof(unsigned short)) {
00789 snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00790 errorf(tmp);
00791 } else
00792 ies->refresh = ntohs(get_unaligned_uint16(data + 2));
00793 break;
00794 case IAX_IE_DPSTATUS:
00795 if (len != (int)sizeof(unsigned short)) {
00796 snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00797 errorf(tmp);
00798 } else
00799 ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
00800 break;
00801 case IAX_IE_CALLNO:
00802 if (len != (int)sizeof(unsigned short)) {
00803 snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00804 errorf(tmp);
00805 } else
00806 ies->callno = ntohs(get_unaligned_uint16(data + 2));
00807 break;
00808 case IAX_IE_CAUSE:
00809 ies->cause = (char *)data + 2;
00810 break;
00811 case IAX_IE_CAUSECODE:
00812 if (len != 1) {
00813 snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
00814 errorf(tmp);
00815 } else {
00816 ies->causecode = data[2];
00817 }
00818 break;
00819 case IAX_IE_IAX_UNKNOWN:
00820 if (len == 1)
00821 ies->iax_unknown = data[2];
00822 else {
00823 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00824 errorf(tmp);
00825 }
00826 break;
00827 case IAX_IE_MSGCOUNT:
00828 if (len != (int)sizeof(unsigned short)) {
00829 snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00830 errorf(tmp);
00831 } else
00832 ies->msgcount = ntohs(get_unaligned_uint16(data + 2));
00833 break;
00834 case IAX_IE_AUTOANSWER:
00835 ies->autoanswer = 1;
00836 break;
00837 case IAX_IE_MUSICONHOLD:
00838 ies->musiconhold = 1;
00839 break;
00840 case IAX_IE_TRANSFERID:
00841 if (len != (int)sizeof(unsigned int)) {
00842 snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00843 errorf(tmp);
00844 } else
00845 ies->transferid = ntohl(get_unaligned_uint32(data + 2));
00846 break;
00847 case IAX_IE_DATETIME:
00848 if (len != (int)sizeof(unsigned int)) {
00849 snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00850 errorf(tmp);
00851 } else
00852 ies->datetime = ntohl(get_unaligned_uint32(data + 2));
00853 break;
00854 case IAX_IE_FIRMWAREVER:
00855 if (len != (int)sizeof(unsigned short)) {
00856 snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00857 errorf(tmp);
00858 } else
00859 ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));
00860 break;
00861 case IAX_IE_DEVICETYPE:
00862 ies->devicetype = (char *)data + 2;
00863 break;
00864 case IAX_IE_SERVICEIDENT:
00865 ies->serviceident = (char *)data + 2;
00866 break;
00867 case IAX_IE_FWBLOCKDESC:
00868 if (len != (int)sizeof(unsigned int)) {
00869 snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00870 errorf(tmp);
00871 } else
00872 ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
00873 break;
00874 case IAX_IE_FWBLOCKDATA:
00875 ies->fwdata = data + 2;
00876 ies->fwdatalen = len;
00877 break;
00878 case IAX_IE_ENCKEY:
00879 ies->enckey = data + 2;
00880 ies->enckeylen = len;
00881 break;
00882 case IAX_IE_PROVVER:
00883 if (len != (int)sizeof(unsigned int)) {
00884 snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00885 errorf(tmp);
00886 } else {
00887 ies->provverpres = 1;
00888 ies->provver = ntohl(get_unaligned_uint32(data + 2));
00889 }
00890 break;
00891 case IAX_IE_CALLINGPRES:
00892 if (len == 1)
00893 ies->calling_pres = data[2];
00894 else {
00895 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
00896 errorf(tmp);
00897 }
00898 break;
00899 case IAX_IE_CALLINGTON:
00900 if (len == 1)
00901 ies->calling_ton = data[2];
00902 else {
00903 snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
00904 errorf(tmp);
00905 }
00906 break;
00907 case IAX_IE_CALLINGTNS:
00908 if (len != (int)sizeof(unsigned short)) {
00909 snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00910 errorf(tmp);
00911 } else
00912 ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));
00913 break;
00914 case IAX_IE_RR_JITTER:
00915 if (len != (int)sizeof(unsigned int)) {
00916 snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00917 errorf(tmp);
00918 } else {
00919 ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
00920 }
00921 break;
00922 case IAX_IE_RR_LOSS:
00923 if (len != (int)sizeof(unsigned int)) {
00924 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00925 errorf(tmp);
00926 } else {
00927 ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
00928 }
00929 break;
00930 case IAX_IE_RR_PKTS:
00931 if (len != (int)sizeof(unsigned int)) {
00932 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00933 errorf(tmp);
00934 } else {
00935 ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
00936 }
00937 break;
00938 case IAX_IE_RR_DELAY:
00939 if (len != (int)sizeof(unsigned short)) {
00940 snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00941 errorf(tmp);
00942 } else {
00943 ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
00944 }
00945 break;
00946 case IAX_IE_RR_DROPPED:
00947 if (len != (int)sizeof(unsigned int)) {
00948 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00949 errorf(tmp);
00950 } else {
00951 ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
00952 }
00953 break;
00954 case IAX_IE_RR_OOO:
00955 if (len != (int)sizeof(unsigned int)) {
00956 snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00957 errorf(tmp);
00958 } else {
00959 ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
00960 }
00961 break;
00962 default:
00963 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
00964 outputf(tmp);
00965 }
00966
00967 data[0] = 0;
00968 datalen -= (len + 2);
00969 data += (len + 2);
00970 }
00971
00972 *data = '\0';
00973 if (datalen) {
00974 errorf("Invalid information element contents, strange boundary\n");
00975 return -1;
00976 }
00977 return 0;
00978 }
00979
00980 void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
00981 {
00982 fr->af.frametype = f->frametype;
00983 fr->af.subclass = f->subclass;
00984 fr->af.mallocd = 0;
00985 fr->af.datalen = f->datalen;
00986 fr->af.samples = f->samples;
00987 fr->af.offset = AST_FRIENDLY_OFFSET;
00988 fr->af.src = f->src;
00989 fr->af.delivery.tv_sec = 0;
00990 fr->af.delivery.tv_usec = 0;
00991 fr->af.data = fr->afdata;
00992 fr->af.len = f->len;
00993 if (fr->af.datalen) {
00994 size_t copy_len = fr->af.datalen;
00995 if (copy_len > fr->afdatalen) {
00996 ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
00997 (int) fr->afdatalen, (int) fr->af.datalen);
00998 copy_len = fr->afdatalen;
00999 }
01000 #if __BYTE_ORDER == __LITTLE_ENDIAN
01001
01002 if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
01003
01004 ast_swapcopy_samples(fr->af.data, f->data, copy_len / 2);
01005 } else
01006 #endif
01007 memcpy(fr->af.data, f->data, copy_len);
01008 }
01009 }
01010
01011 struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
01012 {
01013 struct iax_frame *fr = NULL;
01014
01015 #if !defined(LOW_MEMORY)
01016 struct iax_frames *iax_frames;
01017
01018
01019 if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01020 AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
01021 if (fr->afdatalen >= datalen) {
01022 size_t afdatalen = fr->afdatalen;
01023 AST_LIST_REMOVE_CURRENT(&iax_frames->list, list);
01024 iax_frames->size--;
01025 memset(fr, 0, sizeof(*fr));
01026 fr->afdatalen = afdatalen;
01027 break;
01028 }
01029 }
01030 AST_LIST_TRAVERSE_SAFE_END
01031 }
01032 if (!fr) {
01033 if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
01034 return NULL;
01035 fr->afdatalen = datalen;
01036 }
01037 #else
01038 if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
01039 return NULL;
01040 fr->afdatalen = datalen;
01041 #endif
01042
01043
01044 fr->direction = direction;
01045 fr->retrans = -1;
01046 fr->cacheable = cacheable;
01047
01048 if (fr->direction == DIRECTION_INGRESS)
01049 ast_atomic_fetchadd_int(&iframes, 1);
01050 else
01051 ast_atomic_fetchadd_int(&oframes, 1);
01052
01053 ast_atomic_fetchadd_int(&frames, 1);
01054
01055 return fr;
01056 }
01057
01058 void iax_frame_free(struct iax_frame *fr)
01059 {
01060 #if !defined(LOW_MEMORY)
01061 struct iax_frames *iax_frames;
01062 #endif
01063
01064
01065 if (fr->direction == DIRECTION_INGRESS)
01066 ast_atomic_fetchadd_int(&iframes, -1);
01067 else if (fr->direction == DIRECTION_OUTGRESS)
01068 ast_atomic_fetchadd_int(&oframes, -1);
01069 else {
01070 errorf("Attempt to double free frame detected\n");
01071 return;
01072 }
01073 ast_atomic_fetchadd_int(&frames, -1);
01074
01075 #if !defined(LOW_MEMORY)
01076 if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
01077 free(fr);
01078 return;
01079 }
01080
01081 if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
01082 fr->direction = 0;
01083 AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
01084 iax_frames->size++;
01085 return;
01086 }
01087 #endif
01088 free(fr);
01089 }
01090
01091 #if !defined(LOW_MEMORY)
01092 static void frame_cache_cleanup(void *data)
01093 {
01094 struct iax_frames *frames = data;
01095 struct iax_frame *cur;
01096
01097 while ((cur = AST_LIST_REMOVE_HEAD(&frames->list, list)))
01098 free(cur);
01099
01100 free(frames);
01101 }
01102 #endif
01103
01104 int iax_get_frames(void) { return frames; }
01105 int iax_get_iframes(void) { return iframes; }
01106 int iax_get_oframes(void) { return oframes; }