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