summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/rp-pppoe/src
diff options
context:
space:
mode:
authorGuillaume Cottenceau <gc@mandriva.com>2001-06-11 13:49:39 +0000
committerGuillaume Cottenceau <gc@mandriva.com>2001-06-11 13:49:39 +0000
commit0a121a8ecd6de894c14d60daf9da2022ec47405c (patch)
tree3705a0c51f96ffdd2a0594ef43a5677c926eb0cc /mdk-stage1/rp-pppoe/src
parentab5559aaabd1167a18ac882e64d97c5adc0e7d03 (diff)
downloaddrakx-backup-do-not-use-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar
drakx-backup-do-not-use-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar.gz
drakx-backup-do-not-use-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar.bz2
drakx-backup-do-not-use-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar.xz
drakx-backup-do-not-use-0a121a8ecd6de894c14d60daf9da2022ec47405c.zip
Initial revision
Diffstat (limited to 'mdk-stage1/rp-pppoe/src')
-rw-r--r--mdk-stage1/rp-pppoe/src/Makefile.in257
-rw-r--r--mdk-stage1/rp-pppoe/src/common.c485
-rw-r--r--mdk-stage1/rp-pppoe/src/config.h.in134
-rwxr-xr-xmdk-stage1/rp-pppoe/src/configure2356
-rw-r--r--mdk-stage1/rp-pppoe/src/configure.in231
-rw-r--r--mdk-stage1/rp-pppoe/src/debug.c143
-rw-r--r--mdk-stage1/rp-pppoe/src/discovery.c629
-rw-r--r--mdk-stage1/rp-pppoe/src/if.c1092
-rwxr-xr-xmdk-stage1/rp-pppoe/src/install-sh238
-rw-r--r--mdk-stage1/rp-pppoe/src/md5.c246
-rw-r--r--mdk-stage1/rp-pppoe/src/md5.h27
-rw-r--r--mdk-stage1/rp-pppoe/src/plugin.c397
-rw-r--r--mdk-stage1/rp-pppoe/src/ppp.c258
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe-server.c1247
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe-sniff.c258
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe.c834
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe.h331
-rw-r--r--mdk-stage1/rp-pppoe/src/relay.c1541
-rw-r--r--mdk-stage1/rp-pppoe/src/relay.h97
19 files changed, 10801 insertions, 0 deletions
diff --git a/mdk-stage1/rp-pppoe/src/Makefile.in b/mdk-stage1/rp-pppoe/src/Makefile.in
new file mode 100644
index 000000000..8eee012cb
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/Makefile.in
@@ -0,0 +1,257 @@
+# @configure_input@
+#***********************************************************************
+#
+# Makefile
+#
+# Makefile for Roaring Penguin's Linux user-space PPPoE client.
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# This program may be distributed according to the terms of the GNU
+# General Public License, version 2 or (at your option) any later version.
+#
+# $Id$
+#***********************************************************************
+
+# Version is set ONLY IN THE MAKEFILE! Don't delete this!
+VERSION=3.0
+
+DEFINES=
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+mandir=@mandir@
+docdir=@prefix@/doc/rp-pppoe-$(VERSION)
+install=@INSTALL@
+install_dir=@INSTALL@ -d
+sbindir=@sbindir@
+
+# Plugin for pppd on Linux
+LINUX_KERNELMODE_PLUGIN=@LINUX_KERNELMODE_PLUGIN@
+PPPD_INCDIR=@PPPD_INCDIR@
+
+# PPPoE relay -- currently only supported on Linux
+PPPOE_RELAY=@PPPOE_RELAY@
+
+# Program paths
+PPPOE_PATH=$(sbindir)/pppoe
+PPPD_PATH=@PPPD@
+
+# Kernel-mode plugin gets installed here.
+PLUGIN_DIR=/etc/ppp/plugins
+PLUGIN_PATH=$(PLUGIN_DIR)/rp-pppoe.so
+
+# Configuration file paths
+PPPOESERVER_PPPD_OPTIONS=/etc/ppp/pppoe-server-options
+
+PATHS='-DPPPOE_PATH="$(PPPOE_PATH)"' '-DPPPD_PATH="$(PPPD_PATH)"' \
+ '-DPLUGIN_PATH="$(PLUGIN_PATH)"' \
+ '-DPPPOE_SERVER_OPTIONS="$(PPPOESERVER_PPPD_OPTIONS)"'
+
+CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
+TARGETS=@TARGETS@
+
+all: $(TARGETS)
+ @echo ""
+ @echo "Type 'make install' as root to install the software."
+
+pppoe-sniff: pppoe-sniff.o if.o common.o debug.o
+ @CC@ -o pppoe-sniff pppoe-sniff.o if.o common.o debug.o $(LIBS)
+
+pppoe-server: pppoe-server.o if.o debug.o common.o md5.o
+ @CC@ -o pppoe-server pppoe-server.o if.o debug.o common.o md5.o $(LIBS)
+
+pppoe: pppoe.o if.o debug.o common.o ppp.o discovery.o
+ @CC@ -o pppoe pppoe.o if.o debug.o common.o ppp.o discovery.o $(LIBS)
+
+pppoe-relay: relay.o if.o debug.o common.o
+ @CC@ -o pppoe-relay relay.o if.o debug.o common.o $(LIBS)
+
+pppoe.o: pppoe.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe.o pppoe.c
+
+discovery.o: discovery.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o discovery.o discovery.c
+
+ppp.o: ppp.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o ppp.o ppp.c
+
+md5.o: md5.c md5.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o md5.o md5.c
+
+pppoe-server.o: pppoe-server.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-server.o pppoe-server.c
+
+pppoe-sniff.o: pppoe-sniff.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-sniff.o pppoe-sniff.c
+
+if.o: if.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o if.o if.c
+
+common.o: common.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o common.o common.c
+
+debug.o: debug.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o debug.o debug.c
+
+relay.o: relay.c relay.h pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o relay.o relay.c
+
+# Linux-specific plugin
+rp-pppoe.so: plugin/libplugin.a plugin/plugin.o
+ @CC@ -o rp-pppoe.so -shared plugin/plugin.o plugin/libplugin.a
+
+plugin/plugin.o: plugin.c
+ @CC@ '-DVERSION="$(VERSION)"' -I$(PPPD_INCDIR) -c -o plugin/plugin.o -fPIC plugin.c
+
+plugin/libplugin.a: plugin/discovery.o plugin/if.o plugin/common.o plugin/debug.o
+ ar -rc $@ $^
+
+plugin/discovery.o: discovery.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/discovery.o -fPIC discovery.c
+
+plugin/if.o: if.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/if.o -fPIC if.c
+
+plugin/debug.o: debug.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/debug.o -fPIC debug.c
+
+plugin/common.o: common.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/common.o -fPIC common.c
+
+install: all
+ -mkdir -p $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 -s pppoe $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 -s pppoe-server $(RPM_INSTALL_ROOT)$(sbindir)
+ if test -x pppoe-relay ; then $(install) -m 755 -s pppoe-relay $(RPM_INSTALL_ROOT)$(sbindir); fi
+ $(install) -m 755 -s pppoe-sniff $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-connect $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-start $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-status $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-stop $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-setup $(RPM_INSTALL_ROOT)$(sbindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/CHANGES $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/KERNEL-MODE-PPPOE $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/HOW-TO-CONNECT $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/LICENSE $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../README $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../configs/pap-secrets $(RPM_INSTALL_ROOT)$(docdir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man8
+ for i in $(TARGETS) ; do \
+ if test -f ../man/$$i.8 ; then \
+ $(install) -m 644 ../man/$$i.8 $(RPM_INSTALL_ROOT)$(mandir)/man8 || exit 1; \
+ fi; \
+ done
+ $(install) -m 644 ../man/adsl-start.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-stop.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-status.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-connect.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-setup.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man5
+ $(install) -m 644 ../man/pppoe.conf.5 $(RPM_INSTALL_ROOT)$(mandir)/man5
+ -mkdir -p $(RPM_INSTALL_ROOT)/etc/ppp
+ -mkdir -p $(RPM_INSTALL_ROOT)$(PLUGIN_DIR)
+ -echo "# Directory created by rp-pppoe for kernel-mode plugin" > $(RPM_INSTALL_ROOT)$(PLUGIN_DIR)/README
+ @if test -r rp-pppoe.so; then $(install) -m 755 rp-pppoe.so $(RPM_INSTALL_ROOT)$(PLUGIN_DIR); fi
+ @for i in pppoe.conf firewall-standalone firewall-masq ; do \
+ if [ ! -f $(RPM_INSTALL_ROOT)/etc/ppp/$$i ] ; then \
+ $(install) -m 644 ../configs/$$i $(RPM_INSTALL_ROOT)/etc/ppp ; \
+ else \
+ echo "NOT overwriting existing $(RPM_INSTALL_ROOT)/etc/ppp/$$i" ;\
+ $(install) -m 644 ../configs/$$i $(RPM_INSTALL_ROOT)/etc/ppp/$$i-$(VERSION) ;\
+ fi ;\
+ done
+ @if [ ! -f $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS) ] ; then \
+ $(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS) ; \
+ else \
+ echo "NOT overwriting existing $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)"; \
+ $(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)-example ; \
+ fi
+ @if [ -f /etc/redhat-release ] ; then \
+ echo "Looks like a Red Hat system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
+ $(install) -m 755 ../scripts/adsl-init $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
+ fi
+ @if [ -f /etc/turbolinux-release ] ; then \
+ echo "Looks like a TurboLinux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
+ $(install) -m 755 adsl-init-turbolinux $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
+ fi
+ @if [ -f /etc/SuSE-release ] ; then \
+ echo "Looks like a SuSE Linux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
+ $(install) -m 755 ../scripts/adsl-init-suse $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
+ fi
+ @echo ""
+ @echo "Type 'adsl-setup' to configure the software."
+
+distro:
+ cd ..; \
+ rm -rf rp-pppoe-$(VERSION) ; \
+ mkdir rp-pppoe-$(VERSION) || exit 1; \
+ for i in README go go-gui rp-pppoe.spec rp-pppoe-gui.spec; do \
+ cp $$i rp-pppoe-$(VERSION) || exit 1; \
+ done ; \
+ mkdir rp-pppoe-$(VERSION)/gui || exit 1; \
+ for i in Makefile.in tkpppoe.in wrapper.c tkpppoe.1 pppoe-wrapper.1 ; do \
+ cp gui/$$i rp-pppoe-$(VERSION)/gui || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/gui/html || exit 1; \
+ for i in mainwin-busy.png mainwin-nonroot.png mainwin.png props-advanced.png props-basic.png props-nic.png props-options.png tkpppoe.html ; do \
+ cp gui/html/$$i rp-pppoe-$(VERSION)/gui/html || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/configs || exit 1; \
+ for i in firewall-masq firewall-standalone pap-secrets pppoe-server-options pppoe.conf ; do \
+ cp configs/$$i rp-pppoe-$(VERSION)/configs || exit 1; \
+ done ; \
+ mkdir rp-pppoe-$(VERSION)/doc || exit 1; \
+ for i in CHANGES KERNEL-MODE-PPPOE HOW-TO-CONNECT LICENSE PROBLEMS ; do \
+ cp doc/$$i rp-pppoe-$(VERSION)/doc || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/man || exit 1; \
+ for i in adsl-connect.8 adsl-setup.8 adsl-start.8 adsl-status.8 adsl-stop.8 pppoe-server.8 pppoe-sniff.8 pppoe.8 pppoe-relay.8 pppoe.conf.5 ; do \
+ cp man/$$i rp-pppoe-$(VERSION)/man || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/scripts || exit 1; \
+ for i in adsl-connect.in adsl-init-suse.in adsl-init-turbolinux.in adsl-init.in adsl-setup.in adsl-start.in adsl-stop.in adsl-status ; do \
+ cp scripts/$$i rp-pppoe-$(VERSION)/scripts || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/src || exit 1; \
+ for i in Makefile.in install-sh common.c config.h.in configure configure.in debug.c discovery.c if.c md5.c md5.h ppp.c pppoe-server.c pppoe-sniff.c pppoe.c pppoe.h plugin.c relay.c relay.h ; do \
+ cp src/$$i rp-pppoe-$(VERSION)/src || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/src/plugin || exit 1; \
+ tar cvf rp-pppoe-$(VERSION).tar rp-pppoe-$(VERSION)/* ; \
+ gzip -f -v -9 rp-pppoe-$(VERSION).tar ; \
+
+rpms: distro
+ cp ../rp-pppoe-$(VERSION).tar.gz /usr/src/redhat/SOURCES
+ cd ..; \
+ rpm -ba rp-pppoe.spec; \
+ rpm -ba rp-pppoe-gui.spec
+
+clean:
+ rm -f *.o pppoe pppoe-sniff pppoe-server core rp-pppoe.so plugin/*.o plugin/libplugin.a *~
+
+distclean: clean
+ rm -f Makefile config.h config.cache config.log config.status
+ rm -f ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-setup ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux
+
+update-version:
+ sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe.spec > ../rp-pppoe.spec.new && mv ../rp-pppoe.spec.new ../rp-pppoe.spec
+ sed -e 's+^Source: .*$$+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION).tar.gz+' ../rp-pppoe.spec > ../rp-pppoe.spec.new && mv ../rp-pppoe.spec.new ../rp-pppoe.spec
+ sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+ sed -e 's+^Source: .*$$+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION).tar.gz+' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+ sed -e 's+^Requires: rp-pppoe >=.*$$+Requires: rp-pppoe >= $(VERSION)+' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+
+# Convenience target for David! Don't try to use this one.
+km:
+ ./configure --enable-plugin=/home/dfs/Archive/PPP/ppp-2.4.0.pppoe4-patched-dfs
+
+.PHONY: update-version
+
+.PHONY: clean
+
+.PHONY: distclean
+
+.PHONY: rpms
diff --git a/mdk-stage1/rp-pppoe/src/common.c b/mdk-stage1/rp-pppoe/src/common.c
new file mode 100644
index 000000000..b27302104
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/common.c
@@ -0,0 +1,485 @@
+/***********************************************************************
+*
+* common.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Common functions used by PPPoE client and server
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/**********************************************************************
+*%FUNCTION: parsePacket
+*%ARGUMENTS:
+* packet -- the PPPoE discovery packet to parse
+* func -- function called for each tag in the packet
+* extra -- an opaque data pointer supplied to parsing function
+*%RETURNS:
+* 0 if everything went well; -1 if there was an error
+*%DESCRIPTION:
+* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
+* "func" is passed the additional argument "extra".
+***********************************************************************/
+int
+parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
+{
+ UINT16_t len = ntohs(packet->length);
+ unsigned char *curTag;
+ UINT16_t tagType, tagLen;
+
+ if (packet->ver != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
+ return -1;
+ }
+ if (packet->type != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
+ return -1;
+ }
+
+ /* Do some sanity checks on packet */
+ if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+ syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
+ return -1;
+ }
+
+ /* Step through the tags */
+ curTag = packet->payload;
+ while(curTag - packet->payload < len) {
+ /* Alignment is not guaranteed, so do this by hand... */
+ tagType = (((UINT16_t) curTag[0]) << 8) +
+ (UINT16_t) curTag[1];
+ tagLen = (((UINT16_t) curTag[2]) << 8) +
+ (UINT16_t) curTag[3];
+ if (tagType == TAG_END_OF_LIST) {
+ return 0;
+ }
+ if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+ syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
+ return -1;
+ }
+ func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
+ curTag = curTag + TAG_HDR_SIZE + tagLen;
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: findTag
+*%ARGUMENTS:
+* packet -- the PPPoE discovery packet to parse
+* type -- the type of the tag to look for
+* tag -- will be filled in with tag contents
+*%RETURNS:
+* A pointer to the tag if one of the specified type is found; NULL
+* otherwise.
+*%DESCRIPTION:
+* Looks for a specific tag type.
+***********************************************************************/
+unsigned char *
+findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag)
+{
+ UINT16_t len = ntohs(packet->length);
+ unsigned char *curTag;
+ UINT16_t tagType, tagLen;
+
+ if (packet->ver != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
+ return NULL;
+ }
+ if (packet->type != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
+ return NULL;
+ }
+
+ /* Do some sanity checks on packet */
+ if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+ syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
+ return NULL;
+ }
+
+ /* Step through the tags */
+ curTag = packet->payload;
+ while(curTag - packet->payload < len) {
+ /* Alignment is not guaranteed, so do this by hand... */
+ tagType = (((UINT16_t) curTag[0]) << 8) +
+ (UINT16_t) curTag[1];
+ tagLen = (((UINT16_t) curTag[2]) << 8) +
+ (UINT16_t) curTag[3];
+ if (tagType == TAG_END_OF_LIST) {
+ return NULL;
+ }
+ if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+ syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
+ return NULL;
+ }
+ if (tagType == type) {
+ memcpy(tag, curTag, tagLen + TAG_HDR_SIZE);
+ return curTag;
+ }
+ curTag = curTag + TAG_HDR_SIZE + tagLen;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+*%FUNCTION: printErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog.
+***********************************************************************/
+void
+printErr(char const *str)
+{
+ fprintf(stderr, "pppoe: %s\n", str);
+ syslog(LOG_ERR, "%s", str);
+}
+
+
+/**********************************************************************
+*%FUNCTION: strDup
+*%ARGUMENTS:
+* str -- string to copy
+*%RETURNS:
+* A malloc'd copy of str. Exits if malloc fails.
+***********************************************************************/
+char *
+strDup(char const *str)
+{
+ char *copy = malloc(strlen(str)+1);
+ if (!copy) {
+ rp_fatal("strdup failed");
+ }
+ strcpy(copy, str);
+ return copy;
+}
+
+/**********************************************************************
+*%FUNCTION: computeTCPChecksum
+*%ARGUMENTS:
+* ipHdr -- pointer to IP header
+* tcpHdr -- pointer to TCP header
+*%RETURNS:
+* The computed TCP checksum
+***********************************************************************/
+UINT16_t
+computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr)
+{
+ UINT32_t sum = 0;
+ UINT16_t count = ipHdr[2] * 256 + ipHdr[3];
+ unsigned char *addr = tcpHdr;
+ unsigned char pseudoHeader[12];
+
+ /* Count number of bytes in TCP header and data */
+ count -= (ipHdr[0] & 0x0F) * 4;
+
+ memcpy(pseudoHeader, ipHdr+12, 8);
+ pseudoHeader[8] = 0;
+ pseudoHeader[9] = ipHdr[9];
+ pseudoHeader[10] = (count >> 8) & 0xFF;
+ pseudoHeader[11] = (count & 0xFF);
+
+ /* Checksum the pseudo-header */
+ sum += * (UINT16_t *) pseudoHeader;
+ sum += * ((UINT16_t *) (pseudoHeader+2));
+ sum += * ((UINT16_t *) (pseudoHeader+4));
+ sum += * ((UINT16_t *) (pseudoHeader+6));
+ sum += * ((UINT16_t *) (pseudoHeader+8));
+ sum += * ((UINT16_t *) (pseudoHeader+10));
+
+ /* Checksum the TCP header and data */
+ while (count > 1) {
+ sum += * (UINT16_t *) addr;
+ addr += 2;
+ count -= 2;
+ }
+ if (count > 0) {
+ sum += *addr;
+ }
+
+ while(sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+ return (UINT16_t) (~sum & 0xFFFF);
+}
+
+/**********************************************************************
+*%FUNCTION: clampMSS
+*%ARGUMENTS:
+* packet -- PPPoE session packet
+* dir -- either "incoming" or "outgoing"
+* clampMss -- clamp value
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Clamps MSS option if TCP SYN flag is set.
+***********************************************************************/
+void
+clampMSS(PPPoEPacket *packet, char const *dir, int clampMss)
+{
+ unsigned char *tcpHdr;
+ unsigned char *ipHdr;
+ unsigned char *opt;
+ unsigned char *endHdr;
+ unsigned char *mssopt = NULL;
+ UINT16_t csum;
+
+ int len;
+
+ /* Is it IPv4? */
+ if (packet->payload[0] != 0x00 ||
+ packet->payload[1] != 0x21) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ ipHdr = packet->payload + 2;
+
+ /* Is it too short? */
+ len = (int) ntohs(packet->length);
+ if (len < 42) {
+ /* 20 byte IP header; 20 byte TCP header; 2 byte PPP protocol */
+ return;
+ }
+
+ /* Verify once more that it's IPv4 */
+ if ((ipHdr[0] & 0xF0) != 0x40) {
+ return;
+ }
+
+ /* Is it a fragment that's not at the beginning of the packet? */
+ if ((ipHdr[6] & 0x1F) || ipHdr[7]) {
+ /* Yup, don't touch! */
+ return;
+ }
+ /* Is it TCP? */
+ if (ipHdr[9] != 0x06) {
+ return;
+ }
+
+ /* Get start of TCP header */
+ tcpHdr = ipHdr + (ipHdr[0] & 0x0F) * 4;
+
+ /* Is SYN set? */
+ if (!(tcpHdr[13] & 0x02)) {
+ return;
+ }
+
+ /* Compute and verify TCP checksum -- do not touch a packet with a bad
+ checksum */
+ csum = computeTCPChecksum(ipHdr, tcpHdr);
+ if (csum) {
+ syslog(LOG_ERR, "Bad TCP checksum %x", (unsigned int) csum);
+
+ /* Upper layers will drop it */
+ return;
+ }
+
+ /* Look for existing MSS option */
+ endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2);
+ opt = tcpHdr + 20;
+ while (opt < endHdr) {
+ if (!*opt) break; /* End of options */
+ switch(*opt) {
+ case 1:
+ opt++;
+ break;
+
+ case 2:
+ if (opt[1] != 4) {
+ /* Something fishy about MSS option length. */
+ syslog(LOG_ERR,
+ "Bogus length for MSS option (%u) from %u.%u.%u.%u",
+ (unsigned int) opt[1],
+ (unsigned int) ipHdr[12],
+ (unsigned int) ipHdr[13],
+ (unsigned int) ipHdr[14],
+ (unsigned int) ipHdr[15]);
+ return;
+ }
+ mssopt = opt;
+ break;
+ default:
+ if (opt[1] < 2) {
+ /* Someone's trying to attack us? */
+ syslog(LOG_ERR,
+ "Bogus TCP option length (%u) from %u.%u.%u.%u",
+ (unsigned int) opt[1],
+ (unsigned int) ipHdr[12],
+ (unsigned int) ipHdr[13],
+ (unsigned int) ipHdr[14],
+ (unsigned int) ipHdr[15]);
+ return;
+ }
+ opt += (opt[1]);
+ break;
+ }
+ /* Found existing MSS option? */
+ if (mssopt) break;
+ }
+
+ /* If MSS exists and it's low enough, do nothing */
+ if (mssopt) {
+ unsigned mss = mssopt[2] * 256 + mssopt[3];
+ if (mss <= clampMss) {
+ return;
+ }
+
+ mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF;
+ mssopt[3] = ((unsigned) clampMss) & 0xFF;
+ } else {
+ /* No MSS option. Don't add one; we'll have to use 536. */
+ return;
+ }
+
+ /* Recompute TCP checksum */
+ tcpHdr[16] = 0;
+ tcpHdr[17] = 0;
+ csum = computeTCPChecksum(ipHdr, tcpHdr);
+ (* (UINT16_t *) (tcpHdr+16)) = csum;
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADT
+*%ARGUMENTS:
+* conn -- PPPoE connection
+* msg -- if non-NULL, extra error message to include in PADT packet.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADT packet
+***********************************************************************/
+void
+sendPADT(PPPoEConnection *conn, char const *msg)
+{
+ PPPoEPacket packet;
+ unsigned char *cursor = packet.payload;
+
+ UINT16_t plen = 0;
+
+ /* Do nothing if no session established yet */
+ if (!conn->session) return;
+
+ /* Do nothing if no discovery socket */
+ if (conn->discoverySocket < 0) return;
+
+ memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_PADT;
+ packet.session = conn->session;
+
+ /* Reset Session to zero so there is no possibility of
+ recursive calls to this function by any signal handler */
+ conn->session = 0;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->useHostUniq) {
+ PPPoETag hostUniq;
+ pid_t pid = getpid();
+ hostUniq.type = htons(TAG_HOST_UNIQ);
+ hostUniq.length = htons(sizeof(pid));
+ memcpy(hostUniq.payload, &pid, sizeof(pid));
+ memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+ cursor += sizeof(pid) + TAG_HDR_SIZE;
+ plen += sizeof(pid) + TAG_HDR_SIZE;
+ }
+
+ /* Copy error message */
+ if (msg) {
+ PPPoETag err;
+ size_t elen = strlen(msg);
+ err.type = htons(TAG_GENERIC_ERROR);
+ err.length = htons(elen);
+ strcpy(err.payload, msg);
+ memcpy(cursor, &err, elen + TAG_HDR_SIZE);
+ cursor += elen + TAG_HDR_SIZE;
+ plen += elen + TAG_HDR_SIZE;
+ }
+
+ /* Copy cookie and relay-ID if needed */
+ if (conn->cookie.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ }
+
+ if (conn->relayId.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+ syslog(LOG_INFO,"Sent PADT");
+}
+
+/**********************************************************************
+*%FUNCTION: parseLogErrs
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks error tags out of a packet and logs them.
+***********************************************************************/
+void
+parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_SERVICE_NAME_ERROR:
+ syslog(LOG_ERR, "PADT: Service-Name-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADT: Service-Name-Error: %.*s\n", (int) len, data);
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ syslog(LOG_ERR, "PADT: System-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADT: System-Error: %.*s\n", (int) len, data);
+ break;
+ case TAG_GENERIC_ERROR:
+ syslog(LOG_ERR, "PADT: Generic-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADT: Generic-Error: %.*s\n", (int) len, data);
+ break;
+ }
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/config.h.in b/mdk-stage1/rp-pppoe/src/config.h.in
new file mode 100644
index 000000000..e3340389d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/config.h.in
@@ -0,0 +1,134 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define if the setvbuf function takes the buffering type as its second
+ argument and the buffer pointer as the third, as on System V
+ before release 3. */
+#undef SETVBUF_REVERSED
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm. */
+#undef TM_IN_SYS_TIME
+
+#undef HAVE_STRUCT_SOCKADDR_LL
+
+/* The number of bytes in a unsigned int. */
+#undef SIZEOF_UNSIGNED_INT
+
+/* The number of bytes in a unsigned long. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* The number of bytes in a unsigned short. */
+#undef SIZEOF_UNSIGNED_SHORT
+
+/* Define if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strtol function. */
+#undef HAVE_STRTOL
+
+/* Define if you have the <asm/types.h> header file. */
+#undef HAVE_ASM_TYPES_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <linux/if_ether.h> header file. */
+#undef HAVE_LINUX_IF_ETHER_H
+
+/* Define if you have kernel-mode PPPoE in Linux file. */
+#undef HAVE_LINUX_KERNEL_PPPOE
+
+/* Define if you have the <linux/if_packet.h> header file. */
+#undef HAVE_LINUX_IF_PACKET_H
+
+/* Define if you have the <linux/if_pppox.h> header file. */
+#undef HAVE_LINUX_IF_PPPOX_H
+
+/* Define if you have the <net/bpf.h> header file. */
+#undef HAVE_NET_BPF_H
+
+/* Define if you have the <net/if_arp.h> header file. */
+#undef HAVE_NET_IF_ARP_H
+
+/* Define if you have the <net/ethernet.h> header file. */
+#undef HAVE_NET_ETHERNET_H
+
+/* Define if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define if you have the <linux/if.h> header file. */
+#undef HAVE_LINUX_IF_H
+
+/* Define if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define if you have the <net/if_ether.h> header file. */
+#undef HAVE_NET_IF_ETHER_H
+
+/* Define if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define if you have the <netinet/if_ether.h> header file. */
+#undef HAVE_NETINET_IF_ETHER_H
+
+/* Define if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define if you have the <sys/dlpi.h> header file. */
+#undef HAVE_SYS_DLPI_H
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the N_HDLC line discipline in linux/termios.h */
+#undef HAVE_N_HDLC
+
+/* Define if bitfields are packed in reverse order */
+#undef PACK_BITFIELDS_REVERSED
diff --git a/mdk-stage1/rp-pppoe/src/configure b/mdk-stage1/rp-pppoe/src/configure
new file mode 100755
index 000000000..eede451a1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/configure
@@ -0,0 +1,2356 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_default_prefix=/usr
+ac_help="$ac_help
+ --enable-plugin=pppd_src_path build pppd plugin"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=pppoe.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:536: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:566: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:617: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 660 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:665: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:691: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:696: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:705: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:724: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:758: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 773 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:779: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 790 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:796: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 807 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:813: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:838: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 843 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 868 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 886 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 907 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:942: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 947 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:963: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h net/if_arp.h netinet/if_ether.h getopt.h sys/uio.h sys/param.h fcntl.h net/bpf.h netpacket/packet.h net/ethernet.h asm/types.h linux/if_packet.h linux/if_ether.h linux/if_pppox.h sys/socket.h sys/cdefs.h linux/if.h net/if.h net/if_dl.h net/if_ether.h net/if_types.h netinet/if_ether.h net/if_types.h net/if_dl.h sys/dlpi.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:987: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 992 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:997: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1025: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1030 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1100: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1105 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1133: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1138 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1147: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1168: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1173 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1181: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_tm=time.h
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+ cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+# Extract the first word of "echo", so it can be a program name with args.
+set dummy echo; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1205: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ECHO'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$ECHO" in
+ /*)
+ ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_ECHO="$ECHO" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="/usr/ucb/bin:$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_ECHO="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_ECHO" && ac_cv_path_ECHO=""""
+ ;;
+esac
+fi
+ECHO="$ac_cv_path_ECHO"
+if test -n "$ECHO"; then
+ echo "$ac_t""$ECHO" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+$ECHO -n "checking for struct sockaddr_ll... "
+cat > conftest.$ac_ext <<EOF
+#line 1241 "configure"
+#include "confdefs.h"
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+
+int main() {
+struct sockaddr_ll sa;
+; return 0; }
+EOF
+if { (eval echo configure:1251: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_sockaddr_ll=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_sockaddr_ll=no
+fi
+rm -f conftest*
+$ECHO $ac_cv_struct_sockaddr_ll
+if test "$ac_cv_struct_sockaddr_ll" = yes ; then
+cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_SOCKADDR_LL 1
+EOF
+
+fi
+
+$ECHO -n "checking for N_HDLC line discipline... "
+cat > conftest.$ac_ext <<EOF
+#line 1271 "configure"
+#include "confdefs.h"
+#include <linux/termios.h>
+int main() {
+int x = N_HDLC;
+; return 0; }
+EOF
+if { (eval echo configure:1278: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_n_hdlc=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_n_hdlc=no
+fi
+rm -f conftest*
+$ECHO $ac_cv_n_hdlc
+if test "$ac_cv_n_hdlc" = yes ; then
+cat >> confdefs.h <<\EOF
+#define HAVE_N_HDLC 1
+EOF
+
+fi
+
+# Check whether --enable-plugin or --disable-plugin was given.
+if test "${enable_plugin+set}" = set; then
+ enableval="$enable_plugin"
+ ac_cv_pluginpath=$enableval
+else
+ ac_cv_pluginpath=no
+fi
+
+
+LINUX_KERNELMODE_PLUGIN=""
+PPPD_INCDIR=""
+if test "$ac_cv_header_linux_if_pppox_h" = yes ; then
+ if test "$ac_cv_pluginpath" != no ; then
+ LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
+ PPPD_INCDIR=$ac_cv_pluginpath
+ fi
+fi
+
+
+
+
+PPPOE_RELAY=""
+if test "`uname -s`" = "Linux" ; then
+ PPPOE_RELAY=pppoe-relay
+fi
+
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:1324: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_memcmp_clean=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1332 "configure"
+#include "confdefs.h"
+
+main()
+{
+ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+ exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:1342: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_memcmp_clean=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
+test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+
+echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6
+echo "configure:1360: checking whether setvbuf arguments are reversed" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1368 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+/* If setvbuf has the reversed format, exit 0. */
+main () {
+ /* This call has the arguments reversed.
+ A reversed system may check and see that the address of main
+ is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */
+ if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0)
+ exit(1);
+ putc('\r', stdout);
+ exit(0); /* Non-reversed systems segv here. */
+}
+EOF
+if { (eval echo configure:1382: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_setvbuf_reversed=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_setvbuf_reversed=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6
+if test $ac_cv_func_setvbuf_reversed = yes; then
+ cat >> confdefs.h <<\EOF
+#define SETVBUF_REVERSED 1
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1406: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1411 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1428: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+for ac_func in select socket strerror strtol
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1449: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1454 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1477: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1532: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+echo $ac_n "checking size of unsigned short""... $ac_c" 1>&6
+echo "configure:1586: checking size of unsigned short" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_short'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1594 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(unsigned short));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_unsigned_short=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_unsigned_short=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_short" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short
+EOF
+
+
+echo $ac_n "checking size of unsigned int""... $ac_c" 1>&6
+echo "configure:1625: checking size of unsigned int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_int'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1633 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(unsigned int));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1644: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_unsigned_int=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_unsigned_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int
+EOF
+
+
+echo $ac_n "checking size of unsigned long""... $ac_c" 1>&6
+echo "configure:1664: checking size of unsigned long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_long'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1672 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(unsigned long));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1683: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_unsigned_long=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_unsigned_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+EOF
+
+
+
+# Extract the first word of "pppd", so it can be a program name with args.
+set dummy pppd; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1706: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PPPD'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$PPPD" in
+ /*)
+ ac_cv_path_PPPD="$PPPD" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_PPPD="$PPPD" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_PPPD="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_PPPD" && ac_cv_path_PPPD="NOTFOUND"
+ ;;
+esac
+fi
+PPPD="$ac_cv_path_PPPD"
+if test -n "$PPPD"; then
+ echo "$ac_t""$PPPD" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "setsid", so it can be a program name with args.
+set dummy setsid; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1743: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SETSID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$SETSID" in
+ /*)
+ ac_cv_path_SETSID="$SETSID" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_SETSID="$SETSID" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_SETSID="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_SETSID" && ac_cv_path_SETSID=""""
+ ;;
+esac
+fi
+SETSID="$ac_cv_path_SETSID"
+if test -n "$SETSID"; then
+ echo "$ac_t""$SETSID" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "id", so it can be a program name with args.
+set dummy id; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1780: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$ID" in
+ /*)
+ ac_cv_path_ID="$ID" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_ID="$ID" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="/usr/xpg4/bin:$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_ID="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_ID" && ac_cv_path_ID=""""
+ ;;
+esac
+fi
+ID="$ac_cv_path_ID"
+if test -n "$ID"; then
+ echo "$ac_t""$ID" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+$ECHO -n "checking for Linux 2.4.X kernel-mode PPPoE support..."
+if test "`uname -s`" = "Linux" ; then
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1820 "configure"
+#include "confdefs.h"
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+int main()
+{
+ if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) >= 0) return 0; else return 1;
+}
+
+EOF
+if { (eval echo configure:1832: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_linux_kernel_pppoe=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_linux_kernel_pppoe=no
+fi
+rm -fr conftest*
+fi
+
+else
+ ac_cv_linux_kernel_pppoe=no
+fi
+
+$ECHO $ac_cv_linux_kernel_pppoe
+if test "$ac_cv_linux_kernel_pppoe" = yes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_LINUX_KERNEL_PPPOE 1
+EOF
+
+fi
+
+if test "$GCC" = yes; then
+ CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -ansi -pedantic"
+fi
+
+if test "$PPPD" = "NOTFOUND"; then
+ $ECHO ""
+ $ECHO "*** Oops! I couldn't find pppd, the PPP daemon anywhere."
+ $ECHO "*** You must install pppd, version 2.3.10 or later."
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+fi
+
+
+PPPD_VERSION=`$PPPD --version 2>&1 | awk '{print $NF}'`
+
+case "$PPPD_VERSION" in
+1.*|2.0.*|2.1.*|2.2.*|2.3.0|2.3.1|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6)
+ $ECHO ""
+ $ECHO "*** Oops! Your version of pppd is $PPPD_VERSION, which is too old."
+ $ECHO "*** You need at least 2.3.7 (2.3.10 or newer recommended.)"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+
+2.3.7|2.3.8|2.3.9)
+ $ECHO ""
+ $ECHO "*** Warning. Your version of pppd is $PPPD_VERSION. You will"
+ $ECHO "*** not be able to use connect-on-demand. Upgrade to pppd"
+ $ECHO "*** 2.3.10 or newer if you need connect-on-demand."
+ $ECHO ""
+ ;;
+
+2*|3*|4*|5*|6*|7*|8*|9*)
+ ;;
+
+*)
+ $ECHO ""
+ $ECHO "*** Oops. I cannot figure out what version of pppd you have."
+ $ECHO "*** All I got back was '$PPPD_VERSION'"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+esac
+
+$ECHO -n "checking packing order of bit fields... "
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1905 "configure"
+#include "confdefs.h"
+
+union foo {
+ struct bar {
+ unsigned int ver:4;
+ unsigned int type:4;
+ } bb;
+ unsigned char baz;
+};
+
+int
+main(void)
+{
+ union foo x;
+ x.bb.ver = 1;
+ x.bb.type = 2;
+ if (x.baz == 0x21) {
+ return 1;
+ } else if (x.baz == 0x12) {
+ return 0;
+ } else {
+ return 2;
+ }
+}
+EOF
+if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ PACK=normal
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ PACK=rev
+fi
+rm -fr conftest*
+fi
+
+
+if test "$PACK" = "rev" ; then
+ $ECHO "reversed"
+ cat >> confdefs.h <<\EOF
+#define PACK_BITFIELDS_REVERSED 1
+EOF
+
+else
+ $ECHO "normal"
+fi
+
+# Sigh... got to fix this up for tcl
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Fully resolve WRAPPER for Tcl script.
+WRAPPER=${sbindir}/pppoe-wrapper
+eval "WRAPPER=${WRAPPER}"
+eval "WRAPPER=${WRAPPER}"
+
+
+# Determine what targets to build
+TARGETS="pppoe pppoe-server"
+
+# pppoe-sniff is built only on Linux and Solaris
+if test "$ac_cv_header_linux_if_packet_h" = "yes" -o "$ac_cv_header_sys_dlpi_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-sniff"
+fi
+
+# pppoe-relay is built only on Linux
+if test "$ac_cv_header_linux_if_packet_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-relay"
+fi
+
+# plugin is built only if we have kernel support
+if test -n "$LINUX_KERNELMODE_PLUGIN" ; then
+ TARGETS="$TARGETS $LINUX_KERNELMODE_PLUGIN"
+fi
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@ECHO@%$ECHO%g
+s%@LINUX_KERNELMODE_PLUGIN@%$LINUX_KERNELMODE_PLUGIN%g
+s%@PPPD_INCDIR@%$PPPD_INCDIR%g
+s%@PPPOE_RELAY@%$PPPOE_RELAY%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PPPD@%$PPPD%g
+s%@SETSID@%$SETSID%g
+s%@ID@%$ID%g
+s%@WRAPPER@%$WRAPPER%g
+s%@TARGETS@%$TARGETS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+$ECHO ""
+$ECHO "On this platform, the following targets will be built:"
+$ECHO " $TARGETS"
+$ECHO ""
+$ECHO "Type 'make' to compile the software."
diff --git a/mdk-stage1/rp-pppoe/src/configure.in b/mdk-stage1/rp-pppoe/src/configure.in
new file mode 100644
index 000000000..c11690179
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/configure.in
@@ -0,0 +1,231 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(pppoe.c)
+
+AC_CONFIG_HEADER(config.h)
+
+AC_PREFIX_DEFAULT(/usr)
+
+dnl Checks for programs.
+AC_PROG_CC
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h net/if_arp.h netinet/if_ether.h getopt.h sys/uio.h sys/param.h fcntl.h net/bpf.h netpacket/packet.h net/ethernet.h asm/types.h linux/if_packet.h linux/if_ether.h linux/if_pppox.h sys/socket.h sys/cdefs.h linux/if.h net/if.h net/if_dl.h net/if_ether.h net/if_types.h netinet/if_ether.h net/if_types.h net/if_dl.h sys/dlpi.h )
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl Check for an echo which supports -n -- another hack for Solaris
+AC_PATH_PROG(ECHO, echo, "", /usr/ucb/bin:$PATH)
+
+dnl Check for sockaddr_ll
+$ECHO -n "checking for struct sockaddr_ll... "
+AC_TRY_COMPILE([#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+], [struct sockaddr_ll sa;],
+ac_cv_struct_sockaddr_ll=yes, ac_cv_struct_sockaddr_ll=no)
+$ECHO $ac_cv_struct_sockaddr_ll
+if test "$ac_cv_struct_sockaddr_ll" = yes ; then
+AC_DEFINE(HAVE_STRUCT_SOCKADDR_LL)
+fi
+
+dnl Check for N_HDLC line discipline
+$ECHO -n "checking for N_HDLC line discipline... "
+AC_TRY_COMPILE([#include <linux/termios.h>],
+ [int x = N_HDLC;],
+ ac_cv_n_hdlc=yes, ac_cv_n_hdlc=no)
+$ECHO $ac_cv_n_hdlc
+if test "$ac_cv_n_hdlc" = yes ; then
+AC_DEFINE(HAVE_N_HDLC)
+fi
+
+AC_ARG_ENABLE(plugin, [ --enable-plugin=pppd_src_path build pppd plugin], ac_cv_pluginpath=$enableval, ac_cv_pluginpath=no)
+
+dnl Determine whether or not to build Linux pppd plugin
+LINUX_KERNELMODE_PLUGIN=""
+PPPD_INCDIR=""
+if test "$ac_cv_header_linux_if_pppox_h" = yes ; then
+ if test "$ac_cv_pluginpath" != no ; then
+ LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
+ PPPD_INCDIR=$ac_cv_pluginpath
+ fi
+fi
+
+AC_SUBST(LINUX_KERNELMODE_PLUGIN)
+AC_SUBST(PPPD_INCDIR)
+
+dnl Determine whether or not to build PPPoE relay
+PPPOE_RELAY=""
+if test "`uname -s`" = "Linux" ; then
+ PPPOE_RELAY=pppoe-relay
+fi
+AC_SUBST(PPPOE_RELAY)
+
+dnl Checks for library functions.
+AC_FUNC_MEMCMP
+AC_FUNC_SETVBUF_REVERSED
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS(select socket strerror strtol)
+AC_PROG_INSTALL
+
+dnl Integer sizes
+AC_CHECK_SIZEOF(unsigned short)
+AC_CHECK_SIZEOF(unsigned int)
+AC_CHECK_SIZEOF(unsigned long)
+
+dnl Check for location of pppd
+AC_PATH_PROG(PPPD, pppd, NOTFOUND, $PATH:/sbin:/usr/sbin:/usr/local/sbin)
+
+dnl Check for setsid (probably Linux-specific)
+AC_PATH_PROG(SETSID, setsid, "", $PATH:/sbin:/usr/sbin:/usr/local/sbin)
+
+dnl Check for an "id" which accepts "-u" option -- hack for Solaris.
+AC_PATH_PROG(ID, id, "", /usr/xpg4/bin:$PATH)
+
+dnl Check for Linux-specific kernel support for PPPoE
+$ECHO -n "checking for Linux 2.4.X kernel-mode PPPoE support..."
+if test "`uname -s`" = "Linux" ; then
+AC_TRY_RUN([#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+int main()
+{
+ if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) >= 0) return 0; else return 1;
+}
+], ac_cv_linux_kernel_pppoe=yes, ac_cv_linux_kernel_pppoe=no)
+else
+ ac_cv_linux_kernel_pppoe=no
+fi
+
+$ECHO $ac_cv_linux_kernel_pppoe
+if test "$ac_cv_linux_kernel_pppoe" = yes ; then
+ AC_DEFINE(HAVE_LINUX_KERNEL_PPPOE)
+fi
+
+dnl GCC warning level
+if test "$GCC" = yes; then
+ CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
+fi
+
+dnl If we couldn't find pppd, die
+if test "$PPPD" = "NOTFOUND"; then
+ $ECHO ""
+ $ECHO "*** Oops! I couldn't find pppd, the PPP daemon anywhere."
+ $ECHO "*** You must install pppd, version 2.3.10 or later."
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+fi
+
+dnl Figure out pppd version. 2.3.7 to 2.3.9 -- issue warning. Less than
+dnl 2.3.7 -- stop
+
+PPPD_VERSION=`$PPPD --version 2>&1 | awk '{print $NF}'`
+
+case "$PPPD_VERSION" in
+1.*|2.0.*|2.1.*|2.2.*|2.3.0|2.3.1|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6)
+ $ECHO ""
+ $ECHO "*** Oops! Your version of pppd is $PPPD_VERSION, which is too old."
+ $ECHO "*** You need at least 2.3.7 (2.3.10 or newer recommended.)"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+
+2.3.7|2.3.8|2.3.9)
+ $ECHO ""
+ $ECHO "*** Warning. Your version of pppd is $PPPD_VERSION. You will"
+ $ECHO "*** not be able to use connect-on-demand. Upgrade to pppd"
+ $ECHO "*** 2.3.10 or newer if you need connect-on-demand."
+ $ECHO ""
+ ;;
+
+2*|3*|4*|5*|6*|7*|8*|9*)
+ ;;
+
+*)
+ $ECHO ""
+ $ECHO "*** Oops. I cannot figure out what version of pppd you have."
+ $ECHO "*** All I got back was '$PPPD_VERSION'"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+esac
+
+dnl Figure out packing order of structures
+$ECHO -n "checking packing order of bit fields... "
+AC_TRY_RUN([
+union foo {
+ struct bar {
+ unsigned int ver:4;
+ unsigned int type:4;
+ } bb;
+ unsigned char baz;
+};
+
+int
+main(void)
+{
+ union foo x;
+ x.bb.ver = 1;
+ x.bb.type = 2;
+ if (x.baz == 0x21) {
+ return 1;
+ } else if (x.baz == 0x12) {
+ return 0;
+ } else {
+ return 2;
+ }
+}], PACK=normal, PACK=rev)
+
+if test "$PACK" = "rev" ; then
+ $ECHO "reversed"
+ AC_DEFINE(PACK_BITFIELDS_REVERSED)
+else
+ $ECHO "normal"
+fi
+
+# Sigh... got to fix this up for tcl
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Fully resolve WRAPPER for Tcl script.
+WRAPPER=${sbindir}/pppoe-wrapper
+eval "WRAPPER=${WRAPPER}"
+eval "WRAPPER=${WRAPPER}"
+AC_SUBST(WRAPPER)
+
+# Determine what targets to build
+TARGETS="pppoe pppoe-server"
+
+# pppoe-sniff is built only on Linux and Solaris
+if test "$ac_cv_header_linux_if_packet_h" = "yes" -o "$ac_cv_header_sys_dlpi_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-sniff"
+fi
+
+# pppoe-relay is built only on Linux
+if test "$ac_cv_header_linux_if_packet_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-relay"
+fi
+
+# plugin is built only if we have kernel support
+if test -n "$LINUX_KERNELMODE_PLUGIN" ; then
+ TARGETS="$TARGETS $LINUX_KERNELMODE_PLUGIN"
+fi
+
+AC_SUBST(TARGETS)
+
+AC_OUTPUT(Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe)
+
+$ECHO ""
+$ECHO "On this platform, the following targets will be built:"
+$ECHO " $TARGETS"
+$ECHO ""
+$ECHO "Type 'make' to compile the software."
diff --git a/mdk-stage1/rp-pppoe/src/debug.c b/mdk-stage1/rp-pppoe/src/debug.c
new file mode 100644
index 000000000..052dca6c7
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/debug.c
@@ -0,0 +1,143 @@
+/***********************************************************************
+*
+* debug.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for printing debugging information
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/**********************************************************************
+*%FUNCTION: dumpHex
+*%ARGUMENTS:
+* fp -- file to dump to
+* buf -- buffer to dump
+* len -- length of data
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Dumps buffer to fp in an easy-to-read format
+***********************************************************************/
+void
+dumpHex(FILE *fp, unsigned char const *buf, int len)
+{
+ int i;
+ int base;
+
+ if (!fp) return;
+
+ /* do NOT dump PAP packets */
+ if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
+ fprintf(fp, "(PAP Authentication Frame -- Contents not dumped)\n");
+ return;
+ }
+
+ for (base=0; base<len; base += 16) {
+ for (i=base; i<base+16; i++) {
+ if (i < len) {
+ fprintf(fp, "%02x ", (unsigned) buf[i]);
+ } else {
+ fprintf(fp, " ");
+ }
+ }
+ fprintf(fp, " ");
+ for (i=base; i<base+16; i++) {
+ if (i < len) {
+ if (isprint(buf[i])) {
+ fprintf(fp, "%c", buf[i]);
+ } else {
+ fprintf(fp, ".");
+ }
+ } else {
+ break;
+ }
+ }
+ fprintf(fp, "\n");
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: dumpPacket
+*%ARGUMENTS:
+* fp -- file to dump to
+* packet -- a PPPoE packet
+* dir -- either SENT or RCVD
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Dumps the PPPoE packet to fp in an easy-to-read format
+***********************************************************************/
+void
+dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir)
+{
+ int len = ntohs(packet->length);
+
+ /* Sheesh... printing times is a pain... */
+ struct timeval tv;
+ time_t now;
+ int millisec;
+ struct tm *lt;
+ char timebuf[256];
+
+ UINT16_t type = etherType(packet);
+ if (!fp) return;
+ gettimeofday(&tv, NULL);
+ now = (time_t) tv.tv_sec;
+ millisec = tv.tv_usec / 1000;
+ lt = localtime(&now);
+ strftime(timebuf, 256, "%H:%M:%S", lt);
+ fprintf(fp, "%s.%03d %s PPPoE ", timebuf, millisec, dir);
+ if (type == Eth_PPPOE_Discovery) {
+ fprintf(fp, "Discovery (%x) ", (unsigned) type);
+ } else if (type == Eth_PPPOE_Session) {
+ fprintf(fp, "Session (%x) ", (unsigned) type);
+ } else {
+ fprintf(fp, "Unknown (%x) ", (unsigned) type);
+ }
+
+ switch(packet->code) {
+ case CODE_PADI: fprintf(fp, "PADI "); break;
+ case CODE_PADO: fprintf(fp, "PADO "); break;
+ case CODE_PADR: fprintf(fp, "PADR "); break;
+ case CODE_PADS: fprintf(fp, "PADS "); break;
+ case CODE_PADT: fprintf(fp, "PADT "); break;
+ case CODE_SESS: fprintf(fp, "SESS "); break;
+ }
+
+ fprintf(fp, "sess-id %d length %d\n",
+ (int) ntohs(packet->session),
+ len);
+
+ /* Ugly... I apologize... */
+ fprintf(fp,
+ "SourceAddr %02x:%02x:%02x:%02x:%02x:%02x "
+ "DestAddr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned) packet->ethHdr.h_source[0],
+ (unsigned) packet->ethHdr.h_source[1],
+ (unsigned) packet->ethHdr.h_source[2],
+ (unsigned) packet->ethHdr.h_source[3],
+ (unsigned) packet->ethHdr.h_source[4],
+ (unsigned) packet->ethHdr.h_source[5],
+ (unsigned) packet->ethHdr.h_dest[0],
+ (unsigned) packet->ethHdr.h_dest[1],
+ (unsigned) packet->ethHdr.h_dest[2],
+ (unsigned) packet->ethHdr.h_dest[3],
+ (unsigned) packet->ethHdr.h_dest[4],
+ (unsigned) packet->ethHdr.h_dest[5]);
+ dumpHex(fp, packet->payload, ntohs(packet->length));
+}
diff --git a/mdk-stage1/rp-pppoe/src/discovery.c b/mdk-stage1/rp-pppoe/src/discovery.c
new file mode 100644
index 000000000..fc3568db5
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/discovery.c
@@ -0,0 +1,629 @@
+/***********************************************************************
+*
+* discovery.c
+*
+* Perform PPPoE discovery
+*
+* Copyright (C) 1999 by Roaring Penguin Software Inc.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_LINUX_PACKET
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#include <signal.h>
+
+/**********************************************************************
+*%FUNCTION: parseForHostUniq
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data.
+* extra -- user-supplied pointer. This is assumed to be a pointer to int.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* If a HostUnique tag is found which matches our PID, sets *extra to 1.
+***********************************************************************/
+void
+parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ int *val = (int *) extra;
+ if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
+ pid_t tmp;
+ memcpy(&tmp, data, len);
+ if (tmp == getpid()) {
+ *val = 1;
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: packetIsForMe
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* packet -- a received PPPoE packet
+*%RETURNS:
+* 1 if packet is for this PPPoE daemon; 0 otherwise.
+*%DESCRIPTION:
+* If we are using the Host-Unique tag, verifies that packet contains
+* our unique identifier.
+***********************************************************************/
+int
+packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ int forMe = 0;
+
+ /* If we're not using the Host-Unique tag, then accept the packet */
+ if (!conn->useHostUniq) return 1;
+
+ parsePacket(packet, parseForHostUniq, &forMe);
+ return forMe;
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADOTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data. Should point to a PacketCriteria structure
+* which gets filled in according to selected AC name and service
+* name.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADO packet
+***********************************************************************/
+void
+parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ struct PacketCriteria *pc = (struct PacketCriteria *) extra;
+ PPPoEConnection *conn = pc->conn;
+ int i;
+
+ switch(type) {
+ case TAG_AC_NAME:
+ if (conn->printACNames) {
+ printf("Access-Concentrator: %.*s\n", (int) len, data);
+ }
+ if (conn->acName && len == strlen(conn->acName) &&
+ !strncmp((char *) data, conn->acName, len)) {
+ pc->acNameOK = 1;
+ }
+ break;
+ case TAG_SERVICE_NAME:
+ if (conn->printACNames && len > 0) {
+ printf(" Service-Name: %.*s\n", (int) len, data);
+ }
+ if (conn->serviceName && len == strlen(conn->serviceName) &&
+ !strncmp((char *) data, conn->serviceName, len)) {
+ pc->serviceNameOK = 1;
+ }
+ break;
+ case TAG_AC_COOKIE:
+ if (conn->printACNames) {
+ printf("Got a cookie:");
+ /* Print first 20 bytes of cookie */
+ for (i=0; i<len && i < 20; i++) {
+ printf(" %02x", (unsigned) data[i]);
+ }
+ if (i < len) printf("...");
+ printf("\n");
+ }
+ conn->cookie.type = htons(type);
+ conn->cookie.length = htons(len);
+ memcpy(conn->cookie.payload, data, len);
+ break;
+ case TAG_RELAY_SESSION_ID:
+ if (conn->printACNames) {
+ printf("Got a Relay-ID:");
+ /* Print first 20 bytes of relay ID */
+ for (i=0; i<len && i < 20; i++) {
+ printf(" %02x", (unsigned) data[i]);
+ }
+ if (i < len) printf("...");
+ printf("\n");
+ }
+ conn->relayId.type = htons(type);
+ conn->relayId.length = htons(len);
+ memcpy(conn->relayId.payload, data, len);
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ if (conn->printACNames) {
+ printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
+ } else {
+ syslog(LOG_ERR, "PADO: Service-Name-Error: %.*s", (int) len, data);
+ exit(1);
+ }
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ if (conn->printACNames) {
+ printf("Got a System-Error tag: %.*s\n", (int) len, data);
+ } else {
+ syslog(LOG_ERR, "PADO: System-Error: %.*s", (int) len, data);
+ exit(1);
+ }
+ break;
+ case TAG_GENERIC_ERROR:
+ if (conn->printACNames) {
+ printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
+ } else {
+ syslog(LOG_ERR, "PADO: Generic-Error: %.*s", (int) len, data);
+ exit(1);
+ }
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADSTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data (pointer to PPPoEConnection structure)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADS packet
+***********************************************************************/
+void
+parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ PPPoEConnection *conn = (PPPoEConnection *) extra;
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ syslog(LOG_DEBUG, "PADS: Service-Name: '%.*s'", (int) len, data);
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ syslog(LOG_ERR, "PADS: Service-Name-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADS: Service-Name-Error: %.*s\n", (int) len, data);
+ exit(1);
+ case TAG_AC_SYSTEM_ERROR:
+ syslog(LOG_ERR, "PADS: System-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADS: System-Error: %.*s\n", (int) len, data);
+ exit(1);
+ case TAG_GENERIC_ERROR:
+ syslog(LOG_ERR, "PADS: Generic-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADS: Generic-Error: %.*s\n", (int) len, data);
+ exit(1);
+ case TAG_RELAY_SESSION_ID:
+ conn->relayId.type = htons(type);
+ conn->relayId.length = htons(len);
+ memcpy(conn->relayId.payload, data, len);
+ break;
+ }
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADI
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADI packet
+***********************************************************************/
+void
+sendPADI(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ unsigned char *cursor = packet.payload;
+ PPPoETag *svc = (PPPoETag *) (&packet.payload);
+ UINT16_t namelen = 0;
+ UINT16_t plen;
+
+ if (conn->serviceName) {
+ namelen = (UINT16_t) strlen(conn->serviceName);
+ }
+ plen = TAG_HDR_SIZE + namelen;
+ CHECK_ROOM(cursor, packet.payload, plen);
+
+ /* Set destination to Ethernet broadcast address */
+ memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_PADI;
+ packet.session = 0;
+
+ svc->type = TAG_SERVICE_NAME;
+ svc->length = htons(namelen);
+ CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
+
+ if (conn->serviceName) {
+ memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
+ }
+ cursor += namelen + TAG_HDR_SIZE;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->useHostUniq) {
+ PPPoETag hostUniq;
+ pid_t pid = getpid();
+ hostUniq.type = htons(TAG_HOST_UNIQ);
+ hostUniq.length = htons(sizeof(pid));
+ memcpy(hostUniq.payload, &pid, sizeof(pid));
+ CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
+ memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+ cursor += sizeof(pid) + TAG_HDR_SIZE;
+ plen += sizeof(pid) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: waitForPADO
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* timeout -- how long to wait (in seconds)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Waits for a PADO packet and copies useful information
+***********************************************************************/
+void
+waitForPADO(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ PPPoEPacket packet;
+ int len;
+
+ struct PacketCriteria pc;
+ pc.conn = conn;
+ pc.acNameOK = (conn->acName) ? 0 : 1;
+ pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ fatalSys("select (waitForPADO)");
+ }
+ if (r == 0) return; /* Timed out */
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+ /* If it's not for us, loop again */
+ if (!packetIsForMe(conn, &packet)) continue;
+
+ if (packet.code == CODE_PADO) {
+ if (NOT_UNICAST(packet.ethHdr.h_source)) {
+ printErr("Ignoring PADO packet from non-unicast MAC address");
+ continue;
+ }
+ conn->numPADOs++;
+ if (conn->printACNames) {
+ printf("--------------------------------------------------\n");
+ }
+ parsePacket(&packet, parsePADOTags, &pc);
+ if (pc.acNameOK && pc.serviceNameOK) {
+ memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
+ if (conn->printACNames) {
+ printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned) conn->peerEth[0],
+ (unsigned) conn->peerEth[1],
+ (unsigned) conn->peerEth[2],
+ (unsigned) conn->peerEth[3],
+ (unsigned) conn->peerEth[4],
+ (unsigned) conn->peerEth[5]);
+ continue;
+ }
+ conn->discoveryState = STATE_RECEIVED_PADO;
+ break;
+ }
+ }
+ } while (conn->discoveryState != STATE_RECEIVED_PADO);
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADR
+*%ARGUMENTS:
+* conn -- PPPoE connection structur
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADR packet
+***********************************************************************/
+void
+sendPADR(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ PPPoETag *svc = (PPPoETag *) packet.payload;
+ unsigned char *cursor = packet.payload;
+
+ UINT16_t namelen = 0;
+ UINT16_t plen;
+
+ if (conn->serviceName) {
+ namelen = (UINT16_t) strlen(conn->serviceName);
+ }
+ plen = TAG_HDR_SIZE + namelen;
+ CHECK_ROOM(cursor, packet.payload, plen);
+
+ memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_PADR;
+ packet.session = 0;
+
+ svc->type = TAG_SERVICE_NAME;
+ svc->length = htons(namelen);
+ if (conn->serviceName) {
+ memcpy(svc->payload, conn->serviceName, namelen);
+ }
+ cursor += namelen + TAG_HDR_SIZE;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->useHostUniq) {
+ PPPoETag hostUniq;
+ pid_t pid = getpid();
+ hostUniq.type = htons(TAG_HOST_UNIQ);
+ hostUniq.length = htons(sizeof(pid));
+ memcpy(hostUniq.payload, &pid, sizeof(pid));
+ CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
+ memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+ cursor += sizeof(pid) + TAG_HDR_SIZE;
+ plen += sizeof(pid) + TAG_HDR_SIZE;
+ }
+
+ /* Copy cookie and relay-ID if needed */
+ if (conn->cookie.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ }
+
+ if (conn->relayId.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: waitForPADS
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* timeout -- how long to wait (in seconds)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Waits for a PADS packet and copies useful information
+***********************************************************************/
+void
+waitForPADS(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ PPPoEPacket packet;
+ int len;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ fatalSys("select (waitForPADS)");
+ }
+ if (r == 0) return;
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+ /* If it's not from the AC, it's not for me */
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
+
+ /* If it's not for us, loop again */
+ if (!packetIsForMe(conn, &packet)) continue;
+
+ /* Is it PADS? */
+ if (packet.code == CODE_PADS) {
+ /* Parse for goodies */
+ parsePacket(&packet, parsePADSTags, conn);
+ conn->discoveryState = STATE_SESSION;
+ break;
+ }
+ } while (conn->discoveryState != STATE_SESSION);
+
+ /* Don't bother with ntohs; we'll just end up converting it back... */
+ conn->session = packet.session;
+
+ syslog(LOG_INFO, "PPP session is %d", (int) ntohs(conn->session));
+
+ /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
+ if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
+ syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: discovery
+*%ARGUMENTS:
+* conn -- PPPoE connection info structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Performs the PPPoE discovery phase
+***********************************************************************/
+void
+discovery(PPPoEConnection *conn)
+{
+ int padiAttempts = 0;
+ int padrAttempts = 0;
+ int timeout = PADI_TIMEOUT;
+
+ /* Skip discovery and don't open discovery socket? */
+ if (conn->skipDiscovery && conn->noDiscoverySocket) {
+ conn->discoveryState = STATE_SESSION;
+ return;
+ }
+
+ conn->discoverySocket =
+ openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+
+ /* Skip discovery? */
+ if (conn->skipDiscovery) {
+ conn->discoveryState = STATE_SESSION;
+ if (conn->killSession) {
+ sendPADT(conn, "RP-PPPoE: Session killed manually");
+ exit(0);
+ }
+ return;
+ }
+
+ do {
+ padiAttempts++;
+ if (padiAttempts > MAX_PADI_ATTEMPTS) {
+ rp_fatal("Timeout waiting for PADO packets");
+ }
+ sendPADI(conn);
+ conn->discoveryState = STATE_SENT_PADI;
+ waitForPADO(conn, timeout);
+
+ /* If we're just probing for access concentrators, don't do
+ exponential backoff. This reduces the time for an unsuccessful
+ probe to 15 seconds. */
+ if (!conn->printACNames) {
+ timeout *= 2;
+ }
+ if (conn->printACNames && conn->numPADOs) {
+ break;
+ }
+ } while (conn->discoveryState == STATE_SENT_PADI);
+
+ /* If we're only printing access concentrator names, we're done */
+ if (conn->printACNames) {
+ printf("--------------------------------------------------\n");
+ exit(0);
+ }
+
+ timeout = PADI_TIMEOUT;
+ do {
+ padrAttempts++;
+ if (padrAttempts > MAX_PADI_ATTEMPTS) {
+ rp_fatal("Timeout waiting for PADS packets");
+ }
+ sendPADR(conn);
+ conn->discoveryState = STATE_SENT_PADR;
+ waitForPADS(conn, timeout);
+ timeout *= 2;
+ } while (conn->discoveryState == STATE_SENT_PADR);
+
+ /* We're done. */
+ conn->discoveryState = STATE_SESSION;
+ return;
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/if.c b/mdk-stage1/rp-pppoe/src/if.c
new file mode 100644
index 000000000..fec09b273
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/if.c
@@ -0,0 +1,1092 @@
+/***********************************************************************
+*
+* if.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for opening a raw socket and reading/writing raw Ethernet frames.
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_NETPACKET_PACKET_H
+#include <netpacket/packet.h>
+#elif defined(HAVE_LINUX_IF_PACKET_H)
+#include <linux/if_packet.h>
+#endif
+
+#ifdef HAVE_NET_ETHERNET_H
+#include <net/ethernet.h>
+#endif
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+
+#ifdef USE_DLPI
+
+#include <limits.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/dlpi.h>
+#include <sys/bufmod.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stropts.h>
+
+/* function declarations */
+
+void dlpromisconreq( int fd, u_long level);
+void dlinforeq(int fd);
+void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
+void dlinfoack(int fd, char *bufp);
+void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
+void dlattachreq(int fd, u_long ppa);
+void dlokack(int fd, char *bufp);
+void dlbindack(int fd, char *bufp);
+int strioctl(int fd, int cmd, int timout, int len, char *dp);
+void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
+void sigalrm(int sig);
+void expecting(int prim, union DL_primitives *dlp);
+char *dlprim(u_long prim);
+
+/* #define DL_DEBUG */
+
+static int dl_abssaplen;
+static int dl_saplen;
+static int dl_addrlen;
+
+#endif
+
+#ifdef USE_BPF
+#include <net/bpf.h>
+#include <fcntl.h>
+
+unsigned char *bpfBuffer; /* Packet filter buffer */
+int bpfLength = 0; /* Packet filter buffer length */
+int bpfSize = 0; /* Number of unread bytes in buffer */
+int bpfOffset = 0; /* Current offset in bpfBuffer */
+#endif
+
+/* Initialize frame types to RFC 2516 values. Some broken peers apparently
+ use different frame types... sigh... */
+
+UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
+UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
+
+/**********************************************************************
+*%FUNCTION: etherType
+*%ARGUMENTS:
+* packet -- a received PPPoE packet
+*%RETURNS:
+* ethernet packet type (see /usr/include/net/ethertypes.h)
+*%DESCRIPTION:
+* Checks the ethernet packet header to determine its type.
+* We should only be receveing DISCOVERY and SESSION types if the BPF
+* is set up correctly. Logs an error if an unexpected type is received.
+* Note that the ethernet type names come from "pppoe.h" and the packet
+* packet structure names use the LINUX dialect to maintain consistency
+* with the rest of this file. See the BSD section of "pppoe.h" for
+* translations of the data structure names.
+***********************************************************************/
+UINT16_t
+etherType(PPPoEPacket *packet)
+{
+ UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
+ if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
+ syslog(LOG_ERR, "Invalid ether type 0x%x", type);
+ }
+ return type;
+}
+
+#ifdef USE_BPF
+/**********************************************************************
+*%FUNCTION: getHWaddr
+*%ARGUMENTS:
+* ifname -- name of interface
+* hwaddr -- buffer for ehthernet address
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Locates the Ethernet hardware address for an interface.
+***********************************************************************/
+void
+getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
+{
+ char inbuf[8192];
+ const struct sockaddr_dl *sdl;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ int i;
+ int found = 0;
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ fatalSys("SIOCGIFCONF");
+ }
+ ifr = ifc.ifc_req;
+ ifreq.ifr_name[0] = '\0';
+ for (i = 0; i < ifc.ifc_len; ) {
+ ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
+ i += sizeof(ifr->ifr_name) +
+ (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
+ ? ifr->ifr_addr.sa_len
+ : sizeof(struct sockaddr));
+ if (ifr->ifr_addr.sa_family == AF_LINK) {
+ sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
+ if ((sdl->sdl_type == IFT_ETHER) &&
+ (sdl->sdl_alen == ETH_ALEN) &&
+ !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
+ if (found) {
+ char buffer[256];
+ sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
+ rp_fatal(buffer);
+ } else {
+ found = 1;
+ memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
+ }
+ }
+ }
+ }
+ if (!found) {
+ char buffer[256];
+ sprintf(buffer, "interface %.16s has no ethernet address", ifname);
+ rp_fatal(buffer);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: initFilter
+*%ARGUMENTS:
+* fd -- file descriptor of BSD device
+* type -- Ethernet frame type (0 for watch mode)
+* hwaddr -- buffer with ehthernet address
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Initializes the packet filter rules.
+***********************************************************************/
+void
+initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
+{
+ /* Packet Filter Instructions:
+ * Note that the ethernet type names come from "pppoe.h" and are
+ * used here to maintain consistency with the rest of this file. */
+ static struct bpf_insn bpfRun[] = { /* run PPPoE */
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
+#define PPPOE_BCAST_CMPW 4 /* offset of word compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
+#define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
+#define PPPOE_FILTER_CMPW 8 /* offset of word compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
+#define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
+ BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
+ };
+
+ /* Fix the potentially varying parts */
+ bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
+ bpfRun[1].jt = 5;
+ bpfRun[1].jf = 0;
+ bpfRun[1].k = Eth_PPPOE_Session;
+
+ bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
+ bpfRun[2].jt = 0;
+ bpfRun[2].jf = 9;
+ bpfRun[2].k = Eth_PPPOE_Discovery;
+
+ {
+ struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
+ struct bpf_program bpfProgram;
+ memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
+ bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
+ (0xff << 8) | 0xff);
+ bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
+ bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | hwaddr[3]);
+ bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
+ bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
+ bpfProgram.bf_insns = &bpfInsn[0];
+
+ /* Apply the filter */
+ if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
+ fatalSys("ioctl(BIOCSETF)");
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type (0 for any frame type)
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A file descriptor for talking with the Ethernet card. Exits on error.
+* Note that the Linux version of this routine returns a socket instead.
+*%DESCRIPTION:
+* Opens a BPF on an interface for all PPPoE traffic (discovery and
+* session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
+* traffic on this network.
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ static int fd = -1;
+ char bpfName[32];
+ u_int optval;
+ struct bpf_version bpf_ver;
+ struct ifreq ifr;
+ int sock;
+ int i;
+
+ /* BSD only opens one socket for both Discovery and Session packets */
+ if (fd >= 0) {
+ return fd;
+ }
+
+ /* Find a free BPF device */
+ for (i = 0; i < 256; i++) {
+ sprintf(bpfName, "/dev/bpf%d", i);
+ if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
+ (errno != EBUSY)) {
+ break;
+ }
+ }
+ if (fd < 0) {
+ switch (errno) {
+ case EACCES: /* permission denied */
+ {
+ char buffer[256];
+ sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
+ rp_fatal(buffer);
+ }
+ break;
+ case EBUSY:
+ case ENOENT: /* no such file */
+ if (i == 0) {
+ rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
+ } else {
+ rp_fatal("All /dev/bpf* devices are in use");
+ }
+ break;
+ }
+ fatalSys(bpfName);
+ }
+
+ if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
+ fatalSys("socket");
+ }
+
+ /* Check that the interface is up */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFFLAGS)");
+ }
+ if ((ifr.ifr_flags & IFF_UP) == 0) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s is not up\n", ifname);
+ rp_fatal(buffer);
+ }
+
+ /* Fill in hardware address and initialize the packet filter rules */
+ if (hwaddr == NULL) {
+ rp_fatal("openInterface: no hwaddr arg.");
+ }
+ getHWaddr(sock, ifname, hwaddr);
+ initFilter(fd, type, hwaddr);
+
+ /* Sanity check on MTU -- apparently does not work on OpenBSD */
+#if !defined(__OpenBSD__)
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFMTU)");
+ }
+ if (ifr.ifr_mtu < ETH_DATA_LEN) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
+ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+ printErr(buffer);
+ }
+#endif
+
+ /* done with the socket */
+ if (close(sock) < 0) {
+ fatalSys("close");
+ }
+
+ /* Check the BPF version number */
+ if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
+ fatalSys("ioctl(BIOCVERSION)");
+ }
+ if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
+ (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
+ char buffer[256];
+ sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+ bpf_ver.bv_major, bpf_ver.bv_minor);
+ rp_fatal(buffer);
+ }
+
+ /* allocate a receive packet buffer */
+ if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
+ fatalSys("ioctl(BIOCGBLEN)");
+ }
+ if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
+ rp_fatal("malloc");
+ }
+
+ /* reads should return as soon as there is a packet available */
+ optval = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
+ fatalSys("ioctl(BIOCIMMEDIATE)");
+ }
+
+ /* Bind the interface to the filter */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
+ char buffer[256];
+ sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
+ ifname);
+ rp_fatal(buffer);
+ }
+
+ syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
+ ifname,
+ hwaddr[0], hwaddr[1], hwaddr[2],
+ hwaddr[3], hwaddr[4], hwaddr[5],
+ bpfName, bpfLength);
+ return fd;
+}
+
+#endif /* USE_BPF */
+
+#ifdef USE_LINUX_PACKET
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A raw socket for talking to the Ethernet card. Exits on error.
+*%DESCRIPTION:
+* Opens a raw Ethernet socket
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ int optval=1;
+ int fd;
+ struct ifreq ifr;
+ int domain, stype;
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ struct sockaddr_ll sa;
+#else
+ struct sockaddr sa;
+#endif
+
+ memset(&sa, 0, sizeof(sa));
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ domain = PF_PACKET;
+ stype = SOCK_RAW;
+#else
+ domain = PF_INET;
+ stype = SOCK_PACKET;
+#endif
+
+ if ((fd = socket(domain, stype, htons(type))) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
+ fatalSys("socket");
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
+ fatalSys("setsockopt");
+ }
+
+ /* Fill in hardware address */
+ if (hwaddr) {
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFHWADDR)");
+ }
+ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+#ifdef ARPHRD_ETHER
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
+ rp_fatal(buffer);
+ }
+#endif
+ if (NOT_UNICAST(hwaddr)) {
+ char buffer[256];
+ sprintf(buffer,
+ "Interface %.16s has broadcast/multicast MAC address??",
+ ifname);
+ rp_fatal(buffer);
+ }
+ }
+
+ /* Sanity check on MTU */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFMTU)");
+ }
+ if (ifr.ifr_mtu < ETH_DATA_LEN) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
+ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+ printErr(buffer);
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ /* Get interface index */
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons(type);
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
+ }
+ sa.sll_ifindex = ifr.ifr_ifindex;
+
+#else
+ strcpy(sa.sa_data, ifname);
+#endif
+
+ /* We're only interested in packets on specified interface */
+ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ fatalSys("bind");
+ }
+
+ return fd;
+}
+
+#endif /* USE_LINUX */
+
+/***********************************************************************
+*%FUNCTION: sendPacket
+*%ARGUMENTS:
+* sock -- socket to send to
+* pkt -- the packet to transmit
+* size -- size of packet (in bytes)
+*%RETURNS:
+* 0 on success; -1 on failure
+*%DESCRIPTION:
+* Transmits a packet
+***********************************************************************/
+int
+sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
+{
+#if defined(USE_BPF)
+ if (write(sock, pkt, size) < 0) {
+ sysErr("write (sendPacket)");
+ return -1;
+ }
+#elif defined(HAVE_STRUCT_SOCKADDR_LL)
+ if (send(sock, pkt, size, 0) < 0) {
+ sysErr("send (sendPacket)");
+ return -1;
+ }
+#else
+#ifdef USE_DLPI
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+ u_char addr[MAXDLADDR];
+ u_char phys[MAXDLADDR];
+ u_char sap[MAXDLADDR];
+ u_char xmitbuf[MAXDLBUF];
+ int data_size;
+
+ short tmp_sap;
+
+ tmp_sap = htons(pkt->ethHdr.h_proto);
+ data_size = size - sizeof(struct ethhdr);
+
+ memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
+ memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
+ memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
+
+ if (dl_saplen > 0) { /* order is sap+phys */
+ (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
+ (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
+ } else { /* order is phys+sap */
+ (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
+ (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
+ }
+
+#ifdef DL_DEBUG
+ printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
+ addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
+ addr[6],addr[7]);
+#endif
+
+ dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
+
+
+
+#else
+ struct sockaddr sa;
+
+ if (!conn) {
+ rp_fatal("relay and server not supported on Linux 2.0 kernels");
+ }
+ strcpy(sa.sa_data, conn->ifName);
+ if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
+ sysErr("sendto (sendPacket)");
+ return -1;
+ }
+#endif
+#endif
+ return 0;
+}
+
+#ifdef USE_BPF
+/***********************************************************************
+*%FUNCTION: clearPacketHeader
+*%ARGUMENTS:
+* pkt -- packet that needs its head clearing
+*%RETURNS:
+* nothing
+*%DESCRIPTION:
+* Clears a PPPoE packet header after a truncated packet has been
+* received. Insures that the packet will fail any integrity tests
+* and will be discarded by upper level routines. Also resets the
+* bpfSize and bpfOffset variables to force a new read on the next
+* call to receivePacket().
+***********************************************************************/
+void
+clearPacketHeader(PPPoEPacket *pkt)
+{
+ bpfSize = bpfOffset = 0;
+ memset(pkt, 0, HDR_SIZE);
+}
+#endif
+
+/***********************************************************************
+*%FUNCTION: receivePacket
+*%ARGUMENTS:
+* sock -- socket to read from
+* pkt -- place to store the received packet
+* size -- set to size of packet in bytes
+*%RETURNS:
+* >= 0 if all OK; < 0 if error
+*%DESCRIPTION:
+* Receives a packet
+***********************************************************************/
+int
+receivePacket(int sock, PPPoEPacket *pkt, int *size)
+{
+#ifdef USE_BPF
+ struct bpf_hdr hdr;
+ int seglen, copylen;
+
+ if (bpfSize <= 0) {
+ bpfOffset = 0;
+ if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
+ sysErr("read (receivePacket)");
+ return -1;
+ }
+ }
+ if (bpfSize < sizeof(hdr)) {
+ syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
+ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
+ return 0;
+ }
+ memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
+ if (hdr.bh_caplen != hdr.bh_datalen) {
+ syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
+ hdr.bh_caplen, hdr.bh_datalen);
+ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
+ return 0;
+ }
+ seglen = hdr.bh_hdrlen + hdr.bh_caplen;
+ if (seglen > bpfSize) {
+ syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
+ seglen, bpfSize);
+ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
+ return 0;
+ }
+ seglen = BPF_WORDALIGN(seglen);
+ *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
+ hdr.bh_caplen : sizeof(PPPoEPacket));
+ memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
+ if (seglen >= bpfSize) {
+ bpfSize = bpfOffset = 0;
+ } else {
+ bpfSize -= seglen;
+ bpfOffset += seglen;
+ }
+#else
+#ifdef USE_DLPI
+ struct strbuf data;
+ int flags = 0;
+ int retval;
+
+ data.buf = (char *) pkt;
+ data.maxlen = MAXDLBUF;
+ data.len = 0;
+
+ if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
+ sysErr("read (receivePacket)");
+ return -1;
+ }
+
+ *size = data.len;
+
+#else
+ if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+ sysErr("recv (receivePacket)");
+ return -1;
+ }
+#endif
+#endif
+ return 0;
+}
+
+#ifdef USE_DLPI
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A raw socket for talking to the Ethernet card. Exits on error.
+*%DESCRIPTION:
+* Opens a raw Ethernet socket
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ int fd;
+ long buf[MAXDLBUF];
+
+ union DL_primitives *dlp;
+
+ char base_dev[PATH_MAX];
+ int ppa;
+
+ if(strlen(ifname) > PATH_MAX) {
+ rp_fatal("socket: string to long");
+ }
+
+ ppa = atoi(&ifname[strlen(ifname)-1]);
+ strncpy(base_dev, ifname, PATH_MAX);
+ base_dev[strlen(base_dev)-1] = '\0';
+
+ if (( fd = open(base_dev, O_RDWR)) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
+ fatalSys("socket");
+ }
+
+ dlinforeq(fd);
+ dlinfoack(fd, (char *)buf);
+
+ dlp = (union DL_primitives*) buf;
+
+ dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
+ dl_saplen = dlp->info_ack.dl_sap_length;
+ if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
+ fatalSys("invalid destination physical address length");
+ dl_addrlen = dl_abssaplen + ETHERADDRL;
+
+ dlattachreq(fd, ppa);
+ dlokack(fd, (char *)buf);
+
+ dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
+ dlbindack(fd, (char *)buf);
+
+ if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
+ fatalSys("DLIOCRAW");
+ }
+
+ if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
+
+ return fd;
+}
+
+/* cloned from dlcommon.c */
+
+void dlpromisconreq(int fd, u_long level)
+{
+ dl_promiscon_req_t promiscon_req;
+ struct strbuf ctl;
+ int flags;
+
+ promiscon_req.dl_primitive = DL_PROMISCON_REQ;
+ promiscon_req.dl_level = level;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (promiscon_req);
+ ctl.buf = (char *) &promiscon_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlpromiscon: putmsg");
+
+}
+
+void dlinforeq(int fd)
+{
+ dl_info_req_t info_req;
+ struct strbuf ctl;
+ int flags;
+
+ info_req.dl_primitive = DL_INFO_REQ;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (info_req);
+ ctl.buf = (char *) &info_req;
+
+ flags = RS_HIPRI;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlinforeq: putmsg");
+}
+
+void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
+{
+ long buf[MAXDLBUF];
+ union DL_primitives *dlp;
+ struct strbuf data, ctl;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
+ dlp->unitdata_req.dl_dest_addr_length = addrlen;
+ dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
+ dlp->unitdata_req.dl_priority.dl_min = minpri;
+ dlp->unitdata_req.dl_priority.dl_max = maxpri;
+
+ (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
+ ctl.buf = (char *) buf;
+
+ data.maxlen = 0;
+ data.len = datalen;
+ data.buf = (char *) datap;
+
+ if (putmsg(fd, &ctl, &data, 0) < 0)
+ fatalSys("dlunitdatareq: putmsg");
+}
+
+void dlinfoack(int fd, char *bufp)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_INFO_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_info_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+
+ if (flags != RS_HIPRI)
+ rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_info_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+}
+
+void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
+{
+ dl_bind_req_t bind_req;
+ struct strbuf ctl;
+ int flags;
+
+ bind_req.dl_primitive = DL_BIND_REQ;
+ bind_req.dl_sap = sap;
+ bind_req.dl_max_conind = max_conind;
+ bind_req.dl_service_mode = service_mode;
+ bind_req.dl_conn_mgmt = conn_mgmt;
+ bind_req.dl_xidtest_flg = xidtest;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (bind_req);
+ ctl.buf = (char *) &bind_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlbindreq: putmsg");
+}
+
+void dlattachreq(int fd, u_long ppa)
+{
+ dl_attach_req_t attach_req;
+ struct strbuf ctl;
+ int flags;
+
+ attach_req.dl_primitive = DL_ATTACH_REQ;
+ attach_req.dl_ppa = ppa;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (attach_req);
+ ctl.buf = (char *) &attach_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlattachreq: putmsg");
+}
+
+void dlokack(int fd, char *bufp)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_OK_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_ok_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlokack: response ctl.len too short: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+
+ if (flags != RS_HIPRI)
+ rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_ok_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlokack: short response ctl.len: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+}
+
+void dlbindack(int fd, char *bufp)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_BIND_ACK, dlp);
+
+ if (flags != RS_HIPRI)
+ rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_bind_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+}
+
+int strioctl(int fd, int cmd, int timout, int len, char *dp)
+{
+ struct strioctl sioc;
+ int rc;
+
+ sioc.ic_cmd = cmd;
+ sioc.ic_timout = timout;
+ sioc.ic_len = len;
+ sioc.ic_dp = dp;
+ rc = ioctl(fd, I_STR, &sioc);
+
+ if (rc < 0)
+ return (rc);
+ else
+ return (sioc.ic_len);
+}
+
+void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
+{
+ int rc;
+ static char errmsg[80];
+
+ /*
+ * Start timer.
+ */
+ (void) signal(SIGALRM, sigalrm);
+ if (alarm(MAXWAIT) < 0) {
+ (void) sprintf(errmsg, "%s: alarm", caller);
+ fatalSys(errmsg);
+ }
+
+ /*
+ * Set flags argument and issue getmsg().
+ */
+ *flagsp = 0;
+ if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
+ (void) sprintf(errmsg, "%s: getmsg", caller);
+ fatalSys(errmsg);
+ }
+
+ /*
+ * Stop timer.
+ */
+ if (alarm(0) < 0) {
+ (void) sprintf(errmsg, "%s: alarm", caller);
+ fatalSys(errmsg);
+ }
+
+ /*
+ * Check for MOREDATA and/or MORECTL.
+ */
+ if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
+ char buffer[256];
+ sprintf(buffer, "%s: MORECTL|MOREDATA", caller);
+ rp_fatal(buffer);
+ }
+
+ if (rc & MORECTL) {
+ char buffer[256];
+ sprintf(buffer, "%s: MORECTL", caller);
+ rp_fatal(buffer);
+ }
+
+ if (rc & MOREDATA) {
+ char buffer[256];
+ sprintf(buffer, "%s: MOREDATA", caller);
+ rp_fatal(buffer);
+ }
+
+ /*
+ * Check for at least sizeof (long) control data portion.
+ */
+ if (ctlp->len < sizeof (long)) {
+ char buffer[256];
+ sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len);
+ rp_fatal(buffer);
+ }
+}
+
+void sigalrm(int sig)
+{
+ (void) rp_fatal("sigalrm: TIMEOUT");
+}
+
+void expecting(int prim, union DL_primitives *dlp)
+{
+ if (dlp->dl_primitive != (u_long)prim) {
+ char buffer[256];
+ sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
+ rp_fatal(buffer);
+ exit(1);
+ }
+}
+
+char *dlprim(u_long prim)
+{
+ static char primbuf[80];
+
+ switch ((int)prim) {
+ CASERET(DL_INFO_REQ);
+ CASERET(DL_INFO_ACK);
+ CASERET(DL_ATTACH_REQ);
+ CASERET(DL_DETACH_REQ);
+ CASERET(DL_BIND_REQ);
+ CASERET(DL_BIND_ACK);
+ CASERET(DL_UNBIND_REQ);
+ CASERET(DL_OK_ACK);
+ CASERET(DL_ERROR_ACK);
+ CASERET(DL_SUBS_BIND_REQ);
+ CASERET(DL_SUBS_BIND_ACK);
+ CASERET(DL_UNITDATA_REQ);
+ CASERET(DL_UNITDATA_IND);
+ CASERET(DL_UDERROR_IND);
+ CASERET(DL_UDQOS_REQ);
+ CASERET(DL_CONNECT_REQ);
+ CASERET(DL_CONNECT_IND);
+ CASERET(DL_CONNECT_RES);
+ CASERET(DL_CONNECT_CON);
+ CASERET(DL_TOKEN_REQ);
+ CASERET(DL_TOKEN_ACK);
+ CASERET(DL_DISCONNECT_REQ);
+ CASERET(DL_DISCONNECT_IND);
+ CASERET(DL_RESET_REQ);
+ CASERET(DL_RESET_IND);
+ CASERET(DL_RESET_RES);
+ CASERET(DL_RESET_CON);
+ default:
+ (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
+ return (primbuf);
+ }
+}
+
+#endif /* USE_DLPI */
diff --git a/mdk-stage1/rp-pppoe/src/install-sh b/mdk-stage1/rp-pppoe/src/install-sh
new file mode 100755
index 000000000..58719246f
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/install-sh
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/src/md5.c b/mdk-stage1/rp-pppoe/src/md5.c
new file mode 100644
index 000000000..5b7a0d7b2
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/md5.c
@@ -0,0 +1,246 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
diff --git a/mdk-stage1/rp-pppoe/src/md5.h b/mdk-stage1/rp-pppoe/src/md5.h
new file mode 100644
index 000000000..e264f686d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/md5.h
@@ -0,0 +1,27 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/mdk-stage1/rp-pppoe/src/plugin.c b/mdk-stage1/rp-pppoe/src/plugin.c
new file mode 100644
index 000000000..d1097e291
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/plugin.c
@@ -0,0 +1,397 @@
+/***********************************************************************
+*
+* plugin.c
+*
+* pppd plugin for kernel-mode PPPoE on Linux
+*
+* Copyright (C) 2001 by Roaring Penguin Software Inc., Michal Ostrowski
+* and Jamal Hadi Salim.
+*
+* Much code and many ideas derived from pppoe plugin by Michal
+* Ostrowski and Jamal Hadi Salim, which carries this copyright:
+*
+* Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
+* Jamal Hadi Salim <hadi@cyberus.ca>
+* Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
+* which is based in part on work from Jens Axboe and Paul Mackerras.
+*
+* 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.
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+
+#include "pppd/pppd.h"
+#include "pppd/fsm.h"
+#include "pppd/lcp.h"
+#include "pppd/ipcp.h"
+#include "pppd/ccp.h"
+#include "pppd/pathnames.h"
+
+#include <linux/types.h>
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#include <linux/if_pppox.h>
+
+/* From sys-linux.c in pppd -- MUST FIX THIS! */
+extern int new_style_driver;
+
+static char *service = NULL;
+static char *acName = NULL;
+static char *existingSession = NULL;
+
+static option_t Options[] = {
+ { "rp_pppoe_service", o_string, &service,
+ "Desired PPPoE service name" },
+ { "rp_pppoe_ac", o_string, &acName,
+ "Desired PPPoE access concentrator name" },
+ { "rp_pppoe_sess", o_string, &existingSession,
+ "Attach to existing session (sessid:macaddr)" },
+ { NULL }
+};
+int (*OldDevnameHook)(const char *name) = NULL;
+static PPPoEConnection *conn = NULL;
+
+/**********************************************************************
+ * %FUNCTION: PPPOEInitDevice
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ *
+ * %DESCRIPTION:
+ * Initializes PPPoE device.
+ ***********************************************************************/
+static int
+PPPOEInitDevice(void)
+{
+ conn = malloc(sizeof(PPPoEConnection));
+ if (!conn) {
+ fatal("Could not allocate memory for PPPoE session");
+ }
+ memset(conn, 0, sizeof(PPPoEConnection));
+ if (acName) {
+ SET_STRING(conn->acName, acName);
+ }
+ if (service) {
+ SET_STRING(conn->serviceName, acName);
+ }
+ SET_STRING(conn->ifName, devnam);
+ conn->discoverySocket = -1;
+ conn->sessionSocket = -1;
+ conn->useHostUniq = 1;
+ return 1;
+}
+
+/**********************************************************************
+ * %FUNCTION: PPPOEConnectDevice
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Non-negative if all goes well; -1 otherwise
+ * %DESCRIPTION:
+ * Connects PPPoE device.
+ ***********************************************************************/
+static int
+PPPOEConnectDevice(void)
+{
+ struct sockaddr_pppox sp;
+
+ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+ if (existingSession) {
+ unsigned int mac[ETH_ALEN];
+ int i, ses;
+ if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
+ &ses, &mac[0], &mac[1], &mac[2],
+ &mac[3], &mac[4], &mac[5]) != 7) {
+ fatal("Illegal value for rp_pppoe_sess option");
+ }
+ conn->session = htons(ses);
+ for (i=0; i<ETH_ALEN; i++) {
+ conn->peerEth[i] = (unsigned char) mac[i];
+ }
+ } else {
+ discovery(conn);
+ if (conn->discoveryState != STATE_SESSION) {
+ fatal("Unable to complete PPPoE Discovery");
+ }
+ }
+
+ /* Make the session socket */
+ conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
+ if (conn->sessionSocket < 0) {
+ fatal("Failed to create PPPoE socket: %m");
+ }
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OE;
+ sp.sa_addr.pppoe.sid = conn->session;
+ memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
+ memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+ if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+ sizeof(struct sockaddr_pppox)) < 0) {
+ fatal("Failed to connect PPPoE socket: %d %m", errno);
+ return -1;
+ }
+ return conn->sessionSocket;
+}
+
+static void
+PPPOESendConfig(int unit,
+ int mtu,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ int sock;
+ struct ifreq ifr;
+
+ if (mtu > MAX_PPPOE_MTU) {
+ warn("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, &ifr) < 0) {
+ fatal("ioctl(SIOCSIFMTU): %m");
+ }
+ (void) close (sock);
+}
+
+
+static void
+PPPOERecvConfig(int unit,
+ int mru,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ if (mru > MAX_PPPOE_MTU) {
+ error("Couldn't increase MRU to %d", mru);
+ }
+}
+
+static void
+PPPOESetXaccm(int unit,
+ ext_accm accm)
+{
+ /* Do nothing */
+}
+
+/**********************************************************************
+ * %FUNCTION: PPPOEDisconnectDevice
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Nothing
+ * %DESCRIPTION:
+ * Disconnects PPPoE device
+ ***********************************************************************/
+static void
+PPPOEDisconnectDevice(void)
+{
+ struct sockaddr_pppox sp;
+
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OE;
+ sp.sa_addr.pppoe.sid = 0;
+ memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
+ memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+ if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+ sizeof(struct sockaddr_pppox)) < 0) {
+ fatal("Failed to disconnect PPPoE socket: %d %m", errno);
+ return;
+ }
+ close(conn->sessionSocket);
+}
+
+static int
+PPPOESetSpeed(const char *speed)
+{
+ return 0;
+}
+
+static void
+PPPOEDeviceCheckHook(void)
+{
+ if (!options_for_dev(_PATH_ETHOPT, devnam)) {
+ exit(EXIT_OPTION_ERROR);
+ }
+}
+
+/**********************************************************************
+ * %FUNCTION: PPPoEDevnameHook
+ * %ARGUMENTS:
+ * name -- name of device
+ * %RETURNS:
+ * 1 if we will handle this device; 0 otherwise.
+ * %DESCRIPTION:
+ * Checks if name is a valid interface name; if so, returns 1. Also
+ * sets up devnam (string representation of device) and sets devstat.st_mode
+ * so S_ISCHR(devstat.st_mode) != 1 for internal pppd consumption.
+ ***********************************************************************/
+static int
+PPPoEDevnameHook(const char *name)
+{
+ int r = 1;
+ int fd;
+ struct ifreq ifr;
+
+ /* Open a socket */
+ if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
+ r = 0;
+ }
+
+ /* Try getting interface index */
+ if (r) {
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ r = 0;
+ } else {
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ r = 0;
+ } else {
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ error("Interface %s not Ethernet", name);
+ r=0;
+ }
+ }
+ }
+ }
+
+ /* Close socket */
+ close(fd);
+ if (r) {
+ strncpy(devnam, name, sizeof(devnam));
+ if (device_check_hook != PPPOEDeviceCheckHook) {
+ devstat.st_mode = S_IFSOCK;
+ device_init_hook = PPPOEInitDevice;
+ setspeed_hook = PPPOESetSpeed;
+ device_check_hook = PPPOEDeviceCheckHook;
+ connect_device_hook = PPPOEConnectDevice;
+ disconnect_device_hook = PPPOEDisconnectDevice;
+ send_config_hook = PPPOESendConfig;
+ recv_config_hook = PPPOERecvConfig;
+ set_xaccm_hook = PPPOESetXaccm;
+ modem = 0;
+
+ lcp_allowoptions[0].neg_accompression = 0;
+ lcp_wantoptions[0].neg_accompression = 0;
+
+ lcp_allowoptions[0].neg_asyncmap = 0;
+ lcp_wantoptions[0].neg_asyncmap = 0;
+
+ lcp_allowoptions[0].neg_pcompression = 0;
+ lcp_wantoptions[0].neg_pcompression = 0;
+
+ ccp_allowoptions[0].deflate = 0 ;
+ ccp_wantoptions[0].deflate = 0 ;
+
+ ipcp_allowoptions[0].neg_vj=0;
+ ipcp_wantoptions[0].neg_vj=0;
+
+ ccp_allowoptions[0].bsd_compress = 0;
+ ccp_wantoptions[0].bsd_compress = 0;
+
+ PPPOEInitDevice();
+ }
+ return 1;
+ }
+
+ if (OldDevnameHook) r = OldDevnameHook(name);
+ return r;
+}
+
+/**********************************************************************
+ * %FUNCTION: plugin_init
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Nothing
+ * %DESCRIPTION:
+ * Initializes hooks for pppd plugin
+ ***********************************************************************/
+void
+plugin_init(void)
+{
+ if (!new_style_driver) {
+ fatal("Linux kernel does not support PPPoE -- are you running 2.4.x?");
+ }
+ OldDevnameHook = setdevname_hook;
+ setdevname_hook = PPPoEDevnameHook;
+ add_options(Options);
+
+ info("Roaring Penguin PPPoE Plugin Initialized");
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ int i = errno;
+ sprintf(buf, "%.256s: %.256s", str, strerror(i));
+ printErr(buf);
+ sprintf(buf, "RP-PPPoE: %.256s: %.256s", str, strerror(i));
+ sendPADT(conn, buf);
+ exit(1);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ char buf[1024];
+ printErr(str);
+ sprintf(buf, "RP-PPPoE: %.256s", str);
+ sendPADT(conn, buf);
+ exit(1);
+}
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ rp_fatal(str);
+}
diff --git a/mdk-stage1/rp-pppoe/src/ppp.c b/mdk-stage1/rp-pppoe/src/ppp.c
new file mode 100644
index 000000000..72020a76c
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/ppp.c
@@ -0,0 +1,258 @@
+/***********************************************************************
+*
+* ppp.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for talking to PPP daemon
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_N_HDLC
+#ifndef N_HDLC
+#include <linux/termios.h>
+#endif
+#endif
+
+int PPPState;
+int PPPPacketSize;
+unsigned char PPPXorValue;
+
+UINT16_t fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/**********************************************************************
+*%FUNCTION: syncReadFromPPP
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* packet -- buffer in which to place PPPoE packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads from a synchronous PPP device and builds and transmits a PPPoE
+* packet
+***********************************************************************/
+void
+syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ int r;
+#ifndef HAVE_N_HDLC
+ struct iovec vec[2];
+ unsigned char dummy[2];
+ vec[0].iov_base = (void *) dummy;
+ vec[0].iov_len = 2;
+ vec[1].iov_base = (void *) packet->payload;
+ vec[1].iov_len = ETH_DATA_LEN - PPPOE_OVERHEAD;
+
+ /* Use scatter-read to throw away the PPP frame address bytes */
+ r = readv(0, vec, 2);
+#else
+ /* Bloody hell... readv doesn't work with N_HDLC line discipline... GRR! */
+ unsigned char buf[ETH_DATA_LEN - PPPOE_OVERHEAD + 2];
+ r = read(0, buf, ETH_DATA_LEN - PPPOE_OVERHEAD + 2);
+ if (r >= 2) {
+ memcpy(packet->payload, buf+2, r-2);
+ }
+#endif
+ if (r < 0) {
+ /* Catch the Linux "select" bug */
+ if (errno == EAGAIN) {
+ rp_fatal("Linux select bug hit! This message is harmless, but please ask the Linux kernel developers to fix it.");
+ }
+ fatalSys("read (syncReadFromPPP)");
+ }
+ if (r == 0) {
+ syslog(LOG_INFO, "end-of-file in syncReadFromPPP");
+ sendPADT(conn, "RP-PPPoE: EOF in syncReadFromPPP");
+ exit(0);
+ }
+
+ if (r < 2) {
+ rp_fatal("too few characters read from PPP (syncReadFromPPP)");
+ }
+
+ sendSessionPacket(conn, packet, r-2);
+}
+
+/**********************************************************************
+*%FUNCTION: initPPP
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Initializes the PPP state machine
+***********************************************************************/
+void
+initPPP(void)
+{
+ PPPState = STATE_WAITFOR_FRAME_ADDR;
+ PPPPacketSize = 0;
+ PPPXorValue = 0;
+
+}
+/**********************************************************************
+*%FUNCTION: asyncReadFromPPP
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* packet -- buffer in which to place PPPoE packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads from an async PPP device and builds a PPPoE packet to transmit
+***********************************************************************/
+void
+asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ unsigned char buf[READ_CHUNK];
+ unsigned char *ptr = buf;
+ unsigned char c;
+
+ int r;
+
+ r = read(0, buf, READ_CHUNK);
+ if (r < 0) {
+ fatalSys("read (asyncReadFromPPP)");
+ }
+
+ if (r == 0) {
+ syslog(LOG_INFO, "end-of-file in asyncReadFromPPP");
+ sendPADT(conn, "RP-PPPoE: EOF in asyncReadFromPPP");
+ exit(0);
+ }
+
+ while(r) {
+ if (PPPState == STATE_WAITFOR_FRAME_ADDR) {
+ while(r) {
+ --r;
+ if (*ptr++ == FRAME_ADDR) {
+ PPPState = STATE_DROP_PROTO;
+ break;
+ }
+ }
+ }
+
+ /* Still waiting... */
+ if (PPPState == STATE_WAITFOR_FRAME_ADDR) return;
+
+ while(r && PPPState == STATE_DROP_PROTO) {
+ --r;
+ if (*ptr++ == (FRAME_CTRL ^ FRAME_ENC)) {
+ PPPState = STATE_BUILDING_PACKET;
+ }
+ }
+
+ if (PPPState == STATE_DROP_PROTO) return;
+
+ /* Start building frame */
+ while(r && PPPState == STATE_BUILDING_PACKET) {
+ --r;
+ c = *ptr++;
+ switch(c) {
+ case FRAME_ESC:
+ PPPXorValue = FRAME_ENC;
+ break;
+ case FRAME_FLAG:
+ if (PPPPacketSize < 2) {
+ rp_fatal("Packet too short from PPP (asyncReadFromPPP)");
+ }
+ sendSessionPacket(conn, packet, PPPPacketSize-2);
+ PPPPacketSize = 0;
+ PPPXorValue = 0;
+ PPPState = STATE_WAITFOR_FRAME_ADDR;
+ break;
+ default:
+ if (PPPPacketSize >= ETH_DATA_LEN - 4) {
+ syslog(LOG_ERR, "Packet too big! Check MTU on PPP interface");
+ PPPPacketSize = 0;
+ PPPXorValue = 0;
+ PPPState = STATE_WAITFOR_FRAME_ADDR;
+ } else {
+ packet->payload[PPPPacketSize++] = c ^ PPPXorValue;
+ PPPXorValue = 0;
+ }
+ }
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: pppFCS16
+*%ARGUMENTS:
+* fcs -- current fcs
+* cp -- a buffer's worth of data
+* len -- length of buffer "cp"
+*%RETURNS:
+* A new FCS
+*%DESCRIPTION:
+* Updates the PPP FCS.
+***********************************************************************/
+UINT16_t
+pppFCS16(UINT16_t fcs,
+ unsigned char * cp,
+ int len)
+{
+ while (len--)
+ fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+
+ return (fcs);
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/pppoe-server.c b/mdk-stage1/rp-pppoe/src/pppoe-server.c
new file mode 100644
index 000000000..e43e63553
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe-server.c
@@ -0,0 +1,1247 @@
+/***********************************************************************
+*
+* pppoe.h
+*
+* Implementation of a user-space PPPoE server
+*
+* Copyright (C) 2000 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id$
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "config.h"
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define _POSIX_SOURCE 1 /* For sigaction defines */
+#endif
+
+#define _BSD_SOURCE 1 /* for gethostname */
+
+#include "pppoe.h"
+#include "md5.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <signal.h>
+
+/* Hack for daemonizing */
+#define CLOSEFD 64
+
+/* Max. 64 sessions by default */
+#define DEFAULT_MAX_SESSIONS 64
+
+/* A list of client sessions */
+struct ClientSession *Sessions = NULL;
+
+/* The number of session slots */
+size_t NumSessionSlots;
+
+/* Offset of first session */
+size_t SessOffset = 0;
+
+/* Socket for client's discovery phases */
+int Socket = -1;
+
+/* Pipe written on reception of SIGCHLD */
+int Pipe[2] = {-1, -1};
+int ReapPending = 0;
+
+/* Synchronous mode */
+int Synchronous = 0;
+
+/* Random seed for cookie generation */
+#define SEED_LEN 16
+#define MD5_LEN 16
+#define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */
+
+unsigned char CookieSeed[SEED_LEN];
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+char *IfName = NULL;
+
+/* Access concentrator name */
+char *ACName = NULL;
+
+/* Options to pass to pppoe process */
+char PppoeOptions[SMALLBUF] = "";
+
+/* Our local IP address */
+unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1};
+unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */
+
+PPPoETag hostUniq;
+PPPoETag relayId;
+PPPoETag receivedCookie;
+PPPoETag requestedService;
+
+#define HOSTNAMELEN 256
+
+static void startPPPD(struct ClientSession *sess);
+static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest,
+ int errorTag, char *errorMsg);
+
+#define CHECK_ROOM(cursor, start, len) \
+do {\
+ if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
+ syslog(LOG_ERR, "Would create too-long packet"); \
+ return; \
+ } \
+} while(0)
+
+/* Use Linux kernel-mode PPPoE? */
+int UseLinuxKernelModePPPoE = 0;
+
+/**********************************************************************
+*%FUNCTION: parseAddressPool
+*%ARGUMENTS:
+* fname -- name of file containing IP address pool.
+* install -- if true, install IP addresses in sessions.
+*%RETURNS:
+* Number of valid IP addresses found.
+*%DESCRIPTION:
+* Reads a list of IP addresses from a file.
+***********************************************************************/
+static int
+parseAddressPool(char const *fname, int install)
+{
+ FILE *fp = fopen(fname, "r");
+ int numAddrs = 0;
+ unsigned int a, b, c, d;
+
+ if (!fp) {
+ sysErr("Cannot open address pool file");
+ }
+
+ while (!feof(fp)) {
+ if ((fscanf(fp, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) &&
+ a < 256 && b < 256 && c < 256 && d < 256) {
+ if (install) {
+ Sessions[numAddrs].ip[0] = (unsigned char) a;
+ Sessions[numAddrs].ip[1] = (unsigned char) b;
+ Sessions[numAddrs].ip[2] = (unsigned char) c;
+ Sessions[numAddrs].ip[3] = (unsigned char) d;
+ }
+ numAddrs++;
+ }
+ }
+ if (!numAddrs) {
+ rp_fatal("No valid ip addresses found in pool file");
+ }
+ return numAddrs;
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADITags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADI packet
+***********************************************************************/
+void
+parsePADITags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ /* Should do something -- currently ignored */
+ break;
+ case TAG_RELAY_SESSION_ID:
+ relayId.type = htons(type);
+ relayId.length = htons(len);
+ memcpy(relayId.payload, data, len);
+ break;
+ case TAG_HOST_UNIQ:
+ hostUniq.type = htons(type);
+ hostUniq.length = htons(len);
+ memcpy(hostUniq.payload, data, len);
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADRTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADR packet
+***********************************************************************/
+void
+parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_RELAY_SESSION_ID:
+ relayId.type = htons(type);
+ relayId.length = htons(len);
+ memcpy(relayId.payload, data, len);
+ break;
+ case TAG_HOST_UNIQ:
+ hostUniq.type = htons(type);
+ hostUniq.length = htons(len);
+ memcpy(hostUniq.payload, data, len);
+ break;
+ case TAG_AC_COOKIE:
+ receivedCookie.type = htons(type);
+ receivedCookie.length = htons(len);
+ memcpy(receivedCookie.payload, data, len);
+ break;
+ case TAG_SERVICE_NAME:
+ requestedService.type = htons(type);
+ requestedService.length = htons(len);
+ memcpy(requestedService.payload, data, len);
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: findSession
+*%ARGUMENTS:
+* pid -- PID of child which owns session. If PID is 0, searches for
+* empty session slots.
+*%RETURNS:
+* A pointer to the session, or NULL if no such session found.
+*%DESCRIPTION:
+* Searches for specified session.
+**********************************************************************/
+struct ClientSession *
+findSession(pid_t pid)
+{
+ size_t i;
+ for (i=0; i<NumSessionSlots; i++) {
+ if (Sessions[i].pid == pid) {
+ return &Sessions[i];
+ }
+ }
+ return NULL;
+}
+
+/**********************************************************************
+*%FUNCTION: reapSessions
+*%ARGUMENTS:
+* myAddr -- my Ethernet address
+* sock -- my discovery socket
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reaps children which have exited and removes their sessions
+**********************************************************************/
+void
+reapSessions(unsigned char *myAddr, int sock)
+{
+ int status;
+ pid_t pid;
+ struct ClientSession *session;
+
+ /* Temporary structure for sending PADT's. */
+ PPPoEConnection conn;
+ memset(&conn, 0, sizeof(conn));
+
+ /* Initialize fields of conn which do not depend on peer */
+ memcpy(conn.myEth, myAddr, ETH_ALEN);
+ conn.useHostUniq = 0;
+ conn.discoverySocket = sock;
+
+ while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ session = findSession(pid);
+ if (!session) {
+ syslog(LOG_ERR, "Child %d died but couldn't find session!",
+ (int) pid);
+ } else {
+ syslog(LOG_INFO,
+ "Session %d closed for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ conn.session = session->sess;
+ memcpy(conn.peerEth, session->eth, ETH_ALEN);
+ if (session->recvdPADT) {
+ sendPADT(&conn, "RP-PPPoE: Received PADT from peer");
+ } else {
+ sendPADT(&conn, "RP-PPPoE: Child pppd process terminated");
+ }
+ session->pid = 0;
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[SMALLBUF];
+ snprintf(buf, SMALLBUF, "%s: %s", str, strerror(errno));
+ printErr(buf);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ printErr(str);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: genCookie
+*%ARGUMENTS:
+* peerEthAddr -- peer Ethernet address (6 bytes)
+* myEthAddr -- my Ethernet address (6 bytes)
+* seed -- random cookie seed to make things tasty (16 bytes)
+* cookie -- buffer which is filled with server PID and
+* md5 sum of previous items
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Forms the md5 sum of peer MAC address, our MAC address and seed, useful
+* in a PPPoE Cookie tag.
+***********************************************************************/
+void
+genCookie(unsigned char const *peerEthAddr,
+ unsigned char const *myEthAddr,
+ unsigned char const *seed,
+ unsigned char *cookie)
+{
+ struct MD5Context ctx;
+ pid_t pid = getpid();
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, peerEthAddr, ETH_ALEN);
+ MD5Update(&ctx, myEthAddr, ETH_ALEN);
+ MD5Update(&ctx, seed, SEED_LEN);
+ MD5Final(cookie, &ctx);
+ memcpy(cookie+MD5_LEN, &pid, sizeof(pid));
+}
+
+/**********************************************************************
+*%FUNCTION: processPADI
+*%ARGUMENTS:
+* sock -- Ethernet socket
+* myAddr -- my Ethernet address
+* packet -- PPPoE PADI packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADO packet back to client
+***********************************************************************/
+void
+processPADI(int sock, unsigned char *myAddr,
+ PPPoEPacket *packet, int len)
+{
+ PPPoEPacket pado;
+ PPPoETag acname;
+ PPPoETag servname;
+ PPPoETag cookie;
+ size_t acname_len;
+ unsigned char *cursor = pado.payload;
+ UINT16_t plen;
+
+ /* Ignore PADI's which don't come from a unicast address */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR, "PADI packet from non-unicast source address");
+ return;
+ }
+
+ acname.type = htons(TAG_AC_NAME);
+ acname_len = strlen(ACName);
+ acname.length = htons(acname_len);
+ memcpy(acname.payload, ACName, acname_len);
+
+ servname.type = htons(TAG_SERVICE_NAME);
+ servname.length = 0;
+
+ relayId.type = 0;
+ hostUniq.type = 0;
+ parsePacket(packet, parsePADITags, NULL);
+
+ /* Generate a cookie */
+ cookie.type = htons(TAG_AC_COOKIE);
+ cookie.length = htons(COOKIE_LEN);
+ genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookie.payload);
+
+ /* Construct a PADO packet */
+ memcpy(pado.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
+ memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN);
+ pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ pado.ver = 1;
+ pado.type = 1;
+ pado.code = CODE_PADO;
+ pado.session = 0;
+ plen = TAG_HDR_SIZE + acname_len;
+
+ CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE);
+ memcpy(cursor, &acname, acname_len + TAG_HDR_SIZE);
+ cursor += acname_len + TAG_HDR_SIZE;
+
+ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
+ memcpy(cursor, &servname, TAG_HDR_SIZE);
+ cursor += TAG_HDR_SIZE;
+ plen += TAG_HDR_SIZE;
+
+ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);
+ memcpy(cursor, &cookie, TAG_HDR_SIZE + COOKIE_LEN);
+ cursor += TAG_HDR_SIZE + COOKIE_LEN;
+ plen += TAG_HDR_SIZE + COOKIE_LEN;
+
+ if (relayId.type) {
+ CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
+ }
+ if (hostUniq.type) {
+ CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE);
+ memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
+ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ }
+ pado.length = htons(plen);
+ sendPacket(NULL, sock, &pado, (int) (plen + HDR_SIZE));
+}
+
+/**********************************************************************
+*%FUNCTION: processPADT
+*%ARGUMENTS:
+* sock -- Ethernet socket
+* myAddr -- my Ethernet address
+* packet -- PPPoE PADT packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Kills session whose session-ID is in PADT packet.
+***********************************************************************/
+void
+processPADT(int sock, unsigned char *myAddr,
+ PPPoEPacket *packet, int len)
+{
+ size_t i;
+
+ /* Ignore PADT's not directed at us */
+ if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
+
+ /* Get session's index */
+ i = ntohs(packet->session) - 1 - SessOffset;
+ if (i >= NumSessionSlots) return;
+ if (Sessions[i].sess != packet->session) {
+ syslog(LOG_ERR, "Session index %u doesn't match session number %u",
+ (unsigned int) i, (unsigned int) ntohs(packet->session));
+ return;
+ }
+ if (Sessions[i].pid) {
+ Sessions[i].recvdPADT = 1;
+ parsePacket(packet, parseLogErrs, NULL);
+ kill(Sessions[i].pid, SIGTERM);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: processPADR
+*%ARGUMENTS:
+* sock -- Ethernet socket
+* myAddr -- my Ethernet address
+* packet -- PPPoE PADR packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADS packet back to client and starts a PPP session if PADR
+* packet is OK.
+***********************************************************************/
+void
+processPADR(int sock, unsigned char *myAddr,
+ PPPoEPacket *packet, int len)
+{
+ unsigned char cookieBuffer[COOKIE_LEN];
+ struct ClientSession *cliSession;
+ pid_t child;
+ PPPoEPacket pads;
+ unsigned char *cursor = pads.payload;
+ UINT16_t plen;
+ PPPoETag servname;
+
+ /* Initialize some globals */
+ relayId.type = 0;
+ hostUniq.type = 0;
+ receivedCookie.type = 0;
+ requestedService.type = 0;
+
+ /* Ignore PADR's not directed at us */
+ if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
+
+ /* Ignore PADR's from non-unicast addresses */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR, "PADR packet from non-unicast source address");
+ return;
+ }
+
+ parsePacket(packet, parsePADRTags, NULL);
+
+ /* Check that everything's cool */
+ if (!receivedCookie.type) {
+ /* Drop it -- do not send error PADS */
+ return;
+ }
+
+ /* Is cookie kosher? */
+ if (receivedCookie.length != htons(COOKIE_LEN)) {
+ /* Drop it -- do not send error PADS */
+ return;
+ }
+
+ genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookieBuffer);
+ if (memcmp(receivedCookie.payload, cookieBuffer, COOKIE_LEN)) {
+ /* Drop it -- do not send error PADS */
+ return;
+ }
+
+ /* Check service name -- we only offer service "" */
+ if (!requestedService.type) {
+ syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag");
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: No service name tag");
+ return;
+ }
+
+ if (requestedService.length) {
+ syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload);
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: Invalid service name tag");
+ return;
+ }
+
+ /* Looks cool... find a slot for the session */
+ cliSession = findSession(0);
+ if (!cliSession) {
+ syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)",
+ (unsigned int) packet->ethHdr.h_source[0],
+ (unsigned int) packet->ethHdr.h_source[1],
+ (unsigned int) packet->ethHdr.h_source[2],
+ (unsigned int) packet->ethHdr.h_source[3],
+ (unsigned int) packet->ethHdr.h_source[4],
+ (unsigned int) packet->ethHdr.h_source[5]);
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No client slots available");
+ return;
+ }
+
+ /* Set up client session peer Ethernet address */
+ memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN);
+ cliSession->recvdPADT = 0;
+
+ /* Create child process, send PADS packet back */
+ child = fork();
+ if (child < 0) {
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: Unable to start session process");
+ return;
+ }
+ if (child != 0) {
+ /* In the parent process. Mark pid in session slot */
+ cliSession->pid = child;
+ return;
+ }
+
+ /* In the child process. */
+
+ /* pppd has a nasty habit of killing all processes in its process group.
+ Start a new session to stop pppd from killing us! */
+ setsid();
+
+ /* Send PADS and Start pppd */
+ memcpy(pads.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
+ memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN);
+ pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ pads.ver = 1;
+ pads.type = 1;
+ pads.code = CODE_PADS;
+
+ pads.session = cliSession->sess;
+ plen = 0;
+
+ servname.type = htons(TAG_SERVICE_NAME);
+ servname.length = 0;
+
+ memcpy(cursor, &servname, TAG_HDR_SIZE);
+ cursor += TAG_HDR_SIZE;
+ plen += TAG_HDR_SIZE;
+
+ if (relayId.type) {
+ memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
+ }
+ if (hostUniq.type) {
+ memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
+ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ }
+ pads.length = htons(plen);
+ sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
+ startPPPD(cliSession);
+}
+
+/**********************************************************************
+*%FUNCTION: childHandler
+*%ARGUMENTS:
+* sig -- signal number
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Called by SIGCHLD. Writes one byte to Pipe to wake up the select
+* loop and cause reaping of dead sessions
+***********************************************************************/
+void
+childHandler(int sig)
+{
+ if (!ReapPending) {
+ ReapPending = 1;
+ write(Pipe[1], &ReapPending, 1);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- argv[0] from main
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage instructions
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+#ifdef USE_BPF
+ fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n");
+#else
+ fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
+ DEFAULT_IF);
+#endif
+ fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n");
+ fprintf(stderr, " -C name -- Set access concentrator name.\n");
+ fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n");
+ fprintf(stderr, " -L ip -- Set local IP address.\n");
+ fprintf(stderr, " -R ip -- Set start address of remote IP pool.\n");
+ fprintf(stderr, " -p fname -- Optain IP address pool from specified file.\n");
+ fprintf(stderr, " -N num -- Allow 'num' concurrent sessions.\n");
+ fprintf(stderr, " -o offset -- Assign session numbers starting at offset+1.\n");
+ fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n");
+ fprintf(stderr, " -s -- Use synchronous PPP mode.\n");
+#ifdef HAVE_LINUX_KERNEL_PPPOE
+ fprintf(stderr, " -k -- Use kernel-mode PPPoE.\n");
+#endif
+ fprintf(stderr, " -h -- Print usage information.\n\n");
+ fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
+ fprintf(stderr, "under the terms of the GNU General Public License, version 2\n");
+ fprintf(stderr, "or (at your option) any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+}
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- usual suspects
+*%RETURNS:
+* Exit status
+*%DESCRIPTION:
+* Main program of PPPoE server
+***********************************************************************/
+int
+main(int argc, char **argv)
+{
+
+ FILE *fp;
+ int i;
+ int opt;
+ unsigned char myAddr[ETH_ALEN];
+ PPPoEPacket packet;
+ int len;
+ int sock;
+ int d[IPV4ALEN];
+ int beDaemon = 1;
+ struct sigaction act;
+ int maxFD;
+ unsigned int discoveryType, sessionType;
+ char *addressPoolFname = NULL;
+
+#ifndef HAVE_LINUX_KERNEL_PPPOE
+ char *options = "hI:C:L:R:T:m:FN:f:o:sp:";
+#else
+ char *options = "hI:C:L:R:T:m:FN:f:o:skp:";
+#endif
+
+ /* Initialize syslog */
+ openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+
+ /* Default number of session slots */
+ NumSessionSlots = DEFAULT_MAX_SESSIONS;
+
+ /* Parse command-line options */
+ while((opt = getopt(argc, argv, options)) != -1) {
+ switch(opt) {
+#ifdef HAVE_LINUX_KERNEL_PPPOE
+ case 'k':
+ UseLinuxKernelModePPPoE = 1;
+ break;
+#endif
+ case 'p':
+ addressPoolFname = optarg;
+ break;
+ case 's':
+ Synchronous = 1;
+ /* Pass the Synchronous option on to pppoe */
+ snprintf(PppoeOptions + strlen(PppoeOptions),
+ SMALLBUF-strlen(PppoeOptions),
+ " -s");
+ break;
+ case 'f':
+ if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
+ fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
+ exit(EXIT_FAILURE);
+ }
+ Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
+ Eth_PPPOE_Session = (UINT16_t) sessionType;
+ /* This option gets passed to pppoe */
+ snprintf(PppoeOptions + strlen(PppoeOptions),
+ SMALLBUF-strlen(PppoeOptions),
+ " -%c %s", opt, optarg);
+ break;
+ case 'F':
+ beDaemon = 0;
+ break;
+ case 'N':
+ if (sscanf(optarg, "%d", &opt) != 1) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (opt <= 0) {
+ fprintf(stderr, "-N: Value must be positive\n");
+ exit(EXIT_FAILURE);
+ }
+ NumSessionSlots = opt;
+ break;
+ case 'o':
+ if (sscanf(optarg, "%d", &opt) != 1) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (opt < 0) {
+ fprintf(stderr, "-o: Value must be non-negative\n");
+ exit(EXIT_FAILURE);
+ }
+ SessOffset = (size_t) opt;
+ break;
+
+ case 'I':
+ SET_STRING(IfName, optarg);
+ break;
+ case 'C':
+ SET_STRING(ACName, optarg);
+ break;
+ case 'L':
+ case 'R':
+ /* Get local/remote IP address */
+ if (sscanf(optarg, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ for (i=0; i<IPV4ALEN; i++) {
+ if (d[i] < 0 || d[i] > 255) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (opt == 'L') {
+ LocalIP[i] = (unsigned char) d[i];
+ } else {
+ RemoteIP[i] = (unsigned char) d[i];
+ }
+ }
+ break;
+ case 'T':
+ case 'm':
+ /* These just get passed to pppoe */
+ snprintf(PppoeOptions + strlen(PppoeOptions),
+ SMALLBUF-strlen(PppoeOptions),
+ " -%c %s", opt, optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+ fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");
+ exit(EXIT_FAILURE);
+#endif
+#endif
+
+ if (!IfName) {
+ IfName = DEFAULT_IF;
+ }
+
+ if (!ACName) {
+ ACName = malloc(HOSTNAMELEN);
+ if (gethostname(ACName, HOSTNAMELEN) < 0) {
+ fatalSys("gethostname");
+ }
+ }
+
+ /* If address pool filename given, count number of addresses */
+ if (addressPoolFname) {
+ NumSessionSlots = parseAddressPool(addressPoolFname, 0);
+ }
+
+ /* Max 65534 - SessOffset sessions */
+ if (NumSessionSlots + SessOffset > 65534) {
+ fprintf(stderr, "-N and -o options must add up to at most 65534\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate memory for sessions */
+ Sessions = calloc(NumSessionSlots, sizeof(struct ClientSession));
+ if (!Sessions) {
+ rp_fatal("Cannot allocate memory for session slots");
+ }
+
+ /* Fill in remote IP addresses from pool */
+ if (addressPoolFname) {
+ (void) parseAddressPool(addressPoolFname, 1);
+ }
+
+ /* For testing -- generate sequential remote IP addresses */
+ for(i=0; i<NumSessionSlots; i++) {
+ Sessions[i].pid = 0;
+ Sessions[i].sess = htons(i+1+SessOffset);
+
+ if (!addressPoolFname) {
+ memcpy(Sessions[i].ip, RemoteIP, sizeof(RemoteIP));
+
+ /* Increment IP */
+ RemoteIP[3]++;
+ if (!RemoteIP[3]) {
+ RemoteIP[3] = 0;
+ RemoteIP[2]++;
+ if (!RemoteIP[2]) {
+ RemoteIP[1]++;
+ if (!RemoteIP[1]) {
+ RemoteIP[0]++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
+ if (beDaemon) {
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ /* parent */
+ exit(EXIT_SUCCESS);
+ }
+ setsid();
+ signal(SIGHUP, SIG_IGN);
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ exit(EXIT_SUCCESS);
+ }
+
+ chdir("/");
+ closelog();
+ for (i=0; i<CLOSEFD; i++) close(i);
+ /* We nuked our syslog descriptor... */
+ openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+ }
+
+ /* Initialize our random cookie. Try /dev/urandom; if that fails,
+ use PID and rand() */
+ fp = fopen("/dev/urandom", "r");
+ if (fp) {
+ fread(&CookieSeed, 1, SEED_LEN, fp);
+ fclose(fp);
+ } else {
+ CookieSeed[0] = getpid() & 0xFF;
+ CookieSeed[1] = (getpid() >> 8) & 0xFF;
+ for (i=2; i<SEED_LEN; i++) {
+ CookieSeed[i] = (rand() >> (i % 9)) & 0xFF;
+ }
+ }
+
+ sock = openInterface(IfName, Eth_PPPOE_Discovery, myAddr);
+
+ /* Set signal handler for SIGCHLD */
+ act.sa_handler = childHandler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+ if (sigaction(SIGCHLD, &act, NULL) < 0) {
+ fatalSys("sigaction");
+ }
+
+ /* Set up pipe for signal handler */
+ if (pipe(Pipe) < 0) {
+ fatalSys("pipe");
+ }
+
+ /* Main server loop */
+ maxFD = sock;
+ if (Pipe[0] > maxFD) maxFD = Pipe[0];
+ maxFD++;
+
+ for(;;) {
+ fd_set readable;
+ FD_ZERO(&readable);
+ FD_SET(sock, &readable);
+ FD_SET(Pipe[0], &readable);
+
+ while(1) {
+ i = select(maxFD, &readable, NULL, NULL, NULL);
+ if (i >= 0 || errno != EINTR) break;
+ }
+ if (i < 0) {
+ fatalSys("select");
+ }
+
+ if (FD_ISSET(Pipe[0], &readable)) {
+ /* Clear pipe */
+ char buf[SMALLBUF];
+ read(Pipe[0], buf, SMALLBUF);
+ }
+
+ if (ReapPending) {
+ ReapPending = 0;
+ reapSessions(myAddr, sock);
+ }
+ if (!FD_ISSET(sock, &readable)) {
+ continue;
+ }
+
+ if (receivePacket(sock, &packet, &len) < 0) {
+ continue;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+ /* Sanity check on packet */
+ if (packet.ver != 1 || packet.type != 1) {
+ /* Syslog an error */
+ continue;
+ }
+ switch(packet.code) {
+ case CODE_PADI:
+ processPADI(sock, myAddr, &packet, len);
+ break;
+ case CODE_PADR:
+ processPADR(sock, myAddr, &packet, len);
+ break;
+ case CODE_PADT:
+ /* Kill the child */
+ processPADT(sock, myAddr, &packet, len);
+ break;
+ case CODE_SESS:
+ /* Ignore SESS -- children will handle them */
+ break;
+ case CODE_PADO:
+ case CODE_PADS:
+ /* Ignore PADO and PADS totally */
+ break;
+ default:
+ /* Syslog an error */
+ break;
+ }
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: sendErrorPADS
+*%ARGUMENTS:
+* sock -- socket to write to
+* source -- source Ethernet address
+* dest -- destination Ethernet address
+* errorTag -- error tag
+* errorMsg -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADS packet with an error message
+***********************************************************************/
+void
+sendErrorPADS(int sock,
+ unsigned char *source,
+ unsigned char *dest,
+ int errorTag,
+ char *errorMsg)
+{
+ PPPoEPacket pads;
+ unsigned char *cursor = pads.payload;
+ UINT16_t plen;
+ PPPoETag err;
+ int elen = strlen(errorMsg);
+
+ memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN);
+ memcpy(pads.ethHdr.h_source, source, ETH_ALEN);
+ pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ pads.ver = 1;
+ pads.type = 1;
+ pads.code = CODE_PADS;
+
+ pads.session = htons(0);
+ plen = 0;
+
+ err.type = htons(errorTag);
+ err.length = htons(elen);
+
+ memcpy(err.payload, errorMsg, elen);
+ memcpy(cursor, &err, TAG_HDR_SIZE+elen);
+ cursor += TAG_HDR_SIZE + elen;
+ plen += TAG_HDR_SIZE + elen;
+
+ if (relayId.type) {
+ memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
+ }
+ if (hostUniq.type) {
+ memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
+ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ }
+ pads.length = htons(plen);
+ sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
+}
+
+
+/**********************************************************************
+*%FUNCTION: startPPPDUserMode
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD for user-mode PPPoE
+***********************************************************************/
+void
+startPPPDUserMode(struct ClientSession *session)
+{
+ /* Leave some room */
+ char *argv[20];
+
+ char buffer[SMALLBUF];
+
+ argv[0] = "pppd";
+ argv[1] = "pty";
+
+ snprintf(buffer, SMALLBUF, "%s -n -I %s -e %d:%02x:%02x:%02x:%02x:%02x:%02x%s",
+ PPPOE_PATH, IfName,
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ PppoeOptions);
+ argv[2] = strdup(buffer);
+ if (!argv[2]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+
+ argv[3] = "file";
+ argv[4] = PPPOE_SERVER_OPTIONS;
+
+ snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+ (int) LocalIP[0], (int) LocalIP[1],
+ (int) LocalIP[2], (int) LocalIP[3],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ syslog(LOG_INFO,
+ "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ argv[5] = buffer; /* No need for strdup -- about to execv! */
+ argv[6] = "nodetach";
+ argv[7] = "noaccomp";
+ argv[8] = "nobsdcomp";
+ argv[9] = "nodeflate";
+ argv[10] = "nopcomp";
+ argv[11] = "novj";
+ argv[12] = "novjccomp";
+ argv[13] = "default-asyncmap";
+ if (Synchronous) {
+ argv[14] = "sync";
+ argv[15] = NULL;
+ } else {
+ argv[14] = NULL;
+ }
+
+ execv(PPPD_PATH, argv);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: startPPPDLinuxKernelMode
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD for kernel-mode PPPoE on Linux
+***********************************************************************/
+void
+startPPPDLinuxKernelMode(struct ClientSession *session)
+{
+ /* Leave some room */
+ char *argv[20];
+
+ char buffer[SMALLBUF];
+
+ argv[0] = "pppd";
+ argv[1] = "plugin";
+ argv[2] = PLUGIN_PATH;
+ argv[3] = IfName;
+ snprintf(buffer, SMALLBUF, "%d:%02x:%02x:%02x:%02x:%02x:%02x",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5]);
+ argv[4] = "rp_pppoe_sess";
+ argv[5] = strdup(buffer);
+ if (!argv[5]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+ argv[6] = "file";
+ argv[7] = PPPOE_SERVER_OPTIONS;
+
+ snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+ (int) LocalIP[0], (int) LocalIP[1],
+ (int) LocalIP[2], (int) LocalIP[3],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ syslog(LOG_INFO,
+ "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ argv[8] = buffer;
+ argv[9] = "nodetach";
+ argv[10] = "noaccomp";
+ argv[11] = "nobsdcomp";
+ argv[12] = "nodeflate";
+ argv[13] = "nopcomp";
+ argv[14] = "novj";
+ argv[15] = "novjccomp";
+ argv[16] = "default-asyncmap";
+ argv[17] = NULL;
+ execv(PPPD_PATH, argv);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: startPPPD
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD
+***********************************************************************/
+void
+startPPPD(struct ClientSession *session)
+{
+ if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
+ else startPPPDUserMode(session);
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/pppoe-sniff.c b/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
new file mode 100644
index 000000000..aa796547b
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
@@ -0,0 +1,258 @@
+/***********************************************************************
+*
+* pppoe-sniff.c
+*
+* Sniff a network for likely-looking PPPoE frames and deduce the value
+* to supply to PPPOE_EXTRA in /etc/ppp/pppoe.conf. USE AT YOUR OWN RISK.
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef USE_DLPI
+#include <sys/dlpi.h>
+/* function declarations */
+void dlpromisconreq( int fd, u_long level);
+void dlokack(int fd, char *bufp);
+#endif
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+
+/* Global vars */
+int SeenPADR = 0;
+int SeenSess = 0;
+UINT16_t SessType, DiscType;
+
+char *IfName = NULL; /* Interface name */
+char *ServiceName = NULL; /* Service name */
+
+/**********************************************************************
+*%FUNCTION: parsePADRTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADR packet
+***********************************************************************/
+void
+parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ ServiceName = malloc(len+1);
+ if (ServiceName) {
+ memcpy(ServiceName, data, len);
+ ServiceName[len] = 0;
+ }
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+ exit(1);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ printErr(str);
+ exit(1);
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
+ DEFAULT_IF);
+ fprintf(stderr, " -V -- Print version and exit.\n");
+ fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2000 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+ fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+ exit(0);
+}
+
+#if !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
+
+int
+main()
+{
+ fprintf(stderr, "Sorry, pppoe-sniff works only on Linux.\n");
+ return 1;
+}
+
+#else
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- count and values of command-line arguments
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Main program
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int sock;
+ PPPoEPacket pkt;
+ int size;
+#ifdef USE_DLPI
+ long buf[MAXDLBUF];
+#endif
+
+ while((opt = getopt(argc, argv, "I:V")) != -1) {
+ switch(opt) {
+ case 'I':
+ SET_STRING(IfName, optarg);
+ break;
+ case 'V':
+ printf("pppoe-sniff: Roaring Penguin PPPoE Version %s\n", VERSION);
+ exit(0);
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ /* Pick a default interface name */
+ if (!IfName) {
+ IfName = DEFAULT_IF;
+ }
+
+ /* Open the interface */
+#ifdef USE_DLPI
+ sock = openInterface(IfName, Eth_PPPOE_Discovery, NULL);
+ dlpromisconreq(sock, DL_PROMISC_PHYS);
+ dlokack(sock, (char *)buf);
+ dlpromisconreq(sock, DL_PROMISC_SAP);
+ dlokack(sock, (char *)buf);
+#else
+
+ sock = openInterface(IfName, ETH_P_ALL, NULL);
+
+#endif
+
+ /* We assume interface is in promiscuous mode -- use ifconfig to
+ ensure this */
+ fprintf(stderr, "Sniffing for PADR. Start your connection on another machine...\n");
+ while (!SeenPADR) {
+ if (receivePacket(sock, &pkt, &size) < 0) continue;
+ if (ntohs(pkt.length) + HDR_SIZE > size) continue;
+ if (pkt.ver != 1 || pkt.type != 1) continue;
+ if (pkt.code != CODE_PADR) continue;
+
+ /* Looks promising... parse it */
+ if (parsePacket(&pkt, parsePADRTags, NULL) < 0) {
+ continue;
+ }
+ DiscType = ntohs(pkt.ethHdr.h_proto);
+ fprintf(stderr, "\nExcellent! Sniffed a likely-looking PADR.\n");
+ break;
+ }
+
+ while (!SeenSess) {
+ if (receivePacket(sock, &pkt, &size) < 0) continue;
+ if (ntohs(pkt.length) + HDR_SIZE > size) continue;
+ if (pkt.ver != 1 || pkt.type != 1) continue;
+ if (pkt.code != CODE_SESS) continue;
+
+ /* Cool! */
+ SessType = ntohs(pkt.ethHdr.h_proto);
+ break;
+ }
+
+ fprintf(stderr, "Wonderful! Sniffed a likely-looking session packet.\n");
+ if ((ServiceName == NULL || *ServiceName == 0) &&
+ DiscType == ETH_PPPOE_DISCOVERY &&
+ SessType == ETH_PPPOE_SESSION) {
+ fprintf(stderr, "\nGreat! It looks like a standard PPPoE service.\nYou should not need anything special in the configuration file.\n");
+ return 0;
+ }
+
+ fprintf(stderr, "\nOK, looks like you need something special in the configuration file.\nTry this:\n\n");
+ if (ServiceName != NULL && *ServiceName != 0) {
+ fprintf(stderr, "SERVICENAME='%s'\n", ServiceName);
+ }
+ if (DiscType != ETH_PPPOE_DISCOVERY || SessType != ETH_PPPOE_SESSION) {
+ fprintf(stderr, " PPPOE_EXTRA='-f %x:%x'\n", DiscType, SessType);
+ }
+ return 0;
+}
+
+#endif
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
diff --git a/mdk-stage1/rp-pppoe/src/pppoe.c b/mdk-stage1/rp-pppoe/src/pppoe.c
new file mode 100644
index 000000000..8ffe37248
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe.c
@@ -0,0 +1,834 @@
+/***********************************************************************
+*
+* pppoe.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_LINUX_PACKET
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#include <signal.h>
+
+#ifdef HAVE_N_HDLC
+#ifndef N_HDLC
+#include <linux/termios.h>
+#endif
+#endif
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+
+/* Global variables -- options */
+int optInactivityTimeout = 0; /* Inactivity timeout */
+int optClampMSS = 0; /* Clamp MSS to this value */
+int optSkipSession = 0; /* Perform discovery, print session info
+ and exit */
+
+PPPoEConnection *Connection = NULL; /* Must be global -- used
+ in signal handler */
+/***********************************************************************
+*%FUNCTION: sendSessionPacket
+*%ARGUMENTS:
+* conn -- PPPoE connection
+* packet -- the packet to send
+* len -- length of data to send
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Transmits a session packet to the peer.
+***********************************************************************/
+void
+sendSessionPacket(PPPoEConnection *conn, PPPoEPacket *packet, int len)
+{
+ packet->length = htons(len);
+ if (optClampMSS) {
+ clampMSS(packet, "outgoing", optClampMSS);
+ }
+ if (sendPacket(conn, conn->sessionSocket, packet, len + HDR_SIZE) < 0) {
+ exit(EXIT_FAILURE);
+ }
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+#ifdef USE_BPF
+/**********************************************************************
+*%FUNCTION: sessionDiscoveryPacket
+*%ARGUMENTS:
+* packet -- the discovery packet that was received
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* We got a discovery packet during the session stage. This most likely
+* means a PADT.
+*
+* The BSD version uses a single socket for both discovery and session
+* packets. When a packet comes in over the wire once we are in
+* session mode, either syncReadFromEth() or asyncReadFromEth() will
+* have already read the packet and determined it to be a discovery
+* packet before passing it here.
+***********************************************************************/
+void
+sessionDiscoveryPacket(PPPoEPacket *packet)
+{
+ /* Sanity check */
+ if (packet->code != CODE_PADT) {
+ return;
+ }
+
+ /* It's a PADT, all right. Is it for us? */
+ if (packet->session != Connection->session) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ syslog(LOG_INFO,
+ "Session terminated -- received PADT from access concentrator");
+ parsePacket(packet, parseLogErrs, NULL);
+ exit(EXIT_SUCCESS);
+}
+#else
+/**********************************************************************
+*%FUNCTION: sessionDiscoveryPacket
+*%ARGUMENTS:
+* conn -- PPPoE connection
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* We got a discovery packet during the session stage. This most likely
+* means a PADT.
+***********************************************************************/
+void
+sessionDiscoveryPacket(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ int len;
+
+ if (receivePacket(conn->discoverySocket, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+ if (packet.code != CODE_PADT) {
+ /* Not PADT; ignore it */
+ return;
+ }
+
+ /* It's a PADT, all right. Is it for us? */
+ if (packet.session != conn->session) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ syslog(LOG_INFO,
+ "Session terminated -- received PADT from peer");
+ parsePacket(&packet, parseLogErrs, NULL);
+ exit(EXIT_SUCCESS);
+}
+#endif /* USE_BPF */
+
+/**********************************************************************
+*%FUNCTION: session
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Handles the "session" phase of PPPoE
+***********************************************************************/
+void
+session(PPPoEConnection *conn)
+{
+ fd_set readable;
+ PPPoEPacket packet;
+ struct timeval tv;
+ struct timeval *tvp = NULL;
+ int maxFD = 0;
+ int r;
+
+ /* Open a session socket */
+ conn->sessionSocket = openInterface(conn->ifName, Eth_PPPOE_Session, conn->myEth);
+
+ /* Prepare for select() */
+ if (conn->sessionSocket > maxFD) maxFD = conn->sessionSocket;
+ if (conn->discoverySocket > maxFD) maxFD = conn->discoverySocket;
+ maxFD++;
+
+ /* Fill in the constant fields of the packet to save time */
+ memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Session);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_SESS;
+ packet.session = conn->session;
+
+ initPPP();
+
+#ifdef USE_BPF
+ /* check for buffered session data */
+ while (BPF_BUFFER_HAS_DATA) {
+ if (conn->synchronous) {
+ syncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ } else {
+ asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ }
+ }
+#endif
+
+ for (;;) {
+ if (optInactivityTimeout > 0) {
+ tv.tv_sec = optInactivityTimeout;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+ FD_ZERO(&readable);
+ FD_SET(0, &readable); /* ppp packets come from stdin */
+ if (conn->discoverySocket >= 0) {
+ FD_SET(conn->discoverySocket, &readable);
+ }
+ FD_SET(conn->sessionSocket, &readable);
+ while(1) {
+ r = select(maxFD, &readable, NULL, NULL, tvp);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ fatalSys("select (session)");
+ }
+ if (r == 0) { /* Inactivity timeout */
+ syslog(LOG_ERR, "Inactivity timeout... something wicked happened");
+ sendPADT(conn, "RP-PPPoE: Inactivity timeout");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Handle ready sockets */
+ if (FD_ISSET(0, &readable)) {
+ if (conn->synchronous) {
+ syncReadFromPPP(conn, &packet);
+ } else {
+ asyncReadFromPPP(conn, &packet);
+ }
+ }
+
+ if (FD_ISSET(conn->sessionSocket, &readable)) {
+ do {
+ if (conn->synchronous) {
+ syncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ } else {
+ asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ }
+ } while (BPF_BUFFER_HAS_DATA);
+ }
+
+#ifndef USE_BPF
+ /* BSD uses a single socket, see *syncReadFromEth() */
+ /* for calls to sessionDiscoveryPacket() */
+ if (conn->discoverySocket >= 0) {
+ if (FD_ISSET(conn->discoverySocket, &readable)) {
+ sessionDiscoveryPacket(conn);
+ }
+ }
+#endif
+
+ }
+}
+
+
+/***********************************************************************
+*%FUNCTION: sigPADT
+*%ARGUMENTS:
+* src -- signal received
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* If an established session exists send PADT to terminate from session
+* from our end
+***********************************************************************/
+void
+sigPADT(int src)
+{
+ syslog(LOG_DEBUG,"Received signal %d.",(int)src);
+ sendPADT(Connection, "RP-PPPoE: Received signal");
+ exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+#ifdef USE_BPF
+ fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n");
+#else
+ fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
+ DEFAULT_IF);
+#endif
+ fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n");
+ fprintf(stderr, " -D filename -- Log debugging information in filename.\n");
+ fprintf(stderr, " -V -- Print version and exit.\n");
+ fprintf(stderr, " -A -- Print access concentrator names and exit.\n");
+ fprintf(stderr, " -S name -- Set desired service name.\n");
+ fprintf(stderr, " -C name -- Set desired access concentrator name.\n");
+ fprintf(stderr, " -U -- Use Host-Unique to allow multiple PPPoE sessions.\n");
+ fprintf(stderr, " -s -- Use synchronous PPP encapsulation.\n");
+ fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n");
+ fprintf(stderr, " -p pidfile -- Write process-ID to pidfile.\n");
+ fprintf(stderr, " -e sess:mac -- Skip discovery phase; use existing session.\n");
+ fprintf(stderr, " -n -- Do not open discovery socket.\n");
+ fprintf(stderr, " -k -- Kill a session with PADT (requires -e)\n");
+ fprintf(stderr, " -d -- Perform discovery, print session info and exit.\n");
+ fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n");
+ fprintf(stderr, " -h -- Print usage information.\n\n");
+ fprintf(stderr, "PPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+ fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+ exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- count and values of command-line arguments
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Main program
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int n;
+ unsigned int m[6]; /* MAC address in -e option */
+ unsigned int s; /* Temporary to hold session */
+ FILE *pidfile;
+ unsigned int discoveryType, sessionType;
+
+ PPPoEConnection conn;
+
+#ifdef HAVE_N_HDLC
+ int disc = N_HDLC;
+ long flags;
+#endif
+
+ /* Initialize connection info */
+ memset(&conn, 0, sizeof(conn));
+ conn.discoverySocket = -1;
+ conn.sessionSocket = -1;
+
+ /* For signal handler */
+ Connection = &conn;
+
+ /* Initialize syslog */
+ openlog("pppoe", LOG_PID, LOG_DAEMON);
+
+ while((opt = getopt(argc, argv, "I:VAT:D:hS:C:Usm:np:e:kdf:")) != -1) {
+ switch(opt) {
+ case 'f':
+ if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
+ fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
+ exit(EXIT_FAILURE);
+ }
+ Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
+ Eth_PPPOE_Session = (UINT16_t) sessionType;
+ break;
+ case 'd':
+ optSkipSession = 1;
+ break;
+
+ case 'k':
+ conn.killSession = 1;
+ break;
+
+ case 'n':
+ /* Do not even open a discovery socket -- used when invoked
+ by pppoe-server */
+ conn.noDiscoverySocket = 1;
+ break;
+
+ case 'e':
+ /* Existing session: "sess:xx:yy:zz:aa:bb:cc" where "sess" is
+ session-ID, and xx:yy:zz:aa:bb:cc is MAC-address of peer */
+ n = sscanf(optarg, "%u:%2x:%2x:%2x:%2x:%2x:%2x",
+ &s, &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]);
+ if (n != 7) {
+ fprintf(stderr, "Illegal argument to -e: Should be sess:xx:yy:zz:aa:bb:cc\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Copy MAC address of peer */
+ for (n=0; n<6; n++) {
+ conn.peerEth[n] = (unsigned char) m[n];
+ }
+
+ /* Convert session */
+ conn.session = htons(s);
+
+ /* Skip discovery phase! */
+ conn.skipDiscovery = 1;
+ break;
+
+ case 'p':
+ pidfile = fopen(optarg, "w");
+ if (pidfile) {
+ fprintf(pidfile, "%lu\n", (unsigned long) getpid());
+ fclose(pidfile);
+ }
+ break;
+ case 'S':
+ SET_STRING(conn.serviceName, optarg);
+ break;
+ case 'C':
+ SET_STRING(conn.acName, optarg);
+ break;
+ case 's':
+ conn.synchronous = 1;
+ break;
+ case 'U':
+ conn.useHostUniq = 1;
+ break;
+ case 'D':
+ conn.debugFile = fopen(optarg, "w");
+ if (!conn.debugFile) {
+ fprintf(stderr, "Could not open %s: %s\n",
+ optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ fprintf(conn.debugFile, "rp-pppoe-%s\n", VERSION);
+ fflush(conn.debugFile);
+ break;
+ case 'T':
+ optInactivityTimeout = (int) strtol(optarg, NULL, 10);
+ if (optInactivityTimeout < 0) {
+ optInactivityTimeout = 0;
+ }
+ break;
+ case 'm':
+ optClampMSS = (int) strtol(optarg, NULL, 10);
+ if (optClampMSS < 536) {
+ fprintf(stderr, "-m: %d is too low (min 536)\n", optClampMSS);
+ exit(EXIT_FAILURE);
+ }
+ if (optClampMSS > 1452) {
+ fprintf(stderr, "-m: %d is too high (max 1452)\n", optClampMSS);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'I':
+ SET_STRING(conn.ifName, optarg);
+ break;
+ case 'V':
+ printf("Roaring Penguin PPPoE Version %s\n", VERSION);
+ exit(EXIT_SUCCESS);
+ case 'A':
+ conn.printACNames = 1;
+ break;
+ case 'h':
+ usage(argv[0]);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ /* Pick a default interface name */
+ if (!conn.ifName) {
+#ifdef USE_BPF
+ fprintf(stderr, "No interface specified (-I option)\n");
+ exit(EXIT_FAILURE);
+#else
+ SET_STRING(conn.ifName, DEFAULT_IF);
+#endif
+ }
+
+ /* Set signal handlers: send PADT on TERM, HUP and INT */
+ if (!conn.printACNames) {
+ signal(SIGTERM, sigPADT);
+ signal(SIGHUP, sigPADT);
+ signal(SIGINT, sigPADT);
+
+#ifdef HAVE_N_HDLC
+ if (conn.synchronous) {
+ if (ioctl(0, TIOCSETD, &disc) < 0) {
+ printErr("Unable to set line discipline to N_HDLC -- synchronous mode probably will fail");
+ } else {
+ syslog(LOG_INFO,
+ "Changed pty line discipline to N_HDLC for synchronous mode");
+ }
+ /* There is a bug in Linux's select which returns a descriptor
+ * as readable if N_HDLC line discipline is on, even if
+ * it isn't really readable. This return happens only when
+ * select() times out. To avoid blocking forever in read(),
+ * make descriptor 0 non-blocking */
+ flags = fcntl(0, F_GETFL);
+ if (flags < 0) fatalSys("fcntl(F_GETFL)");
+ if (fcntl(0, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
+ fatalSys("fcntl(F_SETFL)");
+ }
+ }
+#endif
+
+ }
+
+ discovery(&conn);
+ if (optSkipSession) {
+ printf("%u:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ntohs(conn.session),
+ conn.peerEth[0],
+ conn.peerEth[1],
+ conn.peerEth[2],
+ conn.peerEth[3],
+ conn.peerEth[4],
+ conn.peerEth[5]);
+ exit(EXIT_SUCCESS);
+ }
+ session(&conn);
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+ sendPADT(Connection, "RP-PPPoE: System call error");
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ char buf[1024];
+ printErr(str);
+ sprintf(buf, "RP-PPPoE: %.256s", str);
+ sendPADT(Connection, buf);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: asyncReadFromEth
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* sock -- Ethernet socket
+* clampMss -- if non-zero, do MSS-clamping
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads a packet from the Ethernet interface and sends it to async PPP
+* device.
+***********************************************************************/
+void
+asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
+{
+ PPPoEPacket packet;
+ int len;
+ int plen;
+ int i;
+ unsigned char pppBuf[4096];
+ unsigned char *ptr = pppBuf;
+ unsigned char c;
+ UINT16_t fcs;
+ unsigned char header[2] = {FRAME_ADDR, FRAME_CTRL};
+ unsigned char tail[2];
+#ifdef USE_BPF
+ int type;
+#endif
+
+ if (receivePacket(sock, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+#ifdef USE_BPF
+ /* Make sure this is a session packet before processing further */
+ type = etherType(&packet);
+ if (type == Eth_PPPOE_Discovery) {
+ sessionDiscoveryPacket(&packet);
+ } else if (type != Eth_PPPOE_Session) {
+ return;
+ }
+#endif
+
+ /* Sanity check */
+ if (packet.code != CODE_SESS) {
+ syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code);
+ return;
+ }
+ if (packet.ver != 1) {
+ syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver);
+ return;
+ }
+ if (packet.type != 1) {
+ syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type);
+ return;
+ }
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+
+ if (packet.session != conn->session) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+ plen = ntohs(packet.length);
+ if (plen + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+ (int) plen, (int) len);
+ return;
+ }
+
+ /* Clamp MSS */
+ if (clampMss) {
+ clampMSS(&packet, "incoming", clampMss);
+ }
+
+ /* Compute FCS */
+ fcs = pppFCS16(PPPINITFCS16, header, 2);
+ fcs = pppFCS16(fcs, packet.payload, plen) ^ 0xffff;
+ tail[0] = fcs & 0x00ff;
+ tail[1] = (fcs >> 8) & 0x00ff;
+
+ /* Build a buffer to send to PPP */
+ *ptr++ = FRAME_FLAG;
+ *ptr++ = FRAME_ADDR;
+ *ptr++ = FRAME_ESC;
+ *ptr++ = FRAME_CTRL ^ FRAME_ENC;
+
+ for (i=0; i<plen; i++) {
+ c = packet.payload[i];
+ if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+ *ptr++ = FRAME_ESC;
+ *ptr++ = c ^ FRAME_ENC;
+ } else {
+ *ptr++ = c;
+ }
+ }
+ for (i=0; i<2; i++) {
+ c = tail[i];
+ if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+ *ptr++ = FRAME_ESC;
+ *ptr++ = c ^ FRAME_ENC;
+ } else {
+ *ptr++ = c;
+ }
+ }
+ *ptr++ = FRAME_FLAG;
+
+ /* Ship it out */
+ if (write(1, pppBuf, (ptr-pppBuf)) < 0) {
+ fatalSys("asyncReadFromEth: write");
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: syncReadFromEth
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* sock -- Ethernet socket
+* clampMss -- if true, clamp MSS.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads a packet from the Ethernet interface and sends it to sync PPP
+* device.
+***********************************************************************/
+void
+syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
+{
+ PPPoEPacket packet;
+ int len;
+ int plen;
+ struct iovec vec[2];
+ unsigned char dummy[2];
+#ifdef USE_BPF
+ int type;
+#endif
+
+ if (receivePacket(sock, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+#ifdef USE_BPF
+ /* Make sure this is a session packet before processing further */
+ type = etherType(&packet);
+ if (type == Eth_PPPOE_Discovery) {
+ sessionDiscoveryPacket(&packet);
+ } else if (type != Eth_PPPOE_Session) {
+ return;
+ }
+#endif
+
+ /* Sanity check */
+ if (packet.code != CODE_SESS) {
+ syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code);
+ return;
+ }
+ if (packet.ver != 1) {
+ syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver);
+ return;
+ }
+ if (packet.type != 1) {
+ syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type);
+ return;
+ }
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+ if (packet.session != conn->session) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+ plen = ntohs(packet.length);
+ if (plen + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+ (int) plen, (int) len);
+ return;
+ }
+
+ /* Clamp MSS */
+ if (clampMss) {
+ clampMSS(&packet, "incoming", clampMss);
+ }
+
+ /* Ship it out */
+ vec[0].iov_base = (void *) dummy;
+ dummy[0] = FRAME_ADDR;
+ dummy[1] = FRAME_CTRL;
+ vec[0].iov_len = 2;
+ vec[1].iov_base = (void *) packet.payload;
+ vec[1].iov_len = plen;
+
+ if (writev(1, vec, 2) < 0) {
+ fatalSys("syncReadFromEth: write");
+ }
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/pppoe.h b/mdk-stage1/rp-pppoe/src/pppoe.h
new file mode 100644
index 000000000..da300c17d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe.h
@@ -0,0 +1,331 @@
+/***********************************************************************
+*
+* pppoe.h
+*
+* Declaration of various PPPoE constants
+*
+* Copyright (C) 2000 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id$
+*
+***********************************************************************/
+
+#ifdef __sun__
+#define __EXTENSIONS__
+#endif
+
+#include "config.h"
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define _POSIX_SOURCE 1 /* For sigaction defines */
+#endif
+
+#include <stdio.h> /* For FILE */
+#include <sys/types.h> /* For pid_t */
+
+/* How do we access raw Ethernet devices? */
+#undef USE_LINUX_PACKET
+#undef USE_BPF
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define USE_LINUX_PACKET 1
+#elif defined(HAVE_NET_BPF_H)
+#define USE_BPF 1
+#elif defined(HAVE_SYS_DLPI_H)
+#define USE_DLPI
+#endif
+
+/* Sanity check */
+#if !defined(USE_BPF) && !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
+#error Unknown method for accessing raw Ethernet frames
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+/* Ugly header files on some Linux boxes... */
+#if defined(HAVE_LINUX_IF_H)
+#include <linux/if.h>
+#elif defined(HAVE_NET_IF_H)
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_NET_IF_TYPES_H
+#include <net/if_types.h>
+#endif
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+
+/* I'm not sure why this is needed... I do not have OpenBSD */
+#if defined(__OpenBSD__)
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#endif
+
+#ifdef USE_BPF
+extern int bpfSize;
+struct PPPoEPacketStruct;
+void sessionDiscoveryPacket(struct PPPoEPacketStruct *packet);
+#define BPF_BUFFER_IS_EMPTY (bpfSize <= 0)
+#define BPF_BUFFER_HAS_DATA (bpfSize > 0)
+#define ethhdr ether_header
+#define h_dest ether_dhost
+#define h_source ether_shost
+#define h_proto ether_type
+#define ETH_DATA_LEN ETHERMTU
+#define ETH_ALEN ETHER_ADDR_LEN
+#else
+#undef USE_BPF
+#define BPF_BUFFER_IS_EMPTY 1
+#define BPF_BUFFER_HAS_DATA 0
+#endif
+
+#ifdef USE_DLPI
+#include <sys/ethernet.h>
+#define ethhdr ether_header
+#define ETH_DATA_LEN ETHERMTU
+#define ETH_ALEN ETHERADDRL
+#define h_dest ether_dhost.ether_addr_octet
+#define h_source ether_shost.ether_addr_octet
+#define h_proto ether_type
+
+/* cloned from dltest.h */
+#define MAXDLBUF 8192
+#define MAXDLADDR 1024
+#define MAXWAIT 15
+#define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n))
+#define CASERET(s) case s: return ("s")
+
+#endif
+
+/* Define various integer types -- assumes a char is 8 bits */
+#if SIZEOF_UNSIGNED_SHORT == 2
+typedef unsigned short UINT16_t;
+#elif SIZEOF_UNSIGNED_INT == 2
+typedef unsigned int UINT16_t;
+#else
+#error Could not find a 16-bit integer type
+#endif
+
+#if SIZEOF_UNSIGNED_SHORT == 4
+typedef unsigned short UINT32_t;
+#elif SIZEOF_UNSIGNED_INT == 4
+typedef unsigned int UINT32_t;
+#elif SIZEOF_UNSIGNED_LONG == 4
+typedef unsigned long UINT32_t;
+#else
+#error Could not find a 16-bit integer type
+#endif
+
+#ifdef HAVE_LINUX_IF_ETHER_H
+#include <linux/if_ether.h>
+#endif
+
+#include <netinet/in.h>
+
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifndef HAVE_SYS_DLPI_H
+#include <netinet/if_ether.h>
+#endif
+#endif
+
+
+
+/* Ethernet frame types according to RFC 2516 */
+#define ETH_PPPOE_DISCOVERY 0x8863
+#define ETH_PPPOE_SESSION 0x8864
+
+/* But some brain-dead peers disobey the RFC, so frame types are variables */
+extern UINT16_t Eth_PPPOE_Discovery;
+extern UINT16_t Eth_PPPOE_Session;
+
+/* PPPoE codes */
+#define CODE_PADI 0x09
+#define CODE_PADO 0x07
+#define CODE_PADR 0x19
+#define CODE_PADS 0x65
+#define CODE_PADT 0xA7
+#define CODE_SESS 0x00
+
+/* PPPoE Tags */
+#define TAG_END_OF_LIST 0x0000
+#define TAG_SERVICE_NAME 0x0101
+#define TAG_AC_NAME 0x0102
+#define TAG_HOST_UNIQ 0x0103
+#define TAG_AC_COOKIE 0x0104
+#define TAG_VENDOR_SPECIFIC 0x0105
+#define TAG_RELAY_SESSION_ID 0x0110
+#define TAG_SERVICE_NAME_ERROR 0x0201
+#define TAG_AC_SYSTEM_ERROR 0x0202
+#define TAG_GENERIC_ERROR 0x0203
+
+/* Discovery phase states */
+#define STATE_SENT_PADI 0
+#define STATE_RECEIVED_PADO 1
+#define STATE_SENT_PADR 2
+#define STATE_SESSION 3
+#define STATE_TERMINATED 4
+
+/* How many PADI/PADS attempts? */
+#define MAX_PADI_ATTEMPTS 3
+
+/* Initial timeout for PADO/PADS */
+#define PADI_TIMEOUT 5
+
+/* States for scanning PPP frames */
+#define STATE_WAITFOR_FRAME_ADDR 0
+#define STATE_DROP_PROTO 1
+#define STATE_BUILDING_PACKET 2
+
+/* Special PPP frame characters */
+#define FRAME_ESC 0x7D
+#define FRAME_FLAG 0x7E
+#define FRAME_ADDR 0xFF
+#define FRAME_CTRL 0x03
+#define FRAME_ENC 0x20
+
+#define IPV4ALEN 4
+#define SMALLBUF 256
+
+/* A PPPoE Packet, including Ethernet headers */
+typedef struct PPPoEPacketStruct {
+ struct ethhdr ethHdr; /* Ethernet header */
+#ifdef PACK_BITFIELDS_REVERSED
+ unsigned int type:4; /* PPPoE Type (must be 1) */
+ unsigned int ver:4; /* PPPoE Version (must be 1) */
+#else
+ unsigned int ver:4; /* PPPoE Version (must be 1) */
+ unsigned int type:4; /* PPPoE Type (must be 1) */
+#endif
+ unsigned int code:8; /* PPPoE code */
+ unsigned int session:16; /* PPPoE session */
+ unsigned int length:16; /* Payload length */
+ unsigned char payload[ETH_DATA_LEN]; /* A bit of room to spare */
+} PPPoEPacket;
+
+/* Header size of a PPPoE packet */
+#define PPPOE_OVERHEAD 6 /* type, code, session, length */
+#define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD)
+#define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD)
+#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2)
+
+/* PPPoE Tag */
+
+typedef struct PPPoETagStruct {
+ unsigned int type:16; /* tag type */
+ unsigned int length:16; /* Length of payload */
+ unsigned char payload[ETH_DATA_LEN]; /* A LOT of room to spare */
+} PPPoETag;
+/* Header size of a PPPoE tag */
+#define TAG_HDR_SIZE 4
+
+/* Chunk to read from stdin */
+#define READ_CHUNK 4096
+
+/* Function passed to parsePacket */
+typedef void ParseFunc(UINT16_t type,
+ UINT16_t len,
+ unsigned char *data,
+ void *extra);
+
+/* Structures used by PPPoE server */
+struct ClientSession {
+ pid_t pid; /* PID of child handling session */
+ unsigned char ip[IPV4ALEN]; /* IP address of peer */
+ UINT16_t sess; /* Session number */
+ unsigned char eth[ETH_ALEN]; /* Peer's Ethernet address */
+ int recvdPADT; /* Peer sent a PADT */
+};
+
+#define PPPINITFCS16 0xffff /* Initial FCS value */
+
+/* Keep track of the state of a connection -- collect everything in
+ one spot */
+
+typedef struct PPPoEConnectionStruct {
+ int discoveryState; /* Where we are in discovery */
+ int discoverySocket; /* Raw socket for discovery frames */
+ int sessionSocket; /* Raw socket for session frames */
+ unsigned char myEth[ETH_ALEN]; /* My MAC address */
+ unsigned char peerEth[ETH_ALEN]; /* Peer's MAC address */
+ UINT16_t session; /* Session ID */
+ char *ifName; /* Interface name */
+ char *serviceName; /* Desired service name, if any */
+ char *acName; /* Desired AC name, if any */
+ int synchronous; /* Use synchronous PPP */
+ int useHostUniq; /* Use Host-Uniq tag */
+ int printACNames; /* Just print AC names */
+ int skipDiscovery; /* Skip discovery */
+ int noDiscoverySocket; /* Don't even open discovery socket */
+ int killSession; /* Kill session and exit */
+ FILE *debugFile; /* Debug file for dumping packets */
+ int numPADOs; /* Number of PADO packets received */
+ PPPoETag cookie; /* We have to send this if we get it */
+ PPPoETag relayId; /* Ditto */
+} PPPoEConnection;
+
+/* Structure used to determine acceptable PADO or PADS packet */
+struct PacketCriteria {
+ PPPoEConnection *conn;
+ int acNameOK;
+ int serviceNameOK;
+};
+
+/* Function Prototypes */
+UINT16_t etherType(PPPoEPacket *packet);
+int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr);
+int sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size);
+int receivePacket(int sock, PPPoEPacket *pkt, int *size);
+void fatalSys(char const *str);
+void rp_fatal(char const *str);
+void printErr(char const *str);
+void sysErr(char const *str);
+void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir);
+void dumpHex(FILE *fp, unsigned char const *buf, int len);
+int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra);
+void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra);
+void syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
+void asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
+void asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+char *strDup(char const *str);
+void sendPADT(PPPoEConnection *conn, char const *msg);
+void sendSessionPacket(PPPoEConnection *conn,
+ PPPoEPacket *packet, int len);
+void initPPP(void);
+void clampMSS(PPPoEPacket *packet, char const *dir, int clampMss);
+UINT16_t computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr);
+UINT16_t pppFCS16(UINT16_t fcs, unsigned char *cp, int len);
+void discovery(PPPoEConnection *conn);
+unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
+ PPPoETag *tag);
+
+#define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0);
+
+#define CHECK_ROOM(cursor, start, len) \
+do {\
+ if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
+ syslog(LOG_ERR, "Would create too-long packet"); \
+ return; \
+ } \
+} while(0)
+
+/* True if Ethernet address is broadcast or multicast */
+#define NOT_UNICAST(e) ((e[0] & 0x01) != 0)
+#define BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) == 0xFF)
+#define NOT_BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) != 0xFF)
diff --git a/mdk-stage1/rp-pppoe/src/relay.c b/mdk-stage1/rp-pppoe/src/relay.c
new file mode 100644
index 000000000..9738cb8a8
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/relay.c
@@ -0,0 +1,1541 @@
+/***********************************************************************
+*
+* relay.c
+*
+* Implementation of PPPoE relay
+*
+* Copyright (C) 2001 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id$
+*
+***********************************************************************/
+static char const RCSID[] =
+"$Id$";
+
+#define _GNU_SOURCE 1 /* For SA_RESTART */
+
+#include "relay.h"
+
+#include <signal.h>
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* Interfaces (max MAX_INTERFACES) */
+PPPoEInterface Interfaces[MAX_INTERFACES];
+int NumInterfaces;
+
+/* Relay info */
+int NumSessions;
+int MaxSessions;
+PPPoESession *AllSessions;
+PPPoESession *FreeSessions;
+PPPoESession *ActiveSessions;
+
+SessionHash *AllHashes;
+SessionHash *FreeHashes;
+SessionHash *Buckets[HASHTAB_SIZE];
+
+volatile unsigned int Epoch = 0;
+volatile unsigned int CleanCounter = 0;
+
+/* How often to clean up stale sessions? */
+#define MIN_CLEAN_PERIOD 30 /* Minimum period to run cleaner */
+#define TIMEOUT_DIVISOR 20 /* How often to run cleaner per timeout period */
+unsigned int CleanPeriod = MIN_CLEAN_PERIOD;
+
+/* How long a session can be idle before it is cleaned up? */
+unsigned int IdleTimeout = MIN_CLEAN_PERIOD * TIMEOUT_DIVISOR;
+
+/* Pipe for breaking select() to initiate periodic cleaning */
+int CleanPipe[2];
+
+/* Our relay: if_index followed by peer_mac */
+#define MY_RELAY_TAG_LEN (sizeof(int) + ETH_ALEN)
+
+/* Hack for daemonizing */
+#define CLOSEFD 64
+
+/**********************************************************************
+*%FUNCTION: keepDescriptor
+*%ARGUMENTS:
+* fd -- a file descriptor
+*%RETURNS:
+* 1 if descriptor should NOT be closed during daemonizing; 0 otherwise.
+***********************************************************************/
+static int
+keepDescriptor(int fd)
+{
+ int i;
+ if (fd == CleanPipe[0] || fd == CleanPipe[1]) return 1;
+ for (i=0; i<NumInterfaces; i++) {
+ if (fd == Interfaces[i].discoverySock ||
+ fd == Interfaces[i].sessionSock) return 1;
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: addTag
+*%ARGUMENTS:
+* packet -- a PPPoE packet
+* tag -- tag to add
+*%RETURNS:
+* -1 if no room in packet; number of bytes added otherwise.
+*%DESCRIPTION:
+* Inserts a tag as the first tag in a PPPoE packet.
+***********************************************************************/
+int
+addTag(PPPoEPacket *packet, PPPoETag const *tag)
+{
+ return insertBytes(packet, packet->payload, tag,
+ ntohs(tag->length) + TAG_HDR_SIZE);
+}
+
+/**********************************************************************
+*%FUNCTION: insertBytes
+*%ARGUMENTS:
+* packet -- a PPPoE packet
+* loc -- location at which to insert bytes of data
+* bytes -- the data to insert
+* len -- length of data to insert
+*%RETURNS:
+* -1 if no room in packet; len otherwise.
+*%DESCRIPTION:
+* Inserts "len" bytes of data at location "loc" in "packet", moving all
+* other data up to make room.
+***********************************************************************/
+int
+insertBytes(PPPoEPacket *packet,
+ unsigned char *loc,
+ void const *bytes,
+ int len)
+{
+ int toMove;
+ int plen = ntohs(packet->length);
+ /* Sanity checks */
+ if (loc < packet->payload ||
+ loc > packet->payload + plen ||
+ len + plen > MAX_PPPOE_PAYLOAD) {
+ return -1;
+ }
+
+ toMove = (packet->payload + plen) - loc;
+ memmove(loc+len, loc, toMove);
+ memcpy(loc, bytes, len);
+ packet->length = htons(plen + len);
+ return len;
+}
+
+/**********************************************************************
+*%FUNCTION: removeBytes
+*%ARGUMENTS:
+* packet -- a PPPoE packet
+* loc -- location at which to remove bytes of data
+* len -- length of data to remove
+*%RETURNS:
+* -1 if there was a problem, len otherwise
+*%DESCRIPTION:
+* Removes "len" bytes of data from location "loc" in "packet", moving all
+* other data down to close the gap
+***********************************************************************/
+int
+removeBytes(PPPoEPacket *packet,
+ unsigned char *loc,
+ int len)
+{
+ int toMove;
+ int plen = ntohs(packet->length);
+ /* Sanity checks */
+ if (len < 0 || len > plen ||
+ loc < packet->payload ||
+ loc + len > packet->payload + plen) {
+ return -1;
+ }
+
+ toMove = ((packet->payload + plen) - loc) - len;
+ memmove(loc, loc+len, toMove);
+ packet->length = htons(plen - len);
+ return len;
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -S if_name -- Specify interface for PPPoE Server\n");
+ fprintf(stderr, " -C if_name -- Specify interface for PPPoE Client\n");
+ fprintf(stderr, " -B if_name -- Specify interface for both clients and server\n");
+ fprintf(stderr, " -n nsess -- Maxmimum number of sessions to relay\n");
+ fprintf(stderr, " -i timeout -- Idle timeout in seconds (0 = no timeout)\n");
+ fprintf(stderr, " -F -- Do not fork into background\n");
+ fprintf(stderr, " -h -- Print this help message\n");
+
+ fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+ fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+ exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- usual suspects
+*%RETURNS:
+* EXIT_SUCCESS or EXIT_FAILURE
+*%DESCRIPTION:
+* Main program. Options:
+* -C ifname -- Use interface for PPPoE clients
+* -S ifname -- Use interface for PPPoE servers
+* -B ifname -- Use interface for both clients and servers
+* -n sessions -- Maximum of "n" sessions
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int nsess = DEFAULT_SESSIONS;
+ struct sigaction sa;
+ int beDaemon = 1;
+ openlog("pppoe-relay", LOG_PID, LOG_DAEMON);
+
+ while((opt = getopt(argc, argv, "hC:S:B:n:i:F")) != -1) {
+ switch(opt) {
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'F':
+ beDaemon = 0;
+ break;
+ case 'C':
+ addInterface(optarg, 1, 0);
+ break;
+ case 'S':
+ addInterface(optarg, 0, 1);
+ break;
+ case 'B':
+ addInterface(optarg, 1, 1);
+ break;
+ case 'i':
+ if (sscanf(optarg, "%u", &IdleTimeout) != 1) {
+ fprintf(stderr, "Illegal argument to -i: should be -i timeout\n");
+ exit(EXIT_FAILURE);
+ }
+ CleanPeriod = IdleTimeout / TIMEOUT_DIVISOR;
+ if (CleanPeriod < MIN_CLEAN_PERIOD) CleanPeriod = MIN_CLEAN_PERIOD;
+ break;
+ case 'n':
+ if (sscanf(optarg, "%d", &nsess) != 1) {
+ fprintf(stderr, "Illegal argument to -n: should be -n #sessions\n");
+ exit(EXIT_FAILURE);
+ }
+ if (nsess < 1 || nsess > 65534) {
+ fprintf(stderr, "Illegal argument to -n: must range from 1 to 65534\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+ fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");
+ exit(EXIT_FAILURE);
+#endif
+#endif
+
+ /* Check that at least two interfaces were defined */
+ if (NumInterfaces < 2) {
+ fprintf(stderr, "%s: Must define at least two interfaces\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Make a pipe for the cleaner */
+ if (pipe(CleanPipe) < 0) {
+ fatalSys("pipe");
+ }
+
+ /* Set up alarm handler */
+ sa.sa_handler = alarmHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGALRM, &sa, NULL) < 0) {
+ fatalSys("sigaction");
+ }
+
+ /* Allocate memory for sessions, etc. */
+ initRelay(nsess);
+
+ /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
+ if (beDaemon) {
+ int i;
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ /* parent */
+ exit(0);
+ }
+ setsid();
+ signal(SIGHUP, SIG_IGN);
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ exit(0);
+ }
+
+ chdir("/");
+ closelog();
+ for (i=0; i<CLOSEFD; i++) {
+ if (!keepDescriptor(i)) {
+ close(i);
+ }
+ }
+ /* We nuked our syslog descriptor... */
+ openlog("pppoe-relay", LOG_PID, LOG_DAEMON);
+ }
+
+ /* Kick off SIGALRM if there is an idle timeout */
+ if (IdleTimeout) alarm(1);
+
+ /* Enter the relay loop */
+ relayLoop();
+
+ /* Shouldn't ever get here... */
+ return EXIT_FAILURE;
+}
+
+/**********************************************************************
+*%FUNCTION: addInterface
+*%ARGUMENTS:
+* ifname -- interface name
+* clientOK -- true if this interface should relay PADI, PADR packets.
+* acOK -- true if this interface should relay PADO, PADS packets.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Opens an interface; sets up discovery and session sockets.
+***********************************************************************/
+void
+addInterface(char const *ifname,
+ int clientOK,
+ int acOK)
+{
+ PPPoEInterface *i;
+ if (NumInterfaces >= MAX_INTERFACES) {
+ fprintf(stderr, "Too many interfaces (%d max)\n",
+ MAX_INTERFACES);
+ exit(EXIT_FAILURE);
+ }
+ i = &Interfaces[NumInterfaces++];
+ strncpy(i->name, ifname, IFNAMSIZ);
+ i->name[IFNAMSIZ] = 0;
+
+ i->discoverySock = openInterface(ifname, Eth_PPPOE_Discovery, i->mac);
+ i->sessionSock = openInterface(ifname, Eth_PPPOE_Session, NULL);
+ i->clientOK = clientOK;
+ i->acOK = acOK;
+}
+
+/**********************************************************************
+*%FUNCTION: initRelay
+*%ARGUMENTS:
+* nsess -- maximum allowable number of sessions
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Initializes relay hash table and session tables.
+***********************************************************************/
+void
+initRelay(int nsess)
+{
+ int i;
+ NumSessions = 0;
+ MaxSessions = nsess;
+
+ AllSessions = calloc(MaxSessions, sizeof(PPPoESession));
+ if (!AllSessions) {
+ rp_fatal("Unable to allocate memory for PPPoE session table");
+ }
+ AllHashes = calloc(MaxSessions*2, sizeof(SessionHash));
+ if (!AllHashes) {
+ rp_fatal("Unable to allocate memory for PPPoE hash table");
+ }
+
+ /* Initialize sessions in a linked list */
+ AllSessions[0].prev = NULL;
+ if (MaxSessions > 1) {
+ AllSessions[0].next = &AllSessions[1];
+ } else {
+ AllSessions[0].next = NULL;
+ }
+ for (i=1; i<MaxSessions-1; i++) {
+ AllSessions[i].prev = &AllSessions[i-1];
+ AllSessions[i].next = &AllSessions[i+1];
+ }
+ if (MaxSessions > 1) {
+ AllSessions[MaxSessions-1].prev = &AllSessions[MaxSessions-2];
+ AllSessions[MaxSessions-1].next = NULL;
+ }
+
+ FreeSessions = AllSessions;
+ ActiveSessions = NULL;
+
+ /* Initialize session numbers which we hand out */
+ for (i=0; i<MaxSessions; i++) {
+ AllSessions[i].sesNum = htons((UINT16_t) i+1);
+ }
+
+ /* Initialize hashes in a linked list */
+ AllHashes[0].prev = NULL;
+ AllHashes[0].next = &AllHashes[1];
+ for (i=1; i<2*MaxSessions-1; i++) {
+ AllHashes[i].prev = &AllHashes[i-1];
+ AllHashes[i].next = &AllHashes[i+1];
+ }
+ AllHashes[2*MaxSessions-1].prev = &AllHashes[2*MaxSessions-2];
+ AllHashes[2*MaxSessions-1].next = NULL;
+
+ FreeHashes = AllHashes;
+}
+
+/**********************************************************************
+*%FUNCTION: createSession
+*%ARGUMENTS:
+* ac -- Ethernet interface on access-concentrator side
+* cli -- Ethernet interface on client side
+* acMac -- Access concentrator's MAC address
+* cliMac -- Client's MAC address
+* acSess -- Access concentrator's session ID.
+*%RETURNS:
+* PPPoESession structure; NULL if one could not be allocated
+*%DESCRIPTION:
+* Initializes relay hash table and session tables.
+***********************************************************************/
+PPPoESession *
+createSession(PPPoEInterface const *ac,
+ PPPoEInterface const *cli,
+ unsigned char const *acMac,
+ unsigned char const *cliMac,
+ UINT16_t acSes)
+{
+ PPPoESession *sess;
+ SessionHash *acHash, *cliHash;
+
+ if (NumSessions >= MaxSessions) {
+ printErr("Maximum number of sessions reached -- cannot create new session");
+ return NULL;
+ }
+
+ /* Grab a free session */
+ sess = FreeSessions;
+ FreeSessions = sess->next;
+ NumSessions++;
+
+ /* Link it to the active list */
+ sess->next = ActiveSessions;
+ if (sess->next) {
+ sess->next->prev = sess;
+ }
+ ActiveSessions = sess;
+ sess->prev = NULL;
+
+ sess->epoch = Epoch;
+
+ /* Get two hash entries */
+ acHash = FreeHashes;
+ cliHash = acHash->next;
+ FreeHashes = cliHash->next;
+
+ acHash->peer = cliHash;
+ cliHash->peer = acHash;
+
+ sess->acHash = acHash;
+ sess->clientHash = cliHash;
+
+ acHash->interface = ac;
+ cliHash->interface = cli;
+
+ memcpy(acHash->peerMac, acMac, ETH_ALEN);
+ acHash->sesNum = acSes;
+ acHash->ses = sess;
+
+ memcpy(cliHash->peerMac, cliMac, ETH_ALEN);
+ cliHash->sesNum = sess->sesNum;
+ cliHash->ses = sess;
+
+ addHash(acHash);
+ addHash(cliHash);
+
+ /* Log */
+ syslog(LOG_INFO,
+ "Opened session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d)",
+ acHash->peerMac[0], acHash->peerMac[1],
+ acHash->peerMac[2], acHash->peerMac[3],
+ acHash->peerMac[4], acHash->peerMac[5],
+ acHash->interface->name,
+ ntohs(acHash->sesNum),
+ cliHash->peerMac[0], cliHash->peerMac[1],
+ cliHash->peerMac[2], cliHash->peerMac[3],
+ cliHash->peerMac[4], cliHash->peerMac[5],
+ cliHash->interface->name,
+ ntohs(cliHash->sesNum));
+
+ return sess;
+}
+
+/**********************************************************************
+*%FUNCTION: freeSession
+*%ARGUMENTS:
+* ses -- session to free
+* msg -- extra message to log on syslog.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Frees data used by a PPPoE session -- adds hashes and session back
+* to the free list
+***********************************************************************/
+void
+freeSession(PPPoESession *ses, char const *msg)
+{
+ syslog(LOG_INFO,
+ "Closed session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d): %s",
+ ses->acHash->peerMac[0], ses->acHash->peerMac[1],
+ ses->acHash->peerMac[2], ses->acHash->peerMac[3],
+ ses->acHash->peerMac[4], ses->acHash->peerMac[5],
+ ses->acHash->interface->name,
+ ntohs(ses->acHash->sesNum),
+ ses->clientHash->peerMac[0], ses->clientHash->peerMac[1],
+ ses->clientHash->peerMac[2], ses->clientHash->peerMac[3],
+ ses->clientHash->peerMac[4], ses->clientHash->peerMac[5],
+ ses->clientHash->interface->name,
+ ntohs(ses->clientHash->sesNum), msg);
+
+ /* Unlink from active sessions */
+ if (ses->prev) {
+ ses->prev->next = ses->next;
+ } else {
+ ActiveSessions = ses->next;
+ }
+ if (ses->next) {
+ ses->next->prev = ses->prev;
+ }
+
+ /* Link onto free list -- this is a singly-linked list, so
+ we do not care about prev */
+ ses->next = FreeSessions;
+ FreeSessions = ses;
+
+ unhash(ses->acHash);
+ unhash(ses->clientHash);
+ NumSessions--;
+}
+
+/**********************************************************************
+*%FUNCTION: unhash
+*%ARGUMENTS:
+* sh -- session hash to free
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Frees a session hash -- takes it out of hash table and puts it on
+* free list.
+***********************************************************************/
+void
+unhash(SessionHash *sh)
+{
+ unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE;
+ if (sh->prev) {
+ sh->prev->next = sh->next;
+ } else {
+ Buckets[b] = sh->next;
+ }
+
+ if (sh->next) {
+ sh->next->prev = sh->prev;
+ }
+
+ /* Add to free list (singly-linked) */
+ sh->next = FreeHashes;
+ FreeHashes = sh;
+}
+
+/**********************************************************************
+*%FUNCTION: addHash
+*%ARGUMENTS:
+* sh -- a session hash
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Adds a SessionHash to the hash table
+***********************************************************************/
+void
+addHash(SessionHash *sh)
+{
+ unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE;
+ sh->next = Buckets[b];
+ sh->prev = NULL;
+ if (sh->next) {
+ sh->next->prev = sh;
+ }
+ Buckets[b] = sh;
+}
+
+/**********************************************************************
+*%FUNCTION: hash
+*%ARGUMENTS:
+* mac -- an Ethernet address
+* sesNum -- a session number
+*%RETURNS:
+* A hash value combining Ethernet address with session number.
+* Currently very simplistic; we may need to experiment with different
+* hash values.
+***********************************************************************/
+unsigned int
+hash(unsigned char const *mac, UINT16_t sesNum)
+{
+ unsigned int ans1 =
+ ((unsigned int) mac[0]) |
+ (((unsigned int) mac[1]) << 8) |
+ (((unsigned int) mac[2]) << 16) |
+ (((unsigned int) mac[3]) << 24);
+ unsigned int ans2 =
+ ((unsigned int) sesNum) |
+ (((unsigned int) mac[4]) << 16) |
+ (((unsigned int) mac[5]) << 24);
+ return ans1 ^ ans2;
+}
+
+/**********************************************************************
+*%FUNCTION: findSession
+*%ARGUMENTS:
+* mac -- an Ethernet address
+* sesNum -- a session number
+*%RETURNS:
+* The session hash for peer address "mac", session number sesNum
+***********************************************************************/
+SessionHash *
+findSession(unsigned char const *mac, UINT16_t sesNum)
+{
+ unsigned int b = hash(mac, sesNum) % HASHTAB_SIZE;
+ SessionHash *sh = Buckets[b];
+ while(sh) {
+ if (!memcmp(mac, sh->peerMac, ETH_ALEN) && sesNum == sh->sesNum) {
+ return sh;
+ }
+ sh = sh->next;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ printErr(str);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: relayLoop
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Runs the relay loop. This function never returns
+***********************************************************************/
+void
+relayLoop()
+{
+ fd_set readable, readableCopy;
+ int maxFD;
+ int i, r;
+ int sock;
+
+ /* Build the select set */
+ FD_ZERO(&readable);
+ maxFD = 0;
+ for (i=0; i<NumInterfaces; i++) {
+ sock = Interfaces[i].discoverySock;
+ if (sock > maxFD) maxFD = sock;
+ FD_SET(sock, &readable);
+ sock = Interfaces[i].sessionSock;
+ if (sock > maxFD) maxFD = sock;
+ FD_SET(sock, &readable);
+ if (CleanPipe[0] > maxFD) maxFD = CleanPipe[0];
+ FD_SET(CleanPipe[0], &readable);
+ }
+ maxFD++;
+ for(;;) {
+ readableCopy = readable;
+ for(;;) {
+ r = select(maxFD, &readableCopy, NULL, NULL, NULL);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ sysErr("select (relayLoop)");
+ continue;
+ }
+
+ /* Handle session packets first */
+ for (i=0; i<NumInterfaces; i++) {
+ if (FD_ISSET(Interfaces[i].sessionSock, &readableCopy)) {
+ relayGotSessionPacket(&Interfaces[i]);
+ }
+ }
+
+ /* Now handle discovery packets */
+ for (i=0; i<NumInterfaces; i++) {
+ if (FD_ISSET(Interfaces[i].discoverySock, &readableCopy)) {
+ relayGotDiscoveryPacket(&Interfaces[i]);
+ }
+ }
+
+ /* Handle the session-cleaning process */
+ if (FD_ISSET(CleanPipe[0], &readableCopy)) {
+ char dummy;
+ CleanCounter = 0;
+ read(CleanPipe[0], &dummy, 1);
+ if (IdleTimeout) cleanSessions();
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: relayGotDiscoveryPacket
+*%ARGUMENTS:
+* iface -- interface on which packet is waiting
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a discovery packet.
+***********************************************************************/
+void
+relayGotDiscoveryPacket(PPPoEInterface const *iface)
+{
+ PPPoEPacket packet;
+ int size;
+
+ if (receivePacket(iface->discoverySock, &packet, &size) < 0) {
+ return;
+ }
+ /* Ignore unknown code/version */
+ if (packet.ver != 1 || packet.type != 1) {
+ return;
+ }
+
+ /* Validate length */
+ if (ntohs(packet.length) + HDR_SIZE > size) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ /* Drop Ethernet frame padding */
+ if (size > ntohs(packet.length) + HDR_SIZE) {
+ size = ntohs(packet.length) + HDR_SIZE;
+ }
+
+ switch(packet.code) {
+ case CODE_PADT:
+ relayHandlePADT(iface, &packet, size);
+ break;
+ case CODE_PADI:
+ relayHandlePADI(iface, &packet, size);
+ break;
+ case CODE_PADO:
+ relayHandlePADO(iface, &packet, size);
+ break;
+ case CODE_PADR:
+ relayHandlePADR(iface, &packet, size);
+ break;
+ case CODE_PADS:
+ relayHandlePADS(iface, &packet, size);
+ break;
+ default:
+ syslog(LOG_ERR, "Discovery packet on %s with unknown code %d",
+ iface->name, (int) packet.code);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: relayGotSessionPacket
+*%ARGUMENTS:
+* iface -- interface on which packet is waiting
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a session packet.
+***********************************************************************/
+void
+relayGotSessionPacket(PPPoEInterface const *iface)
+{
+ PPPoEPacket packet;
+ int size;
+ SessionHash *sh;
+ PPPoESession *ses;
+
+ if (receivePacket(iface->sessionSock, &packet, &size) < 0) {
+ return;
+ }
+
+ /* Ignore unknown code/version */
+ if (packet.ver != 1 || packet.type != 1) {
+ return;
+ }
+
+ /* Must be a session packet */
+ if (packet.code != CODE_SESS) {
+ syslog(LOG_ERR, "Session packet with code %d", (int) packet.code);
+ return;
+ }
+
+ /* Ignore session packets whose destination address isn't ours */
+ if (memcmp(packet.ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Validate length */
+ if (ntohs(packet.length) + HDR_SIZE > size) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ /* Drop Ethernet frame padding */
+ if (size > ntohs(packet.length) + HDR_SIZE) {
+ size = ntohs(packet.length) + HDR_SIZE;
+ }
+
+ /* We're in business! Find the hash */
+ sh = findSession(packet.ethHdr.h_source, packet.session);
+ if (!sh) {
+ /* Don't log this. Someone could be running the client and the
+ relay on the same box. */
+ return;
+ }
+
+ /* Relay it */
+ ses = sh->ses;
+ ses->epoch = Epoch;
+ sh = sh->peer;
+ packet.session = sh->sesNum;
+ memcpy(packet.ethHdr.h_source, sh->interface->mac, ETH_ALEN);
+ memcpy(packet.ethHdr.h_dest, sh->peerMac, ETH_ALEN);
+#if 0
+ fprintf(stderr, "Relaying %02x:%02x:%02x:%02x:%02x:%02x(%s:%d) to %02x:%02x:%02x:%02x:%02x:%02x(%s:%d)\n",
+ sh->peer->peerMac[0], sh->peer->peerMac[1], sh->peer->peerMac[2],
+ sh->peer->peerMac[3], sh->peer->peerMac[4], sh->peer->peerMac[5],
+ sh->peer->interface->name, ntohs(sh->peer->sesNum),
+ sh->peerMac[0], sh->peerMac[1], sh->peerMac[2],
+ sh->peerMac[3], sh->peerMac[4], sh->peerMac[5],
+ sh->interface->name, ntohs(sh->sesNum));
+#endif
+ sendPacket(NULL, sh->interface->sessionSock, &packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADT
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADT packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADT packet.
+***********************************************************************/
+void
+relayHandlePADT(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ SessionHash *sh;
+ PPPoESession *ses;
+
+ sh = findSession(packet->ethHdr.h_source, packet->session);
+ if (!sh) {
+ return;
+ }
+ /* Relay the PADT to the peer */
+ sh = sh->peer;
+ ses = sh->ses;
+ packet->session = sh->sesNum;
+ memcpy(packet->ethHdr.h_source, sh->interface->mac, ETH_ALEN);
+ memcpy(packet->ethHdr.h_dest, sh->peerMac, ETH_ALEN);
+ sendPacket(NULL, sh->interface->sessionSock, packet, size);
+
+ /* Destroy the session */
+ freeSession(ses, "Received PADT");
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADI
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADI packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADI packet.
+***********************************************************************/
+void
+relayHandlePADI(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int i, r;
+
+ int ifIndex;
+
+ /* Can a client legally be behind this interface? */
+ if (!iface->clientOK) {
+ syslog(LOG_ERR,
+ "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be broadcast */
+ if (NOT_BROADCAST(packet->ethHdr.h_dest)) {
+ syslog(LOG_ERR,
+ "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Get array index of interface */
+ ifIndex = iface - Interfaces;
+
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ tag.type = htons(TAG_RELAY_SESSION_ID);
+ tag.length = htons(MY_RELAY_TAG_LEN);
+ memcpy(tag.payload, &ifIndex, sizeof(ifIndex));
+ memcpy(tag.payload+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+ /* Add a relay tag if there's room */
+ r = addTag(packet, &tag);
+ if (r < 0) return;
+ size += r;
+ } else {
+ /* We do not re-use relay-id tags. Drop the frame. The RFC says the
+ relay agent SHOULD return a Generic-Error tag, but this does not
+ make sense for PADI packets. */
+ return;
+ }
+
+ /* Broadcast the PADI on all AC-capable interfaces except the interface
+ on which it came */
+ for (i=0; i < NumInterfaces; i++) {
+ if (iface == &Interfaces[i]) continue;
+ if (!Interfaces[i].acOK) continue;
+ memcpy(packet->ethHdr.h_source, Interfaces[i].mac, ETH_ALEN);
+ sendPacket(NULL, Interfaces[i].discoverySock, packet, size);
+ }
+
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADO
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADO packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADO packet.
+***********************************************************************/
+void
+relayHandlePADO(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int ifIndex;
+ int acIndex;
+
+ /* Can a server legally be behind this interface? */
+ if (!iface->acOK) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ acIndex = iface - Interfaces;
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be interface's MAC address */
+ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Find relay tag */
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If it's the wrong length, ignore it */
+ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Extract interface index */
+ memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+ if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+ !Interfaces[ifIndex].clientOK ||
+ iface == &Interfaces[ifIndex]) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Replace Relay-ID tag with opposite-direction tag */
+ memcpy(loc+TAG_HDR_SIZE, &acIndex, sizeof(acIndex));
+ memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+
+ /* Set destination address to MAC address in relay ID */
+ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+ /* Set source address to MAC address of interface */
+ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
+
+ /* Send the PADO to the proper client */
+ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADR
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADR packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADR packet.
+***********************************************************************/
+void
+relayHandlePADR(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int ifIndex;
+ int cliIndex;
+
+ /* Can a client legally be behind this interface? */
+ if (!iface->clientOK) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ cliIndex = iface - Interfaces;
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be interface's MAC address */
+ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Find relay tag */
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If it's the wrong length, ignore it */
+ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Extract interface index */
+ memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+ if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+ !Interfaces[ifIndex].acOK ||
+ iface == &Interfaces[ifIndex]) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Replace Relay-ID tag with opposite-direction tag */
+ memcpy(loc+TAG_HDR_SIZE, &cliIndex, sizeof(cliIndex));
+ memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+
+ /* Set destination address to MAC address in relay ID */
+ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+ /* Set source address to MAC address of interface */
+ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
+
+ /* Send the PADR to the proper access concentrator */
+ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADS
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADS packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADS packet.
+***********************************************************************/
+void
+relayHandlePADS(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int ifIndex;
+ int acIndex;
+ PPPoESession *ses = NULL;
+ SessionHash *sh;
+
+ /* Can a server legally be behind this interface? */
+ if (!iface->acOK) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ acIndex = iface - Interfaces;
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be interface's MAC address */
+ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Find relay tag */
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If it's the wrong length, ignore it */
+ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Extract interface index */
+ memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+ if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+ !Interfaces[ifIndex].clientOK ||
+ iface == &Interfaces[ifIndex]) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If session ID is zero, it's the AC respoding with an error.
+ Just relay it; do not create a session */
+ if (packet->session != htons(0)) {
+ /* Check for existing session */
+ sh = findSession(packet->ethHdr.h_source, packet->session);
+ if (sh) ses = sh->ses;
+
+ /* If already an existing session, assume it's a duplicate PADS. Send
+ the frame, but do not create a new session. Is this the right
+ thing to do? Arguably, should send an error to the client and
+ a PADT to the server, because this could happen due to a
+ server crash and reboot. */
+
+ if (!ses) {
+ /* Create a new session */
+ ses = createSession(iface, &Interfaces[ifIndex],
+ packet->ethHdr.h_source,
+ loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->session);
+ if (!ses) {
+ /* Can't allocate session -- send error PADS to client and
+ PADT to server */
+ PPPoETag hostUniq, *hu;
+ if (findTag(packet, TAG_HOST_UNIQ, &hostUniq)) {
+ hu = &hostUniq;
+ } else {
+ hu = NULL;
+ }
+ relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex],
+ loc + TAG_HDR_SIZE + sizeof(ifIndex),
+ hu, "RP-PPPoE: Relay: Unable to allocate session");
+ relaySendError(CODE_PADT, packet->session, iface,
+ packet->ethHdr.h_source, NULL,
+ "RP-PPPoE: Relay: Unable to allocate session");
+ return;
+ }
+ }
+ /* Replace session number */
+ packet->session = ses->sesNum;
+ }
+
+ /* Remove relay-ID tag */
+ removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
+ size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
+
+ /* Set destination address to MAC address in relay ID */
+ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+ /* Set source address to MAC address of interface */
+ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
+
+ /* Send the PADS to the proper client */
+ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relaySendError
+*%ARGUMENTS:
+* code -- PPPoE packet code (PADS or PADT, typically)
+* session -- PPPoE session number
+* iface -- interface on which to send frame
+* mac -- Ethernet address to which frame should be sent
+* hostUniq -- if non-NULL, a hostUniq tag to add to error frame
+* errMsg -- error message to insert into Generic-Error tag.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends either a PADS or PADT packet with a Generic-Error tag and an
+* error message.
+***********************************************************************/
+void
+relaySendError(unsigned char code,
+ UINT16_t session,
+ PPPoEInterface const *iface,
+ unsigned char const *mac,
+ PPPoETag const *hostUniq,
+ char const *errMsg)
+{
+ PPPoEPacket packet;
+ PPPoETag errTag;
+ int size;
+
+ memcpy(packet.ethHdr.h_source, iface->mac, ETH_ALEN);
+ memcpy(packet.ethHdr.h_dest, mac, ETH_ALEN);
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.type = 1;
+ packet.ver = 1;
+ packet.code = code;
+ packet.session = session;
+ packet.length = htons(0);
+ if (hostUniq) {
+ if (addTag(&packet, hostUniq) < 0) return;
+ }
+ errTag.type = htons(TAG_GENERIC_ERROR);
+ errTag.length = htons(strlen(errMsg));
+ strcpy(errTag.payload, errMsg);
+ if (addTag(&packet, &errTag) < 0) return;
+ size = ntohs(packet.length) + HDR_SIZE;
+ if (code == CODE_PADT) {
+ sendPacket(NULL, iface->discoverySock, &packet, size);
+ } else {
+ sendPacket(NULL, iface->sessionSock, &packet, size);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: alarmHandler
+*%ARGUMENTS:
+* sig -- signal number
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* SIGALRM handler. Increments Epoch; if necessary, writes a byte of
+* data to the alarm pipe to trigger the stale-session cleaner.
+***********************************************************************/
+void
+alarmHandler(int sig)
+{
+ alarm(1);
+ Epoch++;
+ CleanCounter++;
+ if (CleanCounter == CleanPeriod) {
+ write(CleanPipe[1], "", 1);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: cleanSessions
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Goes through active sessions and cleans sessions idle for longer
+* than IdleTimeout seconds.
+***********************************************************************/
+void cleanSessions(void)
+{
+ PPPoESession *cur, *next;
+ cur = ActiveSessions;
+ while(cur) {
+ next = cur->next;
+ if (Epoch - cur->epoch > IdleTimeout) {
+ /* Send PADT to each peer */
+ relaySendError(CODE_PADT, cur->acHash->sesNum,
+ cur->acHash->interface,
+ cur->acHash->peerMac, NULL,
+ "RP-PPPoE: Relay: Session exceeded idle timeout");
+ relaySendError(CODE_PADT, cur->clientHash->sesNum,
+ cur->clientHash->interface,
+ cur->clientHash->peerMac, NULL,
+ "RP-PPPoE: Relay: Session exceeded idle timeout");
+ freeSession(cur, "Idle Timeout");
+ }
+ cur = next;
+ }
+}
diff --git a/mdk-stage1/rp-pppoe/src/relay.h b/mdk-stage1/rp-pppoe/src/relay.h
new file mode 100644
index 000000000..d438a657f
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/relay.h
@@ -0,0 +1,97 @@
+/**********************************************************************
+*
+* relay.h
+*
+* Definitions for PPPoE relay
+*
+* Copyright (C) 2001 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id$
+*
+***********************************************************************/
+
+#include "pppoe.h"
+
+/* Description for each active Ethernet interface */
+typedef struct InterfaceStruct {
+ char name[IFNAMSIZ+1]; /* Interface name */
+ int discoverySock; /* Socket for discovery frames */
+ int sessionSock; /* Socket for session frames */
+ int clientOK; /* Client requests allowed (PADI, PADR) */
+ int acOK; /* AC replies allowed (PADO, PADS) */
+ unsigned char mac[ETH_ALEN]; /* MAC address */
+} PPPoEInterface;
+
+/* Session state for relay */
+struct SessionHashStruct;
+typedef struct SessionStruct {
+ struct SessionStruct *next; /* Free list link */
+ struct SessionStruct *prev; /* Free list link */
+ struct SessionHashStruct *acHash; /* Hash bucket for AC MAC/Session */
+ struct SessionHashStruct *clientHash; /* Hash bucket for client MAC/Session */
+ unsigned int epoch; /* Epoch when last activity was seen */
+ UINT16_t sesNum; /* Session number assigned by relay */
+} PPPoESession;
+
+/* Hash table entry to find sessions */
+typedef struct SessionHashStruct {
+ struct SessionHashStruct *next; /* Link in hash chain */
+ struct SessionHashStruct *prev; /* Link in hash chain */
+ struct SessionHashStruct *peer; /* Peer for this session */
+ PPPoEInterface const *interface; /* Interface */
+ unsigned char peerMac[ETH_ALEN]; /* Peer's MAC address */
+ UINT16_t sesNum; /* Session number */
+ PPPoESession *ses; /* Session data */
+} SessionHash;
+
+/* Function prototypes */
+
+void relayGotSessionPacket(PPPoEInterface const *i);
+void relayGotDiscoveryPacket(PPPoEInterface const *i);
+PPPoEInterface *findInterface(int sock);
+unsigned int hash(unsigned char const *mac, UINT16_t sesNum);
+SessionHash *findSession(unsigned char const *mac, UINT16_t sesNum);
+void deleteHash(SessionHash *hash);
+PPPoESession *createSession(PPPoEInterface const *ac,
+ PPPoEInterface const *cli,
+ unsigned char const *acMac,
+ unsigned char const *cliMac,
+ UINT16_t acSes);
+void freeSession(PPPoESession *ses, char const *msg);
+void addInterface(char const *ifname, int clientOK, int acOK);
+void usage(char const *progname);
+void initRelay(int nsess);
+void relayLoop(void);
+void addHash(SessionHash *sh);
+void unhash(SessionHash *sh);
+
+void relayHandlePADT(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADI(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADO(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADR(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADS(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+
+int addTag(PPPoEPacket *packet, PPPoETag const *tag);
+int insertBytes(PPPoEPacket *packet, unsigned char *loc,
+ void const *bytes, int length);
+int removeBytes(PPPoEPacket *packet, unsigned char *loc,
+ int length);
+void relaySendError(unsigned char code,
+ UINT16_t session,
+ PPPoEInterface const *iface,
+ unsigned char const *mac,
+ PPPoETag const *hostUniq,
+ char const *errMsg);
+
+void alarmHandler(int sig);
+void cleanSessions(void);
+
+#define MAX_INTERFACES 8
+#define DEFAULT_SESSIONS 5000
+
+/* Hash table size -- a prime number; gives load factor of around 6
+ for 65534 sessions */
+#define HASHTAB_SIZE 18917