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 #include "asterisk.h"
00026
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 130130 $")
00028
00029 #include <sys/socket.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032
00033 #include "asterisk/frame.h"
00034 #include "asterisk/utils.h"
00035 #include "asterisk/dundi.h"
00036 #include "dundi-parser.h"
00037
00038 static void internaloutput(const char *str)
00039 {
00040 fputs(str, stdout);
00041 }
00042
00043 static void internalerror(const char *str)
00044 {
00045 fprintf(stderr, "WARNING: %s", str);
00046 }
00047
00048 static void (*outputf)(const char *str) = internaloutput;
00049 static void (*errorf)(const char *str) = internalerror;
00050
00051 char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid)
00052 {
00053 int x;
00054 char *os = s;
00055 if (maxlen < 18) {
00056 if (s && (maxlen > 0))
00057 *s = '\0';
00058 } else {
00059 for (x=0;x<5;x++) {
00060 sprintf(s, "%02x:", eid->eid[x]);
00061 s += 3;
00062 }
00063 sprintf(s, "%02x", eid->eid[5]);
00064 }
00065 return os;
00066 }
00067
00068 char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
00069 {
00070 int x;
00071 char *os = s;
00072 if (maxlen < 13) {
00073 if (s && (maxlen > 0))
00074 *s = '\0';
00075 } else {
00076 for (x=0;x<6;x++) {
00077 sprintf(s, "%02X", eid->eid[x]);
00078 s += 2;
00079 }
00080 }
00081 return os;
00082 }
00083
00084 int dundi_str_to_eid(dundi_eid *eid, const char *s)
00085 {
00086 unsigned int eid_int[6];
00087 int x;
00088 if (sscanf(s, "%x:%x:%x:%x:%x:%x", &eid_int[0], &eid_int[1], &eid_int[2],
00089 &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
00090 return -1;
00091 for (x=0;x<6;x++)
00092 eid->eid[x] = eid_int[x];
00093 return 0;
00094 }
00095
00096 int dundi_str_short_to_eid(dundi_eid *eid, const char *s)
00097 {
00098 unsigned int eid_int[6];
00099 int x;
00100 if (sscanf(s, "%2x%2x%2x%2x%2x%2x", &eid_int[0], &eid_int[1], &eid_int[2],
00101 &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
00102 return -1;
00103 for (x = 0; x < 6; x++)
00104 eid->eid[x] = eid_int[x];
00105 return 0;
00106 }
00107
00108 int dundi_eid_zero(dundi_eid *eid)
00109 {
00110 int x;
00111 for (x = 0; x < ARRAY_LEN(eid->eid); x++)
00112 if (eid->eid[x]) return 0;
00113 return 1;
00114 }
00115
00116 int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2)
00117 {
00118 return memcmp(eid1, eid2, sizeof(dundi_eid));
00119 }
00120
00121 static void dump_string(char *output, int maxlen, void *value, int len)
00122 {
00123 if (maxlen > len + 1)
00124 maxlen = len + 1;
00125
00126 snprintf(output, maxlen, "%s", (char *) value);
00127 }
00128
00129 static void dump_cbypass(char *output, int maxlen, void *value, int len)
00130 {
00131 snprintf(output, maxlen, "Bypass Caches");
00132 }
00133
00134 static void dump_eid(char *output, int maxlen, void *value, int len)
00135 {
00136 if (len == 6)
00137 dundi_eid_to_str(output, maxlen, (dundi_eid *)value);
00138 else
00139 snprintf(output, maxlen, "Invalid EID len %d", len);
00140 }
00141
00142 char *dundi_hint2str(char *buf, int bufsiz, int flags)
00143 {
00144 strcpy(buf, "");
00145 buf[bufsiz-1] = '\0';
00146 if (flags & DUNDI_HINT_TTL_EXPIRED) {
00147 strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1);
00148 }
00149 if (flags & DUNDI_HINT_DONT_ASK) {
00150 strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1);
00151 }
00152 if (flags & DUNDI_HINT_UNAFFECTED) {
00153 strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1);
00154 }
00155
00156 if (ast_strlen_zero(buf))
00157 strcpy(buf, "NONE|");
00158 buf[strlen(buf)-1] = '\0';
00159 return buf;
00160 }
00161
00162 static void dump_hint(char *output, int maxlen, void *value, int len)
00163 {
00164 char tmp2[256];
00165 char tmp3[256];
00166 int datalen;
00167 struct dundi_hint *hint;
00168 if (len < sizeof(*hint)) {
00169 snprintf(output, maxlen, "<invalid contents>");
00170 return;
00171 }
00172
00173 hint = (struct dundi_hint *) value;;
00174
00175 datalen = len - offsetof(struct dundi_hint, data);
00176 if (datalen > sizeof(tmp3) - 1)
00177 datalen = sizeof(tmp3) - 1;
00178
00179 memcpy(tmp3, hint->data, datalen);
00180 tmp3[datalen] = '\0';
00181
00182 dundi_hint2str(tmp2, sizeof(tmp2), ntohs(hint->flags));
00183
00184 if (ast_strlen_zero(tmp3))
00185 snprintf(output, maxlen, "[%s]", tmp2);
00186 else
00187 snprintf(output, maxlen, "[%s] %s", tmp2, tmp3);
00188 }
00189
00190 static void dump_cause(char *output, int maxlen, void *value, int len)
00191 {
00192 static char *causes[] = {
00193 "SUCCESS",
00194 "GENERAL",
00195 "DYNAMIC",
00196 "NOAUTH" ,
00197 };
00198 char tmp2[256];
00199 struct dundi_cause *cause;
00200 int datalen;
00201 int causecode;
00202
00203 if (len < sizeof(*cause)) {
00204 snprintf(output, maxlen, "<invalid contents>");
00205 return;
00206 }
00207
00208 cause = (struct dundi_cause*) value;
00209 causecode = cause->causecode;
00210
00211 datalen = len - offsetof(struct dundi_cause, desc);
00212 if (datalen > sizeof(tmp2) - 1)
00213 datalen = sizeof(tmp2) - 1;
00214
00215 memcpy(tmp2, cause->desc, datalen);
00216 tmp2[datalen] = '\0';
00217
00218 if (causecode < ARRAY_LEN(causes)) {
00219 if (ast_strlen_zero(tmp2))
00220 snprintf(output, maxlen, "%s", causes[causecode]);
00221 else
00222 snprintf(output, maxlen, "%s: %s", causes[causecode], tmp2);
00223 } else {
00224 if (ast_strlen_zero(tmp2))
00225 snprintf(output, maxlen, "%d", causecode);
00226 else
00227 snprintf(output, maxlen, "%d: %s", causecode, tmp2);
00228 }
00229 }
00230
00231 static void dump_int(char *output, int maxlen, void *value, int len)
00232 {
00233 if (len == (int)sizeof(unsigned int))
00234 snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
00235 else
00236 ast_copy_string(output, "Invalid INT", maxlen);
00237 }
00238
00239 static void dump_short(char *output, int maxlen, void *value, int len)
00240 {
00241 if (len == (int)sizeof(unsigned short))
00242 snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
00243 else
00244 ast_copy_string(output, "Invalid SHORT", maxlen);
00245 }
00246
00247 static void dump_byte(char *output, int maxlen, void *value, int len)
00248 {
00249 if (len == (int)sizeof(unsigned char))
00250 snprintf(output, maxlen, "%d", *((unsigned char *)value));
00251 else
00252 ast_copy_string(output, "Invalid BYTE", maxlen);
00253 }
00254
00255 static char *proto2str(int proto, char *buf, int bufsiz)
00256 {
00257 switch(proto) {
00258 case DUNDI_PROTO_NONE:
00259 strncpy(buf, "None", bufsiz - 1);
00260 break;
00261 case DUNDI_PROTO_IAX:
00262 strncpy(buf, "IAX", bufsiz - 1);
00263 break;
00264 case DUNDI_PROTO_SIP:
00265 strncpy(buf, "SIP", bufsiz - 1);
00266 break;
00267 case DUNDI_PROTO_H323:
00268 strncpy(buf, "H.323", bufsiz - 1);
00269 break;
00270 default:
00271 snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
00272 }
00273 buf[bufsiz-1] = '\0';
00274 return buf;
00275 }
00276
00277 char *dundi_flags2str(char *buf, int bufsiz, int flags)
00278 {
00279 strcpy(buf, "");
00280 buf[bufsiz-1] = '\0';
00281 if (flags & DUNDI_FLAG_EXISTS) {
00282 strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
00283 }
00284 if (flags & DUNDI_FLAG_MATCHMORE) {
00285 strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
00286 }
00287 if (flags & DUNDI_FLAG_CANMATCH) {
00288 strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
00289 }
00290 if (flags & DUNDI_FLAG_IGNOREPAT) {
00291 strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
00292 }
00293 if (flags & DUNDI_FLAG_RESIDENTIAL) {
00294 strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
00295 }
00296 if (flags & DUNDI_FLAG_COMMERCIAL) {
00297 strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
00298 }
00299 if (flags & DUNDI_FLAG_MOBILE) {
00300 strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
00301 }
00302 if (flags & DUNDI_FLAG_NOUNSOLICITED) {
00303 strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
00304 }
00305 if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
00306 strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
00307 }
00308
00309 if (ast_strlen_zero(buf))
00310 strcpy(buf, "NONE|");
00311 buf[strlen(buf)-1] = '\0';
00312 return buf;
00313 }
00314
00315 static void dump_answer(char *output, int maxlen, void *value, int len)
00316 {
00317 struct dundi_answer *answer;
00318 char proto[40];
00319 char flags[40];
00320 char eid_str[40];
00321 char tmp[512]="";
00322 int datalen;
00323
00324 if (len < sizeof(*answer)) {
00325 snprintf(output, maxlen, "Invalid Answer");
00326 return;
00327 }
00328
00329 answer = (struct dundi_answer *)(value);
00330
00331 datalen = len - offsetof(struct dundi_answer, data);
00332 if (datalen > sizeof(tmp) - 1)
00333 datalen = sizeof(tmp) - 1;
00334
00335 memcpy(tmp, answer->data, datalen);
00336 tmp[datalen] = '\0';
00337
00338 dundi_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
00339 snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]",
00340 dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)),
00341 ntohs(answer->weight),
00342 proto2str(answer->protocol, proto, sizeof(proto)),
00343 tmp, eid_str);
00344 }
00345
00346 static void dump_encrypted(char *output, int maxlen, void *value, int len)
00347 {
00348 char iv[33];
00349 int x;
00350 if ((len > 16) && !(len % 16)) {
00351
00352 for (x=0;x<16;x++) {
00353 snprintf(iv + (x << 1), 3, "%02x", ((unsigned char *)value)[x]);
00354 }
00355 snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
00356 } else
00357 snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
00358 }
00359
00360 static void dump_raw(char *output, int maxlen, void *value, int len)
00361 {
00362 int x;
00363 unsigned char *u = value;
00364 output[maxlen - 1] = '\0';
00365 strcpy(output, "[ ");
00366 for (x=0;x<len;x++) {
00367 snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", u[x]);
00368 }
00369 strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
00370 }
00371
00372 static struct dundi_ie {
00373 int ie;
00374 char *name;
00375 void (*dump)(char *output, int maxlen, void *value, int len);
00376 } ies[] = {
00377 { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
00378 { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
00379 { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
00380 { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
00381 { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
00382 { DUNDI_IE_TTL, "TTL", dump_short },
00383 { DUNDI_IE_VERSION, "VERSION", dump_short },
00384 { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
00385 { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
00386 { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
00387 { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
00388 { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
00389 { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
00390 { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
00391 { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
00392 { DUNDI_IE_HINT, "HINT", dump_hint },
00393 { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
00394 { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
00395 { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
00396 { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
00397 { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
00398 { DUNDI_IE_EMAIL, "EMAIL", dump_string },
00399 { DUNDI_IE_PHONE, "PHONE", dump_string },
00400 { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
00401 { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
00402 };
00403
00404 const char *dundi_ie2str(int ie)
00405 {
00406 int x;
00407 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00408 if (ies[x].ie == ie)
00409 return ies[x].name;
00410 }
00411 return "Unknown IE";
00412 }
00413
00414 static void dump_ies(unsigned char *iedata, int spaces, int len)
00415 {
00416 int ielen;
00417 int ie;
00418 int x;
00419 int found;
00420 char interp[1024];
00421 char tmp[1024];
00422 if (len < 2)
00423 return;
00424 while(len >= 2) {
00425 ie = iedata[0];
00426 ielen = iedata[1];
00427
00428 if (ie == DUNDI_IE_ENCDATA)
00429 ielen = len - 2;
00430 if (ielen + 2> len) {
00431 snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
00432 outputf(tmp);
00433 return;
00434 }
00435 found = 0;
00436 for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
00437 if (ies[x].ie == ie) {
00438 if (ies[x].dump) {
00439 ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
00440 snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp);
00441 outputf(tmp);
00442 } else {
00443 if (ielen)
00444 snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
00445 else
00446 strcpy(interp, "Present");
00447 snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp);
00448 outputf(tmp);
00449 }
00450 found++;
00451 }
00452 }
00453 if (!found) {
00454 snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie);
00455 outputf(tmp);
00456 }
00457 iedata += (2 + ielen);
00458 len -= (2 + ielen);
00459 }
00460 outputf("\n");
00461 }
00462
00463 void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
00464 {
00465 char *pref[] = {
00466 "Tx",
00467 "Rx",
00468 " ETx",
00469 " Erx" };
00470 char *commands[] = {
00471 "ACK ",
00472 "DPDISCOVER ",
00473 "DPRESPONSE ",
00474 "EIDQUERY ",
00475 "EIDRESPONSE ",
00476 "PRECACHERQ ",
00477 "PRECACHERP ",
00478 "INVALID ",
00479 "UNKNOWN CMD ",
00480 "NULL ",
00481 "REQREQ ",
00482 "REGRESPONSE ",
00483 "CANCEL ",
00484 "ENCRYPT ",
00485 "ENCREJ " };
00486 char class2[20];
00487 char *class;
00488 char subclass2[20];
00489 char *subclass;
00490 char tmp[256];
00491 char retries[20];
00492 if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS)
00493 strcpy(retries, "Yes");
00494 else
00495 strcpy(retries, "No");
00496 if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) {
00497
00498 return;
00499 }
00500 if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
00501 snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
00502 class = class2;
00503 } else {
00504 class = commands[(int)(fhi->cmdresp & 0x3f)];
00505 }
00506 snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags);
00507 subclass = subclass2;
00508 snprintf(tmp, (int)sizeof(tmp),
00509 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
00510 pref[rx],
00511 retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
00512 outputf(tmp);
00513 snprintf(tmp, (int)sizeof(tmp),
00514 "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "",
00515 subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
00516 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00517 fhi->cmdresp & 0x80 ? " (Final)" : "");
00518 outputf(tmp);
00519 dump_ies(fhi->ies, rx > 1, datalen);
00520 }
00521
00522 int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
00523 {
00524 char tmp[256];
00525 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00526 snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
00527 errorf(tmp);
00528 return -1;
00529 }
00530 ied->buf[ied->pos++] = ie;
00531 ied->buf[ied->pos++] = datalen;
00532 memcpy(ied->buf + ied->pos, data, datalen);
00533 ied->pos += datalen;
00534 return 0;
00535 }
00536
00537 int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
00538 {
00539 char tmp[256];
00540 int datalen = data ? strlen(data) + 1 : 1;
00541 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00542 snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
00543 errorf(tmp);
00544 return -1;
00545 }
00546 ied->buf[ied->pos++] = ie;
00547 ied->buf[ied->pos++] = datalen;
00548 ied->buf[ied->pos++] = cause;
00549 memcpy(ied->buf + ied->pos, data, datalen-1);
00550 ied->pos += datalen-1;
00551 return 0;
00552 }
00553
00554 int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
00555 {
00556 char tmp[256];
00557 int datalen = data ? strlen(data) + 2 : 2;
00558 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00559 snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
00560 errorf(tmp);
00561 return -1;
00562 }
00563 ied->buf[ied->pos++] = ie;
00564 ied->buf[ied->pos++] = datalen;
00565 flags = htons(flags);
00566 memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
00567 ied->pos += 2;
00568 memcpy(ied->buf + ied->pos, data, datalen-1);
00569 ied->pos += datalen-2;
00570 return 0;
00571 }
00572
00573 int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
00574 {
00575 char tmp[256];
00576 datalen += 16;
00577 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00578 snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
00579 errorf(tmp);
00580 return -1;
00581 }
00582 ied->buf[ied->pos++] = ie;
00583 ied->buf[ied->pos++] = datalen;
00584 memcpy(ied->buf + ied->pos, iv, 16);
00585 ied->pos += 16;
00586 if (data) {
00587 memcpy(ied->buf + ied->pos, data, datalen-16);
00588 ied->pos += datalen-16;
00589 }
00590 return 0;
00591 }
00592
00593 int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *data)
00594 {
00595 char tmp[256];
00596 int datalen = data ? strlen(data) + 11 : 11;
00597 int x;
00598 unsigned short myw;
00599 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00600 snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
00601 errorf(tmp);
00602 return -1;
00603 }
00604 ied->buf[ied->pos++] = ie;
00605 ied->buf[ied->pos++] = datalen;
00606 for (x=0;x<6;x++)
00607 ied->buf[ied->pos++] = eid->eid[x];
00608 ied->buf[ied->pos++] = protocol;
00609 myw = htons(flags);
00610 memcpy(ied->buf + ied->pos, &myw, 2);
00611 ied->pos += 2;
00612 myw = htons(weight);
00613 memcpy(ied->buf + ied->pos, &myw, 2);
00614 ied->pos += 2;
00615 memcpy(ied->buf + ied->pos, data, datalen-11);
00616 ied->pos += datalen-11;
00617 return 0;
00618 }
00619
00620 int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
00621 {
00622 return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00623 }
00624
00625 int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
00626 {
00627 unsigned int newval;
00628 newval = htonl(value);
00629 return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00630 }
00631
00632 int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
00633 {
00634 unsigned short newval;
00635 newval = htons(value);
00636 return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00637 }
00638
00639 int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
00640 {
00641 return dundi_ie_append_raw(ied, ie, str, strlen(str));
00642 }
00643
00644 int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
00645 {
00646 return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
00647 }
00648
00649 int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
00650 {
00651 return dundi_ie_append_raw(ied, ie, &dat, 1);
00652 }
00653
00654 int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
00655 {
00656 return dundi_ie_append_raw(ied, ie, NULL, 0);
00657 }
00658
00659 void dundi_set_output(void (*func)(const char *))
00660 {
00661 outputf = func;
00662 }
00663
00664 void dundi_set_error(void (*func)(const char *))
00665 {
00666 errorf = func;
00667 }
00668
00669 int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
00670 {
00671
00672 int len;
00673 int ie;
00674 char tmp[256];
00675 memset(ies, 0, (int)sizeof(struct dundi_ies));
00676 ies->ttl = -1;
00677 ies->expiration = -1;
00678 ies->unknowncmd = -1;
00679 ies->cause = -1;
00680 while(datalen >= 2) {
00681 ie = data[0];
00682 len = data[1];
00683 if (len > datalen - 2) {
00684 errorf("Information element length exceeds message size\n");
00685 return -1;
00686 }
00687 switch(ie) {
00688 case DUNDI_IE_EID:
00689 case DUNDI_IE_EID_DIRECT:
00690 if (len != (int)sizeof(dundi_eid)) {
00691 errorf("Improper entity identifer, expecting 6 bytes!\n");
00692 } else if (ies->eidcount < DUNDI_MAX_STACK) {
00693 ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
00694 ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
00695 ies->eidcount++;
00696 } else
00697 errorf("Too many entities in stack!\n");
00698 break;
00699 case DUNDI_IE_REQEID:
00700 if (len != (int)sizeof(dundi_eid)) {
00701 errorf("Improper requested entity identifer, expecting 6 bytes!\n");
00702 } else
00703 ies->reqeid = (dundi_eid *)(data + 2);
00704 break;
00705 case DUNDI_IE_CALLED_CONTEXT:
00706 ies->called_context = (char *)data + 2;
00707 break;
00708 case DUNDI_IE_CALLED_NUMBER:
00709 ies->called_number = (char *)data + 2;
00710 break;
00711 case DUNDI_IE_ANSWER:
00712 if (len < sizeof(struct dundi_answer)) {
00713 snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
00714 errorf(tmp);
00715 } else {
00716 if (ies->anscount < DUNDI_MAX_ANSWERS)
00717 ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
00718 else
00719 errorf("Ignoring extra answers!\n");
00720 }
00721 break;
00722 case DUNDI_IE_TTL:
00723 if (len != (int)sizeof(unsigned short)) {
00724 snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00725 errorf(tmp);
00726 } else
00727 ies->ttl = ntohs(*((unsigned short *)(data + 2)));
00728 break;
00729 case DUNDI_IE_VERSION:
00730 if (len != (int)sizeof(unsigned short)) {
00731 snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00732 errorf(tmp);
00733 } else
00734 ies->version = ntohs(*((unsigned short *)(data + 2)));
00735 break;
00736 case DUNDI_IE_EXPIRATION:
00737 if (len != (int)sizeof(unsigned short)) {
00738 snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00739 errorf(tmp);
00740 } else
00741 ies->expiration = ntohs(*((unsigned short *)(data + 2)));
00742 break;
00743 case DUNDI_IE_KEYCRC32:
00744 if (len != (int)sizeof(unsigned int)) {
00745 snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00746 errorf(tmp);
00747 } else
00748 ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
00749 break;
00750 case DUNDI_IE_UNKNOWN:
00751 if (len == 1)
00752 ies->unknowncmd = data[2];
00753 else {
00754 snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00755 errorf(tmp);
00756 }
00757 break;
00758 case DUNDI_IE_CAUSE:
00759 if (len >= 1) {
00760 ies->cause = data[2];
00761 ies->causestr = (char *)data + 3;
00762 } else {
00763 snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
00764 errorf(tmp);
00765 }
00766 break;
00767 case DUNDI_IE_HINT:
00768 if (len >= 2) {
00769 ies->hint = (struct dundi_hint *)(data + 2);
00770 } else {
00771 snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
00772 errorf(tmp);
00773 }
00774 break;
00775 case DUNDI_IE_DEPARTMENT:
00776 ies->q_dept = (char *)data + 2;
00777 break;
00778 case DUNDI_IE_ORGANIZATION:
00779 ies->q_org = (char *)data + 2;
00780 break;
00781 case DUNDI_IE_LOCALITY:
00782 ies->q_locality = (char *)data + 2;
00783 break;
00784 case DUNDI_IE_STATE_PROV:
00785 ies->q_stateprov = (char *)data + 2;
00786 break;
00787 case DUNDI_IE_COUNTRY:
00788 ies->q_country = (char *)data + 2;
00789 break;
00790 case DUNDI_IE_EMAIL:
00791 ies->q_email = (char *)data + 2;
00792 break;
00793 case DUNDI_IE_PHONE:
00794 ies->q_phone = (char *)data + 2;
00795 break;
00796 case DUNDI_IE_IPADDR:
00797 ies->q_ipaddr = (char *)data + 2;
00798 break;
00799 case DUNDI_IE_ENCDATA:
00800
00801
00802 len = datalen - 2;
00803 if ((len > 16) && !(len % 16)) {
00804 ies->encblock = (struct dundi_encblock *)(data + 2);
00805 ies->enclen = len - 16;
00806 } else {
00807 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
00808 errorf(tmp);
00809 }
00810 break;
00811 case DUNDI_IE_SHAREDKEY:
00812 if (len == 128) {
00813 ies->encsharedkey = (unsigned char *)(data + 2);
00814 } else {
00815 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
00816 errorf(tmp);
00817 }
00818 break;
00819 case DUNDI_IE_SIGNATURE:
00820 if (len == 128) {
00821 ies->encsig = (unsigned char *)(data + 2);
00822 } else {
00823 snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
00824 errorf(tmp);
00825 }
00826 break;
00827 case DUNDI_IE_CACHEBYPASS:
00828 ies->cbypass = 1;
00829 break;
00830 default:
00831 snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
00832 outputf(tmp);
00833 }
00834
00835 data[0] = 0;
00836 datalen -= (len + 2);
00837 data += (len + 2);
00838 }
00839
00840 *data = '\0';
00841 if (datalen) {
00842 errorf("Invalid information element contents, strange boundary\n");
00843 return -1;
00844 }
00845 return 0;
00846 }