summaryrefslogtreecommitdiff
path: root/pppd/plugins/pppoatm/ans.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commitdab68864983c4a0c6ef9e6d7e5834472c4c75f9c (patch)
treeb4293a1636331777f640f43f814667a9e1b0bbb7 /pppd/plugins/pppoatm/ans.c
parent82c907af479178801a7a8701341b22c9d20fdb7e (diff)
downloadppp-dab68864983c4a0c6ef9e6d7e5834472c4c75f9c.tar.gz
Diffstat (limited to 'pppd/plugins/pppoatm/ans.c')
-rw-r--r--pppd/plugins/pppoatm/ans.c262
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);
+ }
+}