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