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