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