]> git.ozlabs.org Git - ppp.git/commitdiff
New pppoatm plugin, sent in by David Woodhouse.
authorPaul Mackerras <paulus@samba.org>
Sat, 6 Nov 2004 11:36:54 +0000 (11:36 +0000)
committerPaul Mackerras <paulus@samba.org>
Sat, 6 Nov 2004 11:36:54 +0000 (11:36 +0000)
13 files changed:
README
configure
pppd/plugins/Makefile.linux
pppd/plugins/pppoatm/COPYING [new file with mode: 0644]
pppd/plugins/pppoatm/Makefile.linux [new file with mode: 0644]
pppd/plugins/pppoatm/ans.c [new file with mode: 0644]
pppd/plugins/pppoatm/atm.h [new file with mode: 0644]
pppd/plugins/pppoatm/atmres.h [new file with mode: 0644]
pppd/plugins/pppoatm/atmsap.h [new file with mode: 0644]
pppd/plugins/pppoatm/misc.c [new file with mode: 0644]
pppd/plugins/pppoatm/pppoatm.c [new file with mode: 0644]
pppd/plugins/pppoatm/text2atm.c [new file with mode: 0644]
pppd/plugins/pppoatm/text2qos.c [new file with mode: 0644]

diff --git a/README b/README
index e03f6c48eb5f480c2689f13c5c7634f1e512a46a..e67b72820634901185c1db7a38755233f5e79601 100644 (file)
--- a/README
+++ b/README
@@ -92,6 +92,9 @@ What's new in ppp-2.4.3.
   team, which provides the ability to authenticate the peer against an
   NT domain controller using MS-CHAP or MS-CHAPV2.
 
+* There is a new pppoatm plugin, by various authors, sent in by David
+  Woodhouse.
+
 
 What was new in ppp-2.4.2.
 **************************
@@ -245,4 +248,4 @@ The primary site for releases of this software is:
        ftp://ftp.samba.org/pub/ppp/
 
 
-($Id: README,v 1.32 2004/11/06 05:59:42 paulus Exp $)
+($Id: README,v 1.33 2004/11/06 11:36:54 paulus Exp $)
index 06e264ba1a9f06fea59aa158018c58fadad0076e..8d2fc58de249c37c222f1737dda52325f6216a2b 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Id: configure,v 1.34 2004/11/01 03:54:47 paulus Exp $
+# $Id: configure,v 1.35 2004/11/06 11:36:54 paulus Exp $
 
 # Where to install stuff by default
 DESTDIR=/usr/local
@@ -174,7 +174,7 @@ if [ -d "$ksrc" ]; then
     mkmkf $ksrc/Makefile.top Makefile
     mkmkf $ksrc/Makedefs$compiletype Makedefs.com
     for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/rp-pppoe \
-              pppd/plugins/radius; do
+              pppd/plugins/radius pppd/plugins/pppoatm; do
        mkmkf $dir/Makefile.$makext $dir/Makefile
     done
     if [ "$archvariant" ]; then
index 10bc4f0c7de9641045c57e5c68021783d32ced3a..e3737003a06cfb182ad6e0a4c4bc1e1ce668d8c2 100644 (file)
@@ -9,7 +9,7 @@ BINDIR = $(DESTDIR)/sbin
 MANDIR = $(DESTDIR)/share/man/man8
 LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
 
-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 winbind.so
diff --git a/pppd/plugins/pppoatm/COPYING b/pppd/plugins/pppoatm/COPYING
new file mode 100644 (file)
index 0000000..16b2621
--- /dev/null
@@ -0,0 +1,7 @@
+The files ans.c, atm.h, atmres.h, atmsap.h, misc.c, text2atm.c  and
+text2qos.c are taken from the linux-atm libraries.  These are 
+Copyright 1995-2000 EPFL-LRC/ICA, and are licensed under the GNU Lesser
+General Public License.
+
+The file pppoatm.c contains its own copyright notice, and is licensed
+under the GPL.
diff --git a/pppd/plugins/pppoatm/Makefile.linux b/pppd/plugins/pppoatm/Makefile.linux
new file mode 100644 (file)
index 0000000..3a75161
--- /dev/null
@@ -0,0 +1,44 @@
+CC     = gcc
+COPTS  = -O2 -g
+CFLAGS = $(COPTS) -I../.. -I../../../include -fPIC
+LDFLAGS        = -shared
+INSTALL        = install
+
+#***********************************************************************
+
+DESTDIR = @DESTDIR@
+LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
+
+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 $@ $<
diff --git a/pppd/plugins/pppoatm/ans.c b/pppd/plugins/pppoatm/ans.c
new file mode 100644 (file)
index 0000000..973eb33
--- /dev/null
@@ -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);
+    }
+}
diff --git a/pppd/plugins/pppoatm/atm.h b/pppd/plugins/pppoatm/atm.h
new file mode 100644 (file)
index 0000000..3b15dda
--- /dev/null
@@ -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
diff --git a/pppd/plugins/pppoatm/atmres.h b/pppd/plugins/pppoatm/atmres.h
new file mode 100644 (file)
index 0000000..d5b3b8c
--- /dev/null
@@ -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
diff --git a/pppd/plugins/pppoatm/atmsap.h b/pppd/plugins/pppoatm/atmsap.h
new file mode 100644 (file)
index 0000000..aea0c8e
--- /dev/null
@@ -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
diff --git a/pppd/plugins/pppoatm/misc.c b/pppd/plugins/pppoatm/misc.c
new file mode 100644 (file)
index 0000000..5e6975f
--- /dev/null
@@ -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;
+}
diff --git a/pppd/plugins/pppoatm/pppoatm.c b/pppd/plugins/pppoatm/pppoatm.c
new file mode 100644 (file)
index 0000000..f99fd0a
--- /dev/null
@@ -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
+};
diff --git a/pppd/plugins/pppoatm/text2atm.c b/pppd/plugins/pppoatm/text2atm.c
new file mode 100644 (file)
index 0000000..c283b52
--- /dev/null
@@ -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;
+}
diff --git a/pppd/plugins/pppoatm/text2qos.c b/pppd/plugins/pppoatm/text2qos.c
new file mode 100644 (file)
index 0000000..060407a
--- /dev/null
@@ -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;
+}