dundi-parser.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Distributed Universal Number Discovery (DUNDi)
00022  *
00023  */
00024 
00025 /*** MODULEINFO
00026    <support_level>extended</support_level>
00027  ***/
00028 
00029 #include "asterisk.h"
00030 
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 429683 $")
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, "%02hhX", (unsigned char)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    /* Get rid of trailing | */
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    /* Get rid of trailing | */
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       /* Build up IV */
00322       for (x=0;x<16;x++) {
00323          snprintf(iv + (x << 1), 3, "%02hhx", ((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, "%02hhx ", 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       /* Encrypted data is the remainder */
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), "%02hhx", (unsigned char)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    /* Parse data into information elements */
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          /* Recalculate len as the remainder of the message, regardless of
00766             theoretical length */
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       /* Overwrite information element with 0, to null terminate previous portion */
00800       data[0] = 0;
00801       datalen -= (len + 2);
00802       data += (len + 2);
00803    }
00804    /* Null-terminate last field */
00805    *data = '\0';
00806    if (datalen) {
00807       errorf("Invalid information element contents, strange boundary\n");
00808       return -1;
00809    }
00810    return 0;
00811 }

Generated on Thu Apr 16 06:27:33 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6