Sun Aug 6 15:02:40 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Generated on Sun Aug 6 15:02:40 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2