Blob Blame History Raw
--- ppp-2.4.2/configure.atm1	2002-11-09 11:24:41.000000000 +0000
+++ ppp-2.4.2/configure	2004-10-04 12:11:55.000000000 +0100
@@ -141,7 +141,7 @@ if [ -d "$ksrc" ]; then
   rm -f Makedefs.com
   ln -s $ksrc/Makedefs$compiletype Makedefs.com
   echo "  $ksrc/Makedefs$compiletype -> Makedefs.com"
-  for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/rp-pppoe pppd/plugins/radius; do
+  for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/rp-pppoe pppd/plugins/radius pppd/plugins/pppoatm; do
     rm -f $dir/Makefile
     if [ -f $dir/Makefile.$makext ]; then
       ln -s Makefile.$makext $dir/Makefile
--- ppp-2.4.2/pppd/plugins/Makefile.linux.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/Makefile.linux	2004-10-04 12:11:55.000000000 +0100
@@ -4,7 +4,7 @@ CFLAGS	= $(COPTS) -I.. -I../../include -
 LDFLAGS	= -shared
 INSTALL	= install -o root
 
-SUBDIRS := rp-pppoe
+SUBDIRS := rp-pppoe pppoatm
 # Uncomment the next line to include the radius authentication plugin
 # SUBDIRS += radius
 PLUGINS := minconn.so passprompt.so passwordfd.so
