diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | dab68864983c4a0c6ef9e6d7e5834472c4c75f9c (patch) | |
tree | b4293a1636331777f640f43f814667a9e1b0bbb7 /pppd/plugins/pppoatm/ans.c | |
parent | 82c907af479178801a7a8701341b22c9d20fdb7e (diff) | |
download | ppp-dab68864983c4a0c6ef9e6d7e5834472c4c75f9c.tar.gz |
Initial Contributionandroid-1.0release-1.0cdma-import
Diffstat (limited to 'pppd/plugins/pppoatm/ans.c')
-rw-r--r-- | pppd/plugins/pppoatm/ans.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/pppd/plugins/pppoatm/ans.c b/pppd/plugins/pppoatm/ans.c new file mode 100644 index 0000000..973eb33 --- /dev/null +++ b/pppd/plugins/pppoatm/ans.c @@ -0,0 +1,262 @@ +/* ans.c - Interface for text2atm and atm2text to ANS */ + +/* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */ + + +/* + * This stuff is a temporary hack to avoid using gethostbyname_nsap and such + * without doing the "full upgrade" to getaddrinfo/getnameinfo. This also + * serves as an exercise for me to get all the details right before I propose + * a patch that would eventually end up in libc (and that should therefore be + * as stable as possible). + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> + +#include "atm.h" +#include "atmres.h" + + +#define MAX_ANSWER 2048 +#define MAX_NAME 1024 + +#define MAX_LINE 2048 /* in /etc/e164_cc */ +#define E164_CC_DEFAULT_LEN 2 +#define E164_CC_FILE "/etc/e164_cc" + +#define GET16(pos) (((pos)[0] << 8) | (pos)[1]) + + +static int ans(const char *text,int wanted,void *result,int res_len) +{ + unsigned char answer[MAX_ANSWER]; + unsigned char name[MAX_NAME]; + unsigned char *pos,*data,*found; + int answer_len,name_len,data_len,found_len; + int questions,answers; + + found_len = 0; /* gcc wants it */ + if ((answer_len = res_search(text,C_IN,wanted,answer,MAX_ANSWER)) < 0) + return TRY_OTHER; + /* + * Response header: id, flags, #queries, #answers, #authority, + * #additional (all 16 bits) + */ + pos = answer+12; + if (answer[3] & 15) return TRY_OTHER; /* rcode != 0 */ + questions = GET16(answer+4); + if (questions != 1) return TRY_OTHER; /* trouble ... */ + answers = GET16(answer+6); + if (answers < 1) return TRY_OTHER; + /* + * Query: name, type (16), class (16) + */ + if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0) + return TRY_OTHER; + pos += name_len; + if (GET16(pos) != wanted || GET16(pos+2) != C_IN) return TRY_OTHER; + pos += 4; + /* + * Iterate over answers until we find something we like, giving priority + * to ATMA_AESA (until signaling is fixed to work with E.164 too) + */ + found = NULL; + while (answers--) { + /* + * RR: name, type (16), class (16), TTL (32), resource_len (16), + * resource_data ... + */ + if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) + < 0) return TRY_OTHER; + pos += name_len; + data_len = GET16(pos+8); + data = pos+10; + pos = data+data_len; + if (GET16(data-10) != wanted || GET16(data-8) != C_IN || !--data_len) + continue; + switch (wanted) { + case T_NSAP: + data_len++; + if (data_len != ATM_ESA_LEN) continue; + memcpy(((struct sockaddr_atmsvc *) result)-> + sas_addr.prv,data,ATM_ESA_LEN); + return 0; + case T_ATMA: + switch (*data++) { + case ATMA_AESA: + if (data_len != ATM_ESA_LEN) continue; + memcpy(((struct sockaddr_atmsvc *) result)-> + sas_addr.prv,data,ATM_ESA_LEN); + return 0; + case ATMA_E164: + if (data_len > ATM_E164_LEN) continue; + if (!found) { + found = data; + found_len = data_len; + } + break; + default: + continue; + } + case T_PTR: + if (dn_expand(answer,answer+answer_len,data,result, + res_len) < 0) return FATAL; + return 0; + default: + continue; + } + } + if (!found) return TRY_OTHER; + memcpy(((struct sockaddr_atmsvc *) result)->sas_addr.pub,found, + found_len); + ((struct sockaddr_atmsvc *) result)->sas_addr.pub[found_len] = 0; + return 0; +} + + +int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length, + int flags) +{ + if (!(flags & T2A_SVC) || length != sizeof(*addr)) return TRY_OTHER; + memset(addr,0,sizeof(*addr)); + addr->sas_family = AF_ATMSVC; + if (!ans(text,T_ATMA,addr,length)) return 0; + return ans(text,T_NSAP,addr,length); +} + + +static int encode_nsap(char *buf,const unsigned char *addr) +{ + static int fmt_dcc[] = { 2,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 4,2,0 }; + static int fmt_e164[] = { 2,12,1,1,1,1,1,1,1,1,16,2,0 }; + int *fmt; + int pos,i,j; + + switch (*addr) { + case ATM_AFI_DCC: + case ATM_AFI_ICD: + case ATM_AFI_LOCAL: + case ATM_AFI_DCC_GROUP: + case ATM_AFI_ICD_GROUP: + case ATM_AFI_LOCAL_GROUP: + fmt = fmt_dcc; + break; + case ATM_AFI_E164: + case ATM_AFI_E164_GROUP: + fmt = fmt_e164; + break; + default: + return TRY_OTHER; + } + pos = 2*ATM_ESA_LEN; + for (i = 0; fmt[i]; i++) { + pos -= fmt[i]; + for (j = 0; j < fmt[i]; j++) + sprintf(buf++,"%x", + (addr[(pos+j) >> 1] >> 4*(1-((pos+j) & 1))) & 0xf); + *buf++ = '.'; + } + strcpy(buf,"AESA.ATMA.INT."); + return 0; +} + + +static int encode_nsap_new(char *buf,const unsigned char *addr) +{ + int i; + int digit; + + for (i = 20; i; ) { + i--; + digit = addr[i] & 0x0F; + *(buf++) = digit + (digit >= 10 ? '7' : '0'); + *(buf++) = '.'; + digit = ((unsigned char) (addr[i])) >> 4; + *(buf++) = digit + (digit >= 10 ? '7' : '0'); + *(buf++) = '.'; + } + strcpy (buf, "NSAP.INT."); + return 0; +} + + +static int cc_len(int p0,int p1) +{ + static char *cc_table = NULL; + FILE *file; + char buffer[MAX_LINE]; + char *here; + int cc; + + if (!cc_table) { + if (!(cc_table = malloc(100))) { + perror("malloc"); + return E164_CC_DEFAULT_LEN; + } + memset(cc_table,E164_CC_DEFAULT_LEN,100); + if (!(file = fopen(E164_CC_FILE,"r"))) + perror(E164_CC_FILE); + else { + while (fgets(buffer,MAX_LINE,file)) { + here = strchr(buffer,'#'); + if (here) *here = 0; + if (sscanf(buffer,"%d",&cc) == 1) { + if (cc < 10) cc_table[cc] = 1; + else if (cc < 100) cc_table[cc] = 2; + else cc_table[cc/10] = 3; + } + } + fclose(file); + } + } + if (cc_table[p0] == 1) return 1; + return cc_table[p0*10+p1]; +} + + +static int encode_e164(char *buf,const char *addr) +{ + const char *prefix,*here; + + prefix = addr+cc_len(addr[0]-48,addr[1]-48); + here = strchr(addr,0); + while (here > prefix) { + *buf++ = *--here; + *buf++ = '.'; + } + while (here > addr) *buf++ = *addr++; + strcpy(buf,".E164.ATMA.INT."); + return 0; +} + + +int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr, + int flags) +{ + char tmp[MAX_NAME]; /* could be smaller ... */ + int res; + + if (addr->sas_addr.prv) { + res = encode_nsap(tmp,addr->sas_addr.prv); + if (!res && !ans(tmp,T_PTR,buffer,length)) return 0; + res = encode_nsap_new(tmp,addr->sas_addr.prv); + if (res < 0) return res; + return ans(tmp,T_PTR,buffer,length); + } else { + res = encode_e164(tmp,addr->sas_addr.pub); + if (res < 0) return res; + return ans(tmp,T_PTR,buffer,length); + } +} |