Wed May 16 06:33:32 2012

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: 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    /* 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 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    /* 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    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    /* Parse data into information elements */
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          /* Recalculate len as the remainder of the message, regardless of
00762             theoretical length */
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       /* Overwrite information element with 0, to null terminate previous portion */
00796       data[0] = 0;
00797       datalen -= (len + 2);
00798       data += (len + 2);
00799    }
00800    /* Null-terminate last field */
00801    *data = '\0';
00802    if (datalen) {
00803       errorf("Invalid information element contents, strange boundary\n");
00804       return -1;
00805    }
00806    return 0;
00807 }

Generated on Wed May 16 06:33:32 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6