From dd41357657d1436fe20692aa43613ceae8e03fa0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 6 Nov 2004 11:36:54 +0000 Subject: [PATCH] New pppoatm plugin, sent in by David Woodhouse. --- README | 5 +- configure | 4 +- pppd/plugins/Makefile.linux | 2 +- pppd/plugins/pppoatm/COPYING | 7 + pppd/plugins/pppoatm/Makefile.linux | 44 +++++ pppd/plugins/pppoatm/ans.c | 262 ++++++++++++++++++++++++++++ pppd/plugins/pppoatm/atm.h | 108 ++++++++++++ pppd/plugins/pppoatm/atmres.h | 36 ++++ pppd/plugins/pppoatm/atmsap.h | 45 +++++ pppd/plugins/pppoatm/misc.c | 51 ++++++ pppd/plugins/pppoatm/pppoatm.c | 224 ++++++++++++++++++++++++ pppd/plugins/pppoatm/text2atm.c | 249 ++++++++++++++++++++++++++ pppd/plugins/pppoatm/text2qos.c | 180 +++++++++++++++++++ 13 files changed, 1213 insertions(+), 4 deletions(-) create mode 100644 pppd/plugins/pppoatm/COPYING create mode 100644 pppd/plugins/pppoatm/Makefile.linux create mode 100644 pppd/plugins/pppoatm/ans.c create mode 100644 pppd/plugins/pppoatm/atm.h create mode 100644 pppd/plugins/pppoatm/atmres.h create mode 100644 pppd/plugins/pppoatm/atmsap.h create mode 100644 pppd/plugins/pppoatm/misc.c create mode 100644 pppd/plugins/pppoatm/pppoatm.c create mode 100644 pppd/plugins/pppoatm/text2atm.c create mode 100644 pppd/plugins/pppoatm/text2qos.c diff --git a/README b/README index e03f6c4..e67b728 100644 --- 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 $) diff --git a/configure b/configure index 06e264b..8d2fc58 100755 --- 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 diff --git a/pppd/plugins/Makefile.linux b/pppd/plugins/Makefile.linux index 10bc4f0..e373700 100644 --- a/pppd/plugins/Makefile.linux +++ b/pppd/plugins/Makefile.linux @@ -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 index 0000000..16b2621 --- /dev/null +++ b/pppd/plugins/pppoatm/COPYING @@ -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 index 0000000..3a75161 --- /dev/null +++ b/pppd/plugins/pppoatm/Makefile.linux @@ -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 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 +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#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 index 0000000..3b15dda --- /dev/null +++ b/pppd/plugins/pppoatm/atm.h @@ -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 +#include +#include + + +/* + * 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 index 0000000..d5b3b8c --- /dev/null +++ b/pppd/plugins/pppoatm/atmres.h @@ -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 +#include + + +/* 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 index 0000000..aea0c8e --- /dev/null +++ b/pppd/plugins/pppoatm/atmsap.h @@ -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 +#include + + +/* + * 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 index 0000000..5e6975f --- /dev/null +++ b/pppd/plugins/pppoatm/misc.c @@ -0,0 +1,51 @@ +/* misc.c - Miscellaneous library functions */ + +/* Written 1997-2000 by Werner Almesberger, EPFL-ICA/ICA */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include /* for htons */ + +#include +#include + + +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 index 0000000..f99fd0a --- /dev/null +++ b/pppd/plugins/pppoatm/pppoatm.c @@ -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 +#include +#include +#include "pppd.h" +#include "pathnames.h" +#include "fsm.h" /* Needed for lcp.h to include cleanly */ +#include "lcp.h" +#include +#include +#include +#include +#include +#include + +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 index 0000000..c283b52 --- /dev/null +++ b/pppd/plugins/pppoatm/text2atm.c @@ -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 +#endif + +#include +#include +#include +#include + +#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 index 0000000..060407a --- /dev/null +++ b/pppd/plugins/pppoatm/text2qos.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#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; +} -- 2.39.2