--- ppp-2.4.2/pppd/plugins/pppoatm/ans.c.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/ans.c	2004-10-04 12:11:55.000000000 +0100
@@ -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);
+    }
+}
--- ppp-2.4.2/pppd/plugins/pppoatm/Makefile.linux.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/Makefile.linux	2004-10-05 17:32:17.462042440 +0100
@@ -0,0 +1,41 @@
+CC	= gcc
+COPTS	= -O2 -g
+CFLAGS	= $(COPTS) -I../.. -I../../../include -fPIC
+LDFLAGS	= -shared
+INSTALL	= install -o root
+
+#***********************************************************************
+
+PLUGIN := pppoatm.so
+PLUGIN_OBJS := pppoatm.o 
+
+#*******
+# Do we have the ATM libraries installed? Set HAVE_LIBATM to use them,
+# or leave it unset to build the few routines we actually _use_ into
+# the plugin directly.
+#
+#HAVE_LIBATM=yes
+
+ifdef HAVE_LIBATM
+LIBS := -latm
+else
+CFLAGS += -I.
+PLUGIN_OBJS += text2qos.o text2atm.o misc.o ans.o
+LIBS := -lresolv
+endif
+
+#*********
+all: $(PLUGIN)
+
+$(PLUGIN): $(PLUGIN_OBJS)
+	$(CC) $(CFLAGS) -o $@ -shared $^ $(LIBS)
+
+install: all
+	$(INSTALL) -d -m 755 $(LIBDIR)
+	$(INSTALL) -c -m 4550 $(PLUGIN) $(LIBDIR)
+
+clean:
+	rm -f *.o *.so
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
--- ppp-2.4.2/pppd/plugins/pppoatm/text2atm.c.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/text2atm.c	2004-10-04 12:11:55.000000000 +0100
@@ -0,0 +1,249 @@
+/* text2atm.c - Converts textual representation of ATM address to binary
+		encoding */
+
+/* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#include "atm.h"
+#include "atmsap.h"
+#include "atmres.h"
+
+
+static int try_pvc(const char *text,struct sockaddr_atmpvc *addr,int flags)
+{
+    int part[3];
+    int i;
+
+    part[0] = part[1] = part[2] = 0;
+    i = 0;
+    while (1) {
+	if (!*text) return FATAL; /* empty or ends with a dot */
+	if (i == 3) return TRY_OTHER; /* too long */
+	if (isdigit(*text)) {
+	    if (*text == '0' && isdigit(text[1])) return TRY_OTHER;
+		/* no leading zeroes */
+	    do {
+		if (part[i] > INT_MAX/10) return TRY_OTHER;/* number too big */
+		part[i] = part[i]*10+*text++-'0';
+	    }
+	    while (isdigit(*text));
+	    i++;
+	    if (!*text) break;
+	    if (*text++ != '.') return TRY_OTHER; /* non-PVC character */
+	    continue;
+	}
+	if (*text == '*') {
+	    if (!(flags & T2A_WILDCARD)) return FATAL; /* not allowed */
+	    part[i++] = ATM_ITF_ANY; /* all *_ANY have the same value */
+	}
+	else {
+	    if (*text != '?') return TRY_OTHER; /* invalid character */
+	    if (!(flags & T2A_UNSPEC)) return FATAL; /* not allowed */
+	    part[i++] = ATM_VPI_UNSPEC; /* all *_UNSPEC have the same
+					   value */
+	}
+	if (!*++text) break;
+	if (*text++ != '.') return FATAL; /* dot required */
+    }
+    if (i < 2) return TRY_OTHER; /* no dots */
+    if (i == 2) {
+	part[2] = part[1];
+	part[1] = part[0];
+	part[0] = 0; /* default interface */
+    }
+    if (part[0] > SHRT_MAX || part[2] > ATM_MAX_VCI)
+	return TRY_OTHER; /* too big */
+    if (part[1] > (flags & T2A_NNI ? ATM_MAX_VPI_NNI : ATM_MAX_VPI))
+	return TRY_OTHER; /* too big */
+    if (part[0] == ATM_VPI_UNSPEC) return FATAL; /* bad */
+    addr->sap_family = AF_ATMPVC;
+    addr->sap_addr.itf = part[0];
+    addr->sap_addr.vpi = part[1];
+    addr->sap_addr.vci = part[2];
+    return 0;
+}
+
+
+static int do_try_nsap(const char *text,struct sockaddr_atmsvc *addr,int flags)
+{
+    const char *walk;
+    int count,pos,dot;
+    int offset,len;
+    char value;
+
+    count = dot = 0;
+    for (walk = text; *walk; walk++)
+	if (isdigit(*walk)) {
+	    if (count++ == 15) break;
+	    dot = 1;
+	}
+	else if (*text != '.') break;
+	    else if (!dot) return FATAL; /* two dots in a row */
+		else dot = 0;
+    if (*walk != ':') {
+	pos = 0;
+	offset = 0;
+    }
+    else {
+	if (!dot || *text == '0') return FATAL;
+	addr->sas_addr.prv[0] = ATM_AFI_E164;
+	addr->sas_addr.prv[1] = 0;
+	memset(addr->sas_addr.prv+1,0,8);
+	for (pos = 18-count-1; *text; text++) {
+	    if (*text == '.') continue;
+	    if (*text == ':') break;
+	    else {
+		if (pos & 1) addr->sas_addr.prv[pos >> 1] |= *text-'0';
+		else addr->sas_addr.prv[pos >> 1] = (*text-'0') << 4;
+		pos++;
+	    }
+ 	}
+	addr->sas_addr.prv[8] |= 0xf;
+	text++;
+	pos++;
+	offset = 72;
+    }
+    for (dot = 0; *text; text++)
+	if (isxdigit(*text)) {
+	    if (pos == ATM_ESA_LEN*2) return TRY_OTHER; /* too long */
+	    value = isdigit(*text) ? *text-'0' : (islower(*text) ?
+	      toupper(*text) : *text)-'A'+10;
+	    if (pos & 1) addr->sas_addr.prv[pos >> 1] |= value;
+	    else addr->sas_addr.prv[pos >> 1] = value << 4;
+	    pos++;
+	    dot = 1;
+	}
+	else 
+	    if (*text == '/' && (flags & T2A_WILDCARD)) break;
+	    else if (*text != '.') return TRY_OTHER;
+		else {
+		    if (!dot) return FATAL; /* two dots in a row */
+		    dot = 0;
+		}
+    if (!dot) return FATAL;
+    if (pos > 1 && !*addr->sas_addr.prv)
+	return TRY_OTHER; /* no leading zeroes */
+    if (!*text)
+	return pos != ATM_ESA_LEN*2 ? TRY_OTHER : ATM_ESA_LEN*2;
+	  /* handle bad length */
+    len = 0;
+    while (*++text) {
+	if (!isdigit(*text)) return -1; /* non-digit in length */
+	if (len >= pos*4) return -1; /* too long */
+	len = len*10+*text-'0';
+    }
+    if (len > 7 && addr->sas_addr.prv[0] != ATM_AFI_E164) offset = 72;
+    if (len < offset) return FATAL;
+    return len > pos*4 ? TRY_OTHER : len;
+}
+
+
+static int try_nsap(const char *text,struct sockaddr_atmsvc *addr,int flags)
+{
+    int result;
+
+    result = do_try_nsap(text,addr,flags);
+    if (result < 0) return result;
+    addr->sas_family = AF_ATMSVC;
+    *addr->sas_addr.pub = 0;
+    return result;
+}
+
+
+static int try_e164(const char *text,struct sockaddr_atmsvc *addr,int flags)
+{
+    int i,dot,result;
+
+    if (*text == ':' || *text == '+') text++;
+    for (i = dot = 0; *text; text++)
+	if (isdigit(*text)) {
+	    if (i == ATM_E164_LEN) return TRY_OTHER; /* too long */
+	    addr->sas_addr.pub[i++] = *text;
+	    dot = 1;
+	}
+	else if (*text != '.') break;
+	    else {
+		if (!dot) return TRY_OTHER; /* two dots in a row */
+		dot = 0;
+	    }
+    if (!dot) return TRY_OTHER;
+    addr->sas_addr.pub[i] = 0;
+    *addr->sas_addr.prv = 0;
+    result = 0;
+    if (*text) {
+	if (*text++ != '+') return TRY_OTHER;
+	else {
+	    result = do_try_nsap(text,addr,flags);
+	    if (result < 0) return FATAL;
+	}
+    }
+    addr->sas_family = AF_ATMSVC;
+    return result;
+}
+
+
+static int search(FILE *file,const char *text,struct sockaddr *addr,int length,
+  int flags)
+{
+    char line[MAX_ATM_NAME_LEN+1];
+    const char *here;
+    int result;
+
+    while (fgets(line,MAX_ATM_NAME_LEN,file)) {
+	if (!strtok(line,"\t\n ")) continue;
+	while ((here = strtok(NULL,"\t\n ")))
+	    if (!strcasecmp(here,text)) {
+		here = strtok(line,"\t\n ");
+		result = text2atm(here,addr,length,flags);
+		if (result >= 0) return result;
+	    }
+    }
+    return TRY_OTHER;
+}
+
+
+static int try_name(const char *text,struct sockaddr *addr,int length,
+  int flags)
+{
+    FILE *file;
+    int result;
+
+    if (!(file = fopen(HOSTS_ATM,"r"))) return TRY_OTHER;
+    result = search(file,text,addr,length,flags);
+    (void) fclose(file);
+    return result;
+}
+
+
+int text2atm(const char *text,struct sockaddr *addr,int length,int flags)
+{
+    int result;
+
+    if (!*text) return -1;
+    if (!(flags & (T2A_PVC | T2A_SVC))) flags |= T2A_PVC | T2A_SVC;
+    if (length < sizeof(struct sockaddr_atmpvc)) return -1;
+    if (flags & T2A_PVC) {
+	result = try_pvc(text,(struct sockaddr_atmpvc *) addr,flags);
+	if (result != TRY_OTHER) return result;
+    }
+    if ((flags & T2A_SVC) && length >= sizeof(struct sockaddr_atmsvc)) {
+	result = try_nsap(text,(struct sockaddr_atmsvc *) addr,flags);
+	if (result != TRY_OTHER) return result;
+	result = try_e164(text,(struct sockaddr_atmsvc *) addr,flags);
+	if (result != TRY_OTHER) return result;
+    }
+    if (!(flags & T2A_NAME)) return -1;
+    result = try_name(text,addr,length,flags & ~T2A_NAME);
+    if (result == TRY_OTHER && !(flags & T2A_LOCAL))
+	result = ans_byname(text,(struct sockaddr_atmsvc *) addr,length,flags);
+    if (result != TRY_OTHER) return result;
+    return -1;
+}
--- ppp-2.4.2/pppd/plugins/pppoatm/text2qos.c.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/text2qos.c	2004-10-04 12:11:55.000000000 +0100
@@ -0,0 +1,180 @@
+/* text2qos.c - Converts textual representation of QOS parameters to binary
+		encoding */
+
+/* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "atm.h"
+
+
+#define fetch __atmlib_fetch
+
+
+#define RATE_ERROR -2
+
+
+int __t2q_get_rate(const char **text,int up)
+{
+    const char mult[] = "kKmMgGg";
+    const char *multiplier;
+    char *end;
+    unsigned int rate,fract;
+    int power;
+
+    if (!strncmp(*text,"max",3)) {
+	*text += 3;
+	return ATM_MAX_PCR;
+    }
+    rate = strtoul(*text,&end,10);
+    power = fract = 0;
+    if (*end == '.')
+	for (end++; *end && isdigit(*end); end++) {
+	    fract = fract*10+*end-48;
+	    if (--power == -9) break;
+	}
+    multiplier = NULL;
+    if (*end && (multiplier = strchr(mult,*end))) {
+	while (multiplier >= mult) {
+	    if (rate > UINT_MAX/1000) return RATE_ERROR;
+	    rate *= 1000;
+	    power += 3;
+	    multiplier -= 2;
+	}
+	end++;
+    }
+    while (power && fract)
+	if (power < 0) {
+	    fract /= 10;
+	    power++;
+	}
+	else {
+	    fract *= 10;
+	    power--;
+	}
+    rate += fract;
+    if (strlen(end) < 3) {
+	if (multiplier) return RATE_ERROR;
+    }
+    else if (!strncmp(end,"cps",3)) end += 3;
+	else if (!strncmp(end,"bps",3)) {
+		rate = (rate+(up ? 8*ATM_CELL_PAYLOAD-1 : 0))/8/
+		  ATM_CELL_PAYLOAD;
+		end += 3;
+	    }
+	    else if (multiplier) return RATE_ERROR;
+    if (rate > INT_MAX) return RATE_ERROR;
+    *text = end;
+    return rate;
+}
+
+
+static int params(const char **text,struct atm_trafprm *a,
+  struct atm_trafprm *b)
+{
+    int value;
+    char *end;
+
+    if (*(*text)++ != ':') return -1;
+    while (1) {
+	if (!**text) return -1;
+	switch (fetch(text,"max_pcr=","pcr=","min_pcr=","max_sdu=","sdu=",
+	  NULL)) {
+	    case 0:
+		if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1;
+		if (a) a->max_pcr = value;
+		if (b) b->max_pcr = value;
+		break;
+	    case 1:
+		if ((value = __t2q_get_rate(text,0)) == RATE_ERROR) return -1;
+		if (a) a->pcr = value;
+		if (b) b->pcr = value;
+		break;
+	    case 2:
+		if ((value = __t2q_get_rate(text,1)) == RATE_ERROR) return -1;
+		if (value == ATM_MAX_PCR) return -1;
+		if (a) a->min_pcr = value;
+		if (b) b->min_pcr = value;
+		break;
+	    case 3:
+	    case 4:
+		value = strtol(*text,&end,10);
+		if (value < 0) return -1;
+		*text = end;
+		if (a) a->max_sdu = value;
+		if (b) b->max_sdu = value;
+		break;
+	    default:
+		return 0;
+	}
+	if (!**text) break;
+	if (*(*text)++ != ',') return -1;
+    }
+    return 0;
+}
+
+
+int text2qos(const char *text,struct atm_qos *qos,int flags)
+{
+    int traffic_class,aal;
+
+    traffic_class = ATM_NONE;
+    aal = ATM_NO_AAL;
+    do {
+	static const unsigned char aal_number[] = { ATM_AAL0, ATM_AAL5 };
+	int item;
+
+	item = fetch(&text,"!none","ubr","cbr","vbr","abr","aal0","aal5",NULL);
+	switch (item) {
+	    case 1:
+	    case 2:
+		/* we don't support VBR yet */
+	    case 4:
+		traffic_class = item;
+		break;
+	    case 5:
+	    case 6:
+		aal = aal_number[item-5];
+		break;
+	    default:
+		return -1;
+	}
+    }
+    while (*text == ',' ? text++ : 0);
+    if (!traffic_class) return -1;
+    if (qos && !(flags & T2Q_DEFAULTS)) memset(qos,0,sizeof(*qos));
+    if (qos) qos->txtp.traffic_class = qos->rxtp.traffic_class = traffic_class;
+    if (qos && aal) qos->aal = aal;
+    if (!*text) return 0;
+    if (params(&text,qos ? &qos->txtp : NULL,qos ? &qos->rxtp : NULL))
+	return -1;
+    if (!*text) return 0;
+    switch (fetch(&text,"tx","rx",NULL)) {
+	case 0:
+	    if (!fetch(&text,":none",NULL)) {
+		if (qos) qos->txtp.traffic_class = ATM_NONE;
+		if (*text == ',') text++;
+		break;
+	    }
+	    if (params(&text,qos ? &qos->txtp : NULL,NULL)) return -1;
+	    break;
+	case 1:
+	    text -= 2;
+	    break;
+	default:
+	    return -1;
+    }
+    if (!*text) return 0;
+    if (fetch(&text,"rx",NULL)) return -1;
+    if (!fetch(&text,":none",NULL) && qos) qos->rxtp.traffic_class = ATM_NONE;
+    else if (params(&text,qos ? &qos->rxtp : NULL,NULL)) return -1;
+    return *text ? -1 : 0;
+}
--- ppp-2.4.2/pppd/plugins/pppoatm/atm.h.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/atm.h	2004-10-05 17:25:10.825900992 +0100
@@ -0,0 +1,108 @@
+/* atm.h - Functions useful for ATM applications */
+ 
+/* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */
+ 
+
+#ifndef _ATM_H
+#define _ATM_H
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <linux/atm.h>
+
+
+/*
+ * For versions of glibc < 2.1
+ */
+
+#ifndef AF_ATMPVC
+#define AF_ATMPVC	8
+#endif
+
+#ifndef AF_ATMSVC
+#define AF_ATMSVC	20
+#endif
+
+#ifndef PF_ATMPVC
+#define PF_ATMPVC	AF_ATMPVC
+#endif
+
+#ifndef PF_ATMSVC
+#define PF_ATMSVC	AF_ATMSVC
+#endif
+
+#ifndef SOL_ATM
+#define SOL_ATM		264
+#endif
+
+#ifndef SOL_AAL
+#define SOL_AAL		265
+#endif
+
+
+#define HOSTS_ATM "/etc/hosts.atm"
+
+/* text2atm flags */
+#define T2A_PVC		  1	/* address is PVC */
+#define T2A_SVC		  2	/* address is SVC */
+#define T2A_UNSPEC	  4	/* allow unspecified parts in PVC address */
+#define T2A_WILDCARD	  8	/* allow wildcards in PVC or SVC address */
+#define T2A_NNI		 16	/* allow NNI VPI range (PVC) */
+#define T2A_NAME	 32	/* allow name resolution */
+#define T2A_REMOTE	 64	/* OBSOLETE */
+#define T2A_LOCAL	128	/* don't use ANS */
+
+/* atm2text flags */
+#define A2T_PRETTY	 1	/* add syntactic sugar */
+#define A2T_NAME	 2	/* attempt name lookup */
+#define A2T_REMOTE	 4	/* OBSOLETE */
+#define A2T_LOCAL	 8	/* don't use ANS */
+
+/* atm_equal flags */
+#define AXE_WILDCARD	 1	/* allow wildcard match */
+#define AXE_PRVOPT	 2	/* private part of SVC address is optional */
+
+/* text2qos flags */
+#define T2Q_DEFAULTS	 1	/* structure contains default values */
+
+/* text2sap flags */
+#define T2S_NAME	 1	/* attempt name lookup */
+#define T2S_LOCAL	 2	/* we may support NIS or such in the future */
+
+/* sap2text flags */
+#define S2T_NAME	 1	/* attempt name lookup */
+#define S2T_LOCAL	 2	/* we may support NIS or such in the future */
+
+/* sap_equal flags */
+#define SXE_COMPATIBLE	 1	/* check for compatibility instead of identity*/
+#define SXE_NEGOTIATION	 2	/* allow negotiation; requires SXE_COMPATIBLE;
+				   assumes "a" defines the available
+				   capabilities */
+#define SXE_RESULT	 4	/* return selected SAP */
+
+#define MAX_ATM_ADDR_LEN (2*ATM_ESA_LEN+ATM_E164_LEN+5)
+				/* 4 dots, 1 plus */
+#define MAX_ATM_NAME_LEN 256	/* wild guess */
+#define MAX_ATM_QOS_LEN 116	/* 5+4+2*(3+3*(7+9)+2)+1 */
+#define MAX_ATM_SAP_LEN	255	/* BHLI(27)+1+3*BLLI(L2=33,L3=41,+1)+2 */
+
+
+int text2atm(const char *text,struct sockaddr *addr,int length,int flags);
+int atm2text(char *buffer,int length,const struct sockaddr *addr,int flags);
+int atm_equal(const struct sockaddr *a,const struct sockaddr *b,int len,
+  int flags);
+
+int sdu2cell(int s,int sizes,const int *sdu_size,int *num_sdu);
+
+int text2qos(const char *text,struct atm_qos *qos,int flags);
+int qos2text(char *buffer,int length,const struct atm_qos *qos,int flags);
+int qos_equal(const struct atm_qos *a,const struct atm_qos *b);
+
+int text2sap(const char *text,struct atm_sap *sap,int flags);
+int sap2text(char *buffer,int length,const struct atm_sap *sap,int flags);
+int sap_equal(const struct atm_sap *a,const struct atm_sap *b,int flags,...);
+
+int __t2q_get_rate(const char **text,int up);
+int __atmlib_fetch(const char **pos,...); /* internal use only */
+
+#endif
--- ppp-2.4.2/pppd/plugins/pppoatm/pppoatm.c.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/pppoatm.c	2004-10-04 12:11:55.000000000 +0100
@@ -0,0 +1,224 @@
+/* pppoatm.c - pppd plugin to implement PPPoATM protocol.
+ *
+ * Copyright 2000 Mitchell Blank Jr.
+ * Based in part on work from Jens Axboe and Paul Mackerras.
+ * Updated to ppp-2.4.1 by Bernhard Kaindl
+ *
+ * Updated to ppp-2.4.2 by David Woodhouse 2004.
+ *  - disconnect method added
+ *  - remove_options() abuse removed.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "pppd.h"
+#include "pathnames.h"
+#include "fsm.h" /* Needed for lcp.h to include cleanly */
+#include "lcp.h"
+#include <atm.h>
+#include <linux/atmdev.h>
+#include <linux/atmppp.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+const char pppd_version[] = VERSION;
+
+static struct sockaddr_atmpvc pvcaddr;
+static char *qosstr = NULL;
+static bool llc_encaps = 0;
+static bool vc_encaps = 0;
+static int device_got_set = 0;
+static int pppoatm_max_mtu, pppoatm_max_mru;
+static int setdevname_pppoatm(const char *cp, const char **argv, int doit);
+struct channel pppoa_channel;
+static int pppoa_fd = -1;
+
+static option_t pppoa_options[] = {
+	{ "device name", o_wild, (void *) &setdevname_pppoatm,
+	  "ATM service provider IDs: VPI.VCI",
+	  OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG  | OPT_A2STRVAL | OPT_STATIC,
+	  devnam},
+	{ "llc-encaps", o_bool, &llc_encaps,
+	  "use LLC encapsulation for PPPoATM", 1},
+	{ "vc-encaps", o_bool, &vc_encaps,
+	  "use VC multiplexing for PPPoATM (default)", 1},
+	{ "qos", o_string, &qosstr,
+	  "set QoS for PPPoATM connection", 1},
+	{ NULL }
+};
+
+/* returns:
+ *  -1 if there's a problem with setting the device
+ *   0 if we can't parse "cp" as a valid name of a device
+ *   1 if "cp" is a reasonable thing to name a device
+ * Note that we don't actually open the device at this point
+ * We do need to fill in:
+ *   devnam: a string representation of the device
+ *   devstat: a stat structure of the device.  In this case
+ *     we're not opening a device, so we just make sure
+ *     to set up S_ISCHR(devstat.st_mode) != 1, so we
+ *     don't get confused that we're on stdin.
+ */
+int (*old_setdevname_hook)(const char* cp) = NULL;
+static int setdevname_pppoatm(const char *cp, const char **argv, int doit)
+{
+	struct sockaddr_atmpvc addr;
+	extern struct stat devstat;
+	if (device_got_set)
+		return 0;
+	//info("PPPoATM setdevname_pppoatm: '%s'", cp);
+	memset(&addr, 0, sizeof addr);
+	if (text2atm(cp, (struct sockaddr *) &addr, sizeof(addr),
+	    T2A_PVC | T2A_NAME) < 0) {
+               if(doit)
+                   info("atm does not recognize: %s", cp);
+		return 0;
+           }
+	if (!doit) return 1;
+	//if (!dev_set_ok()) return -1;
+	memcpy(&pvcaddr, &addr, sizeof pvcaddr);
+	strlcpy(devnam, cp, sizeof devnam);
+	devstat.st_mode = S_IFSOCK;
+	if (the_channel != &pppoa_channel) {
+		the_channel = &pppoa_channel;
+		lcp_wantoptions[0].neg_accompression = 0;
+		lcp_allowoptions[0].neg_accompression = 0;
+		lcp_wantoptions[0].neg_asyncmap = 0;
+		lcp_allowoptions[0].neg_asyncmap = 0;
+		lcp_wantoptions[0].neg_pcompression = 0;
+	}
+	info("PPPoATM setdevname_pppoatm - SUCCESS:%s", cp);
+	device_got_set = 1;
+	return 1;
+}
+
+#define pppoatm_overhead() (llc_encaps ? 6 : 2)
+
+static void no_device_given_pppoatm(void)
+{
+	fatal("No vpi.vci specified");
+}
+
+static void set_line_discipline_pppoatm(int fd)
+{
+	struct atm_backend_ppp be;
+	be.backend_num = ATM_BACKEND_PPP;
+	if (!llc_encaps)
+		be.encaps = PPPOATM_ENCAPS_VC;
+	else if (!vc_encaps)
+		be.encaps = PPPOATM_ENCAPS_LLC;
+	else
+		be.encaps = PPPOATM_ENCAPS_AUTODETECT;
+	if (ioctl(fd, ATM_SETBACKEND, &be) < 0)
+		fatal("ioctl(ATM_SETBACKEND): %m");
+}
+
+#if 0
+static void reset_line_discipline_pppoatm(int fd)
+{
+	atm_backend_t be = ATM_BACKEND_RAW;
+	/* 2.4 doesn't support this yet */
+	(void) ioctl(fd, ATM_SETBACKEND, &be);
+}
+#endif
+
+static int connect_pppoatm(void)
+{
+	int fd;
+	struct atm_qos qos;
+
+	system ("/sbin/modprobe pppoatm");
+
+	if (!device_got_set)
+		no_device_given_pppoatm();
+	fd = socket(AF_ATMPVC, SOCK_DGRAM, 0);
+	if (fd < 0)
+		fatal("failed to create socket: %m");
+	memset(&qos, 0, sizeof qos);
+	qos.txtp.traffic_class = qos.rxtp.traffic_class = ATM_UBR;
+	/* TODO: support simplified QoS setting */
+	if (qosstr != NULL)
+		if (text2qos(qosstr, &qos, 0))
+			fatal("Can't parse QoS: \"%s\"");
+	qos.txtp.max_sdu = lcp_allowoptions[0].mru + pppoatm_overhead();
+	qos.rxtp.max_sdu = lcp_wantoptions[0].mru + pppoatm_overhead();
+	qos.aal = ATM_AAL5;
+	if (setsockopt(fd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0)
+		fatal("setsockopt(SO_ATMQOS): %m");
+	/* TODO: accept on SVCs... */
+	if (connect(fd, (struct sockaddr *) &pvcaddr,
+	    sizeof(struct sockaddr_atmpvc)))
+		fatal("connect(%s): %m", devnam);
+	pppoatm_max_mtu = lcp_allowoptions[0].mru;
+	pppoatm_max_mru = lcp_wantoptions[0].mru;
+	set_line_discipline_pppoatm(fd);
+	strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+	pppoa_fd = fd;
+	return fd;
+}
+
+static void disconnect_pppoatm(void)
+{
+	close(pppoa_fd);
+}
+
+static void send_config_pppoa(int mtu,
+			      u_int32_t asyncmap,
+			      int pcomp,
+			      int accomp)
+{
+	int sock;
+	struct ifreq ifr;
+	if (mtu > pppoatm_max_mtu)
+		error("Couldn't increase MTU to %d", mtu);
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock < 0)
+		fatal("Couldn't create IP socket: %m");
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	ifr.ifr_mtu = mtu;
+	if (ioctl(sock, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+		fatal("ioctl(SIOCSIFMTU): %m");
+	(void) close (sock);
+}
+
+static void recv_config_pppoa(int mru,
+			      u_int32_t asyncmap,
+			      int pcomp,
+			      int accomp)
+{
+	if (mru > pppoatm_max_mru)
+		error("Couldn't increase MRU to %d", mru);
+}
+
+void plugin_init(void)
+{
+#if defined(__linux__)
+	extern int new_style_driver;	/* From sys-linux.c */
+	if (!ppp_available() && !new_style_driver)
+		fatal("Kernel doesn't support ppp_generic - "
+		    "needed for PPPoATM");
+#else
+	fatal("No PPPoATM support on this OS");
+#endif
+	info("PPPoATM plugin_init");
+	add_options(pppoa_options);
+}
+struct channel pppoa_channel = {
+    options: pppoa_options,
+    process_extra_options: NULL,
+    check_options: NULL,
+    connect: &connect_pppoatm,
+    disconnect: &disconnect_pppoatm,
+    establish_ppp: &generic_establish_ppp,
+    disestablish_ppp: &generic_disestablish_ppp,
+    send_config: &send_config_pppoa,
+    recv_config: &recv_config_pppoa,
+    close: NULL,
+    cleanup: NULL
+};
--- ppp-2.4.2/pppd/plugins/pppoatm/atmsap.h.atm1	2004-10-05 17:35:56.772702152 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/atmsap.h	2004-10-05 17:25:10.826900840 +0100
@@ -0,0 +1,45 @@
+/* atmsap.h - ATM Service Access Point addressing definitions */
+
+/* Written 1996-1998 by Werner Almesberger, EPFL LRC/ICA */
+
+
+#ifndef _ATMSAP_H
+#define _ATMSAP_H
+
+#include <stdint.h>
+#include <linux/atmsap.h>
+
+
+/*
+ * Selected ISO/IEC TR 9577 Network Layer Protocol Identifiers (NLPID)
+ */
+
+#define NLPID_IEEE802_1_SNAP	0x80	/* IEEE 802.1 SNAP */
+
+/*
+ * Selected Organizationally Unique Identifiers (OUIs)
+ */
+
+#define ATM_FORUM_OUI		"\x00\xA0\x3E"	/* ATM Forum */
+#define EPFL_OUI		"\x00\x60\xD7"	/* EPF Lausanne, CH */
+
+/*
+ * Selected vendor-specific application identifiers (for B-HLI). Such an
+ * identifier consists of three bytes containing the OUI, followed by four
+ * bytes assigned by the organization owning the OUI.
+ */
+
+#define ANS_HLT_VS_ID		ATM_FORUM_OUI "\x00\x00\x00\x01"
+					 /* ATM Name System, af-saa-0069.000 */
+#define VOD_HLT_VS_ID		ATM_FORUM_OUI "\x00\x00\x00\x02"
+						     /* VoD, af-saa-0049.001 */
+#define AREQUIPA_HLT_VS_ID	EPFL_OUI "\x01\x00\x00\x01"	/* Arequipa  */
+#define TTCP_HLT_VS_ID		EPFL_OUI "\x01\x00\x00\x03"	/* ttcp_atm */
+
+
+/* Mapping of "well-known" TCP, UDP, etc. port numbers to ATM BHLIs.
+   btd-saa-api-bhli-01.02 */
+
+void atm_tcpip_port_mapping(char *vs_id,uint8_t protocol,uint16_t port);
+
+#endif
--- ppp-2.4.2/pppd/plugins/pppoatm/atmres.h.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/atmres.h	2004-10-04 12:11:55.000000000 +0100
@@ -0,0 +1,36 @@
+/* atmres.h - Common definitions and prototypes for resolver functions */
+
+/* Written 1996,1998 by Werner Almesberger, EPFL-LRC/ICA */
+
+
+#ifndef _ATMRES_H
+#define _ATMRES_H
+
+#include <arpa/nameser.h>
+#include <linux/atm.h>
+
+
+/* Some #defines that may be needed if ANS isn't installed on that system */
+
+#ifndef T_ATMA
+#define T_ATMA		34
+#endif
+#ifndef ATMA_AESA
+#define ATMA_AESA	0
+#endif
+#ifndef ATMA_E164
+#define ATMA_E164	1
+#endif
+
+/* Return codes for text2atm and atm2text */
+
+#define TRY_OTHER -2
+#define FATAL	  -1 /* must be -1 */
+
+
+int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length,
+  int flags);
+int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr,
+  int flags);
+
+#endif
--- ppp-2.4.2/pppd/plugins/pppoatm/misc.c.atm1	2004-10-04 12:11:55.000000000 +0100
+++ ppp-2.4.2/pppd/plugins/pppoatm/misc.c	2004-10-04 12:11:55.000000000 +0100
@@ -0,0 +1,51 @@
+/* misc.c - Miscellaneous library functions */
+
+/* Written 1997-2000 by Werner Almesberger, EPFL-ICA/ICA */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h> /* for htons */
+
+#include <atm.h>
+#include <atmsap.h>
+
+
+int __atmlib_fetch(const char **pos,...)
+{
+    const char *value;
+    int ref_len,best_len,len;
+    int i,best;
+    va_list ap;
+
+    va_start(ap,pos);
+    ref_len = strlen(*pos);
+    best_len = 0;
+    best = -1;
+    for (i = 0; (value = va_arg(ap,const char *)); i++) {
+	len = strlen(value);
+	if (*value != '!' && len <= ref_len && len > best_len &&
+	  !strncasecmp(*pos,value,len)) {
+	    best = i;
+	    best_len = len;
+	}
+    }
+    va_end(ap);
+    if (best > -1) (*pos) += best_len;
+    return best;
+}
+
+
+void atm_tcpip_port_mapping(char *vs_id,uint8_t protocol,uint16_t port)
+{
+    memcpy(vs_id,ATM_FORUM_OUI "\x01",4);
+    vs_id[4] = protocol; /* e.g. IP_TCP or IP_UDP; from netinet/protocols.h */
+    vs_id[5] = (htons(port) >> 8) & 255;
+    vs_id[6] = htons(port) & 255;
+}