Wed Oct 28 11:51:03 2009

Asterisk developer's documentation


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 #include "asterisk.h"
00026 
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211569 $")
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    /* Get rid of trailing | */
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 char *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    /* Get rid of trailing | */
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       /* Build up IV */
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       /* Encrypted data is the remainder */
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    char retries[20];
00458    if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS)
00459       strcpy(retries, "Yes");
00460    else
00461       strcpy(retries, "No");
00462    if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) {
00463       /* Ignore frames with high bit set to 1 */
00464       return;
00465    }
00466    if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
00467       snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
00468       class = class2;
00469    } else {
00470       class = commands[(int)(fhi->cmdresp & 0x3f)];
00471    }
00472    snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags);
00473    subclass = subclass2;
00474    snprintf(tmp, (int)sizeof(tmp), 
00475       "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
00476       pref[rx],
00477       retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
00478    outputf(tmp);
00479    snprintf(tmp, (int)sizeof(tmp), 
00480       "%s     Flags: %s STrans: %5.5d  DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? "     " : "",
00481       subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
00482       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00483       fhi->cmdresp & 0x80 ? " (Final)" : "");
00484    outputf(tmp);
00485    dump_ies(fhi->ies, rx > 1, datalen);
00486 }
00487 
00488 int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
00489 {
00490    char tmp[256];
00491    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00492       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);
00493       errorf(tmp);
00494       return -1;
00495    }
00496    ied->buf[ied->pos++] = ie;
00497    ied->buf[ied->pos++] = datalen;
00498    memcpy(ied->buf + ied->pos, data, datalen);
00499    ied->pos += datalen;
00500    return 0;
00501 }
00502 
00503 int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
00504 {
00505    char tmp[256];
00506    int datalen = data ? strlen(data) + 1 : 1;
00507    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00508       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);
00509       errorf(tmp);
00510       return -1;
00511    }
00512    ied->buf[ied->pos++] = ie;
00513    ied->buf[ied->pos++] = datalen;
00514    ied->buf[ied->pos++] = cause;
00515    memcpy(ied->buf + ied->pos, data, datalen-1);
00516    ied->pos += datalen-1;
00517    return 0;
00518 }
00519 
00520 int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
00521 {
00522    char tmp[256];
00523    int datalen = data ? strlen(data) + 2 : 2;
00524    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00525       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);
00526       errorf(tmp);
00527       return -1;
00528    }
00529    ied->buf[ied->pos++] = ie;
00530    ied->buf[ied->pos++] = datalen;
00531    flags = htons(flags);
00532    memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
00533    ied->pos += 2;
00534    memcpy(ied->buf + ied->pos, data, datalen-1);
00535    ied->pos += datalen-2;
00536    return 0;
00537 }
00538 
00539 int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
00540 {
00541    char tmp[256];
00542    datalen += 16;
00543    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00544       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);
00545       errorf(tmp);
00546       return -1;
00547    }
00548    ied->buf[ied->pos++] = ie;
00549    ied->buf[ied->pos++] = datalen;
00550    memcpy(ied->buf + ied->pos, iv, 16);
00551    ied->pos += 16;
00552    if (data) {
00553       memcpy(ied->buf + ied->pos, data, datalen-16);
00554       ied->pos += datalen-16;
00555    }
00556    return 0;
00557 }
00558 
00559 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)
00560 {
00561    char tmp[256];
00562    int datalen = data ? strlen(data) + 11 : 11;
00563    int x;
00564    unsigned short myw;
00565    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00566       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);
00567       errorf(tmp);
00568       return -1;
00569    }
00570    ied->buf[ied->pos++] = ie;
00571    ied->buf[ied->pos++] = datalen;
00572    for (x=0;x<6;x++)
00573       ied->buf[ied->pos++] = eid->eid[x];
00574    ied->buf[ied->pos++] = protocol;
00575    myw = htons(flags);
00576    memcpy(ied->buf + ied->pos, &myw, 2);
00577    ied->pos += 2;
00578    myw = htons(weight);
00579    memcpy(ied->buf + ied->pos, &myw, 2);
00580    ied->pos += 2;
00581    memcpy(ied->buf + ied->pos, data, datalen-11);
00582    ied->pos += datalen-11;
00583    return 0;
00584 }
00585 
00586 int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
00587 {
00588    return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
00589 }
00590 
00591 int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value) 
00592 {
00593    unsigned int newval;
00594    newval = htonl(value);
00595    return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00596 }
00597 
00598 int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value) 
00599 {
00600    unsigned short newval;
00601    newval = htons(value);
00602    return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
00603 }
00604 
00605 int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
00606 {
00607    return dundi_ie_append_raw(ied, ie, str, strlen(str));
00608 }
00609 
00610 int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
00611 {
00612    return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
00613 }
00614 
00615 int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
00616 {
00617    return dundi_ie_append_raw(ied, ie, &dat, 1);
00618 }
00619 
00620 int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie) 
00621 {
00622    return dundi_ie_append_raw(ied, ie, NULL, 0);
00623 }
00624 
00625 void dundi_set_output(void (*func)(const char *))
00626 {
00627    outputf = func;
00628 }
00629 
00630 void dundi_set_error(void (*func)(const char *))
00631 {
00632    errorf = func;
00633 }
00634 
00635 int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
00636 {
00637    /* Parse data into information elements */
00638    int len;
00639    int ie;
00640    char tmp[256];
00641    memset(ies, 0, (int)sizeof(struct dundi_ies));
00642    ies->ttl = -1;
00643    ies->expiration = -1;
00644    ies->unknowncmd = -1;
00645    ies->cause = -1;
00646    while(datalen >= 2) {
00647       ie = data[0];
00648       len = data[1];
00649       if (len > datalen - 2) {
00650          errorf("Information element length exceeds message size\n");
00651          return -1;
00652       }
00653       switch(ie) {
00654       case DUNDI_IE_EID:
00655       case DUNDI_IE_EID_DIRECT:
00656          if (len != (int)sizeof(dundi_eid)) {
00657             errorf("Improper entity identifer, expecting 6 bytes!\n");
00658          } else if (ies->eidcount < DUNDI_MAX_STACK) {
00659             ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
00660             ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
00661             ies->eidcount++;
00662          } else
00663             errorf("Too many entities in stack!\n");
00664          break;
00665       case DUNDI_IE_REQEID:
00666          if (len != (int)sizeof(dundi_eid)) {
00667             errorf("Improper requested entity identifer, expecting 6 bytes!\n");
00668          } else
00669             ies->reqeid = (dundi_eid *)(data + 2);
00670          break;
00671       case DUNDI_IE_CALLED_CONTEXT:
00672          ies->called_context = (char *)data + 2;
00673          break;
00674       case DUNDI_IE_CALLED_NUMBER:
00675          ies->called_number = (char *)data + 2;
00676          break;
00677       case DUNDI_IE_ANSWER:
00678          if (len < sizeof(struct dundi_answer)) {
00679             snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
00680             errorf(tmp);
00681          } else {
00682             if (ies->anscount < DUNDI_MAX_ANSWERS)
00683                ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
00684             else 
00685                errorf("Ignoring extra answers!\n");
00686          }
00687          break;
00688       case DUNDI_IE_TTL:
00689          if (len != (int)sizeof(unsigned short)) {
00690             snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00691             errorf(tmp);
00692          } else
00693             ies->ttl = ntohs(*((unsigned short *)(data + 2)));
00694          break;
00695       case DUNDI_IE_VERSION:
00696          if (len != (int)sizeof(unsigned short)) {
00697             snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00698             errorf(tmp);
00699          } else
00700             ies->version = ntohs(*((unsigned short *)(data + 2)));
00701          break;
00702       case DUNDI_IE_EXPIRATION:
00703          if (len != (int)sizeof(unsigned short)) {
00704             snprintf(tmp, (int)sizeof(tmp),  "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
00705             errorf(tmp);
00706          } else
00707             ies->expiration = ntohs(*((unsigned short *)(data + 2)));
00708          break;
00709       case DUNDI_IE_KEYCRC32:
00710          if (len != (int)sizeof(unsigned int)) {
00711             snprintf(tmp, (int)sizeof(tmp),  "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
00712             errorf(tmp);
00713          } else
00714             ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
00715          break;
00716       case DUNDI_IE_UNKNOWN:
00717          if (len == 1)
00718             ies->unknowncmd = data[2];
00719          else {
00720             snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
00721             errorf(tmp);
00722          }
00723          break;
00724       case DUNDI_IE_CAUSE:
00725          if (len >= 1) {
00726             ies->cause = data[2];
00727             ies->causestr = (char *)data + 3;
00728          } else {
00729             snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
00730             errorf(tmp);
00731          }
00732          break;
00733       case DUNDI_IE_HINT:
00734          if (len >= 2) {
00735             ies->hint = (struct dundi_hint *)(data + 2);
00736          } else {
00737             snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
00738             errorf(tmp);
00739          }
00740          break;
00741       case DUNDI_IE_DEPARTMENT:
00742          ies->q_dept = (char *)data + 2;
00743          break;
00744       case DUNDI_IE_ORGANIZATION:
00745          ies->q_org = (char *)data + 2;
00746          break;
00747       case DUNDI_IE_LOCALITY:
00748          ies->q_locality = (char *)data + 2;
00749          break;
00750       case DUNDI_IE_STATE_PROV:
00751          ies->q_stateprov = (char *)data + 2;
00752          break;
00753       case DUNDI_IE_COUNTRY:
00754          ies->q_country = (char *)data + 2;
00755          break;
00756       case DUNDI_IE_EMAIL:
00757          ies->q_email = (char *)data + 2;
00758          break;
00759       case DUNDI_IE_PHONE:
00760          ies->q_phone = (char *)data + 2;
00761          break;
00762       case DUNDI_IE_IPADDR:
00763          ies->q_ipaddr = (char *)data + 2;
00764          break;
00765       case DUNDI_IE_ENCDATA:
00766          /* Recalculate len as the remainder of the message, regardless of
00767             theoretical length */
00768          len = datalen - 2;
00769          if ((len > 16) && !(len % 16)) {
00770             ies->encblock = (struct dundi_encblock *)(data + 2);
00771             ies->enclen = len - 16;
00772          } else {
00773             snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
00774             errorf(tmp);
00775          }
00776          break;
00777       case DUNDI_IE_SHAREDKEY:
00778          if (len == 128) {
00779             ies->encsharedkey = (unsigned char *)(data + 2);
00780          } else {
00781             snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
00782             errorf(tmp);
00783          }
00784          break;
00785       case DUNDI_IE_SIGNATURE:
00786          if (len == 128) {
00787             ies->encsig = (unsigned char *)(data + 2);
00788          } else {
00789             snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
00790             errorf(tmp);
00791          }
00792          break;
00793       case DUNDI_IE_CACHEBYPASS:
00794          ies->cbypass = 1;
00795          break;
00796       default:
00797          snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
00798          outputf(tmp);
00799       }
00800       /* Overwrite information element with 0, to null terminate previous portion */
00801       data[0] = 0;
00802       datalen -= (len + 2);
00803       data += (len + 2);
00804    }
00805    /* Null-terminate last field */
00806    *data = '\0';
00807    if (datalen) {
00808       errorf("Invalid information element contents, strange boundary\n");
00809       return -1;
00810    }
00811    return 0;
00812 }

Generated on Wed Oct 28 11:51:03 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6