summaryrefslogtreecommitdiffstats
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
parentab5559aaabd1167a18ac882e64d97c5adc0e7d03 (diff)
downloaddrakx-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar
drakx-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar.gz
drakx-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar.bz2
drakx-0a121a8ecd6de894c14d60daf9da2022ec47405c.tar.xz
drakx-0a121a8ecd6de894c14d60daf9da2022ec47405c.zip
Initial revision
-rw-r--r--mdk-stage1/rp-pppoe/README87
-rw-r--r--mdk-stage1/rp-pppoe/configs/firewall-masq35
-rw-r--r--mdk-stage1/rp-pppoe/configs/firewall-standalone32
-rw-r--r--mdk-stage1/rp-pppoe/configs/pap-secrets9
-rw-r--r--mdk-stage1/rp-pppoe/configs/pppoe-server-options5
-rw-r--r--mdk-stage1/rp-pppoe/configs/pppoe.conf126
-rw-r--r--mdk-stage1/rp-pppoe/doc/CHANGES177
-rw-r--r--mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT295
-rw-r--r--mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE39
-rw-r--r--mdk-stage1/rp-pppoe/doc/LICENSE339
-rw-r--r--mdk-stage1/rp-pppoe/doc/PROBLEMS3
-rwxr-xr-xmdk-stage1/rp-pppoe/go43
-rwxr-xr-xmdk-stage1/rp-pppoe/go-gui92
-rw-r--r--mdk-stage1/rp-pppoe/gui/Makefile.in64
-rw-r--r--mdk-stage1/rp-pppoe/gui/html/tkpppoe.html181
-rw-r--r--mdk-stage1/rp-pppoe/gui/pppoe-wrapper.145
-rw-r--r--mdk-stage1/rp-pppoe/gui/tkpppoe.136
-rwxr-xr-xmdk-stage1/rp-pppoe/gui/tkpppoe.in2891
-rw-r--r--mdk-stage1/rp-pppoe/gui/wrapper.c234
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-connect.866
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-setup.823
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-start.827
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-status.825
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-stop.821
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe-relay.8124
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe-server.8123
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe-sniff.877
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe.8236
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe.conf.5168
-rw-r--r--mdk-stage1/rp-pppoe/rp-pppoe-gui.spec98
-rw-r--r--mdk-stage1/rp-pppoe/rp-pppoe.spec71
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-connect.in278
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-init-suse.in62
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in62
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-init.in64
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-setup.in346
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-start.in186
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-status82
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-stop.in84
-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
58 files changed, 17757 insertions, 0 deletions
diff --git a/mdk-stage1/rp-pppoe/README b/mdk-stage1/rp-pppoe/README
new file mode 100644
index 000000000..269fc16be
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/README
@@ -0,0 +1,87 @@
+pppoe: a PPP-over-Ethernet redirector for pppd
+Copyright (C) 2001 Roaring Penguin Software Inc.
+
+Much inspiration from an earlier client by Luke Stras.
+
+The MSS clamping was inspired by mssclampfw by Marc Boucher <marc@mbsi.ca>
+with acknowledgements to Rebel.com (http://www.rebel.com). However, the
+actual MSS clamping code is original and is licensed under the GPL, unlike
+the original mssclampfw.
+
+Introduction
+============
+
+pppoe is a user-space redirector which permits the use of PPPoE
+(Point-to-Point Over Ethernet) with Linux. PPPoE is used by many
+ADSL service providers.
+
+Installation
+============
+
+Requirements
+------------
+
+1) Linux 2.2.9 or later on Intel, Sparc or PowerPC. It may work on
+ Alpha, too -- anyone care to let me know?
+
+ OR
+
+ Linux 2.0.36 or later.
+
+ OR
+
+ FreeBSD, NetBSD or OpenBSD with BPF support. I have access only
+ to FreeBSD. In general, I can't answer questions about the *BSD's
+ as well as I can about Linux.
+
+
+2) pppd 2.3.10 or later. Versions 2.3.7 and later work unless you use
+ demand-dialling. For demand dialling, you *must* use 2.3.10 or later.
+
+QUICKSTART
+----------
+
+If you're lucky, the "quickstart" method will work. After unpacking
+the archive, become root and type:
+
+ ./go
+
+This should configure, compile and install the software and set up your
+ADSL connection. You'll have to answer a few questions along the way.
+
+If you want the GUI wrapper, type:
+
+ ./go-gui
+
+If ./go and ./go-gui didn't work, read the rest of this README.
+
+Compiling
+---------
+
+Compile and install pppd if you don't already have it. Then:
+
+1) Unpack:
+
+ $ tar xzvf rp-pppoe-xxx.tar.gz
+
+2) Change to source directory:
+
+ $ cd src
+
+3) Configure:
+
+ $ ./configure
+
+4) Compile:
+
+ $ make
+
+4) Install (this step must be done as root)
+
+ # make install
+
+5) Now read doc/HOW-TO-CONNECT
+
+--
+David F. Skoll <dfs@roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com | Linux and UNIX Specialists \ No newline at end of file
diff --git a/mdk-stage1/rp-pppoe/configs/firewall-masq b/mdk-stage1/rp-pppoe/configs/firewall-masq
new file mode 100644
index 000000000..cb16fbecf
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/firewall-masq
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# firewall-masq This script sets up firewall rules for a machine
+# acting as a masquerading gateway
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Interface to Internet
+EXTIF=ppp+
+
+ANY=0.0.0.0/0
+
+ipchains -P input ACCEPT
+ipchains -P output ACCEPT
+ipchains -P forward DENY
+
+ipchains -F forward
+ipchains -F input
+ipchains -F output
+
+# Deny TCP and UDP packets to privileged ports
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p udp -j DENY
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p tcp -j DENY
+
+# Deny TCP connection attempts
+ipchains -A input -l -i $EXTIF -p tcp -y -j DENY
+
+# Deny ICMP echo-requests
+ipchains -A input -l -i $EXTIF -s $ANY echo-request -p icmp -j DENY
+
+# Do masquerading
+ipchains -A forward -j MASQ
+echo 1 > /proc/sys/net/ipv4/ip_forward
diff --git a/mdk-stage1/rp-pppoe/configs/firewall-standalone b/mdk-stage1/rp-pppoe/configs/firewall-standalone
new file mode 100644
index 000000000..bcb1e92b1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/firewall-standalone
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# firewall-standalone This script sets up firewall rules for a standalone
+# machine
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Interface to Internet
+EXTIF=ppp+
+
+ANY=0.0.0.0/0
+
+ipchains -P input ACCEPT
+ipchains -P output ACCEPT
+ipchains -P forward DENY
+
+ipchains -F forward
+ipchains -F input
+ipchains -F output
+
+# Deny TCP and UDP packets to privileged ports
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p udp -j DENY
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p tcp -j DENY
+
+# Deny TCP connection attempts
+ipchains -A input -l -i $EXTIF -p tcp -y -j DENY
+
+# Deny ICMP echo-requests
+ipchains -A input -l -i $EXTIF -s $ANY echo-request -p icmp -j DENY
+
diff --git a/mdk-stage1/rp-pppoe/configs/pap-secrets b/mdk-stage1/rp-pppoe/configs/pap-secrets
new file mode 100644
index 000000000..f4483a723
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/pap-secrets
@@ -0,0 +1,9 @@
+# Edit this file and place it in /etc/ppp/pap-secrets
+
+#User #Server #Password #IP
+bxxxxx@sympatico.ca * my_password *
+
+# Replace bxxxxx@sympatico.ca with your Sympatico user-ID
+# Replace my_password with your Sympatico password
+
+# For Magma, use xxyyzz@magma.ca
diff --git a/mdk-stage1/rp-pppoe/configs/pppoe-server-options b/mdk-stage1/rp-pppoe/configs/pppoe-server-options
new file mode 100644
index 000000000..8319870ac
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/pppoe-server-options
@@ -0,0 +1,5 @@
+# PPP options for the PPPoE server
+require-pap
+login
+lcp-echo-interval 10
+lcp-echo-failure 2
diff --git a/mdk-stage1/rp-pppoe/configs/pppoe.conf b/mdk-stage1/rp-pppoe/configs/pppoe.conf
new file mode 100644
index 000000000..9f77b913c
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/pppoe.conf
@@ -0,0 +1,126 @@
+#***********************************************************************
+#
+# pppoe.conf
+#
+# Configuration file for rp-pppoe. Edit as appropriate and install in
+# /etc/ppp/pppoe.conf
+#
+# NOTE: This file is used by the adsl-start, adsl-stop, adsl-connect and
+# adsl-status shell scripts. It is *not* used in any way by the
+# "pppoe" executable.
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# $Id$
+#***********************************************************************
+
+# When you configure a variable, DO NOT leave spaces around the "=" sign.
+
+# Ethernet card connected to ADSL modem
+ETH=eth1
+
+# ADSL user name. You may have to supply "@provider.com" Sympatico
+# users in Canada do need to include "@sympatico.ca"
+# Sympatico uses PAP authentication. Make sure /etc/ppp/pap-secrets
+# contains the right username/password combination.
+# For Magma, use xxyyzz@magma.ca
+USER=bxxxnxnx@sympatico.ca
+
+# Bring link up on demand? Default is to leave link up all the time.
+# If you want the link to come up on demand, set DEMAND to a number indicating
+# the idle time after which the link is brought down.
+DEMAND=no
+#DEMAND=300
+
+# DNS type: SERVER=obtain from server; SPECIFY=use DNS1 and DNS2;
+# NOCHANGE=do not adjust.
+DNSTYPE=SERVER
+
+# Obtain DNS server addresses from the peer (recent versions of pppd only)
+USEPEERDNS=yes
+
+DNS1=
+DNS2=
+
+### ONLY TOUCH THE FOLLOWING SETTINGS IF YOU'RE AN EXPERT
+
+# How long adsl-start waits for a new PPP interface to appear before
+# concluding something went wrong. If you use 0, then adsl-start
+# exits immediately with a successful status and does not wait for the
+# link to come up. Time is in seconds.
+#
+# WARNING WARNING WARNING:
+#
+# If you are using rp-pppoe on a physically-inaccessible host, set
+# CONNECT_TIMEOUT to 0. This makes SURE that the machine keeps trying
+# to connect forever after adsl-start is called. Otherwise, it will
+# give out after CONNECT_TIMEOUT seconds and will not attempt to
+# connect again, making it impossible to reach.
+CONNECT_TIMEOUT=30
+
+# How often in seconds adsl-start polls to check if link is up
+CONNECT_POLL=2
+
+# Specific desired AC Name
+ACNAME=
+
+# Specific desired service name
+SERVICENAME=
+
+# Character to echo at each poll. Use PING="" if you don't want
+# anything echoed
+PING="."
+
+# File where the adsl-connect script writes its process-ID.
+# Three files are actually used:
+# $PIDFILE contains PID of adsl-connect script
+# $PIDFILE.pppoe contains PID of pppoe process
+# $PIDFILE.pppd contains PID of pppd process
+CF_BASE=`basename $CONFIG`
+PIDFILE="/var/run/$CF_BASE-adsl.pid"
+
+# Do you want to use synchronous PPP? "yes" or "no". "yes" is much
+# easier on CPU usage, but may not work for you. It is safer to use
+# "no", but you may want to experiment with "yes". "yes" is generally
+# safe on Linux machines with the n_hdlc line discipline; unsafe on others.
+SYNCHRONOUS=no
+
+# Do you want to clamp the MSS? Here's how to decide:
+# - If you have only a SINGLE computer connected to the ADSL modem, choose
+# "no".
+# - If you have a computer acting as a gateway for a LAN, choose "1412".
+# The setting of 1412 is safe for either setup, but uses slightly more
+# CPU power.
+CLAMPMSS=1412
+#CLAMPMSS=no
+
+# LCP echo interval and failure count.
+LCP_INTERVAL=20
+LCP_FAILURE=3
+
+# PPPOE_TIMEOUT should be about 4*LCP_INTERVAL
+PPPOE_TIMEOUT=80
+
+# Firewalling: One of NONE, STANDALONE or MASQUERADE
+FIREWALL=NONE
+
+# Linux kernel-mode plugin for pppd. If you want to try the kernel-mode
+# plugin, use LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
+LINUX_PLUGIN=
+
+# Any extra arguments to pass to pppoe. Normally, use a blank string
+# like this:
+PPPOE_EXTRA=""
+
+# Rumour has it that "Citizen's Communications" with a 3Com
+# HomeConnect ADSL Modem DualLink requires these extra options:
+# PPPOE_EXTRA="-f 3c12:3c13 -S ISP"
+
+# Any extra arguments to pass to pppd. Normally, use a blank string
+# like this:
+PPPD_EXTRA=""
+
+
diff --git a/mdk-stage1/rp-pppoe/doc/CHANGES b/mdk-stage1/rp-pppoe/doc/CHANGES
new file mode 100644
index 000000000..9afce027d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/CHANGES
@@ -0,0 +1,177 @@
+Changes from Version 2.8 to 3.0:
+
+- Many small improvements to server. Server now only makes one
+ discovery socket, systemwide, with addition of "-n" option to pppoe.
+
+- Fixes for compilation problems on BSD, Solaris and some Linux platforms.
+
+- Added "-p" option to pppoe-server to allow you to specify a pool of
+ IP addresses to assign to clients.
+
+- Added GUI system (tkpppoe). This work was funded by Iospan
+ Wireless, Inc. The GUI includes a Set-UID wrapper (pppoe-wrapper)
+ which allows ordinary users to control a link (if so authorized.)
+ I believe the wrapper script is secure, but please audit the
+ source code (gui/wrapper.c) if you have any concerns.
+
+- Changes to scripts and pppoe.conf. DNS setup is now dynamic (happens
+ each time adsl-connect runs.)
+
+- Made relay.c check packet lengths rigorously; made it throw out Ethernet
+ frame padding on session packets as well as discovery packets.
+
+Changes from Version 2.7 to 2.8:
+
+- Added init scripts for TurboLinux, courtesy of Yasuhiro Sumi.
+
+- Made relay.c check packet lengths rigorously; made it throw out Ethernet
+ frame padding on discovery packets.
+
+*** NOTE: 2.7 was not released publicly
+
+Changes from Version 2.6 to 2.7:
+
+- Completely restructured source file tree.
+
+- Much internal restructuring to eliminate a bunch of global variables.
+
+- adsl-connect now executes /etc/ppp/adsl-lost whenever connection is dropped
+ or cannot be established.
+
+- Split pppoe.c into pppoe.c and discovery.c.
+
+- Added relay agent (pppoe-relay).
+
+- Made adsl-connect script use the "-U" (host-unique) option to better support
+ multiple PPPoE links.
+
+- Added support for kernel-mode PPPoE (EXPERIMENTAL, UNSUPPORTED!)
+
+- Added "-o" option to PPPoE server; encoded server PID in pppoe-server
+ cookie.
+
+Changes from Version 2.5 to 2.6:
+
+- Code should now compile cleanly on Caldera and Slackware Linux
+
+- Fixed rp-pppoe.spec file to work on Mandrake and Red Hat.
+
+- Deleted some obsolete files
+
+- Fixed bug in Solaris/x86 port (thanks to Philippe Levan)
+
+- Made shell scripts nicer under Solaris (again, Philippe Levan)
+
+- Made adsl-status look under /var/run and /etc/ppp for PID files. Should
+ fix problems with NetBSD.
+
+- Added PPPD_EXTRA to pppoe.conf; made the PID file depend on the config
+ file name. This makes it easier to run multiple PPPoE sessions.
+
+Changes from Version 2.4 to 2.5:
+
+- Tested for zero-length TCP option-length field, and for reverse-packing
+ of type/code bitfields. Thanks to Robert Schlabbach for pointing out
+ these problems.
+
+- Set umask to 077 in adsl-setup.in to protect created files like
+ /etc/ppp/pap-secrets.
+
+Changes from Version 2.3 to 2.4:
+
+- Fixed spec file to automatically add .gz extension to man files as required
+
+- Tightened firewall rules.
+
+- Better check for /var/run in adsl-status; minor shell script fixes and
+ cleanups for NetBSD and Solaris.
+
+- Added FAQ to HOW-TO-CONNECT regarding running a script each time a
+ connection is made.
+
+Changes from Version 2.2 to 2.3:
+
+- Fixed the init script to create/remove /var/lock/subsys/adsl (patch
+ courtesy of Charley Carter.)
+
+- Added support (under Linux) for N_HDLC line discipline which should
+ greatly reduce CPU usage. My tests show it cuts CPU usage in half.
+ My 486 DX2/66 gets 800 kb/s at 22% CPU usage.
+
+- adsl-connect uses "setsid" (if available) so that adsl-stop doesn't kill
+ its caller. There is (IMO) a bug in pppd which kills all processes in
+ its process group if the "pty" option is used. The setsid program gets
+ around this bug, on Linux at least.
+
+- Port to Solaris, courtesy of David Holland.
+
+- Renamed spec file from "spec" to "rp-pppoe.spec" and made some cleanups.
+ NOTE: Red Hat, in their infinite wisdom, decided to make the new RPM
+ compress man pages automatically. You may have problems building RPM's
+ from source unless you get the latest rpm package and make sure it
+ compresses man pages.
+
+Changes from Version 2.1 to 2.2:
+
+- Added "-f" option to pppoe to allow use of any Ethernet frame type
+ for PPPoE. USE WITH CAUTION -- this is a workaround for broken DSL
+ providers, not something you should monkey with freely!
+
+- Added pppoe-sniff program to help expose non-standard PPPoE implementations.
+
+Changes from Version 2.0 to 2.1:
+
+- Fixed minor bugs in bounds-checking
+
+- Modified adsl-status to use output of "netstat -r -n" to determine whether
+ or not link is up. This should make it independent of locale, I hope!
+
+- Added "-k" and "-d" options to pppoe.
+
+Changes from Version 1.9 to 2.0:
+
+- Addition of pppoe-server
+
+- Massive internal code restructuring
+
+- Zealous bounds-checking everywhere.
+
+- adsl-setup now quotes user name and password in /etc/ppp/pap-secrets.
+
+- Ported to OpenBSD, FreeBSD and NetBSD, courtesy of Geoff Mottram
+ and Yannis Sismanis.
+
+- Rearranged adsl-* shell scripts, courtesy of Heiko Schlittermann.
+
+- Fixed bug in which Host-Uniq did not work if access concentrator sent
+ a cookie.
+
+- Addition of SuSE-specific "init" script, courtesy of Gary Cameron.
+
+Changes from Version 1.8 to 1.9:
+
+- Added some more documentation to HOW-TO-CONNECT
+
+- Demand-dialling option now works correctly
+
+- SIGHUP terminates pppoe after sending a PADT to the access concentrator
+
+- Minor cleanups to connection shell scripts
+
+Changes from Version 1.7 to 1.8:
+
+- Added demand-dialling option
+
+- Clarified HOW-TO-CONNECT
+
+- Added adsl-status script
+
+- Added "restart" and "status" options to Red Hat /etc/rc.d/init.d/adsl script
+
+- Made adsl-setup check for existence of pppd
+
+- Wildcarded external interface in firewall rules
+
+- Made pppoe send a PADT frame if connection is terminated
+
+$Id$
diff --git a/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT b/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT
new file mode 100644
index 000000000..3e888af69
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT
@@ -0,0 +1,295 @@
+$Id$
+
+This package lets you connect a Linux machine to Sympatico HSE or Magma's
+high-speed service using a Nortel 1-meg modem.
+
+Follow these steps and you should have your high-speed service up and running.
+
+0. Install the rp-pppoe-software
+--------------------------------
+
+You should have already done this by the time you're reading this. If not,
+go back and read README.
+
+1. Set up your Ethernet hardware
+--------------------------------
+
+First, make sure the Ethernet card you intend to use with the modem is
+visible to the Linux kernel. Just how to do this is beyond the scope
+of this document. However, if the card is the only Ethernet card in
+the system, executing:
+
+ ifconfig eth0
+
+should display something like this:
+
+ eth0 Link encap:Ethernet HWaddr 00:60:67:62:31:D4
+
+plust some more lines. Your HWaddr will be different. As long as you see
+the HWaddr line, your card should be working.
+
+DO NOT assign an IP address to the Ethernet card. DO NOT configure the
+card to come up at boot time.
+
+2. Configure various files
+--------------------------
+
+Several files need editing. The easiest way to do this is to run
+the following command as root:
+
+ adsl-setup
+
+Answer the questions and you should be all set. If you want to know what
+goes on behind the scenes, continue reading this document. If you don't
+care and your connection works, stop reading. :-)
+
+3. Edit pap-secrets
+-------------------
+
+Edit the "pap-secrets" file, inserting your proper user-ID and password.
+Install the file (or copy the relevant lines) to /etc/ppp/pap-secrets.
+Your ISP may use CHAP authentication. In this case, add the line to
+/etc/ppp/chap-secrets.
+
+4. Edit /etc/ppp/pppoe.conf
+-----------------------------
+
+The file /etc/ppp/pppoe.conf contains configuration information for the
+ADSL connection. You need to edit the following items:
+
+- Change ETH=eth1 to the correct Ethernet device for your modem.
+- Change USER=bxxxnxnx@sympatico.ca to your proper ADSL user-ID.
+
+Don't edit any of the other settings unless you're an expert.
+
+5. Set up DNS
+-------------
+
+If you are using DNS servers supplied by your ISP, edit the file
+/etc/resolv.conf to contain these lines:
+
+ nameserver ip_addr_of_first_dns_server
+ nameserver ip_addr_of_second_dns_server
+
+For example:
+
+ nameserver 204.101.251.1
+ nameserver 204.101.251.2
+
+
+6. Firewall your machine
+------------------------
+
+MAKE SURE YOU FIREWALL YOUR MACHINE. A sample firewall script is given
+in the shell script "firewall" To install the script:
+
+a) Copy it to /etc/rc.d/init.d/firewall
+b) Type: chkconfig firewall on
+c) Start the firewall: sh /etc/rc.d/init.d/firewall start
+
+(The above procedure works ONLY on Red Hat-like systems.)
+
+You may want to tweak the script somewhat.
+
+7. Bring up the connection at boot time
+---------------------------------------
+
+On a Red Hat system, the installation procedure should have installed
+a script called /etc/rc.d/init.d/adsl. To bring up the connection
+at boot time, just type this command as root:
+
+ chkconfig --add adsl
+
+On non-Red-Hat systems, add this line to the end
+of /etc/rc.d/rc.local:
+
+ /usr/sbin/adsl-start
+
+8. Configure LAN Hosts
+----------------------
+
+If you have a LAN behind the firewall, you have to lower the TCP
+maximum segment size from the normal 1460 to 1452 (or better, 1412.)
+You have two options: Either set the MTU of all the interfaces on
+other hosts on the LAN to 1452, or use the "-m 1412" option to pppoe.
+The "-m" option for pppoe is far simpler and makes it easier to add
+hosts to the LAN, but consumes some extra CPU time.
+
+If you want to manually configure the LAN hosts, here's how:
+
+In Linux, use: "ifconfig eth0 mtu 1452". For best results, put this
+in an /etc/rc.d/rc.local script.
+
+For Windows, machines, see http://lan.cns.ksu.edu/OS/WIN95/slip95.htm.
+Set the MaxMTU to 1452.
+
+9. Commands to control the ADSL link
+------------------------------------
+
+As root, bring up the link by typing: adsl-start
+As root, bring down the link by typing: adsl-stop
+
+That's it!
+
+--
+David F. Skoll <dfs@roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com | Linux and UNIX Specialists
+
+PROBLEMS! DAVE, IT DOESN'T WORK!
+---------------------------------
+
+Here are some problems PPPoE users have encountered.
+
+-----------------------------------------------------------------------------
+A) Can't see the Ethernet interface
+
+Well, I can't really help you here. To use these instructions, you must
+have Linux working to the point where it recognizes your Ethernet card.
+If you type "ifconfig ethx" and you get back a HWAddr value, your Ethernet
+card is probably OK. But I really can't help with hardware configuration
+issues.
+
+-----------------------------------------------------------------------------
+B) Connection seems to come up, but I can't browse the web or ping anything
+
+You probably don't have DNS set up. See step 6.
+
+-----------------------------------------------------------------------------
+C) Can't compile PPPoE
+
+I have only tested compilation on 2.2-kernel machines. Make sure you have
+"make", the C compiler and all development header files installed.
+
+-----------------------------------------------------------------------------
+D) pppd complains about (i) "unknown option pty" or (ii) "pty option precludes
+ specifying device name"
+
+(i) Your pppd is too old. You need at least 2.3.7.
+(ii) Your /etc/ppp/options file is not empty. Empty it!
+
+-----------------------------------------------------------------------------
+E) pppoe dies with the log message "Message too long"
+
+You set the MTU of the Ethernet interface connected to the ADSL modem
+to less than 1500. Don't do that.
+
+-----------------------------------------------------------------------------
+F) Internal hosts can't see the Internet
+
+Do you have masquerading set up? I can't help you in great detail, but
+see the IPCHAINS-HOWTO and the IP-Masquerade mini-HOWTO.
+
+-----------------------------------------------------------------------------
+G) Authentication fails
+
+Make sure you have the right secret in /etc/ppp/pap-secrets. Your ISP
+may be using CHAP; it won't hurt to copy the line to /etc/ppp/chap-secrets.
+
+Also, MAKE SURE that /etc/ppp/options is EMPTY. The "adsl-connect" script
+supplies all required options on the command line; additional options
+in /etc/ppp/options may mess things up.
+
+-----------------------------------------------------------------------------
+H) VPN software does not work
+
+If you are using VPN software on a Windows or Linux machine with another
+Linux machine running PPPoE as the gateway, you MUST NOT use the "-m" option
+to pppoe. This alters IP packets, which will break any VPN which uses IPSec.
+In /etc/ppp/pppoe.conf, set CLAMPMSS to "no". You'll also have to reduce
+the MTU on the hosts behind the gateway to 1452.
+
+-----------------------------------------------------------------------------
+I) I can browse some web sites just fine, but others stall forever.
+
+There is probably a buggy router or firewall between you and the Web server.
+One possible workaround: In /etc/ppp/pppoe.conf, find the line which reads:
+
+ CLAMPMSS=1412
+
+Try lowering the 1412 until it works (go down in steps of 100 or so.) Each
+time you lower the value, you have to restart your connection like this:
+
+ adsl-stop; adsl-start
+
+This should work around buggy routers which do not support Path MTU discovery.
+
+-----------------------------------------------------------------------------
+J) Whenever I connect using ADSL, my internal LAN no longer sees the gateway
+
+You are more than likely running a 2.0.X Linux kernel. To solve this
+problem, give the Ethernet card connected to the DSL modem a fake IP
+address. For example, if eth0 is your internal LAN card and eth1 goes to
+the DSL modem, do something like this:
+
+ ifconfig eth1 10.0.0.1 netmask 255.255.255.0
+
+(You may have to choose a different IP address; experiment.)
+-----------------------------------------------------------------------------
+K) How can I run a script every time I connect and get a new IP address?
+
+Put the script in /etc/ppp/ip-up. See the pppd(8) man page.
+-----------------------------------------------------------------------------
+L) Nothing works!
+
+You may need to put your Ethernet card in half-duplex, 10Mb/s mode to
+work with the DSL modem. You may have to run a DOS program to do this,
+or pass special parameters to the Linux driver.
+
+Some providers object to attempts to set the MRU or MTU. Try removing
+"mtu 1492 mru 1492" from PPP_STD_OPTIONS in the adsl-connect script.
+This problem has been seen with an ISP in Hong Kong.
+
+Your DSL provider may be using non-standard PPPoE frames or require
+something special in the Service-Name field. If you have two computers,
+you can try sniffing out these values with the "pppoe-sniff" program.
+Type "man pppoe-sniff" for details. If you don't have two computers,
+you'll have to ask your DSL provider if it uses non-standard PPPoE frames
+or special Service-Name fields. Good luck getting an answer...
+
+If pppoe-sniff indicates that nothing is amiss, make sure the Ethernet
+card associated with the ADSL modem does NOT have a valid IP address.
+(NOTE: For 2.0 kernels, you may have to give it a fake IP address
+which is not on your internal subnet. Something like 192.168.42.42
+might work if you are not using 192.168.42.*)
+
+If you are using synchronous PPP on a slow machine, try switching to
+asynchronous PPP.
+
+Make sure no entries in the routing table go through the Ethernet card
+connected to the ADSL modem. You might want to add these lines in
+adsl-connect:
+
+ ifconfig ethx down
+ ifconfig ethx up mtu 1500
+
+which should reset things to sane values.
+
+#######################################################################
+# WHEN ALL ELSE FAILS: #
+#######################################################################
+
+If you are completely unable to connect, run the adsl-start script in
+debugging mode. If you are using bash as your shell (if you don't
+know what your shell is, it's probably bash), type this:
+
+ DEBUG=1 adsl-start
+
+In tcsh or csh, use:
+
+ setenv DEBUG 1; adsl-start
+
+Then follow the instructions to mail the debugging file to me. PLEASE
+DON'T DO THIS until you have exhausted all other avenues; rp-pppoe is
+free software and it costs me time and money to help people with
+problems. While I don't mind doing this, I do mind it if you don't
+make an effort to fix the problem yourself first.
+
+WARNING: If you run adsl-start in debugging mode and you manage to
+connect, your connection will be extremely slow and huge amounts of
+data will quickly fill your /tmp directory. Do not use debugging mode
+unless you really cannot get your connection to work.
+
+Be aware that debugging mode produces hex dumps which potentially reveal
+your user name and password. If the debugging output includes packets
+labeled "PPPOE Session", you may wish to remove these packets from the
+dump before mailing it to me.
diff --git a/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE b/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE
new file mode 100644
index 000000000..454c4b870
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE
@@ -0,0 +1,39 @@
+RP-PPPoE now supports kernel-mode PPPoE on Linux kernels 2.4.x. However,
+the default "./go" build procedure does not make kernel-mode support.
+
+Here's what you need to do:
+
+1) Download Michal Ostrowski's patched version of pppd which supports
+a PPPoE plugin. The latest version as of this writing is
+at http://www.math.uwaterloo.ca/~mostrows/ in
+http://www.math.uwaterloo.ca/~mostrows/ppp-2.4.0-pppoe4.tgz. It is
+also mirrored at http://www.roaringpenguin.com/pppoe/
+
+2) Unpack that version of pppd and build and install it.
+
+3) In the rp-pppoe directory, change to src/ and type:
+
+ ./configure --enable-plugin=/path/to/ppp-tree
+
+Here, /path/to/ppp-tree is where you unpacked the pppd software. It
+should be the directory named ppp-2.4.0.pppoe
+
+4) Type make; make install
+
+5) Edit /etc/ppp/pppoe.conf to include this line:
+
+ LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
+
+6) Make sure your kernel was built with support for PPP, PPPOX and that
+all modules are locatable by modprobe. Make sure you have a /dev/ppp
+device:
+
+ mknod /dev/ppp c 108 0
+
+After that, adsl-start should use kernel-mode PPPoE.
+
+This code is experimental and unsupported. Use at your own risk.
+
+--
+David F. Skoll <dfs@roaringpenguin.com>
+
diff --git a/mdk-stage1/rp-pppoe/doc/LICENSE b/mdk-stage1/rp-pppoe/doc/LICENSE
new file mode 100644
index 000000000..9ed341535
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mdk-stage1/rp-pppoe/doc/PROBLEMS b/mdk-stage1/rp-pppoe/doc/PROBLEMS
new file mode 100644
index 000000000..f0b7d7d59
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/PROBLEMS
@@ -0,0 +1,3 @@
+Problems?
+
+See the last section of HOW-TO-CONNECT.
diff --git a/mdk-stage1/rp-pppoe/go b/mdk-stage1/rp-pppoe/go
new file mode 100755
index 000000000..305ac9ee4
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/go
@@ -0,0 +1,43 @@
+#!/bin/sh
+#***********************************************************************
+#
+# go
+#
+# Quick-start shell script to set up ADSL
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#***********************************************************************
+
+# Figure out directory of script
+MYDIR=`dirname $0`
+cd $MYDIR/src
+
+echo "Running ./configure..."
+./configure
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like ./configure failed."
+ exit 1
+fi
+
+echo "Running make..."
+make
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make failed."
+ exit 1
+fi
+
+echo "Running make install..."
+make install
+
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make install failed."
+ exit 1
+fi
+
+for i in a a a a a a a a a a a a a a a a a a a a a a a a a a a a ; do
+ echo ""
+done
+
+sh ../scripts/adsl-setup
diff --git a/mdk-stage1/rp-pppoe/go-gui b/mdk-stage1/rp-pppoe/go-gui
new file mode 100755
index 000000000..ddce984fd
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/go-gui
@@ -0,0 +1,92 @@
+#!/bin/sh
+#***********************************************************************
+#
+# go-gui
+#
+# Quick-start shell script to set up ADSL and GUI wrapper
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#***********************************************************************
+
+# GUI only works on Linux
+if test "`uname`" != "Linux" ; then
+ echo "Sorry, the GUI only works on Linux."
+ exit 1
+fi
+
+# Figure out directory of script
+MYDIR=`dirname $0`
+cd $MYDIR/src
+
+echo "Running ./configure..."
+./configure
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like ./configure failed."
+ exit 1
+fi
+
+echo "Running make..."
+make
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make failed."
+ exit 1
+fi
+
+echo "Running make install..."
+make install
+
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make install failed."
+ exit 1
+fi
+
+echo "Building GUI wrapper..."
+cd ../gui
+make
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make failed."
+ exit 1
+fi
+
+echo "Installing GUI..."
+make install
+
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make install failed."
+ exit 1
+fi
+
+# Install entry in KDE menu
+if test -n "$KDEDIR" ; then
+ echo "Installing KDE menu entry Internet : TkPPPoE..."
+ mkdir -p "$KDEDIR/share/applnk/Internet"
+ cat <<EOF > "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+# KDE Config File
+[KDE Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+
+# Install entry in GNOME menus
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+ echo "Installing GNOME menu entry Internet : TkPPPoE..."
+ mkdir -p "$GNOMEDIR/gnome/apps/Internet"
+cat <<EOF > "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+[Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+echo "Running GUI configuration tool..."
+tkpppoe &
+exit 0
diff --git a/mdk-stage1/rp-pppoe/gui/Makefile.in b/mdk-stage1/rp-pppoe/gui/Makefile.in
new file mode 100644
index 000000000..a9b0844c0
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/Makefile.in
@@ -0,0 +1,64 @@
+# @configure_input@
+#***********************************************************************
+#
+# Makefile
+#
+# Makefile for GUI for Roaring Penguin's Linux user-space PPPoE client.
+#
+# 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$
+#***********************************************************************
+DEFINES=
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+mandir=@mandir@
+install=@INSTALL@
+install_dir=@INSTALL@ -d
+sbindir=@sbindir@
+bindir=@bindir@
+
+ADSL_START_PATH=@sbindir@/adsl-start
+ADSL_STOP_PATH=@sbindir@/adsl-stop
+ADSL_STATUS_PATH=@sbindir@/adsl-status
+
+PATHS='-DADSL_START_PATH="$(ADSL_START_PATH)"' '-DADSL_STOP_PATH="$(ADSL_STOP_PATH)"' '-DADSL_STATUS_PATH="$(ADSL_STATUS_PATH)"'
+
+CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
+
+all: pppoe-wrapper
+ @echo ""
+ @echo "Type 'make install' as root to install the software."
+
+pppoe-wrapper: wrapper.o
+ @CC@ -o pppoe-wrapper wrapper.o
+
+wrapper.o: wrapper.c
+ @CC@ $(CFLAGS) -c -o wrapper.o wrapper.c
+
+install: all
+ -mkdir -p $(RPM_INSTALL_ROOT)$(sbindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(bindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)/etc/ppp/rp-pppoe-gui
+ $(install) -m 4755 -s pppoe-wrapper $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 tkpppoe $(RPM_INSTALL_ROOT)$(bindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man1
+ $(install) -m 644 pppoe-wrapper.1 $(RPM_INSTALL_ROOT)$(mandir)/man1
+ $(install) -m 644 tkpppoe.1 $(RPM_INSTALL_ROOT)$(mandir)/man1
+ -mkdir -p $(RPM_INSTALL_ROOT)/usr/share/rp-pppoe-gui
+ for i in tkpppoe.html mainwin-busy.png mainwin-nonroot.png mainwin.png props-advanced.png props-basic.png props-nic.png props-options.png ; do \
+ $(install) -m 644 html/$$i $(RPM_INSTALL_ROOT)/usr/share/rp-pppoe-gui; \
+ done
+
+clean:
+ rm -f *.o *~ pppoe-wrapper
+
+distclean: clean
+ rm -f Makefile tkpppoe
+
+.PHONY: clean
+
+.PHONY: distclean
diff --git a/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html b/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html
new file mode 100644
index 000000000..51aadb895
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html
@@ -0,0 +1,181 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.76 [en] (X11; U; Linux 2.2.14-5.0 i686) [Netscape]">
+ <title>TkPPPoE Manual</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#59188E" alink="#FF0000">
+
+<center>
+<h1>tkpppoe - A GUI for managing PPPoE Connections</h1>
+</center>
+
+<h1>Introduction</h1>
+
+TkPPPoE is a graphical user interface for managing PPPoE connections. It
+performs two different functions:
+<ul>
+<li>TkPPPoE lets you <em>define</em> connection properties. This step must
+be done as root.
+<li>TkPPPoE lets you <em>start and stop</em> PPPoE connections. This step
+may be done as a normal user, depending on how you configured the connection.
+</ul>
+
+<h1>Defining Connections</h1>
+
+To define connections, start TkPPPoE as root. You can do this from
+a terminal by typing <code>tkpppoe</code>, or from the KDE or GNOME menus
+by selecting <b>Internet : TkPPPoE</b>. The following window pops up:
+
+<p>
+<center><img src="mainwin.png" width="361" height="73" alt="Main Window">
+</center>
+
+<p>
+Because you have not yet defined any connections, the connection property
+window also pops up:
+
+<p>
+<center><img src="props-basic.png" width="440" height="259" alt="Connection Properties - Basic">
+</center>
+
+You can pop up the connection property window at any time by clicking
+<b>New Connection...</b> You can edit the properties of an existing
+connection by selecting the connection's name and clicking
+<b>Properties...</b>
+<h4>Basic Information</h4>
+
+Let's fill in the basic information:
+<ul>
+<li>For <b>Connection Name</b>, enter a unique name for this connection. It
+can be anything you like, but must contain only letters, numbers, underscores
+or dashes. In particular, it can't contain spaces. If you have only one
+PPPoE connection, a good name is <b>Default</b>.
+<li>For <b>User Name</b>, enter the user name supplied by your ISP. Enter
+only the user name; do not enter an "@isp.com" part.
+<li>For <b>Network</b>, you may have to enter your ISP's domain name.
+(For example, <b>isp.com</b>.) Some DSL providers add this to your user
+name; others do not. You may have to experiment a bit. The two most likely
+choices are your ISP's domain name, or blank. Try both.
+<li>For <b>Password</b>, enter the password your ISP provided you with.
+</ul>
+
+<h4>NIC and DNS</h4>
+Click on the <b>NIC and DNS</b> tab:
+
+<p>
+<center><img src="props-nic.png" width="440" height="259" alt="Connection Properties - NIC and DNS"></center>
+<p>
+<ul>
+<li>For <b>Ethernet Interface</b>, enter the Ethernet interface connected
+to the DSL modem. It is something like <b>eth0</b> or <b>eth1</b>. Click
+on <b>...</b> to browse a list of detected Ethernet interfaces.
+<li>For <b>DNS Setup</b>, you have three options:
+<ol>
+<li><b>From Server</b> means that the system will obtain DNS information from
+the PPPoE server. This is the correct choice for most ISPs.
+<li><b>Specify</b> means that you will enter the IP addresses of your DNS
+servers manually. In this case, enter the addresses in the <b>Primary DNS</b>
+and <b>Secondary DNS</b> entries.
+<li><b>Do not Adjust</b> means that you want RP-PPPoE to leave your
+DNS setup alone. Use this if you are running your own caching DNS server
+or know that you don't want the DNS setup touched.
+</ol>
+</ul>
+
+<h4>Options</h4>
+Click on the <b>Options</b> tab:
+
+<p>
+<center><img src="props-options.png" width="440" height="259" alt="Connection Properties - Options"></center>
+<p>
+<ul>
+<li>If you want ordinary users to be able to start and stop this connection,
+enable <b>Allow use by non-root users</b>. If you do not enable this,
+non-root users will be able to monitor the connection, but not control it.
+<li>If you want to use synchronous PPP, enable <b>Use synchronous PPP</b>.
+This is recommended as it conserves CPU usage, but may not work on some
+(misconfigured) Linux kernels.
+<li>For <b>Firewalling</b>, you have three options:
+<ol>
+<li><b>Stand-Alone</b> installs a simple firewall ruleset for stand-alone
+machines. Use this if you have only a single computer connected to the DSL
+modem.
+<li><b>Masquerading</b> installs a simple firewall ruleset for using
+your Linux computer as an Internet sharing device. If you have two Ethernet
+cards, you can connect one card to the DSL modem and the other to an
+internal LAN. The masquerading firewall ruleset lets internal machines
+share the DSL connection.
+<li><b>None</b>. If you already have your own firewall rules, or you wish
+to run servers on your machine, select None. This is <em>not recommended</em>
+unless you take steps to secure your machine, and know what you are doing.
+</ol>
+</ul>
+
+<h4>Advanced</h4>
+Click on the <b>Advanced</b> tab:
+
+<p>
+<center><img src="props-advanced.png" width="440" height="259" alt="Connection Properties - Advanced"></center>
+<p>
+
+In most cases, you can leave <b>AC-Name</b> and <b>Service-Name</b> blank.
+In some cases, your ISP may require you to enter information in these fields;
+contact your ISP for more information.
+
+<h1>Controlling Connections</h1>
+For these examples, run <code>tkpppoe</code> as a normal user (not root).
+The main window appears like this:
+
+<p>
+<center><img src="mainwin-nonroot.png" width="206" height="73" alt="Main Window - Non-root">
+</center>
+<p>
+<ul>
+<li>To start a connection, press <b>Start</b>. The two LEDs flash red
+and grey. If the connection is established, they turn green.
+<li>To stop a connection, press <b>Stop</b>.
+</ul>
+
+<p>The two rectangles to the right of the connection name are the
+<em>status LEDs</em>. The top LED corresponds to transmitted data and
+the bottom to received. The LEDs are colored as follows:
+<ul>
+<li>Grey -- connection is not established.
+<li>Flashing red/grey -- connection is being started.
+<li>Green -- connection is up, but idle.
+<li>Yellow -- connection is up and data is being sent or received.
+<li>Red -- connection has been lost, but the system is trying to reestablish it.
+</ul>
+
+<p>
+When a connection is established, two graphs appear:
+
+<p>
+<center><img src="mainwin-busy.png" width="206" height="73" alt="Main Window - Established Connection">
+</center>
+<p>
+
+The left (red) graph shows transmitted packets and the average
+transmission speed (in bits per second) over the sample time. The
+right (green) graph shows received packets.
+
+<h1>Miscellaneous Information</h1>
+<ul>
+<li>The connection menu has an entry called <b>User's Manual</b> which
+will pop up this user manual (if you have Netscape installed.)
+<li>You can define multiple PPPoE connections, but you should not use
+more than one simultaneuously unless you feel comfortable editing scripts
+and setting up routing tables. By default, TkPPPoE tries to add a default
+route for connections. This does not work well with multiple simultaneous
+connections.
+<li>If you exit from TkPPPoE, connections which are up remain up. You
+have to explicitly stop connections if you want them terminated.
+</ul>
+<hr>
+<a href="http://www.roaringpenguin.com/pppoe/">TkPPPoE</a> is Copyright 2001 by <a href="http://www.roaringpenguin.com">Roaring Penguin Software Inc</a> and
+is licensed under the GNU General Public License.
+<p>Screenshots show TkPPPoE running under the <a href="http://www.xfce.org">XFCE</a> desktop, a lightweight UNIX and Linux desktop.
+</body>
+</html>
diff --git a/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1 b/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1
new file mode 100644
index 000000000..4fbf2bce2
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1
@@ -0,0 +1,45 @@
+.\" $Id$
+.TH PPPOE-WRAPPER 1 "26 February 2001"
+.UC 4
+.SH NAME
+pppoe-wrapper \- SUID wrapper for starting and stopping PPPoE connections.
+.SH SYNOPSIS
+.B pppoe-wrapper start linkname
+.P
+.B pppoe-wrapper stop linkname
+.P
+.B pppoe-wrapper status linkname
+
+.SH DESCRIPTION
+\fBpppoe-wrapper\fR is a small SUID program which allows non-root users
+to start and stop PPPoE links. It operates as follows:
+
+.TP
+.B o
+First, \fIlinkname\fR is sanity-checked. Too-long names and names containing
+illegal characters are rejected.
+
+.TP
+.B o
+Second, \fBpppoe-wrapper\fR opens the file \fB/etc/ppp/rp-pppoe-gui/\fR\fIlinkname\fR for reading. If that file does not contain the line:
+.nf
+
+ NONROOT=OK
+
+.fi
+then \fBpppoe-wrapper\fR fails.
+
+.TP
+.B o
+Otherwise, \fBpppoe-wrapper\fR runs \fBadsl-start\fR, \fBadsl-stop\fR or
+\fBadsl-status\fR with the above filename as its single argument.
+
+.SH AUTHOR
+\fBpppoe-wrapper\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-status(8), tkpppoe(1)
+
+
diff --git a/mdk-stage1/rp-pppoe/gui/tkpppoe.1 b/mdk-stage1/rp-pppoe/gui/tkpppoe.1
new file mode 100644
index 000000000..183476568
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/tkpppoe.1
@@ -0,0 +1,36 @@
+.\" $Id$
+.TH TKPPPOE 1 "26 February 2001"
+.UC 4
+.SH NAME
+tkpppoe \- Graphical interface for controlling rp-pppoe
+.SH SYNOPSIS
+.B tkpppoe
+
+.SH DESCRIPTION
+\fBtkpppoe\fR is a graphical program for controlling PPPoE links.
+It works with the RP-PPPoE package and has its own HTML manual.
+
+.SH FILES
+
+.TP
+.B /etc/ppp/rp-pppoe-gui/connection-info
+Contains connection information. This file is not human-editable.
+
+.TP
+.B /etc/ppp/rp-pppoe-gui/passwd
+Contains passwords for each connection. This file is not human-editable.
+
+.TP
+.B /etc/ppp/rp-pppoe-gui/conf.*
+These configuration files are used by \fBadsl-start\fR. They are
+generated anew by \fBtkpppoe\fR each time a change is made to a
+connection's properties.
+
+.SH AUTHOR
+\fBtkpppoe\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), pppoe-wrapper(8).
+
diff --git a/mdk-stage1/rp-pppoe/gui/tkpppoe.in b/mdk-stage1/rp-pppoe/gui/tkpppoe.in
new file mode 100755
index 000000000..37dbf8cc1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/tkpppoe.in
@@ -0,0 +1,2891 @@
+#!/bin/sh
+# -*-Mode: TCL;-*-
+
+#--------------------------------------------------------------
+# tkpppoe
+#
+# A graphical front-end for configuring and using rp-pppoe.
+#
+# Copyright (C) 2001 by Roaring Penguin Software Inc.
+# This file may be distributed under the terms of the GNU General Public
+# License, Version 2, or (at your option) any later version.
+#
+# The "Roaring Penguin" logo is a trademark of Roaring Penguin Software Inc.
+#
+# http://www.roaringpenguin.com
+#
+#--------------------------------------------------------------
+
+# $Id$
+
+# the next line restarts using wish \
+umask 022; \
+exec wish "$0" "$@" || clear; echo "*****"; echo "Cannot find 'wish' -- you need Tcl/Tk installed to run this program"; exit 1
+
+# Set app name
+tk appname TkPPPoE
+
+# Set this to one if you want to allow multiple instances of TkPPPoE
+set AllowMultipleInstances 0
+
+# Check for other instances
+if {"[tk appname]" != "TkPPPoE"} {
+ # Must be another instance running...
+ if {!$AllowMultipleInstances} {
+ send TkPPPoE AnotherInstance
+ exit 0
+ }
+}
+
+# Location of config directory
+set ConfigDir /etc/ppp/rp-pppoe-gui
+
+# Are we running as root?
+set Admin 0
+
+# Location of connection info file
+set ConnectionInfoFile [file join $ConfigDir connection-info]
+
+# Location of password file
+set PasswordFile [file join $ConfigDir passwd]
+
+# Location of "already run" file
+set AlreadyRunFile [file join $ConfigDir gui-already-run]
+
+# Connection information
+set ConnectionInfo {}
+
+# Connection options
+set OPTS(nonroot) 0
+set OPTS(sync) 1
+
+# Location of wrapper
+set Wrapper "@WRAPPER@"
+
+# Timer token for UpdateConnectionState
+set UpdateToken {}
+
+# Update interval in milliseconds
+set UpdateInterval 500
+
+# Packet counters for signalling activity
+set Packets(in) 0
+set Packets(out) 0
+set Bytes(in) 0
+set Bytes(out) 0
+set MeasureTime 0
+
+# Set up some options to make it look better
+option add *Button.borderWidth 1
+option add *Button.Pad 1
+option add *Menubutton.borderWidth 1
+option add *Menubutton.Pad 1
+option add *Entry.Background white
+
+# Array holding help strings for windows
+array set HelpData {}
+
+bind HelpWin <Enter> "HelpWindowEntered %W"
+bind HelpWin <Leave> "HelpWindowLeft %W"
+
+proc AnotherInstance {} {
+ wm deiconify .
+ raise .
+}
+
+#***********************************************************************
+# %PROCEDURE: HelpWindowEntered
+# %ARGUMENTS:
+# w -- window
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Looks for procedure in HelpData; evals it if found.
+#***********************************************************************
+proc HelpWindowEntered { w } {
+ global HelpData
+ if {[info exists HelpData($w)]} {
+ set cmd "$HelpData($w) Enter"
+ uplevel #0 $cmd
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: HelpWindowLeft
+# %ARGUMENTS:
+# w -- window
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Looks for procedure in HelpData; evals it if found.
+#***********************************************************************
+proc HelpWindowLeft { w } {
+ global HelpData
+ if {[info exists HelpData($w)]} {
+ set cmd "$HelpData($w) Leave"
+ uplevel #0 $cmd
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: RegisterHelpWindow
+# %ARGUMENTS:
+# w -- window we need help about
+# helptext -- the help text
+# win -- window in which to put help messages
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Sets things up so help text appears in "$win" when mouse enters "$w"
+#***********************************************************************
+proc RegisterHelpWindow {w helptext win} {
+ global HelpData
+ set tags [bindtags $w]
+ if {[lsearch -exact $tags HelpWin] < 0} {
+ lappend tags HelpWin
+ bindtags $w $tags
+ }
+ set HelpData($w) [list HelpInTextWin $helptext $win]
+}
+
+#***********************************************************************
+# %PROCEDURE: HelpInTextWin
+# %ARGUMENTS:
+# text -- help text
+# tw -- window in which to write text
+# what -- one of "Enter" or "Leave"
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Clears out $tw; if $what is "Enter", puts $text in $tw.
+#***********************************************************************
+proc HelpInTextWin {text tw what} {
+ $tw configure -state normal
+ $tw delete 1.0 end
+ if {"$what" == "Enter"} {
+ $tw insert end $text
+ }
+ $tw configure -state disabled
+}
+
+
+#***********************************************************************
+# %PROCEDURE: drawLogo
+# %ARGUMENTS:
+# c -- canvas to draw logo in
+# bg -- background color of canvas
+# pencolor -- color of the word "Penguin"
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Draws Roaring Penguin logo in a Tcl canvas
+#***********************************************************************
+proc drawLogo { c bg {pengcolor #6699cc} } {
+ $c create polygon 372.249 5.182 361.23 5.519 \
+ 346.164 8.892 316.482 20.023 305.463 17.774 296.468 \
+ 19.573 288.935 24.97 282.864 33.177 267.348 55.102 \
+ 254.531 77.814 236.204 125.26 225.635 174.844 \
+ 221.026 226.113 213.605 228.025 208.658 232.634 \
+ 225.523 240.28 250.708 243.316 282.752 242.416 \
+ 320.079 238.818 330.985 193.17 338.181 146.735 \
+ 338.743 99.963 335.483 76.577 329.524 53.191 345.602 \
+ 48.131 353.135 45.995 359.768 41.048 342.679 43.184 \
+ 324.689 40.036 334.583 28.905 348.3 18.674 372.249 \
+ 5.182 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create line 372.249 5.182 361.23 5.519 \
+ 346.164 8.892 316.482 20.023 305.463 17.774 296.468 \
+ 19.573 288.935 24.97 282.864 33.177 267.348 55.102 \
+ 254.531 77.814 236.204 125.26 225.635 174.844 \
+ 221.026 226.113 213.605 228.025 208.658 232.634 \
+ 225.523 240.28 250.708 243.316 282.752 242.416 \
+ 320.079 238.818 330.985 193.17 338.181 146.735 \
+ 338.743 99.963 335.483 76.577 329.524 53.191 345.602 \
+ 48.131 353.135 45.995 359.768 41.048 342.679 43.184 \
+ 324.689 40.036 334.583 28.905 348.3 18.674 372.249 \
+ 5.182 -tags logo
+
+ $c create polygon 298.605 109.632 290.734 \
+ 159.328 282.752 182.939 271.958 205.65 262.851 \
+ 171.133 263.75 138.752 264.537 164.5 271.958 192.833 \
+ 286.687 157.192 298.605 109.632 -fill #ffffff \
+ -outline {} -width 1 -tags logo
+
+ $c create line 298.605 109.632 290.734 159.328 \
+ 282.752 182.939 271.958 205.65 262.851 171.133 \
+ 263.75 138.752 264.537 164.5 271.958 192.833 286.687 \
+ 157.192 298.605 109.632 -tags logo
+
+ $c create polygon 312.546 30.592 315.132 35.876 \
+ 310.747 39.586 308.161 34.414 312.546 30.592 -fill \
+ #ffffff -outline {} -width 1 -tags logo
+
+ $c create line 312.546 30.592 315.132 35.876 \
+ 310.747 39.586 308.161 34.414 312.546 30.592 -tags logo
+
+ $c create polygon 328.624 54.427 322.665 58.7 \
+ 314.458 61.286 289.16 59.15 284.55 74.665 285.338 \
+ 90.181 303.214 98.951 308.499 106.259 310.523 \
+ 116.378 305.913 130.208 312.771 141.563 308.049 \
+ 167.76 299.729 192.158 279.041 238.593 313.558 \
+ 233.871 327.388 185.75 335.033 139.989 335.82 96.253 \
+ 328.624 54.427 -fill #ffffff -outline {} -width 1 -tags logo
+
+ $c create line 328.624 54.427 322.665 58.7 \
+ 314.458 61.286 289.16 59.15 284.55 74.665 285.338 \
+ 90.181 303.214 98.951 308.499 106.259 310.523 \
+ 116.378 305.913 130.208 312.771 141.563 308.049 \
+ 167.76 299.729 192.158 279.041 238.593 313.558 \
+ 233.871 327.388 185.75 335.033 139.989 335.82 96.253 \
+ 328.624 54.427 -tags logo
+
+ $c create polygon 53.837 185.412 54.399 185.862 \
+ 53.837 188.223 54.399 188.673 53.837 188.673 53.837 \
+ 189.572 53.837 190.472 53.387 191.034 52.938 192.833 \
+ 50.577 195.644 49.677 196.656 49.677 197.105 48.215 \
+ 198.455 47.316 198.904 46.866 198.904 44.505 200.816 \
+ 43.606 200.366 42.594 201.265 42.144 201.715 41.245 \
+ 202.277 40.795 202.727 40.345 202.277 39.783 202.277 \
+ 36.972 203.177 36.522 203.177 36.073 203.177 35.623 \
+ 203.627 34.723 203.627 34.161 203.627 34.161 204.076 \
+ 30.901 204.526 28.54 205.538 26.291 205.088 25.729 \
+ 205.088 24.829 205.088 24.38 204.526 23.93 204.526 \
+ 23.48 204.526 22.918 205.088 22.918 206.437 22.918 \
+ 206.887 22.918 207.337 22.468 207.337 22.468 208.798 \
+ 22.018 209.248 22.018 211.16 22.018 211.609 21.569 \
+ 213.521 21.119 215.769 21.569 216.781 20.669 218.13 \
+ 20.669 219.592 20.669 220.042 20.107 220.941 20.107 \
+ 221.953 20.107 223.752 19.657 225.664 19.208 226.113 \
+ 19.657 227.013 18.308 230.835 17.858 240.167 17.296 \
+ 248.15 17.296 249.05 16.846 250.062 15.947 250.062 \
+ 15.048 250.062 15.048 250.511 12.686 251.86 12.237 \
+ 251.86 11.675 251.411 11.675 250.511 11.675 246.689 \
+ 11.225 245.339 11.225 243.878 10.775 240.617 11.225 \
+ 239.268 11.225 238.818 10.775 238.256 10.325 237.357 \
+ 10.325 236.007 9.876 232.634 9.876 231.735 9.876 \
+ 231.285 9.876 230.835 9.876 230.386 9.876 229.824 \
+ 9.426 229.374 9.426 226.113 9.876 226.113 9.876 \
+ 225.664 9.426 224.202 9.426 223.752 9.426 223.302 \
+ 10.325 221.953 9.426 220.941 9.426 219.592 9.426 \
+ 219.142 9.426 218.58 9.426 217.681 9.426 217.231 \
+ 9.426 216.781 8.864 216.332 8.864 214.42 8.864 \
+ 213.97 8.414 213.521 8.414 210.148 8.414 209.248 \
+ 7.964 207.899 8.414 205.988 8.414 204.526 7.065 \
+ 201.265 7.515 200.816 9.426 201.715 10.325 201.265 \
+ 10.775 200.816 10.775 198.904 11.225 198.005 11.225 \
+ 197.555 10.775 197.555 9.876 196.094 9.426 194.744 \
+ 7.515 194.295 6.615 193.845 6.053 193.845 5.153 \
+ 193.283 3.804 191.484 3.804 190.022 3.804 189.572 \
+ 3.804 189.123 3.242 188.673 3.242 186.762 3.804 \
+ 185.412 4.254 184.85 4.704 184.4 7.964 180.24 10.325 \
+ 178.779 11.225 178.779 12.237 177.879 14.036 176.98 \
+ 15.497 175.968 21.569 173.607 22.918 173.157 23.48 \
+ 173.157 24.38 172.707 24.829 172.707 29.102 171.808 \
+ 29.551 171.808 30.001 171.358 31.35 170.796 31.913 \
+ 171.358 32.362 170.796 39.783 171.358 40.345 170.796 \
+ 42.144 171.358 47.766 174.619 48.778 176.418 49.227 \
+ 176.418 49.677 176.98 50.127 176.98 51.588 178.329 \
+ 52.038 179.228 52.488 180.69 52.038 181.14 52.038 \
+ 181.59 52.488 182.039 52.938 182.039 53.387 182.601 \
+ 53.837 183.051 53.837 183.501 53.837 185.412 -fill \
+ $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 42.594 222.853 43.156 221.953 \
+ 41.694 222.403 39.783 224.202 39.783 224.764 39.783 \
+ 225.214 40.345 225.214 41.245 224.202 41.694 223.752 \
+ 42.594 222.853 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 58.559 234.096 59.009 234.096 \
+ 59.009 234.546 58.559 234.995 58.559 235.445 57.21 \
+ 236.907 56.648 237.806 52.938 241.067 52.038 241.629 \
+ 52.038 242.079 51.026 242.529 50.577 242.978 50.127 \
+ 242.978 49.227 244.44 45.405 246.239 44.055 246.689 \
+ 43.606 246.689 43.606 247.251 42.144 247.251 41.694 \
+ 247.7 40.795 247.7 38.434 248.15 36.522 248.15 \
+ 35.173 247.7 34.161 246.689 33.711 246.239 32.812 \
+ 244.44 32.362 241.629 32.812 239.718 32.812 239.268 \
+ 33.711 234.995 36.522 229.824 35.623 228.474 35.623 \
+ 227.013 36.522 225.664 37.534 224.202 38.883 222.853 \
+ 41.694 220.492 42.594 219.592 43.156 219.592 43.606 \
+ 219.142 45.405 217.681 45.967 217.681 46.416 217.231 \
+ 48.778 215.769 52.038 214.87 53.387 214.42 54.849 \
+ 214.87 55.299 214.87 56.198 215.769 56.198 217.681 \
+ 56.198 218.58 54.399 221.953 53.837 222.853 53.837 \
+ 223.302 53.387 223.752 50.577 226.113 49.677 226.563 \
+ 47.316 228.474 43.156 230.386 41.245 230.835 40.795 \
+ 230.835 40.345 230.835 39.333 230.835 38.883 230.835 \
+ 38.883 229.824 39.783 229.374 40.795 228.474 41.694 \
+ 228.025 42.594 227.575 45.967 227.013 46.866 226.563 \
+ 50.127 224.764 51.588 223.302 52.488 221.953 52.488 \
+ 220.492 52.488 219.142 51.026 218.13 49.677 218.13 \
+ 48.778 218.13 47.766 219.142 47.316 219.142 47.316 \
+ 219.592 46.866 219.592 45.967 220.941 44.505 221.953 \
+ 44.055 222.403 43.606 222.853 42.594 223.752 41.694 \
+ 225.664 41.245 225.664 41.245 226.113 40.345 226.563 \
+ 39.333 227.575 39.333 228.474 38.434 229.374 36.522 \
+ 233.197 35.623 236.457 35.623 237.357 35.623 238.256 \
+ 35.173 241.067 35.623 242.079 36.522 243.428 37.534 \
+ 243.878 37.984 244.44 38.434 244.89 38.883 244.89 \
+ 39.783 245.339 43.156 245.339 45.967 244.44 49.227 \
+ 242.529 50.127 241.629 50.577 241.067 54.399 238.818 \
+ 54.399 238.256 54.399 237.806 56.198 236.907 58.559 \
+ 234.096 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 92.289 248.6 92.739 249.05 \
+ 92.289 249.05 91.84 249.05 90.94 248.6 90.378 248.6 \
+ 89.478 247.7 89.029 247.251 88.129 246.689 87.117 \
+ 245.789 85.768 244.89 85.318 244.44 85.768 244.44 \
+ 85.318 242.529 84.756 242.079 84.756 240.617 84.756 \
+ 240.167 84.756 239.718 84.756 239.268 83.857 236.457 \
+ 83.407 234.096 83.407 233.197 83.407 231.735 83.407 \
+ 223.302 83.407 221.391 82.957 220.941 82.508 221.953 \
+ 80.596 226.113 80.146 226.563 80.146 227.013 79.697 \
+ 228.025 79.135 228.474 79.697 228.474 76.324 234.096 \
+ 75.874 234.995 75.424 236.457 74.975 236.457 74.975 \
+ 236.907 74.975 237.357 74.075 239.268 73.513 239.718 \
+ 73.063 240.167 72.613 241.067 72.164 242.529 71.714 \
+ 242.529 71.714 243.878 70.252 245.789 69.803 246.689 \
+ 68.903 246.689 68.903 247.251 67.891 247.7 66.542 \
+ 247.7 66.092 247.7 65.643 247.7 65.08 247.251 65.08 \
+ 246.689 65.08 245.789 64.631 242.079 65.08 242.079 \
+ 64.631 241.629 65.08 241.067 65.08 238.818 64.631 \
+ 237.806 64.631 236.457 64.631 234.546 64.631 233.197 \
+ 64.631 232.634 64.631 232.185 64.631 231.735 64.631 \
+ 228.924 64.631 227.575 64.631 225.664 64.631 225.214 \
+ 64.631 224.764 64.631 223.302 64.631 217.231 65.08 \
+ 216.332 65.643 215.769 69.803 214.87 70.252 215.32 \
+ 70.252 216.332 70.252 217.681 70.252 218.58 69.803 \
+ 219.142 69.803 220.492 69.353 220.941 69.353 221.391 \
+ 68.903 221.953 68.903 225.664 68.453 226.563 68.453 \
+ 228.025 68.453 228.474 67.891 228.924 67.891 230.835 \
+ 68.453 236.457 68.453 237.806 68.453 238.818 68.453 \
+ 240.617 68.453 241.067 68.903 241.067 68.903 241.629 \
+ 69.353 241.629 70.702 241.067 70.702 240.617 71.264 \
+ 240.167 71.264 239.268 72.164 238.256 73.063 236.457 \
+ 74.525 234.546 74.975 233.197 76.324 230.835 77.336 \
+ 229.824 78.235 227.575 78.235 227.013 78.685 226.563 \
+ 78.685 225.664 79.135 225.214 79.697 224.764 79.697 \
+ 224.202 80.146 222.403 81.046 220.941 81.945 217.681 \
+ 82.957 215.769 85.318 214.87 85.768 214.87 87.567 \
+ 214.42 87.567 215.769 87.117 216.332 87.567 216.781 \
+ 88.129 219.592 87.567 219.592 87.567 220.492 87.567 \
+ 221.391 87.567 224.764 87.567 225.664 87.567 226.113 \
+ 87.117 226.113 87.117 227.575 87.567 229.374 88.579 \
+ 235.445 89.029 239.268 89.029 239.718 89.029 241.067 \
+ 89.478 242.529 89.478 242.978 89.928 243.878 89.928 \
+ 244.44 90.378 244.89 90.94 246.239 92.289 248.6 \
+ -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 117.587 220.492 118.037 \
+ 222.403 117.587 222.853 117.587 224.764 116.687 \
+ 226.113 116.687 227.013 116.238 228.025 114.776 \
+ 229.374 113.877 231.285 112.865 231.735 109.154 \
+ 234.995 106.343 236.457 105.444 237.357 103.982 \
+ 237.806 103.083 238.256 102.633 238.818 102.183 \
+ 238.818 101.172 239.268 99.822 239.718 98.361 \
+ 239.268 97.461 239.718 96.562 239.268 96.0 238.818 \
+ 95.55 238.818 94.201 236.907 94.201 235.445 94.201 \
+ 233.646 94.65 233.197 94.65 232.634 95.1 232.185 \
+ 95.1 231.735 95.55 231.735 96.0 230.386 97.461 \
+ 228.025 97.461 227.575 98.361 226.563 99.822 224.764 \
+ 101.172 223.302 101.172 222.853 102.633 221.391 \
+ 103.083 220.941 104.432 219.592 103.982 218.58 \
+ 103.982 217.231 103.982 216.781 103.982 215.32 \
+ 104.432 214.42 103.982 210.148 103.982 209.698 \
+ 103.982 209.248 104.432 208.798 104.432 207.899 \
+ 104.432 205.988 104.432 205.538 104.994 203.177 \
+ 104.994 202.277 104.994 201.265 104.994 200.816 \
+ 104.994 200.366 104.994 199.916 105.894 199.467 \
+ 106.343 198.904 106.793 198.455 107.243 198.904 \
+ 108.255 198.904 108.255 199.467 108.705 199.467 \
+ 108.705 202.727 108.255 204.076 108.255 205.538 \
+ 108.255 205.988 107.805 205.988 107.805 206.887 \
+ 107.805 209.698 107.243 210.71 106.793 212.059 \
+ 106.343 214.87 106.343 215.32 106.343 215.769 \
+ 105.894 217.681 106.343 217.681 106.793 217.681 \
+ 107.243 217.231 108.705 215.32 109.604 215.32 \
+ 110.054 214.42 110.054 213.97 110.616 213.97 110.616 \
+ 214.42 111.965 214.87 112.415 214.87 112.865 215.32 \
+ 114.326 216.332 116.238 217.681 116.687 218.58 \
+ 117.137 219.592 117.587 220.042 117.587 220.492 \
+ -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 123.658 258.944 123.658 \
+ 259.394 123.658 260.293 123.658 261.755 123.658 \
+ 262.654 123.658 263.104 123.209 266.364 123.209 \
+ 267.376 122.759 269.175 122.309 269.737 121.859 \
+ 271.087 121.859 271.536 121.859 271.986 121.297 \
+ 271.986 121.297 272.548 120.847 273.448 120.398 \
+ 273.448 120.398 273.897 118.486 276.259 118.037 \
+ 276.708 117.587 277.608 117.137 278.17 116.687 \
+ 278.17 115.675 278.62 115.675 279.069 113.427 \
+ 280.419 112.865 280.981 112.415 280.981 111.965 \
+ 281.43 110.054 282.33 109.154 282.33 108.705 282.78 \
+ 108.255 282.78 107.805 283.229 104.994 283.792 \
+ 104.432 283.792 103.982 283.792 103.533 283.792 \
+ 103.083 283.792 102.633 283.792 102.183 283.792 \
+ 101.172 283.792 100.722 283.792 99.822 283.792 98.81 \
+ 283.792 96.562 282.33 96.0 282.78 95.1 281.88 94.201 \
+ 281.43 91.84 279.969 92.289 279.519 92.289 278.62 \
+ 93.751 279.069 93.751 279.519 94.201 279.519 94.65 \
+ 279.969 95.1 279.969 96.0 280.981 98.81 281.88 \
+ 101.172 281.88 101.621 281.88 102.633 281.88 103.083 \
+ 281.88 103.533 281.88 104.432 281.43 104.994 281.88 \
+ 105.444 281.43 106.793 281.43 107.805 280.981 \
+ 108.705 280.419 109.154 280.419 109.604 279.969 \
+ 110.054 279.969 110.616 279.969 111.066 279.519 \
+ 112.865 278.17 113.427 277.608 113.877 277.608 \
+ 113.877 277.158 114.326 277.158 114.326 276.708 \
+ 114.776 276.259 115.226 276.259 116.238 274.347 \
+ 116.687 274.347 116.687 273.897 117.587 272.998 \
+ 117.587 272.548 118.037 271.986 119.498 267.826 \
+ 120.398 265.015 120.398 262.204 119.948 259.843 \
+ 119.948 259.394 119.948 258.944 119.498 257.482 \
+ 118.486 254.222 118.037 253.772 117.587 251.86 \
+ 115.675 249.05 115.226 248.6 114.776 248.15 113.877 \
+ 247.251 111.965 246.239 111.515 246.239 110.616 \
+ 246.239 110.054 246.239 109.154 246.239 107.243 \
+ 247.251 106.343 247.251 105.444 247.7 104.994 247.7 \
+ 103.083 248.15 102.183 248.6 101.621 248.6 101.172 \
+ 249.05 100.722 249.499 99.822 250.062 98.361 250.062 \
+ 97.461 249.499 97.012 249.499 96.562 249.05 96.562 \
+ 248.6 97.012 248.15 99.822 245.789 100.272 245.339 \
+ 101.621 244.44 101.621 243.878 102.183 243.428 \
+ 102.633 243.428 102.633 242.978 103.982 241.629 \
+ 103.982 241.067 103.982 240.617 103.982 240.167 \
+ 105.444 239.268 108.705 236.907 108.705 236.457 \
+ 109.154 236.457 110.054 235.445 111.066 234.546 \
+ 112.415 234.096 112.865 233.646 113.427 233.646 \
+ 113.877 233.646 113.877 234.096 114.326 234.995 \
+ 114.776 235.445 114.776 236.457 114.326 237.357 \
+ 113.427 238.818 112.415 239.268 112.415 240.167 \
+ 111.965 240.167 111.515 240.617 110.054 241.629 \
+ 110.054 242.079 109.604 242.529 108.705 242.978 \
+ 110.054 242.978 113.427 242.079 114.326 242.529 \
+ 115.226 242.978 116.687 244.44 119.048 246.689 \
+ 119.498 247.7 119.498 248.15 119.948 248.6 119.948 \
+ 249.05 120.398 249.05 120.398 249.499 120.847 \
+ 249.499 120.847 250.062 121.297 250.511 121.297 \
+ 251.411 121.859 252.31 122.759 252.872 122.759 \
+ 254.222 122.759 254.671 123.658 258.494 123.658 \
+ 258.944 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 147.607 215.769 148.506 215.32 \
+ 148.506 217.231 148.506 217.681 148.506 218.13 \
+ 148.956 218.58 148.506 220.492 148.506 220.941 \
+ 148.506 222.853 148.956 224.764 148.956 226.113 \
+ 148.506 226.563 148.956 226.563 148.506 228.924 \
+ 148.956 229.824 148.956 231.285 148.506 232.185 \
+ 148.956 232.634 148.956 233.646 149.405 234.995 \
+ 148.956 234.995 149.405 235.445 149.405 236.907 \
+ 149.405 237.357 149.968 238.818 150.867 240.167 \
+ 150.867 240.617 151.317 242.079 152.216 243.428 \
+ 153.228 245.339 154.128 245.789 155.027 246.239 \
+ 156.939 245.789 157.388 246.239 156.489 246.689 \
+ 155.027 247.7 154.128 247.7 153.228 247.7 152.216 \
+ 247.7 151.767 247.7 150.867 247.251 150.417 246.239 \
+ 149.405 246.239 148.056 245.339 147.607 244.44 \
+ 147.157 243.428 145.695 241.629 145.695 240.617 \
+ 145.245 240.167 145.245 239.718 144.796 238.256 \
+ 144.346 236.907 144.346 235.445 143.784 234.546 \
+ 143.784 233.197 143.784 232.185 143.784 230.835 \
+ 143.334 229.824 143.784 229.374 143.334 229.374 \
+ 143.334 228.474 142.884 230.386 141.985 231.735 \
+ 140.973 233.197 140.523 234.096 140.523 234.546 \
+ 140.523 234.995 139.624 236.457 139.174 237.806 \
+ 138.162 239.718 137.263 241.067 136.813 242.079 \
+ 135.913 242.978 134.452 244.89 134.002 245.789 \
+ 133.552 245.789 132.091 246.689 131.191 247.251 \
+ 129.73 248.15 129.28 248.15 128.38 247.7 128.38 \
+ 248.15 126.919 247.7 126.019 247.251 125.12 246.239 \
+ 125.12 245.339 124.67 244.89 124.67 244.44 124.67 \
+ 243.428 124.67 242.529 124.67 241.067 124.67 239.718 \
+ 125.12 239.268 124.67 239.268 124.67 238.256 125.12 \
+ 237.806 125.12 237.357 125.12 236.907 125.12 236.007 \
+ 125.12 234.096 125.57 233.197 125.57 232.185 126.019 \
+ 232.185 126.019 231.285 126.019 230.386 126.019 \
+ 229.374 126.469 228.474 126.469 227.013 126.469 \
+ 225.214 126.019 225.214 126.469 225.214 126.019 \
+ 223.302 126.019 221.953 126.019 220.492 125.57 \
+ 220.042 125.12 219.592 124.108 219.142 123.209 \
+ 219.142 121.859 220.042 121.297 220.042 120.398 \
+ 220.941 119.498 221.391 119.048 221.391 118.486 \
+ 221.953 118.037 221.953 118.037 221.391 118.486 \
+ 220.941 119.498 220.042 120.847 219.142 122.759 \
+ 217.681 124.108 216.781 125.12 215.769 126.469 \
+ 214.87 126.919 214.87 127.481 214.87 128.38 214.87 \
+ 128.83 214.87 129.73 214.87 129.73 215.769 130.292 \
+ 215.769 130.742 216.781 130.742 217.681 130.292 \
+ 219.142 130.292 221.953 130.292 223.302 130.292 \
+ 224.202 129.73 225.214 129.28 227.013 128.83 227.575 \
+ 129.28 227.575 129.28 228.474 128.83 229.374 129.28 \
+ 229.824 129.28 230.386 128.83 231.735 128.38 234.096 \
+ 128.38 234.995 127.931 236.457 127.931 239.268 \
+ 127.931 240.167 127.931 241.629 128.83 242.978 \
+ 129.28 243.878 129.73 244.44 130.742 244.44 131.191 \
+ 244.44 132.091 244.44 133.103 243.878 134.002 \
+ 242.978 134.902 242.079 135.351 241.067 135.913 \
+ 240.167 136.363 239.268 136.813 238.818 137.263 \
+ 237.806 137.712 236.907 138.162 235.445 138.724 \
+ 234.546 139.174 233.646 139.624 232.634 140.523 \
+ 230.835 140.973 228.924 141.535 227.013 142.435 \
+ 225.664 142.884 223.302 143.334 221.391 143.334 \
+ 220.941 143.334 219.142 144.346 217.681 144.796 \
+ 216.781 145.695 216.332 146.595 216.332 147.607 \
+ 215.769 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 165.371 241.067 165.371 \
+ 241.067 164.921 243.878 164.921 246.239 163.46 \
+ 246.689 161.211 247.251 160.649 247.251 160.199 \
+ 244.44 160.199 243.878 160.199 243.428 160.199 \
+ 242.079 160.199 240.167 160.199 239.718 159.749 \
+ 239.268 160.199 237.806 159.749 237.357 159.749 \
+ 236.007 159.749 230.835 159.749 229.824 159.749 \
+ 228.924 159.749 226.113 159.749 225.664 159.749 \
+ 223.752 159.749 222.853 159.749 218.58 159.749 \
+ 218.13 159.749 217.681 160.199 217.231 161.661 \
+ 216.781 162.11 216.781 162.56 216.781 163.46 216.781 \
+ 164.022 219.142 163.46 222.403 163.46 222.853 163.46 \
+ 224.202 163.46 225.664 163.46 226.563 163.46 227.013 \
+ 163.46 228.924 163.01 230.835 163.01 232.634 163.46 \
+ 233.197 164.022 232.634 164.472 232.634 164.921 \
+ 232.185 164.921 231.735 165.371 231.735 165.821 \
+ 232.185 165.371 233.646 165.821 236.007 165.371 \
+ 238.256 165.371 238.818 165.371 240.617 165.371 \
+ 241.067 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 165.821 214.42 166.833 215.32 \
+ 166.271 215.32 165.821 216.332 165.371 216.332 \
+ 165.371 216.781 165.821 217.681 165.821 218.13 \
+ 165.371 219.142 165.371 220.042 164.921 222.853 \
+ 165.371 224.764 164.921 225.664 165.371 227.575 \
+ 165.371 228.474 164.921 228.474 164.472 227.575 \
+ 164.472 226.113 164.022 224.764 164.472 224.202 \
+ 164.472 223.752 164.472 222.403 164.921 214.87 \
+ 164.472 213.521 164.472 212.959 164.472 212.509 \
+ 164.022 212.509 163.46 212.509 163.01 212.959 162.56 \
+ 212.959 161.661 212.959 161.211 212.059 161.211 \
+ 211.609 160.649 211.609 160.199 209.698 160.649 \
+ 208.349 163.46 206.437 164.472 206.437 165.821 \
+ 207.899 165.821 208.349 166.833 210.148 166.833 \
+ 210.71 165.821 211.609 165.371 212.059 165.371 \
+ 212.959 165.821 213.97 165.821 214.42 -fill $pengcolor \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 201.462 248.6 201.462 249.05 \
+ 201.012 249.05 200.563 249.05 200.001 248.6 199.551 \
+ 248.6 198.651 247.7 197.752 247.251 196.74 246.689 \
+ 196.29 245.789 194.379 244.89 194.379 244.44 194.379 \
+ 242.529 193.929 242.079 193.479 240.617 193.479 \
+ 240.167 193.929 239.718 193.479 239.268 193.03 \
+ 236.457 192.58 234.096 192.58 233.197 192.58 231.735 \
+ 192.58 223.302 192.58 221.391 192.13 220.941 191.568 \
+ 221.953 189.769 226.113 189.319 226.563 189.319 \
+ 227.013 188.757 228.025 188.307 228.474 188.757 \
+ 228.474 185.497 234.096 185.047 234.995 184.597 \
+ 236.457 184.147 236.457 184.147 236.907 184.147 \
+ 237.357 183.136 239.268 182.686 239.268 182.686 \
+ 239.718 182.236 240.167 181.786 241.067 181.337 \
+ 242.529 180.887 242.529 180.887 243.878 179.425 \
+ 245.789 178.975 246.689 178.076 246.689 178.076 \
+ 247.251 177.064 247.7 175.715 247.7 175.265 247.7 \
+ 174.703 247.7 174.253 247.251 174.253 246.689 \
+ 174.253 245.789 173.804 242.079 174.253 242.079 \
+ 173.804 241.629 173.804 241.067 173.804 238.818 \
+ 173.804 237.806 173.804 236.457 173.354 234.546 \
+ 173.354 233.197 173.804 232.634 173.804 232.185 \
+ 173.804 231.735 173.804 228.924 173.354 227.575 \
+ 173.804 227.575 173.804 225.664 173.804 225.214 \
+ 173.804 224.764 173.804 223.302 173.804 217.231 \
+ 174.253 216.332 174.703 215.769 178.526 214.87 \
+ 179.425 215.32 179.425 216.332 179.425 217.681 \
+ 179.425 218.58 178.975 219.142 178.526 220.492 \
+ 178.526 220.941 178.076 221.391 178.076 221.953 \
+ 178.076 225.664 177.514 226.563 177.514 228.025 \
+ 177.064 228.474 177.064 228.924 177.064 230.835 \
+ 177.514 236.457 177.064 237.806 177.514 237.806 \
+ 177.514 238.818 177.514 240.617 177.514 241.067 \
+ 178.076 241.629 178.526 241.629 179.425 241.067 \
+ 179.875 240.617 179.875 240.167 180.325 239.268 \
+ 181.337 238.256 182.236 236.457 183.698 234.546 \
+ 184.147 233.197 185.497 230.835 186.509 229.824 \
+ 187.408 227.575 187.408 227.013 187.408 226.563 \
+ 187.858 225.664 188.307 225.214 188.757 224.764 \
+ 188.757 224.202 189.319 222.403 190.219 220.941 \
+ 191.118 217.681 192.13 215.769 194.379 214.87 \
+ 194.941 214.87 196.74 214.42 196.74 215.769 196.29 \
+ 215.769 196.29 216.332 196.29 216.781 196.74 219.592 \
+ 196.74 220.492 196.29 221.391 196.74 224.764 196.29 \
+ 225.664 196.29 226.113 196.29 227.575 196.74 229.374 \
+ 197.19 235.445 198.202 239.268 198.202 239.718 \
+ 198.202 241.067 198.202 242.529 198.651 242.978 \
+ 199.101 243.878 199.101 244.44 199.551 244.89 \
+ 200.001 246.239 201.462 248.6 -fill $pengcolor -outline \
+ {} -width 1 -tags logo
+
+ $c create polygon 71.714 185.412 71.714 110.869 \
+ 81.496 110.869 82.845 110.981 83.969 111.431 85.094 \
+ 112.106 86.105 113.118 86.893 114.467 87.567 116.041 \
+ 88.017 117.39 88.242 118.065 88.467 118.852 88.579 \
+ 119.639 88.804 120.538 88.916 121.438 89.029 122.337 \
+ 89.141 123.349 89.254 124.361 89.366 125.485 89.366 \
+ 126.61 89.478 127.734 89.478 128.971 89.478 130.208 \
+ 89.478 131.444 89.478 132.456 89.478 133.468 89.478 \
+ 134.48 89.366 135.492 89.254 136.391 89.254 137.291 \
+ 89.141 138.19 89.029 139.09 88.916 139.877 88.804 \
+ 140.664 88.691 141.451 88.579 142.238 88.354 143.362 \
+ 88.129 144.374 87.904 145.386 87.567 146.398 87.342 \
+ 147.297 87.005 148.197 86.668 148.984 86.218 149.771 \
+ 87.005 151.233 87.342 152.02 87.68 152.919 87.904 \
+ 153.931 88.129 154.943 88.129 155.505 88.354 156.854 \
+ 88.354 157.641 88.354 158.428 88.467 159.328 88.467 \
+ 160.34 88.467 161.352 88.467 162.476 88.579 163.6 \
+ 88.579 164.837 88.579 166.186 88.579 166.973 88.691 \
+ 167.873 88.804 168.885 88.916 169.897 89.029 171.021 \
+ 89.029 172.258 89.029 173.719 89.029 175.068 89.029 \
+ 176.305 89.029 177.542 89.141 178.554 89.141 179.566 \
+ 89.141 180.353 89.141 181.14 89.254 181.814 89.366 \
+ 182.714 89.478 183.051 89.478 185.412 83.857 185.412 \
+ 83.857 184.738 83.744 183.951 83.744 183.276 83.744 \
+ 182.489 83.744 180.803 83.857 179.791 83.857 178.891 \
+ 83.857 177.879 83.857 176.867 83.857 175.743 83.857 \
+ 174.619 83.857 173.27 83.857 172.033 83.744 170.908 \
+ 83.744 170.009 83.632 169.109 83.632 168.322 83.52 \
+ 166.973 83.407 166.524 83.407 166.186 83.407 165.062 \
+ 83.407 164.05 83.295 163.151 83.295 162.251 83.295 \
+ 161.464 83.182 160.789 82.957 159.553 81.945 158.203 \
+ 80.596 157.754 76.886 157.754 76.886 185.412 71.714 \
+ 185.412 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 92.289 148.309 92.289 147.185 \
+ 92.289 146.061 92.289 145.049 92.402 143.924 92.402 \
+ 142.8 92.402 141.788 92.402 140.664 92.514 139.652 \
+ 92.514 138.64 92.627 137.628 92.627 136.616 92.739 \
+ 135.717 92.739 134.705 92.851 133.805 92.964 132.793 \
+ 92.964 131.894 93.076 130.995 93.301 129.196 93.414 \
+ 128.409 93.526 127.509 93.639 126.722 93.751 125.935 \
+ 93.863 125.148 93.976 124.361 94.313 122.787 94.426 \
+ 122.112 94.65 121.325 94.763 120.651 95.1 119.301 \
+ 95.55 117.615 96.112 116.041 96.674 114.692 97.236 \
+ 113.455 97.799 112.443 98.361 111.544 99.035 110.757 \
+ 99.71 110.082 100.385 109.632 101.059 109.295 \
+ 101.846 109.07 102.633 108.958 104.207 109.295 \
+ 104.882 109.632 105.556 110.082 106.231 110.757 \
+ 106.906 111.544 107.468 112.443 108.03 113.455 \
+ 108.592 114.692 109.154 116.041 109.604 117.615 \
+ 110.054 119.301 110.279 119.976 110.616 121.325 \
+ 110.841 122.112 110.953 122.787 111.178 123.574 \
+ 111.403 125.148 111.628 125.935 111.74 126.722 \
+ 111.853 127.622 111.965 128.409 112.078 129.308 \
+ 112.19 130.208 112.302 130.995 112.415 132.006 \
+ 112.64 133.805 112.752 134.817 112.865 135.717 \
+ 112.977 136.729 112.977 137.741 113.089 138.752 \
+ 113.089 139.764 113.202 140.776 113.202 141.788 \
+ 113.314 142.912 113.314 143.924 113.314 145.049 \
+ 113.427 146.061 113.427 147.185 113.427 148.309 \
+ 113.427 149.546 113.314 150.783 113.314 151.907 \
+ 113.314 153.032 113.314 154.156 113.202 155.28 \
+ 113.202 156.405 113.089 157.529 113.089 158.541 \
+ 112.977 159.553 112.865 160.565 112.752 161.576 \
+ 112.64 162.588 112.527 163.6 112.415 164.5 112.302 \
+ 165.512 112.19 166.411 112.078 167.311 111.965 \
+ 168.21 111.853 169.109 111.628 169.897 111.515 \
+ 170.796 111.403 171.583 111.178 172.37 111.066 \
+ 173.157 110.616 174.731 110.504 175.518 110.279 \
+ 176.193 110.054 176.98 109.604 178.666 109.154 \
+ 180.128 108.592 181.59 108.03 182.826 107.468 \
+ 183.951 106.906 184.963 106.231 185.75 105.556 \
+ 186.424 104.882 186.986 104.207 187.436 103.42 \
+ 187.661 102.633 187.661 101.846 187.661 101.059 \
+ 187.436 100.385 186.986 99.71 186.424 99.035 185.75 \
+ 98.361 184.963 97.799 183.951 97.236 182.826 96.674 \
+ 181.59 96.112 180.128 95.55 178.666 95.1 176.98 \
+ 94.988 176.193 94.763 175.518 94.538 174.731 94.426 \
+ 173.944 94.088 172.37 93.976 171.583 93.863 170.796 \
+ 93.639 169.897 93.526 169.109 93.414 168.21 93.301 \
+ 167.311 93.189 166.411 93.076 165.512 92.964 164.5 \
+ 92.964 163.6 92.851 162.588 92.739 161.576 92.627 \
+ 160.565 92.627 159.553 92.514 158.541 92.514 157.529 \
+ 92.514 156.405 92.402 155.28 92.402 154.156 92.402 \
+ 153.032 92.289 151.907 92.289 150.783 92.289 149.546 \
+ 92.289 148.309 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 121.859 110.869 127.481 \
+ 110.869 134.902 185.412 129.28 185.412 127.931 \
+ 171.808 120.847 171.808 119.948 185.412 114.326 \
+ 185.412 121.859 110.869 -fill #000000 -outline {} \
+ -width 1 -tags logo
+
+ $c create polygon 137.263 185.412 137.263 \
+ 110.869 147.157 110.869 148.394 110.981 149.518 \
+ 111.431 150.417 112.106 151.317 113.118 152.104 \
+ 114.467 152.778 116.041 153.228 117.39 153.341 \
+ 118.065 153.566 118.852 153.903 120.538 154.015 \
+ 121.438 154.128 122.337 154.24 123.349 154.353 \
+ 124.361 154.465 125.485 154.465 126.61 154.577 \
+ 127.734 154.577 128.971 154.577 130.208 154.577 \
+ 131.444 154.577 132.456 154.577 133.468 154.577 \
+ 134.48 154.577 135.492 154.577 136.391 154.577 \
+ 137.291 154.577 138.19 154.465 139.09 154.465 \
+ 139.877 154.353 140.664 154.24 141.451 154.128 \
+ 142.238 153.903 143.362 153.678 144.374 153.341 \
+ 145.386 153.003 146.398 152.554 147.297 152.216 \
+ 148.197 151.767 148.984 151.317 149.771 152.104 \
+ 151.233 152.441 152.02 152.778 152.919 153.003 \
+ 153.931 153.228 154.943 153.341 155.505 153.453 \
+ 156.854 153.566 157.641 153.678 158.428 153.79 \
+ 159.328 153.903 160.34 154.015 161.352 154.015 \
+ 162.476 154.128 163.6 154.128 164.837 154.128 \
+ 166.186 154.128 166.973 154.128 167.873 154.128 \
+ 168.885 154.128 169.897 154.128 171.021 154.128 \
+ 172.258 154.128 173.719 154.24 175.068 154.24 \
+ 176.305 154.353 177.542 154.353 178.554 154.465 \
+ 179.566 154.577 180.353 154.69 181.14 154.69 181.814 \
+ 154.915 182.714 155.027 183.051 155.027 185.412 \
+ 149.405 185.412 149.405 184.738 149.293 183.951 \
+ 149.293 183.276 149.181 182.489 149.181 180.803 \
+ 149.068 179.791 149.068 178.891 149.068 177.879 \
+ 149.068 176.867 148.956 175.743 148.956 174.619 \
+ 148.956 173.27 148.956 172.033 148.956 170.908 \
+ 148.956 170.009 148.956 169.109 148.956 168.322 \
+ 148.956 166.973 148.956 166.524 148.956 166.186 \
+ 148.956 165.062 148.843 164.05 148.731 163.151 \
+ 148.618 162.251 148.506 161.464 148.394 160.789 \
+ 148.056 159.553 147.269 158.203 146.145 157.754 \
+ 142.435 157.754 142.435 185.412 137.263 185.412 \
+ -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 158.4 185.412 158.4 110.869 \
+ 164.022 110.869 164.022 185.412 158.4 185.412 -fill \
+ #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 168.182 185.412 168.182 \
+ 110.869 173.804 110.869 177.514 135.267 177.739 \
+ 136.054 177.851 136.954 177.964 137.853 178.076 \
+ 138.752 178.301 139.539 178.413 140.439 178.526 \
+ 141.338 178.751 143.137 178.975 144.037 179.088 \
+ 144.824 179.2 145.723 179.313 146.623 179.425 147.41 \
+ 179.538 148.422 179.763 149.321 179.875 150.333 \
+ 180.1 151.233 180.212 152.132 180.437 153.032 180.55 \
+ 154.043 180.774 154.943 180.887 155.842 180.999 \
+ 156.742 181.224 157.754 181.337 158.653 181.337 \
+ 157.641 181.224 156.629 181.224 155.617 181.224 \
+ 154.606 181.224 153.594 181.112 152.582 181.112 \
+ 151.682 181.112 150.67 180.999 149.771 180.999 \
+ 148.759 180.999 147.86 180.887 146.96 180.887 \
+ 145.948 180.887 145.049 180.887 144.149 180.887 \
+ 143.25 180.887 142.125 180.887 141.114 180.887 \
+ 140.102 180.887 139.09 180.887 138.078 180.887 \
+ 137.178 180.887 136.166 180.887 135.267 180.887 \
+ 134.368 180.887 133.468 180.887 132.569 180.887 \
+ 131.669 180.887 130.882 180.887 130.095 180.887 \
+ 110.869 185.946 110.869 185.946 185.412 180.325 \
+ 185.412 176.165 160.565 176.052 159.778 175.94 \
+ 158.99 175.827 158.203 175.602 156.517 175.49 \
+ 155.617 175.378 154.718 175.265 153.931 175.153 \
+ 153.032 175.04 152.02 174.928 151.12 174.703 150.221 \
+ 174.591 149.321 174.478 148.422 174.366 147.41 \
+ 174.141 146.51 174.028 145.611 173.804 144.599 \
+ 173.691 143.587 173.579 142.575 173.354 141.676 \
+ 173.241 140.551 173.017 139.539 172.904 138.528 \
+ 172.904 139.539 172.904 140.551 173.017 141.563 \
+ 173.017 142.575 173.017 143.587 173.129 144.599 \
+ 173.129 145.498 173.129 146.51 173.241 147.41 \
+ 173.241 148.422 173.241 149.321 173.354 150.221 \
+ 173.354 151.233 173.354 152.132 173.354 153.144 \
+ 173.354 154.156 173.354 155.055 173.354 156.067 \
+ 173.354 156.967 173.354 157.866 173.354 158.766 \
+ 173.354 159.553 173.354 160.452 173.354 161.239 \
+ 173.354 162.026 173.354 162.926 173.354 185.412 \
+ 168.182 185.412 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 206.184 185.412 205.622 \
+ 175.968 205.397 177.092 205.172 178.217 204.948 \
+ 179.228 204.61 180.128 204.385 181.027 204.048 \
+ 181.814 203.823 182.489 203.486 183.164 203.149 \
+ 183.838 202.811 184.4 202.024 185.75 201.125 186.762 \
+ 200.113 187.436 199.101 187.661 198.089 187.549 \
+ 197.19 186.986 196.29 186.087 195.391 184.85 194.941 \
+ 184.176 194.491 183.389 194.042 182.489 193.592 \
+ 181.477 193.255 180.465 192.805 179.341 192.467 \
+ 178.217 192.13 176.98 191.905 176.193 191.68 175.406 \
+ 191.568 174.619 191.456 173.832 191.231 172.932 \
+ 191.118 172.145 191.006 171.246 190.781 169.559 \
+ 190.669 168.66 190.556 167.648 190.444 166.748 \
+ 190.331 165.736 190.219 164.725 190.106 163.825 \
+ 189.994 162.926 189.994 162.026 189.882 161.127 \
+ 189.769 160.227 189.769 159.215 189.657 158.316 \
+ 189.544 157.304 189.544 156.405 189.432 155.393 \
+ 189.432 154.381 189.319 153.369 189.319 152.357 \
+ 189.319 151.345 189.319 150.333 189.319 149.321 \
+ 189.319 148.197 189.319 146.96 189.319 145.948 \
+ 189.319 144.824 189.319 143.7 189.319 142.688 \
+ 189.432 141.563 189.432 140.551 189.544 139.539 \
+ 189.544 138.528 189.544 137.516 189.657 136.504 \
+ 189.769 135.492 189.769 134.592 189.882 133.581 \
+ 189.994 132.681 189.994 131.782 190.106 130.882 \
+ 190.219 129.983 190.331 129.083 190.556 127.397 \
+ 190.669 126.61 190.781 125.823 191.006 124.923 \
+ 191.118 124.136 191.231 123.462 191.568 121.887 \
+ 191.793 121.213 191.905 120.426 192.13 119.751 \
+ 192.58 117.952 193.142 116.378 193.704 114.917 \
+ 194.266 113.567 194.941 112.443 195.616 111.431 \
+ 196.29 110.532 196.965 109.857 197.752 109.295 \
+ 198.426 108.845 199.214 108.62 200.001 108.508 \
+ 201.799 108.958 202.699 109.407 203.374 110.194 \
+ 204.161 111.094 204.835 112.218 205.51 113.567 \
+ 206.184 115.141 206.634 116.491 206.859 117.165 \
+ 206.971 117.952 207.421 119.526 207.534 120.426 \
+ 207.758 121.325 207.871 122.225 207.983 123.124 \
+ 208.096 124.136 208.208 125.036 208.321 126.047 \
+ 208.433 127.172 208.545 128.184 208.658 129.308 \
+ 208.77 130.32 208.77 131.557 208.883 132.681 208.995 \
+ 133.805 204.273 133.805 204.161 132.681 203.936 \
+ 131.557 203.711 130.432 203.486 129.533 203.261 \
+ 128.633 202.924 127.734 202.699 126.947 202.362 \
+ 126.385 201.35 124.586 200.001 124.024 199.438 \
+ 124.136 198.989 124.361 198.426 124.923 197.977 \
+ 125.598 197.527 126.497 197.077 127.622 196.628 \
+ 128.971 196.29 130.545 196.178 131.219 195.953 \
+ 132.681 195.84 133.356 195.728 134.143 195.616 \
+ 134.93 195.503 135.829 195.278 137.516 195.278 \
+ 138.303 195.166 139.315 195.166 140.214 195.053 \
+ 141.114 195.053 142.125 194.941 143.137 194.941 \
+ 144.149 194.941 145.161 194.941 146.173 194.941 \
+ 147.297 194.941 148.309 194.941 149.546 194.941 \
+ 150.67 194.941 151.907 194.941 152.919 195.053 \
+ 154.043 195.053 155.168 195.166 156.18 195.166 \
+ 157.192 195.278 158.091 195.391 159.103 195.391 \
+ 160.002 195.503 160.902 195.616 161.801 195.728 \
+ 162.588 195.84 163.375 196.065 164.162 196.178 \
+ 164.949 196.29 165.736 196.628 167.198 197.077 \
+ 168.547 197.527 169.672 197.977 170.571 198.426 \
+ 171.246 198.989 171.808 199.438 172.145 200.001 \
+ 172.258 200.9 171.92 201.575 171.246 202.249 170.009 \
+ 202.811 168.547 203.149 167.76 203.374 166.973 \
+ 203.598 166.186 203.823 165.399 204.048 164.5 \
+ 204.273 163.488 204.385 162.476 204.498 161.464 \
+ 204.61 160.34 204.723 159.103 200.001 159.103 \
+ 200.001 145.049 209.445 145.049 209.445 185.412 \
+ 206.184 185.412 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 148.506 261.305 148.506 \
+ 263.554 143.784 263.554 143.784 261.305 143.671 \
+ 260.068 143.334 259.394 142.772 259.056 141.985 \
+ 258.944 141.085 259.056 140.523 259.394 140.074 \
+ 261.755 140.074 263.104 140.523 264.678 141.085 \
+ 265.465 141.985 266.364 146.145 270.637 147.607 \
+ 271.874 148.506 272.998 148.843 274.01 148.956 \
+ 275.359 148.956 277.158 148.843 278.507 148.506 \
+ 279.632 147.944 280.643 147.157 281.43 146.482 \
+ 281.88 145.695 282.218 144.796 282.442 143.784 \
+ 282.667 142.659 282.78 141.535 282.78 140.298 282.78 \
+ 139.286 282.78 138.387 282.667 137.6 282.442 136.925 \
+ 282.218 136.363 281.88 135.576 281.093 135.014 \
+ 280.194 134.564 278.957 134.452 277.608 134.452 \
+ 275.359 139.624 275.359 139.624 277.608 139.736 \
+ 279.069 140.074 279.969 141.535 280.419 142.659 \
+ 280.081 143.334 279.519 143.671 278.62 143.784 \
+ 277.158 143.784 275.809 143.671 275.022 143.334 \
+ 274.235 142.772 273.448 141.985 272.548 137.263 \
+ 267.376 136.251 266.364 135.351 265.465 135.014 \
+ 264.565 134.902 263.554 134.902 261.755 135.014 \
+ 260.518 135.464 259.506 136.026 258.719 136.813 \
+ 257.932 137.488 257.595 138.275 257.145 139.174 \
+ 256.92 140.186 256.695 141.31 256.583 142.435 \
+ 256.583 143.447 256.583 144.458 256.583 145.245 \
+ 256.695 145.92 256.92 147.157 257.482 147.719 \
+ 258.157 148.169 258.944 148.394 260.068 148.506 \
+ 261.305 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 165.821 270.187 165.821 \
+ 276.708 165.821 277.833 165.708 278.957 165.483 \
+ 279.856 165.259 280.643 164.921 281.318 164.472 \
+ 281.88 163.909 282.218 163.235 282.555 162.448 \
+ 282.667 161.548 282.78 160.536 282.78 159.3 282.78 \
+ 158.175 282.78 157.051 282.78 156.151 282.667 \
+ 155.364 282.555 154.69 282.218 154.128 281.88 \
+ 153.678 281.318 153.341 280.643 153.116 279.856 \
+ 152.891 278.845 152.778 277.833 152.778 276.708 \
+ 152.778 270.187 152.778 269.063 152.891 268.051 \
+ 153.116 267.264 153.341 266.589 154.128 265.465 \
+ 155.364 264.678 156.151 264.453 157.051 264.228 \
+ 158.063 264.116 159.3 264.116 160.424 264.116 \
+ 161.548 264.228 162.448 264.453 163.235 264.678 \
+ 163.909 265.015 164.472 265.465 164.921 265.915 \
+ 165.483 267.264 165.708 268.051 165.821 269.063 \
+ 165.821 270.187 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 177.514 256.583 177.514 \
+ 258.494 177.064 258.494 176.165 258.606 175.715 \
+ 258.944 175.378 259.281 175.265 259.843 175.265 \
+ 264.565 177.514 264.565 177.514 266.927 175.265 \
+ 266.927 175.265 282.78 170.543 282.78 170.543 \
+ 266.927 168.632 266.927 168.632 264.565 170.543 \
+ 264.565 170.543 261.305 170.655 259.843 170.993 \
+ 258.606 171.442 257.707 171.892 257.032 173.579 \
+ 256.358 174.703 256.133 176.165 256.133 176.727 \
+ 256.133 177.064 256.133 177.514 256.583 -fill \
+ #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 185.946 259.843 185.946 \
+ 264.565 188.757 264.565 188.757 266.927 185.946 \
+ 266.927 185.946 278.62 186.171 279.407 186.509 \
+ 279.969 187.071 280.306 187.858 280.419 188.307 \
+ 280.419 188.757 280.419 188.757 282.78 188.645 \
+ 282.78 188.307 282.78 187.183 282.78 186.509 282.78 \
+ 185.159 282.78 183.923 282.555 182.911 282.33 \
+ 182.236 281.88 181.786 281.206 181.561 280.419 \
+ 181.337 279.407 181.337 278.17 181.337 266.927 \
+ 179.425 266.927 179.425 264.565 181.337 264.565 \
+ 181.337 261.305 185.946 259.843 -fill #000000 \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 190.219 264.565 194.379 \
+ 264.565 196.29 279.519 196.74 279.519 199.101 \
+ 264.565 204.723 264.565 207.084 279.519 207.534 \
+ 279.519 209.895 264.565 213.605 264.565 209.895 \
+ 282.78 204.723 282.78 201.912 267.376 201.462 \
+ 267.376 199.101 282.78 193.479 282.78 190.219 \
+ 264.565 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 229.121 269.175 229.121 282.78 \
+ 224.848 282.78 224.848 280.981 224.061 281.768 \
+ 223.049 282.33 221.925 282.667 220.688 282.78 \
+ 219.564 282.78 218.44 282.555 217.54 282.33 216.866 \
+ 281.88 216.528 281.318 216.191 280.531 216.079 \
+ 279.632 215.966 278.62 215.966 275.359 216.079 \
+ 274.347 216.978 272.998 217.877 272.548 218.44 \
+ 272.211 219.114 271.986 219.789 271.761 220.688 \
+ 271.536 221.588 271.424 222.6 271.311 223.724 \
+ 271.199 224.848 271.087 224.848 269.175 224.736 \
+ 267.826 224.399 266.927 223.612 266.477 222.487 \
+ 266.364 221.7 266.477 221.138 266.927 220.688 \
+ 268.726 220.688 269.175 216.416 269.175 216.528 \
+ 267.938 216.753 266.702 217.203 265.69 217.877 \
+ 265.015 218.44 264.678 219.114 264.453 219.901 \
+ 264.228 220.801 264.116 221.925 264.116 223.049 \
+ 264.116 224.061 264.116 225.073 264.116 225.86 \
+ 264.228 226.535 264.453 227.659 265.015 228.334 \
+ 265.69 228.783 266.702 229.008 267.938 229.121 \
+ 269.175 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 243.175 264.565 243.175 \
+ 266.927 242.725 266.927 241.601 266.927 240.701 \
+ 267.151 239.914 267.489 239.352 267.826 239.015 \
+ 268.276 238.678 268.95 238.565 269.737 238.453 \
+ 270.637 238.453 282.78 233.731 282.78 233.731 \
+ 264.565 238.453 264.565 238.453 265.915 239.352 \
+ 265.128 240.364 264.565 242.163 264.116 242.725 \
+ 264.565 243.175 264.565 -fill #000000 -outline {} \
+ -width 1 -tags logo
+
+ $c create polygon 258.129 270.187 258.129 \
+ 274.347 249.696 274.347 249.696 278.17 249.809 \
+ 279.294 250.146 279.969 250.708 280.643 251.607 \
+ 280.981 252.732 280.643 253.406 279.969 253.744 \
+ 279.294 253.969 278.17 253.969 276.708 258.129 \
+ 276.708 258.129 277.608 258.129 278.957 257.904 \
+ 280.081 257.454 281.093 256.779 281.88 256.217 \
+ 282.218 254.643 282.667 253.744 282.78 252.732 \
+ 282.78 251.607 282.78 250.371 282.78 249.359 282.78 \
+ 248.459 282.667 247.672 282.442 246.436 281.88 \
+ 245.986 281.318 245.649 280.643 245.424 279.856 \
+ 245.199 278.957 245.086 277.833 244.974 276.708 \
+ 244.974 270.187 245.086 269.063 245.199 268.051 \
+ 245.311 267.264 245.649 266.589 245.986 265.915 \
+ 246.436 265.465 246.998 265.015 247.672 264.678 \
+ 248.459 264.453 249.359 264.228 250.371 264.116 \
+ 251.607 264.116 252.732 264.116 253.744 264.228 \
+ 254.756 264.453 255.543 264.678 256.217 265.015 \
+ 256.779 265.465 257.229 265.915 257.566 266.589 \
+ 257.791 267.264 258.016 268.051 258.129 269.063 \
+ 258.129 270.187 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 272.183 256.583 277.355 \
+ 256.583 277.355 282.78 272.183 282.78 272.183 \
+ 256.583 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 295.569 268.726 295.569 282.78 \
+ 290.959 282.78 290.959 269.175 290.847 268.051 \
+ 290.509 267.376 289.947 266.702 289.048 266.364 \
+ 287.923 266.702 287.136 267.376 287.024 268.051 \
+ 287.136 269.175 287.136 282.78 282.527 282.78 \
+ 282.527 264.565 286.687 264.565 287.136 265.915 \
+ 288.036 265.128 289.048 264.565 290.172 264.228 \
+ 291.409 264.116 292.533 264.116 293.433 264.341 \
+ 294.107 264.565 294.669 265.015 295.344 266.477 \
+ 295.569 267.489 295.569 268.726 -fill #000000 \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 312.434 269.737 312.434 \
+ 270.637 308.274 270.637 308.274 269.175 308.161 \
+ 267.826 307.824 266.927 307.262 266.477 306.363 \
+ 266.364 305.576 266.477 305.013 266.927 304.676 \
+ 267.826 304.564 269.175 304.564 278.17 304.676 \
+ 279.294 305.013 279.969 306.363 280.981 307.262 \
+ 280.643 307.824 279.969 307.937 279.294 307.824 \
+ 278.17 307.824 276.259 312.434 276.259 312.434 \
+ 277.608 312.434 278.957 312.209 280.081 311.759 \
+ 281.093 311.085 281.88 310.523 282.218 309.173 \
+ 282.667 308.386 282.78 307.374 282.78 306.363 282.78 \
+ 305.238 282.78 304.226 282.78 303.327 282.667 \
+ 302.427 282.442 301.753 282.218 301.191 281.88 \
+ 300.853 281.318 300.516 280.643 300.179 279.856 \
+ 299.954 278.957 299.841 277.833 299.841 276.708 \
+ 299.841 270.187 299.841 269.063 299.954 268.051 \
+ 300.179 267.264 300.404 266.589 301.191 265.465 \
+ 302.427 264.678 303.327 264.453 304.226 264.228 \
+ 305.238 264.116 306.363 264.116 307.374 264.116 \
+ 308.386 264.228 309.173 264.453 309.96 264.678 \
+ 310.523 265.015 311.085 265.465 311.759 266.252 \
+ 312.209 267.264 312.434 268.388 312.434 269.737 \
+ -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 316.706 279.069 320.866 \
+ 279.069 320.866 282.78 316.706 282.78 316.706 \
+ 279.069 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 48.215 186.312 48.215 185.412 \
+ 47.766 184.4 47.766 183.501 47.316 183.501 47.316 \
+ 182.601 46.416 181.59 46.416 181.14 45.967 180.24 \
+ 45.405 179.791 44.955 179.228 44.055 178.329 43.606 \
+ 177.879 43.156 177.43 42.144 176.98 41.694 176.418 \
+ 41.245 175.968 38.883 175.068 36.972 174.169 36.522 \
+ 174.169 35.173 173.607 34.723 174.169 31.913 173.607 \
+ 31.913 174.169 29.551 173.607 29.551 174.169 28.54 \
+ 174.169 28.09 174.619 27.19 174.169 27.19 174.619 \
+ 26.741 174.619 25.729 175.068 23.93 175.518 22.918 \
+ 175.068 22.468 175.518 20.669 176.418 19.657 176.418 \
+ 15.048 178.779 14.036 179.228 12.686 180.24 12.237 \
+ 180.69 11.225 181.59 10.775 182.039 10.325 182.601 \
+ 10.775 182.601 10.325 184.4 10.775 184.85 11.225 \
+ 186.312 14.036 188.223 14.485 188.673 16.846 190.022 \
+ 17.296 190.472 17.296 191.034 15.947 191.933 15.048 \
+ 192.383 14.485 192.833 14.036 193.283 13.136 193.845 \
+ 12.237 194.295 12.686 195.644 12.686 196.094 12.237 \
+ 197.555 12.237 198.005 11.675 198.904 12.237 200.816 \
+ 12.237 202.277 12.237 204.526 11.675 205.988 12.237 \
+ 205.988 12.237 206.437 12.237 207.337 12.686 208.349 \
+ 12.686 209.248 13.136 209.698 12.686 211.16 13.136 \
+ 212.509 13.136 213.521 13.586 215.32 13.586 216.781 \
+ 13.586 217.681 14.036 220.492 14.485 222.403 15.048 \
+ 222.853 15.947 222.853 15.947 222.403 16.397 221.953 \
+ 16.846 216.781 17.296 215.32 17.858 211.609 18.308 \
+ 210.71 18.308 210.148 18.308 209.248 17.858 208.798 \
+ 17.858 207.899 18.308 206.437 18.308 205.538 18.308 \
+ 205.088 18.308 203.627 16.846 203.627 15.947 203.177 \
+ 15.947 202.727 15.947 202.277 16.397 201.715 16.846 \
+ 201.715 17.858 201.715 18.308 201.715 18.758 201.265 \
+ 18.308 200.816 17.858 199.916 18.308 198.455 17.858 \
+ 198.455 17.858 193.283 19.208 192.383 20.107 191.933 \
+ 21.569 191.484 22.018 191.484 22.918 192.383 22.918 \
+ 192.833 23.48 192.833 23.93 198.005 23.48 199.467 \
+ 23.93 202.277 25.279 202.277 29.551 202.727 30.001 \
+ 202.277 30.901 202.277 31.913 202.277 35.623 201.265 \
+ 36.522 201.265 36.972 200.816 37.984 200.816 38.883 \
+ 200.816 39.333 200.366 40.345 199.916 40.795 199.916 \
+ 42.594 198.455 44.055 198.005 44.055 197.555 44.505 \
+ 197.105 46.416 195.644 46.416 194.744 46.866 194.295 \
+ 47.316 193.845 47.766 193.283 47.316 192.833 48.215 \
+ 190.472 48.215 190.022 48.215 189.572 48.215 188.673 \
+ 48.215 187.211 48.215 186.762 48.215 186.312 -fill \
+ $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 76.886 142.688 81.046 142.688 \
+ 82.508 142.35 83.407 140.889 83.632 140.327 83.969 \
+ 138.865 84.082 137.965 84.194 137.066 84.307 136.054 \
+ 84.307 134.93 84.307 133.805 84.307 132.456 84.194 \
+ 131.332 84.082 130.208 83.857 129.308 83.632 128.409 \
+ 83.407 127.734 82.395 126.272 81.046 125.823 76.886 \
+ 125.823 76.886 142.688 -fill $bg -outline {} -width \
+ 1 -tags logo
+
+ $c create polygon 97.461 148.309 97.461 149.546 \
+ 97.461 150.783 97.461 152.02 97.574 153.144 97.574 \
+ 154.268 97.686 155.28 97.686 156.405 97.799 157.416 \
+ 97.799 158.316 97.911 159.328 98.023 160.227 98.136 \
+ 161.127 98.361 162.701 98.473 163.488 98.586 164.275 \
+ 98.698 164.949 98.81 165.736 99.373 167.535 99.822 \
+ 169.109 100.497 170.234 101.059 171.133 101.846 \
+ 171.583 102.633 171.808 104.095 171.133 104.769 \
+ 170.234 105.332 169.109 105.894 167.535 106.343 \
+ 165.736 106.456 164.949 106.681 164.275 106.793 \
+ 163.488 106.906 162.701 107.018 161.914 107.243 \
+ 160.227 107.355 159.328 107.355 158.316 107.468 \
+ 157.416 107.58 156.405 107.58 155.28 107.693 154.268 \
+ 107.693 153.144 107.693 152.02 107.693 150.783 \
+ 107.805 149.546 107.805 148.309 107.805 147.073 \
+ 107.693 145.836 107.693 144.711 107.693 143.587 \
+ 107.693 142.463 107.58 141.338 107.58 140.327 \
+ 107.468 139.315 107.355 138.303 107.355 137.403 \
+ 107.243 136.504 107.131 135.604 106.906 133.918 \
+ 106.793 133.131 106.681 132.456 106.456 131.669 \
+ 106.343 130.995 105.894 129.196 105.332 127.622 \
+ 104.769 126.497 104.095 125.598 103.42 125.148 \
+ 102.633 124.923 101.846 125.148 101.059 125.598 \
+ 100.497 126.497 99.822 127.622 99.373 129.196 98.81 \
+ 130.995 98.698 131.669 98.586 132.456 98.473 133.131 \
+ 98.361 133.918 98.248 134.817 98.023 136.504 97.911 \
+ 137.403 97.799 138.303 97.799 139.315 97.686 140.327 \
+ 97.686 141.338 97.574 142.463 97.574 143.587 97.461 \
+ 144.711 97.461 145.836 97.461 147.073 97.461 148.309 \
+ -fill $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 122.309 156.292 126.919 \
+ 156.292 124.67 130.545 122.309 156.292 -fill $bg \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 142.435 142.688 146.145 \
+ 142.688 147.607 142.35 148.506 140.889 148.731 \
+ 140.327 149.068 138.865 149.181 137.965 149.293 \
+ 137.066 149.405 136.054 149.405 134.93 149.405 \
+ 133.805 149.405 132.456 149.405 131.332 149.405 \
+ 130.208 149.293 129.308 149.181 128.409 148.956 \
+ 127.734 148.056 126.272 146.595 125.823 142.435 \
+ 125.823 142.435 142.688 -fill $bg -outline {} -width \
+ 1 -tags logo
+
+ $c create polygon 111.515 228.924 111.515 \
+ 227.575 111.066 225.664 108.705 221.391 108.255 \
+ 220.042 108.255 219.142 108.255 218.58 108.255 \
+ 218.13 107.805 217.681 106.793 218.58 104.994 \
+ 220.941 104.432 221.953 102.633 224.202 102.183 \
+ 224.764 101.621 225.214 99.822 228.474 97.461 \
+ 233.197 97.461 234.096 97.461 234.995 97.911 235.445 \
+ 98.361 236.007 99.822 236.457 102.633 236.457 \
+ 104.432 235.445 105.894 234.995 106.343 234.546 \
+ 106.793 234.546 107.805 233.646 110.616 230.835 \
+ 111.515 229.824 111.515 229.374 111.515 228.924 \
+ -fill $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 161.211 269.175 160.986 \
+ 267.826 160.649 266.927 160.199 266.477 159.3 \
+ 266.364 158.4 266.477 157.838 266.927 157.613 \
+ 267.826 157.388 269.175 157.388 278.17 157.613 \
+ 279.294 157.838 279.969 159.3 280.981 160.199 \
+ 280.643 160.649 279.969 160.986 279.294 161.211 \
+ 278.17 161.211 269.175 -fill $bg -outline {} -width \
+ 1 -tags logo
+
+ $c create polygon 224.848 273.448 223.836 \
+ 273.448 222.825 273.56 222.15 273.673 221.588 \
+ 273.897 220.913 274.684 220.688 275.809 220.688 \
+ 278.17 220.801 279.294 221.138 279.969 221.7 280.643 \
+ 222.487 280.981 223.612 280.643 224.399 279.969 \
+ 224.736 279.294 224.848 278.17 224.848 273.448 -fill \
+ $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 253.969 269.175 253.744 \
+ 267.826 253.406 266.927 252.732 266.477 251.607 \
+ 266.364 250.708 266.477 250.146 266.927 249.696 \
+ 269.175 249.696 272.548 253.969 272.548 253.969 \
+ 269.175 -fill $bg -outline {} -width 1 -tags logo
+
+}
+
+#***********************************************************************
+# %PROCEDURE: LoadConnectionInfo
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Loads the connection information into the global ConnectionInfo variable
+#***********************************************************************
+proc LoadConnectionInfo {} {
+ global ConnectionInfoFile ConnectionInfo PasswordFile
+ set ConnectionInfo {}
+ if {![file exists $ConnectionInfoFile]} {
+ return
+ }
+ set problem [catch {
+ set fp [open $ConnectionInfoFile "r"]
+ while {1} {
+ if {[gets $fp line] < 0} {
+ break
+ }
+ set line [string trim $line]
+ if {[string match "#*" $line]} {
+ continue
+ }
+ if {"$line" == ""} {
+ continue
+ }
+ set ConnectionInfo $line
+ break
+ }
+ close $fp
+ } err]
+ if {$problem} {
+ tk_dialog .err Error "Error loading configuration file: $err" error 0 OK
+ }
+ # Try loading and merging passwords if the password file is readable
+ if {![file readable $PasswordFile]} {
+ return
+ }
+
+ set fp [open $PasswordFile "r"]
+ while {1} {
+ if {[gets $fp line] < 0} {
+ break
+ }
+ set line [string trim $line]
+ if {[string match "#*" $line]} {
+ continue
+ }
+ if {"$line" == ""} {
+ continue
+ }
+ set passwords $line
+ break
+ }
+ close $fp
+
+ # Merge passwords
+ foreach thing $passwords {
+ set name [value $thing ConnectionName]
+ set password [value $thing Password]
+ set conn [GetConnection $name]
+ if {"$conn" != ""} {
+ lappend conn Password $password
+ ReplaceConnection $conn
+ }
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetConnection
+# %ARGUMENTS:
+# name -- name of connection
+# %RETURNS:
+# key/value pair listing connection configuration, or "" if not found.
+#***********************************************************************
+proc GetConnection { name } {
+ global ConnectionInfo
+ foreach thing $ConnectionInfo {
+ if {[value $thing ConnectionName] == "$name"} {
+ return $thing
+ }
+ }
+ return ""
+}
+
+
+#***********************************************************************
+# %PROCEDURE: DeleteConnection
+# %ARGUMENTS:
+# name -- name of connection
+# %RETURNS:
+# Nothing, but deletes connection named "$name"
+#***********************************************************************
+proc DeleteConnection { name } {
+ global ConnectionInfo ConfigDir
+ set newInfo {}
+ set found 0
+ foreach thing $ConnectionInfo {
+ if {[value $thing ConnectionName] == "$name"} {
+ set found 1
+ } else {
+ lappend newInfo $thing
+ }
+ }
+ if {!$found} {
+ return
+ }
+ set ConnectionInfo $newInfo
+ SaveConnectionInfo
+
+ # Delete the config file
+ set fname [file join $ConfigDir conf.$name]
+ catch { file delete $fname }
+
+ BuildConnectionMenu
+ if {[GetCurrentConnection] == $name} {
+ if {[llength $ConnectionInfo] == 0} {
+ SwitchConnection ""
+ } else {
+ set name [value [lindex $ConnectionInfo 0] ConnectionName]
+ SwitchConnection $name
+ }
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: ReplaceConnection
+# %ARGUMENTS:
+# conn -- new name/value pairs
+# %RETURNS:
+# Nothing, but replaces connection in ConnectionInfo. If no such
+# connection exists, appends new connection.
+#***********************************************************************
+proc ReplaceConnection { conn } {
+ global ConnectionInfo
+ set name [value $conn ConnectionName]
+ set newInfo {}
+ set found 0
+ foreach thing $ConnectionInfo {
+ if {[value $thing ConnectionName] == "$name"} {
+ lappend newInfo $conn
+ set found 1
+ } else {
+ lappend newInfo $thing
+ }
+ }
+ if {!$found} {
+ lappend newInfo $conn
+ }
+ set ConnectionInfo $newInfo
+}
+
+proc DeletePPPoEConnection {} {
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ return
+ }
+ set ans [tk_dialog .confirm "Confirm Deletion - RP-PPPoE" "Are you sure you wish to delete the connection `$conn'?" warning 0 No Yes]
+ if {$ans} {
+ DeleteConnection $conn
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: CreateMainDialog
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Creates the main window
+#***********************************************************************
+proc CreateMainDialog {} {
+ global ConnectionInfoFile
+ global ConnectionInfo
+ global Admin
+ wm title . "RP-PPPoE"
+ wm iconname . "PPPoE"
+ frame .f1
+ label .l1 -text "Connection: "
+ menubutton .m1 -text "" -indicatoron 1 -menu .m1.menu -relief raised
+ menu .m1.menu -tearoff 0
+ pack .l1 .m1 -in .f1 -side left -expand 0 -fill x
+ canvas .c -width 40 -height 20
+ pack .c -in .f1 -side left -expand 0 -fill none
+
+ # Draw the LED's
+ .c create rectangle 10 1 30 8 -outline "#808080" -fill "#A0A0A0" -tags xmitrect
+ .c create rectangle 10 10 30 18 -outline "#808080" -fill "#A0A0A0" -tags recvrect
+
+ frame .buttons
+ button .start -text "Start" -command "StartPPPoEConnection"
+ button .stop -text "Stop" -command "StopPPPoEConnection"
+ button .exit -text "Exit" -command "exit"
+ canvas .graph -width 1 -height 1
+ if {[file writable $ConnectionInfoFile]} {
+ set Admin 1
+ pack .f1 -side top -expand 1 -fill both
+ pack .buttons -side top -expand 0 -fill x
+ button .delete -text "Delete" -command "DeletePPPoEConnection"
+ button .new -text "New Connection..." -command "NewPPPoEConnection"
+ button .props -text "Properties..." -command "EditConnectionProps"
+ pack .graph -in .f1 -side left -expand 1 -fill both
+ pack .start .stop .delete .props .new .exit -in .buttons -side left -expand 0 -fill none
+ } else {
+ set Admin 0
+ pack .f1 -side top -expand 0 -fill x
+ pack .buttons -side top -expand 1 -fill both
+ pack .start .stop .exit -in .buttons -side left -expand 0 -fill none
+ pack .graph -in .buttons -side left -expand 1 -fill both
+ }
+
+ LoadConnectionInfo
+ BuildConnectionMenu
+ # If no connections exist, pop up new connection dialog
+ if {[llength $ConnectionInfo] == 0} {
+ SwitchConnection ""
+ if {$Admin} {
+ update idletasks
+ NewPPPoEConnection
+ } else {
+ tk_dialog .note Note "Note: There are no connections defined. You must run this program as root to define connections" warning 0 OK
+ }
+ } else {
+ set con [lindex $ConnectionInfo 0]
+ set name [value $con ConnectionName]
+ SwitchConnection $name
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetCurrentConnection
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# The name of the current connection in the GUI.
+#***********************************************************************
+proc GetCurrentConnection {} {
+ .m1 cget -text
+}
+
+#***********************************************************************
+# %PROCEDURE: value
+# %ARGUMENTS:
+# lst -- a list of key/value pairs
+# key -- key we're looking for
+# %RETURNS:
+# value corresponding to $key, or "" if not found.
+#***********************************************************************
+proc value { lst key } {
+ set idx [lsearch -exact $lst $key]
+ if {$idx >= 0} {
+ return [lindex $lst [expr $idx+1]]
+ }
+ return ""
+}
+
+#***********************************************************************
+# %PROCEDURE: SwitchConnection
+# %ARGUMENTS:
+# name -- new connection name
+# %DESCRIPTION:
+# Makes $name the active connection
+#***********************************************************************
+proc SwitchConnection { name } {
+ .m1 configure -text $name
+ SetButtonStates
+ UpdateConnectionState 0
+}
+
+#***********************************************************************
+# %PROCEDURE: EditConnectionProps
+# %ARGUMENTS:
+# None
+# %DESCRIPTION:
+# Pops up edit window for current connection
+#***********************************************************************
+proc EditConnectionProps {} {
+ global ConnectionInfo
+ set conn [GetCurrentConnection]
+ NewPPPoEConnection $conn
+}
+
+#***********************************************************************
+# %PROCEDURE: FillConnectionGui
+# %ARGUMENTS:
+# w -- connection property GUI
+# name -- name of connection
+# %DESCRIPTION:
+# Fills GUI with values corresponding to $name.
+#***********************************************************************
+proc FillConnectionGui { w name } {
+ global ConnectionInfo
+ set found [GetConnection $name]
+ if {"$found" != ""} {
+ ListToSetupGui $w $found
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: BuildConnectionMenu
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Builds the connection menu
+#***********************************************************************
+proc BuildConnectionMenu {} {
+ global ConnectionInfo
+ .m1.menu delete 0 end
+ foreach connection $ConnectionInfo {
+ set name [value $connection ConnectionName]
+ .m1.menu add command -label $name -command [list SwitchConnection $name]
+ }
+ .m1.menu add separator
+ .m1.menu add command -label "User's Manual" -command Help
+}
+
+#***********************************************************************
+# %PROCEDURE: SetButtonStates
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Enables or disables buttons, as appropriate
+#***********************************************************************
+proc SetButtonStates {} {
+ global Admin
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ .start configure -state disabled
+ .stop configure -state disabled
+ catch {
+ .delete configure -state disabled
+ .props configure -state disabled
+ .new configure -state normal
+ }
+ } else {
+ foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
+ if {"$startstop" == "started"} {
+ .start configure -state disabled
+ .stop configure -state normal
+ } else {
+ .start configure -state normal
+ .stop configure -state disabled
+ }
+ catch {
+ .delete configure -state normal
+ .props configure -state normal
+ .new configure -state normal
+ }
+ if {!$Admin} {
+ set ok [value [GetConnection $conn] NonrootOK]
+ if {!$ok} {
+ .start configure -state disabled
+ .stop configure -state disabled
+ }
+ }
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetEthernetInterfaces
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# A list of Ethernet interfaces
+#***********************************************************************
+proc GetEthernetInterfaces {} {
+ set ifs {}
+ set fp [open "|/sbin/ifconfig" "r"]
+ while {[gets $fp line] >= 0} {
+ if {[regexp {^eth[0-9]+} $line eth]} {
+ lappend ifs $eth
+ }
+ }
+ return $ifs
+}
+
+#***********************************************************************
+# %PROCEDURE: StartPPPoEConnection
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Starts currently-selected PPPoE connection.
+#***********************************************************************
+proc StartPPPoEConnection {} {
+ global Wrapper
+ global StartState
+ global UpdateToken
+
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ return
+ }
+
+ if {"$UpdateToken" != ""} {
+ after cancel $UpdateToken
+ set UpdateToken ""
+ }
+
+ catch { unset StartState }
+ set StartState(chars) ""
+ set StartState(status) ""
+ set StartState(msg) ""
+ set StartState(flip) 0
+
+ set fp [open "|$Wrapper start $conn" "r"]
+
+ # Set fileevent
+ fileevent $fp readable [list StartFPReadable $fp]
+
+ LockGui $fp
+ vwait StartState(status)
+ UnlockGui
+
+ if {$StartState(status) == "failed"} {
+ tk_dialog .err Error "Error starting connection: $StartState(msg)" error 0 OK
+ }
+ SetButtonStates
+ UpdateConnectionState 0
+}
+
+proc LockGui { fp } {
+ .start configure -state disabled
+ .stop configure -state normal -command [list AbortConnection $fp]
+ .exit configure -state disabled
+ .m1 configure -state disabled
+ grab set .stop
+}
+
+proc UnlockGui {} {
+ .start configure -state normal
+ .stop configure -state disabled -command StopPPPoEConnection
+ .exit configure -state normal
+ .m1 configure -state normal
+ grab release .stop
+}
+
+proc AbortConnection { fp } {
+ global StartState
+ catch { StopPPPoEConnection }
+ catch { close $fp }
+ set StartState(msg) "Connection aborted by user"
+ set StartState(status) "failed"
+}
+
+#***********************************************************************
+# %PROCEDURE: StartFPReadable
+# %ARGUMENTS:
+# fp -- file handle
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Called when the "adsl-start" file handle is readable.
+#***********************************************************************
+proc StartFPReadable { fp } {
+ global StartState
+ set char [read $fp 1]
+ if {$char == ""} {
+ set uhoh [catch {close $fp} err]
+ if {$uhoh} {
+ set StartState(status) "failed"
+ set StartState(msg) $err
+ } else {
+ set StartState(status) "succeeded"
+ }
+ return
+ }
+ append StartState(chars) $char
+ if {$StartState(flip)} {
+ ConnectionStateDown
+ } else {
+ ConnectionStateOff
+ }
+ set StartState(flip) [expr 1 - $StartState(flip)]
+}
+
+#***********************************************************************
+# %PROCEDURE: StopPPPoEConnection
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Stops currently-selected PPPoE connection.
+#***********************************************************************
+proc StopPPPoEConnection {} {
+ global Wrapper
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ return
+ }
+ set fp [open "|$Wrapper stop $conn" "r"]
+ while {1} {
+ set char [read $fp 1]
+ if {"$char" == ""} {
+ break;
+ }
+ }
+ set uhoh [catch {close $fp} err]
+ if {$uhoh} {
+ # Ignore a common error
+ if {![string match "*appears to have died*" $err]} {
+ tk_dialog .err Error "Error stopping connection: $err" error 0 OK
+ }
+ }
+ SetButtonStates
+ UpdateConnectionState 0
+}
+
+#***********************************************************************
+# %PROCEDURE: NewPPPoEConnection
+# %ARGUMENTS:
+# name -- if supplied, we're editing the existing connection "name"
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Creates a new PPPoE connection
+#***********************************************************************
+proc NewPPPoEConnection {{name ""}} {
+ set w .newcon
+ if {[winfo exists $w]} {
+ wm deiconify $w
+ raise $w
+ return
+ }
+
+ toplevel $w
+ if {"$name" == ""} {
+ wm title $w "New Connection - RP-PPPoE"
+ wm iconname $w "New Connection"
+ } else {
+ wm title $w "Edit Connection - RP-PPPoE"
+ wm iconname $w "Edit Connection"
+ }
+ wm withdraw $w
+
+ tabnotebook_create $w.tn
+ set basic [tabnotebook_page $w.tn "Basic"]
+ set interface [tabnotebook_page $w.tn "NIC and DNS"]
+ set opts [tabnotebook_page $w.tn "Options"]
+ set advanced [tabnotebook_page $w.tn "Advanced"]
+
+ # ----------- BASIC PAGE -------------
+ label $w.lconName -text "Connection Name: " -anchor e
+ if {"$name" != ""} {
+ label $w.conName -text $name -anchor w
+ } else {
+ entry $w.conName -width 15
+ RegisterHelpWindow $w.lconName "Enter a name for this connection. It can contain letters, numbers, undescores and the minus-sign." $w.help
+ RegisterHelpWindow $w.conName "Enter a name for this connection. It can contain letters, numbers, undescores and the minus-sign." $w.help
+ }
+
+ label $w.luser -text "User Name: " -anchor e
+ entry $w.user -width 15
+ RegisterHelpWindow $w.luser "Enter your user name. Do not add a domain-name after the user name." $w.help
+ RegisterHelpWindow $w.user "Enter your user name. Do not add a domain-name after the user name." $w.help
+
+ label $w.lnet -text "Network: " -anchor e
+ entry $w.network -width 15
+ RegisterHelpWindow $w.lnet "Some ISP's require you to enter their domain-name here (e.g. \"sympatico.ca\")." $w.help
+ RegisterHelpWindow $w.network "Some ISP's require you to enter their domain-name here (e.g. \"sympatico.ca\")." $w.help
+
+ label $w.lpass -text "Password: " -anchor e
+ entry $w.pass -width 15 -show "*"
+ RegisterHelpWindow $w.lpass "Enter your password." $w.help
+ RegisterHelpWindow $w.pass "Enter your password." $w.help
+
+ grid $w.lconName $w.conName -in $basic -sticky nsew
+ grid $w.luser $w.user -in $basic -sticky nsew
+ grid $w.lnet $w.network -in $basic -sticky nsew
+ grid $w.lpass $w.pass -in $basic -sticky nsew
+ grid columnconfigure $basic 1 -weight 1
+
+ # ----------- INTERFACES PAGE -------------
+ set ifs {}
+ catch {set ifs [GetEthernetInterfaces]}
+
+ label $w.lifname -text "Ethernet Interface: " -anchor e
+ entry $w.ifname -width 8
+ RegisterHelpWindow $w.lifname "Enter Ethernet interface to which DSL modem is attached." $w.help
+ RegisterHelpWindow $w.ifname "Enter Ethernet interface to which DSL modem is attached." $w.help
+
+ if {[llength $ifs] > 0} {
+ menubutton $w.ifmb -relief raised -text "..." -menu $w.ifmb.menu
+ RegisterHelpWindow $w.ifmb "Browse detected Ethernet interface names." $w.help
+ menu $w.ifmb.menu -tearoff 0
+ foreach if $ifs {
+ $w.ifmb.menu add command -label $if -command "$w.ifname delete 0 end; $w.ifname insert end [list $if]"
+ }
+ grid $w.lifname $w.ifname $w.ifmb -in $interface -sticky nsew
+ } else {
+ grid $w.lifname $w.ifname - -in $interface -sticky nsew
+ }
+
+ label $w.ldns -text "DNS Setup: " -anchor e
+ menubutton $w.dns -text "From Server" -menu $w.dns.menu -relief raised -indicatoron 1
+ menu $w.dns.menu -tearoff 0
+ foreach thing {"From Server" "Specify" "Do not Adjust"} {
+ $w.dns.menu add command -label $thing -command [list SetDNSOption $w $thing]
+ }
+ RegisterHelpWindow $w.ldns "DNS server options:\n'From Server' - Let PPPoE server specify DNS servers\n'Specify' - Enter IP addresses of DNS servers yourself\n'Do not Adjust' - Leave your DNS setup alone." $w.help
+ RegisterHelpWindow $w.dns "DNS server options:\n'From Server' - Let PPPoE server specify DNS servers\n'Specify' - Enter IP addresses of DNS servers yourself\n'Do not Adjust' - Leave your DNS setup alone." $w.help
+
+ label $w.ldns1 -text "Primary DNS: " -anchor e
+ entry $w.dns1 -width 16
+ RegisterHelpWindow $w.ldns1 "Enter the IP address of the primary DNS server." $w.help
+ RegisterHelpWindow $w.dns1 "Enter the IP address of the primary DNS server." $w.help
+ label $w.ldns2 -text "Secondary DNS: " -anchor e
+ entry $w.dns2 -width 16
+ RegisterHelpWindow $w.ldns2 "Enter the IP address of the secondary DNS server." $w.help
+ RegisterHelpWindow $w.dns2 "Enter the IP address of the secondary DNS server." $w.help
+
+ SetDNSOption $w "From Server"
+ grid $w.ldns $w.dns - -in $interface -sticky nsew
+ grid $w.ldns1 $w.dns1 - -in $interface -sticky nsew
+ grid $w.ldns2 $w.dns2 - -in $interface -sticky nsew
+
+ # If only one Ethernet interface, select it by default
+ if {[llength $ifs] == 1} {
+ $w.ifname insert end [lindex $ifs 0]
+ }
+
+ grid columnconfigure $interface 1 -weight 1
+ # ----------- OPTS PAGE -------------
+ checkbutton $w.nonroot -text "Allow use by non-root users" -variable OPTS(nonroot) -anchor w
+ RegisterHelpWindow $w.nonroot "If enabled, ordinary users can start and stop this connection." $w.help
+ checkbutton $w.sync -text "Use synchronous PPP" -variable OPTS(sync) -anchor w
+ RegisterHelpWindow $w.sync "Use synchronous PPP (recommended -- easier on the CPU.)" $w.help
+ label $w.lfw -text "Firewalling: " -anchor e
+ if {[llength $ifs] == 1} {
+ set defaultFW "Stand-Alone"
+ } else {
+ set defaultFW "Masquerading"
+ }
+ menubutton $w.fw -text $defaultFW -menu $w.fw.menu -indicatoron 1 -relief raised
+ menu $w.fw.menu -tearoff 0
+ foreach type {Stand-Alone Masquerading None} {
+ $w.fw.menu add command -label $type -command [list $w.fw configure -text $type]
+ }
+
+ RegisterHelpWindow $w.lfw "Firewalling options:\nStand-Alone - A stand-alone machine.\nMasquerading - A gateway machine used for Internet sharing.\nNone - Use if you already have your own firewall rules or want to run servers." $w.help
+ RegisterHelpWindow $w.fw "Firewalling options:\nStand-Alone - A stand-alone machine.\nMasquerading - A gateway machine used for Internet sharing.\nNone - Use if you already have your own firewall rules or want to run servers." $w.help
+ grid $w.nonroot - -in $opts -sticky nsew
+ grid $w.sync - -in $opts -sticky nsew
+ grid $w.lfw $w.fw -in $opts -sticky nsw
+ grid columnconfigure $opts 1 -weight 1
+
+ # ----------- ADVANCED PAGE -------------
+ label $w.lsn -text "Service-Name: " -anchor e
+ entry $w.servicename -width 24
+
+ label $w.lac -text "AC-Name: " -anchor e
+ entry $w.acname -width 24
+
+ RegisterHelpWindow $w.lac "Enter access concentrator name if required. Most ISPs do not require this; try leaving it blank." $w.help
+ RegisterHelpWindow $w.acname "Enter access concentrator name if required. Most ISPs do not require this; try leaving it blank." $w.help
+ grid $w.lsn $w.servicename -in $advanced -sticky nsew
+ grid $w.lac $w.acname -in $advanced -sticky nsew
+ RegisterHelpWindow $w.lsn "Enter service name if required. Most ISPs do not require this; try leaving it blank." $w.help
+ RegisterHelpWindow $w.servicename "Enter service name if required. Most ISPs do not require this; try leaving it blank." $w.help
+
+ grid columnconfigure $advanced 1 -weight 1
+
+ # ----------- BUTTONS -------------
+ frame $w.buttons
+ button $w.ok -text "OK" -command [list NewPPPoEConnectionOK $name $w]
+ button $w.cancel -text "Cancel" -command [list destroy $w]
+ pack $w.ok $w.cancel -in $w.buttons -expand 0 -fill none -side left
+
+ pack $w.tn -side top -expand 1 -fill both
+
+ text $w.help -width 60 -wrap word -state disabled -height 6
+ pack $w.help -side top -expand 0 -fill both
+ pack $w.buttons -side top -expand 0 -fill x
+
+ # If we're editing existing connection, fill GUI with current values
+ if {"$name" != ""} {
+ FillConnectionGui $w $name
+ }
+ wm deiconify $w
+ update idletasks
+ raise $w
+}
+
+#***********************************************************************
+# %PROCEDURE: SetDNSOption
+# %ARGUMENTS:
+# w -- connection-editing window
+# opt -- value of DNS option
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Adjusts GUI for specified option
+#***********************************************************************
+proc SetDNSOption { w opt } {
+ $w.dns configure -text $opt
+ if {"$opt" == "Specify"} {
+ $w.dns1 configure -state normal -background white
+ $w.dns2 configure -state normal -background white
+ } else {
+ $w.dns1 configure -state disabled -background "#d9d9d9"
+ $w.dns2 configure -state disabled -background "#d9d9d9"
+ }
+}
+
+# ----------------------------------------------------------------------
+# Tabbed notebook code from "Effective Tcl/Tk Programming"
+# ----------------------------------------------------------------------
+# EXAMPLE: tabnotebook that can dial up pages
+# ----------------------------------------------------------------------
+# Effective Tcl/Tk Programming
+# Mark Harrison, DSC Communications Corp.
+# Michael McLennan, Bell Labs Innovations for Lucent Technologies
+# Addison-Wesley Professional Computing Series
+# ======================================================================
+# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
+# ======================================================================
+
+option add *Tabnotebook.tabs.background #666666 widgetDefault
+option add *Tabnotebook.margin 6 widgetDefault
+option add *Tabnotebook.tabColor #a6a6a6 widgetDefault
+option add *Tabnotebook.activeTabColor #d9d9d9 widgetDefault
+option add *Tabnotebook.tabFont \
+ -*-helvetica-bold-r-normal--*-120-* widgetDefault
+
+proc tabnotebook_create {win} {
+ global tnInfo
+
+ frame $win -class Tabnotebook
+ canvas $win.tabs -highlightthickness 0
+ pack $win.tabs -fill x
+
+ notebook_create $win.notebook
+ pack $win.notebook -expand yes -fill both
+
+ set tnInfo($win-tabs) ""
+ set tnInfo($win-current) ""
+ set tnInfo($win-pending) ""
+ return $win
+}
+
+proc tabnotebook_page {win name} {
+ global tnInfo
+
+ set page [notebook_page $win.notebook $name]
+ lappend tnInfo($win-tabs) $name
+
+ if {$tnInfo($win-pending) == ""} {
+ set id [after idle [list tabnotebook_refresh $win]]
+ set tnInfo($win-pending) $id
+ }
+ return $page
+}
+
+proc tabnotebook_refresh {win} {
+ global tnInfo
+
+ $win.tabs delete all
+
+ set margin [option get $win margin Margin]
+ set color [option get $win tabColor Color]
+ set font [option get $win tabFont Font]
+ set x 2
+ set maxh 0
+
+ foreach name $tnInfo($win-tabs) {
+ set id [$win.tabs create text \
+ [expr $x+$margin+2] [expr -0.5*$margin] \
+ -anchor sw -text $name -font $font \
+ -tags [list $name]]
+
+ set bbox [$win.tabs bbox $id]
+ set wd [expr [lindex $bbox 2]-[lindex $bbox 0]]
+ set ht [expr [lindex $bbox 3]-[lindex $bbox 1]]
+ if {$ht > $maxh} {
+ set maxh $ht
+ }
+
+ $win.tabs create polygon 0 0 $x 0 \
+ [expr $x+$margin] [expr -$ht-$margin] \
+ [expr $x+$margin+$wd] [expr -$ht-$margin] \
+ [expr $x+$wd+2*$margin] 0 \
+ 2000 0 2000 10 0 10 \
+ -outline black -fill $color \
+ -tags [list $name tab tab-$name]
+
+ $win.tabs raise $id
+
+ $win.tabs bind $name <ButtonPress-1> \
+ [list tabnotebook_display $win $name]
+
+ set x [expr $x+$wd+2*$margin]
+ }
+ set height [expr $maxh+2*$margin]
+ $win.tabs move all 0 $height
+
+ $win.tabs configure -width $x -height [expr $height+4]
+
+ if {$tnInfo($win-current) != ""} {
+ tabnotebook_display $win $tnInfo($win-current)
+ } else {
+ tabnotebook_display $win [lindex $tnInfo($win-tabs) 0]
+ }
+ set tnInfo($win-pending) ""
+}
+
+proc tabnotebook_display {win name} {
+ global tnInfo
+
+ notebook_display $win.notebook $name
+
+ set normal [option get $win tabColor Color]
+ $win.tabs itemconfigure tab -fill $normal
+
+ set active [option get $win activeTabColor Color]
+ $win.tabs itemconfigure tab-$name -fill $active
+ $win.tabs raise $name
+
+ set tnInfo($win-current) $name
+}
+
+# ----------------------------------------------------------------------
+# EXAMPLE: simple notebook that can dial up pages
+# ----------------------------------------------------------------------
+# Effective Tcl/Tk Programming
+# Mark Harrison, DSC Communications Corp.
+# Michael McLennan, Bell Labs Innovations for Lucent Technologies
+# Addison-Wesley Professional Computing Series
+# ======================================================================
+# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
+# ======================================================================
+
+option add *Notebook.borderWidth 2 widgetDefault
+option add *Notebook.relief sunken widgetDefault
+
+proc notebook_create {win} {
+ global nbInfo
+
+ frame $win -class Notebook
+ pack propagate $win 0
+
+ set nbInfo($win-count) 0
+ set nbInfo($win-pages) ""
+ set nbInfo($win-current) ""
+ return $win
+}
+
+proc notebook_page {win name} {
+ global nbInfo
+
+ set page "$win.page[incr nbInfo($win-count)]"
+ lappend nbInfo($win-pages) $page
+ set nbInfo($win-page-$name) $page
+
+ frame $page
+
+ if {$nbInfo($win-count) == 1} {
+ after idle [list notebook_display $win $name]
+ }
+ return $page
+}
+
+proc notebook_display {win name} {
+ global nbInfo
+
+ set page ""
+ if {[info exists nbInfo($win-page-$name)]} {
+ set page $nbInfo($win-page-$name)
+ } elseif {[winfo exists $win.page$name]} {
+ set page $win.page$name
+ }
+ if {$page == ""} {
+ error "bad notebook page \"$name\""
+ }
+
+ notebook_fix_size $win
+
+ if {$nbInfo($win-current) != ""} {
+ pack forget $nbInfo($win-current)
+ }
+ pack $page -expand yes -fill both
+ set nbInfo($win-current) $page
+}
+
+proc notebook_fix_size {win} {
+ global nbInfo
+
+ update idletasks
+
+ set maxw 0
+ set maxh 0
+ foreach page $nbInfo($win-pages) {
+ set w [winfo reqwidth $page]
+ if {$w > $maxw} {
+ set maxw $w
+ }
+ set h [winfo reqheight $page]
+ if {$h > $maxh} {
+ set maxh $h
+ }
+ }
+ set bd [$win cget -borderwidth]
+ set maxw [expr $maxw+2*$bd]
+ set maxh [expr $maxh+2*$bd]
+ $win configure -width $maxw -height $maxh
+}
+
+#***********************************************************************
+# %PROCEDURE: SetupGuiToList
+# %ARGUMENTS:
+# w -- the PPPoE connection setup window
+# %RETURNS:
+# A list of (name value) pairs for the connection.
+# %DESCRIPTION:
+# Reads values from the GUI; makes a list.
+#***********************************************************************
+proc SetupGuiToList { w } {
+ global OPTS
+ set ans {}
+ if {[catch {lappend ans ConnectionName [$w.conName get]}]} {
+ lappend ans ConnectionName [$w.conName cget -text]
+ }
+ lappend ans UserName [$w.user get]
+ lappend ans NetworkName [$w.network get]
+ lappend ans Password [$w.pass get]
+ lappend ans Interface [$w.ifname get]
+ lappend ans DNSType [$w.dns cget -text]
+ lappend ans DNS1 [$w.dns1 get]
+ lappend ans DNS2 [$w.dns2 get]
+ lappend ans NonrootOK $OPTS(nonroot)
+ lappend ans Sync $OPTS(sync)
+ lappend ans FirewallType [$w.fw cget -text]
+ lappend ans ServiceName [$w.servicename get]
+ lappend ans ACName [$w.acname get]
+
+ # Validate
+ set name [value $ans ConnectionName]
+ if {![regexp -nocase {^[-a-z0-9_]+$} $name]} {
+ error "Connection name must be non-blank and contain only letters, digits, `_' and `-'"
+ }
+
+ # Check DNS
+ set type [value $ans DNSType]
+ if {"$type" == "Specify"} {
+ set dns [value $ans DNS1]
+ if {![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} "$dns"]} {
+ error "Primary DNS entry must consist of four dot-separated decimal numbers"
+ }
+ set dns [value $ans DNS2]
+ if {"$dns" != "" && ![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} "$dns"]} {
+ error "Secondary DNS entry must consist of four dot-separated decimal numbers"
+ }
+ }
+ return $ans
+}
+
+#***********************************************************************
+# %PROCEDURE: ListToSetupGui
+# %ARGUMENTS:
+# w -- the PPPoE connection setup window
+# lst -- a list of name/value pairs
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Updates GUI to reflect lst
+#***********************************************************************
+proc ListToSetupGui { w lst } {
+ global OPTS
+ foreach {key value} $lst {
+ switch -exact -- $key {
+ ConnectionName {
+ catch {
+ $w.conName delete 0 end
+ $w.conName insert end $value
+ }
+ catch {
+ $w.conName configure -text $value
+ }
+ }
+ UserName {
+ $w.user delete 0 end
+ $w.user insert end $value
+ }
+ NetworkName {
+ $w.network delete 0 end
+ $w.network insert end $value
+ }
+ Password {
+ $w.pass delete 0 end
+ $w.pass insert end $value
+ }
+ Interface {
+ $w.ifname delete 0 end
+ $w.ifname insert end $value
+ }
+ DNSType {
+ SetDNSOption $w $value
+ }
+ DNS1 {
+ set oldstate [$w.dns1 cget -state]
+ $w.dns1 configure -state normal
+ $w.dns1 delete 0 end
+ $w.dns1 insert end $value
+ $w.dns1 configure -state $oldstate
+ }
+ DNS2 {
+ set oldstate [$w.dns2 cget -state]
+ $w.dns2 configure -state normal
+ $w.dns2 delete 0 end
+ $w.dns2 insert end $value
+ $w.dns2 configure -state $oldstate
+ }
+ NonrootOK {
+ set OPTS(nonroot) $value
+ }
+ Sync {
+ set OPTS(sync) $value
+ }
+ FirewallType {
+ $w.fw configure -text $value
+ }
+ ServiceName {
+ $w.servicename delete 0 end
+ $w.servicename insert end $value
+ }
+ ACName {
+ $w.acname delete 0 end
+ $w.acname insert end $value
+ }
+ }
+ }
+}
+
+proc NewPPPoEConnectionOK { name w } {
+ if {[catch {set conn [SetupGuiToList $w]} err]} {
+ tk_dialog .err "Invalid Parameters" "$err" error 0 OK
+ return
+ }
+ if {"$name" == ""} {
+ set name [value $conn ConnectionName]
+ set tmp [GetConnection $name]
+ if {"$tmp" != ""} {
+ tk_dialog .err "Connection Exists" "The connection `$name' already exists. Pick another name." error 0 OK
+ return
+ }
+ }
+ ReplaceConnection $conn
+ SaveConnectionInfo
+ BuildConnectionMenu
+ SwitchConnection $name
+ destroy $w
+}
+
+proc SaveConnectionInfo {} {
+ global ConnectionInfo ConnectionInfoFile PasswordFile
+ set fp [open "$ConnectionInfoFile.new" "w"]
+ puts $fp "# RP-PPPoE GUI Configuration Information."
+ puts $fp "# This file may *look* human-editable, but it is NOT."
+ puts $fp "# So, you with the text editor: Keep away from this file."
+ puts $fp "#"
+ set expunged {}
+ set passwords {}
+ foreach thing $ConnectionInfo {
+ set name [value $thing ConnectionName]
+ set password [value $thing Password]
+ set pwindex [lsearch -exact $thing Password]
+ set safe [lreplace $thing $pwindex [expr $pwindex+1]]
+ set pwd [list ConnectionName $name Password $password]
+ lappend expunged $safe
+ lappend passwords $pwd
+ }
+ puts $fp $expunged
+ close $fp
+ set fp [open "$PasswordFile.new" "w"]
+ exec chmod 600 "$PasswordFile.new"
+ puts $fp "# RP-PPPoE GUI Configuration Information."
+ puts $fp "# This file may *look* human-editable, but it is NOT."
+ puts $fp "# So, you with the text editor: Keep away from this file."
+ puts $fp "#"
+ puts $fp $passwords
+ close $fp
+ file rename -force "$ConnectionInfoFile.new" "$ConnectionInfoFile"
+ file rename -force "$PasswordFile.new" "$PasswordFile"
+
+ # Generate config files for adsl-start for each connection
+ foreach thing $ConnectionInfo {
+ GenerateConfigFile $thing
+ }
+
+ # Now update /etc/ppp/pap-secrets and /etc/ppp/chap-secrets
+ foreach thing $ConnectionInfo {
+ GenerateSecretsEntry $thing
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: ReadShellEscapedWord
+# %ARGUMENTS:
+# str -- a string
+# %RETURNS:
+# A two-element list -- the first element is a shell-escaped word
+# extracted from $str, just the way pppd parses /etc/ppp/pap-secrets.
+# The second element is the remaining portion of $str
+#***********************************************************************
+proc ReadShellEscapedWord { str } {
+ set ans {}
+ set rest $str
+
+ # Chew up leading spaces
+ set rest [string trimleft $rest]
+
+ # If first char is a quote, read until a quote
+ if {"[string index $rest 0]" == "\""} {
+ set rest [string range $rest 1 end]
+ set nextquote [string first "\"" $rest]
+ # If no following quote, pretend we haven't seen a quote, I guess.
+ if {$nextquote >= 0} {
+ set ans [string range $rest 0 [expr $nextquote-1]]
+ set rest [string range $rest [expr $nextquote+1] end]
+ return [list $ans $rest]
+ }
+ }
+
+ # Not a quote; chew through the string until an unescaped space
+ while {[string length $rest] > 0} {
+ set char [string index $rest 0]
+ set rest [string range $rest 1 end]
+ # Sneaky test for whitespace in Tcl 8.0
+ if {"[string trim $char]" == ""} {
+ return [list $ans $rest]
+ }
+ if {"$char" == "\\"} {
+ set char [string index $rest 0]
+ set rest [string range $rest 1 end]
+ }
+ append ans $char
+ }
+ return [list $ans $rest]
+}
+
+
+#***********************************************************************
+# %PROCEDURE: GenerateSecretsEntry
+# %ARGUMENTS:
+# conn -- a connection key/value list
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Adds entries to /etc/ppp/pap-secrets and /etc/ppp/chap-secrets.
+#***********************************************************************
+proc GenerateSecretsEntry { conn } {
+ set user [value $conn UserName]
+ set net [value $conn NetworkName]
+ set password [value $conn Password]
+ if {"$net" != ""} {
+ set user "$user@$net"
+ }
+ GenerateSecretsEntryForFile $user $password "/etc/ppp/pap-secrets"
+ GenerateSecretsEntryForFile $user $password "/etc/ppp/chap-secrets"
+}
+
+#***********************************************************************
+# %PROCEDURE: GenerateSecretsEntryForFile
+# %ARGUMENTS:
+# user -- user name
+# password -- password
+# fname -- file to add entry to.
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Adds entries to /etc/ppp/pap-secrets or /etc/ppp/chap-secrets.
+#***********************************************************************
+proc GenerateSecretsEntryForFile { user password fname } {
+ # Copy $fname to $fname.new
+ set out [open "$fname.new" "w"]
+ exec chmod go-rwx "$fname.new"
+ if {[file exists $fname]} {
+ set in [open $fname "r"]
+ while {[gets $in line] >= 0} {
+ set trimmed [string trim $line]
+ if {"$trimmed" == ""} {
+ puts $out $line
+ continue
+ }
+ if {[string match "#*" $trimmed]} {
+ puts $out $line
+ continue
+ }
+
+ # Read the user name off the line; copy it unless it's our
+ # user name.
+ foreach {word dummy} [ReadShellEscapedWord $line] {break}
+ if {$word != $user} {
+ puts $out $line
+ }
+ }
+ close $in
+ }
+
+ # Now add our line
+ set user [ShellEscape $user]
+ set password [ShellEscape $password]
+ puts $out "$user\t*\t$password\t*"
+ close $out
+ file rename -force $fname.new $fname
+}
+
+#***********************************************************************
+# %PROCEDURE: ShellEscape
+# %ARGUMENTS:
+# str
+# %RETURNS:
+# A version of $str with shell meta-characters escaped
+#***********************************************************************
+proc ShellEscape { str } {
+ set ans ""
+ foreach char [split $str ""] {
+ if {[string first $char "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_+=-@./"] >= 0} {
+ append ans $char
+ } else {
+ append ans "\\$char"
+ }
+ }
+ return $ans
+}
+
+
+#***********************************************************************
+# %PROCEDURE: GenerateConfigFile
+# %ARGUMENTS:
+# conn -- a connection key/value list
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Generates a configuration file for adsl-start and friends under
+# /etc/ppp/rp-pppoe-gui
+#***********************************************************************
+proc GenerateConfigFile { conn } {
+ global ConfigDir
+ set name [value $conn ConnectionName]
+ set fname [file join $ConfigDir conf.$name]
+ set fp [open "$fname.new" w]
+ puts $fp "# Configuration file for connection `$name'."
+ puts $fp "# Automatically generated. Do not edit by hand."
+ puts $fp ""
+ foreach {var val} $conn {
+ switch -exact $var {
+ UserName {
+ set net [value $conn NetworkName]
+ if {"$net" != ""} {
+ set user "$val@$net"
+ } else {
+ set user "$val"
+ }
+ puts $fp [ShellEscape "USER=$user"]
+ }
+ Interface {
+ puts $fp [ShellEscape "ETH=$val"]
+ }
+ DNSType {
+ if {"$val" == "From Server"} {
+ puts $fp "DNSTYPE=SERVER"
+ puts $fp "USEPEERDNS=yes"
+ } elseif {"$val" == "Specify"} {
+ puts $fp "DNSTYPE=SPECIFY"
+ puts $fp "USEPEERDNS=no"
+ } else {
+ puts $fp "DNSTYPE=NOCHANGE"
+ puts $fp "USEPEERDNS=no"
+ }
+ }
+ DNS1 {
+ puts $fp [ShellEscape "DNS1=$val"]
+ }
+ DNS2 {
+ puts $fp [ShellEscape "DNS2=$val"]
+ }
+ NonrootOK {
+ if {$val} {
+ puts $fp "NONROOT=OK"
+ }
+ }
+ ACName {
+ puts $fp [ShellEscape "ACNAME=$val"]
+ }
+ ServiceName {
+ puts $fp [ShellEscape "SERVICENAME=$val"]
+ }
+ FirewallType {
+ if {"$val" == "None"} {
+ puts $fp "FIREWALL=NONE"
+ } elseif {"$val" == "Masquerading"} {
+ puts $fp "FIREWALL=MASQUERADE"
+ } else {
+ puts $fp "FIREWALL=STANDALONE"
+ }
+ }
+ Sync {
+ if {$val} {
+ puts $fp "SYNCHRONOUS=yes"
+ } else {
+ puts $fp "SYNCHRONOUS=no"
+ }
+ }
+ }
+ }
+ puts $fp "CONNECT_TIMEOUT=30"
+ puts $fp "CONNECT_POLL=1"
+ puts $fp "FORCEPING=\".\""
+ puts $fp "PIDFILE=/var/run/adsl-$name.pid"
+ puts $fp "CLAMPMSS=1412"
+ puts $fp "LCP_INTERVAL=20"
+ puts $fp "LCP_FAILURE=3"
+ puts $fp "PPPOE_TIMEOUT=80"
+ puts $fp "LINUX_PLUGIN="
+ puts $fp "DEMAND=no"
+ close $fp
+ file rename -force "$fname.new" "$fname"
+}
+
+#***********************************************************************
+# %PROCEDURE: GetConnectionStatus
+# %ARGUMENTS:
+# conn -- connection name
+# %RETURNS:
+# A three-element list:
+# {started/stopped up/down if}
+# If first element is "started", then connection has been started.
+# If second element is "up", then connection is up.
+# If connection is up, third element is PPP interface.
+#***********************************************************************
+proc GetConnectionStatus { conn } {
+ set pidfile "/var/run/adsl-$conn.pid"
+
+ # Check for PID file
+ if {![file readable $pidfile]} {
+ return {stopped down ""}
+ }
+ set fp [open $pidfile "r"]
+ gets $fp pid
+ close $fp
+
+ # Check if process is dead
+ if {![file exists "/proc/$pid"]} {
+ # The pppd might still be running... doh...
+ if {![file readable "$pidfile.pppd"]} {
+ return {stopped down ""}
+ }
+ set fp [open "$pidfile.pppd" "r"]
+ gets $fp pid
+ close $fp
+ if {![file exists "/proc/$pid"]} {
+ return {stopped down ""}
+ }
+ }
+
+ # Now get PID of pppd
+ if {![file readable "$pidfile.pppd"]} {
+ return {started down ""}
+ }
+ set fp [open "$pidfile.pppd" "r"]
+ gets $fp pid
+ close $fp
+
+ # Find interface to which it corresponds
+ set pppdfiles [glob -nocomplain "/var/run/ppp*.pid"]
+ set found {}
+ foreach file $pppdfiles {
+ set fp [open $file "r"]
+ gets $fp ifpid
+ close $fp
+ if {$ifpid == $pid} {
+ set found [file rootname [file tail $file]]
+ break
+ }
+ }
+ if {"$found" == ""} {
+ return {started down ""}
+ }
+ return [list started up $found]
+}
+
+#***********************************************************************
+# %PROCEDURE: UpdateConnectionState
+# %ARGUMENTS:
+# fromAfter -- if 1, was called from an "after" callback.
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Updates the "LED" displays; periodically reschedules itself to keep
+# updating display.
+#***********************************************************************
+proc UpdateConnectionState {{fromAfter 1}} {
+ global UpdateToken
+ global Packets
+ global Bytes
+ global UpdateInterval
+ global MeasureTime
+ if {$fromAfter} {
+ set UpdateToken ""
+ }
+
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ ConnectionStateOff
+ ResetGraph
+ if {"$UpdateToken" != ""} {
+ after cancel $UpdateToken
+ set UpdateToken {}
+ }
+ return
+ }
+
+ foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
+ if {"$startstop" == "stopped"} {
+ ConnectionStateOff
+ ResetGraph
+ } elseif {"$updown" == "down"} {
+ ConnectionStateDown
+ ResetGraph
+ } else {
+ # Get the packet counts
+ set found 0
+ set fp [open "/proc/net/dev" "r"]
+ while {[gets $fp line] >= 0} {
+ if {![string match "*$interface:*" $line]} {
+ continue
+ }
+ set colon [string first ":" $line]
+ if {$colon < 0} {
+ continue
+ }
+ set line [string range $line [expr $colon+1] end]
+ set found 1
+ set MeasureTime [clock seconds]
+ break
+ }
+ close $fp
+ if {$found} {
+ foreach {rbytes rpacks rerrs rdrop rfifo rframe rcomp rmulti tbytes tpacks} $line {break}
+ if {!$fromAfter} {
+ set Packets(in) $rpacks
+ set Packets(out) $tpacks
+ set Bytes(in) $rbytes
+ set Bytes(out) $tbytes
+ ConnectionStateUp
+ ResetGraph
+ } else {
+ if {$rpacks != $Packets(in)} {
+ ConnectionReceiveActive
+ } else {
+ ConnectionReceiveUp
+ }
+ if {$tpacks != $Packets(out)} {
+ ConnectionTransmitActive
+ } else {
+ ConnectionTransmitUp
+ }
+ set Packets(in) $rpacks
+ set Packets(out) $tpacks
+ set Bytes(in) $rbytes
+ set Bytes(out) $tbytes
+ UpdateGraph
+ }
+ } else {
+ ConnectionStateUp
+ ResetGraph
+ }
+ }
+ if {"$UpdateToken" == ""} {
+ set UpdateToken [after $UpdateInterval UpdateConnectionState]
+ }
+ if {$fromAfter} {
+ SetButtonStates
+ }
+}
+
+proc ConnectionStateOff {} {
+ .c itemconfigure xmitrect -fill "#A0A0A0"
+ .c itemconfigure recvrect -fill "#A0A0A0"
+}
+
+proc ConnectionStateDown {} {
+ .c itemconfigure xmitrect -fill "#A00000"
+ .c itemconfigure recvrect -fill "#A00000"
+}
+
+proc ConnectionStateUp {} {
+ .c itemconfigure xmitrect -fill "#00D000"
+ .c itemconfigure recvrect -fill "#00D000"
+}
+
+proc ConnectionTransmitActive {} {
+ .c itemconfigure xmitrect -fill "#FFFF00"
+}
+
+proc ConnectionTransmitUp {} {
+ .c itemconfigure xmitrect -fill "#00D000"
+}
+
+proc ConnectionReceiveActive {} {
+ .c itemconfigure recvrect -fill "#FFFF00"
+}
+
+proc ConnectionReceiveUp {} {
+ .c itemconfigure recvrect -fill "#00D000"
+}
+
+proc ResetGraph {} {
+ global GraphPoints
+ set GraphPoints(in) {}
+ set GraphPoints(out) {}
+ set GraphPoints(times) {}
+ .graph delete all
+ UpdateGraph
+}
+
+proc UpdateGraph {} {
+ global GraphPoints Bytes UpdateInterval MeasureTime
+ lappend GraphPoints(times) $MeasureTime
+ lappend GraphPoints(in) $Bytes(in)
+ lappend GraphPoints(out) $Bytes(out)
+
+ set w [winfo width .graph]
+ set w2 [expr $w/2]
+
+ set h [winfo height .graph]
+ set toChop [expr [llength $GraphPoints(in)] - $w2 - 1]
+ if {$toChop > 0} {
+ set GraphPoints(in) [lrange $GraphPoints(in) $toChop end]
+ }
+ set toChop [expr [llength $GraphPoints(out)] - $w2 - 1]
+ if {$toChop > 0} {
+ set GraphPoints(out) [lrange $GraphPoints(out) $toChop end]
+ }
+ set toChop [expr [llength $GraphPoints(times)] - $w2 - 1]
+ if {$toChop > 0} {
+ set GraphPoints(times) [lrange $GraphPoints(times) $toChop end]
+ }
+
+ set prev [lindex $GraphPoints(in) 0]
+ set incoords {}
+ set outcoords {}
+ set inmax 0
+ set outmax 0
+ foreach thing [lrange $GraphPoints(in) 1 end] {
+ set diff [expr $thing - $prev]
+ set prev $thing
+ lappend incoords $diff
+ if {$diff > $inmax} {
+ set inmax $diff
+ }
+ }
+
+ set prev [lindex $GraphPoints(out) 0]
+ foreach thing [lrange $GraphPoints(out) 1 end] {
+ set diff [expr $thing - $prev]
+ set prev $thing
+ lappend outcoords $diff
+ if {$diff > $outmax} {
+ set outmax $diff
+ }
+ }
+
+ if {$inmax == 0} { set inmax 1 }
+ if {$outmax == 0} { set outmax 1 }
+ # Draw the transmit line
+ set x 0
+ set hh [expr $h-4]
+ set scaled {}
+ foreach thing $outcoords {
+ lappend scaled $x [expr double($h) - 2 - (double($hh) * double($thing) / double($outmax))]
+ incr x
+ }
+
+ .graph delete all
+ if {[llength $scaled] >= 4} {
+ eval ".graph create line $scaled -fill #A00000"
+ set bits [expr 8.0 * ([lindex $GraphPoints(out) end] - [lindex $GraphPoints(out) 0])]
+ set timediff [expr [lindex $GraphPoints(times) end] - [lindex $GraphPoints(times) 0]]
+ if {$timediff != 0} {
+ set bps [Pretty [expr double($bits) / $timediff]]
+ .graph create text 2 2 -anchor nw -font fixed -text "$bps"
+ }
+ }
+
+ # Draw the receive line
+ set x $w2
+ set scaled {}
+ foreach thing $incoords {
+ lappend scaled $x [expr double($h) - 2 - (double($hh) * double($thing) / double($inmax))]
+ incr x
+ }
+
+ if {[llength $scaled] >= 4} {
+ eval ".graph create line $scaled -fill #00A000"
+ set bits [expr 8.0 * ([lindex $GraphPoints(in) end] - [lindex $GraphPoints(in) 0])]
+ set timediff [expr [lindex $GraphPoints(times) end] - [lindex $GraphPoints(times) 0]]
+ if {$timediff != 0} {
+ set bps [Pretty [expr double($bits) / $timediff]]
+ .graph create text [expr $w2+2] 2 -anchor nw -font fixed -text "$bps"
+ }
+ }
+}
+
+proc Pretty { n } {
+ if {$n < 0} {
+ return "***"
+ }
+ if {$n < 1000} {
+ return [format "%.1f" $n]
+ }
+ set n [expr $n/1000.0]
+ if {$n < 1000} {
+ return [format "%.1fk" $n]
+ }
+ set n [expr $n/1000.0]
+ if {$n < 1000} {
+ return [format "%.1fM" $n]
+ }
+ set n [expr $n/1000.0]
+ return [format "%.1fG" $n]
+}
+
+#***********************************************************************
+# %PROCEDURE: Help
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Opens help page
+#***********************************************************************
+proc Help {} {
+ if {![file readable /usr/share/rp-pppoe-gui/tkpppoe.html]} {
+ tk_dialog .err Error "Help file '/usr/share/rp-pppoe-gui/tkpppoe.html' is not installed" error 0 OK
+ return
+ }
+ catch { exec /bin/sh -c "netscape -remote 'openURL(/usr/share/rp-pppoe-gui/tkpppoe.html)' || netscape /usr/share/rp-pppoe-gui/tkpppoe.html" > /dev/null 2>/dev/null & }
+}
+
+
+
+#***********************************************************************
+# %PROCEDURE: doLogo
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Does the logo thing
+#***********************************************************************
+proc doLogo {} {
+ global AlreadyRunFile ConfigDir
+ if {[file exists $AlreadyRunFile]} {
+ return
+ }
+ catch { file mkdir $ConfigDir }
+ catch { close [open $AlreadyRunFile "w"] }
+ canvas .c -width 374 -height 286 -bg #FFFFCC
+ pack .c
+ drawLogo .c #FFFFCC
+
+ # Funky effect
+ .c create text 4 4 -anchor nw -text "Welcome to RP-PPPoE" \
+ -fill red -font {-family times -size -24 -weight bold} -tags pppoe
+ .c lower pppoe
+
+ .c move logo -300 0
+
+ update idletasks
+
+ for {set i 0} {$i < 15} {incr i} {
+ .c move logo 20 0
+ update idletasks
+ after 25
+ }
+
+ .c create text 4 28 -anchor nw -text "http://www.roaringpenguin.com" \
+ -fill red -font {-family courier -size -14 -weight bold}
+ update idletasks
+ after 2500
+}
+
+doLogo
+catch { destroy .c }
+
+# Try creating an empty config file if none exists
+if {![file readable $ConnectionInfoFile]} {
+ catch { file mkdir $ConfigDir }
+ catch {
+ set fp [open $ConnectionInfoFile "w"]
+ close $fp
+ }
+}
+
+CreateMainDialog
diff --git a/mdk-stage1/rp-pppoe/gui/wrapper.c b/mdk-stage1/rp-pppoe/gui/wrapper.c
new file mode 100644
index 000000000..e2b99662a
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/wrapper.c
@@ -0,0 +1,234 @@
+/* -*-Mode: C;-*- */
+
+/***********************************************************************
+*
+* wrapper.c
+*
+* C wrapper designed to run SUID root for controlling PPPoE connections.
+*
+* Copyright (C) 2001 by Roaring Penguin Software Inc.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#define _SVID_SOURCE 1 /* For putenv */
+#define _POSIX_SOURCE 1 /* For fileno */
+#define _BSD_SOURCE 1 /* For setreuid */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define CONN_NAME_LEN 64
+#define LINELEN 512
+
+static char const *adsl_start = ADSL_START_PATH;
+static char const *adsl_stop = ADSL_STOP_PATH;
+static char const *adsl_status = ADSL_STATUS_PATH;
+
+/**********************************************************************
+ *%FUNCTION: PathOK
+ *%ARGUMENTS:
+ * fname -- a file name.
+ *%RETURNS:
+ * 1 if path to fname is secure; 0 otherwise.
+ *%DESCRIPTION:
+ * Makes sure ownership/permissions of file and parent directories
+ * are safe.
+ **********************************************************************/
+static int
+PathOK(char const *fname)
+{
+ char path[LINELEN];
+ struct stat buf;
+ char const *slash;
+
+ if (strlen(fname) > LINELEN) {
+ fprintf(stderr, "Pathname '%s' too long\n", fname);
+ return 0;
+ }
+
+ /* Must be absolute path */
+ if (*fname != '/') {
+ fprintf(stderr, "Unsafe path '%s' not absolute\n", fname);
+ return 0;
+ }
+
+ /* Check root directory */
+ if (stat("/", &buf) < 0) {
+ perror("stat");
+ return 0;
+ }
+ if (buf.st_uid) {
+ fprintf(stderr, "SECURITY ALERT: Root directory (/) not owned by root\n");
+ return 0;
+ }
+ if (buf.st_mode & (S_IWGRP | S_IWOTH)) {
+ fprintf(stderr, "SECURITY ALERT: Root directory (/) writable by group or other\n");
+ return 0;
+ }
+
+ /* Check each component */
+ slash = fname;
+
+ while(*slash) {
+ slash = strchr(slash+1, '/');
+ if (!slash) {
+ slash = fname + strlen(fname);
+ }
+ memcpy(path, fname, slash-fname);
+ path[slash-fname] = 0;
+ if (stat(path, &buf) < 0) {
+ perror("stat");
+ return 0;
+ }
+ if (buf.st_uid) {
+ fprintf(stderr, "SECURITY ALERT: '%s' not owned by root\n", path);
+ return 0;
+ }
+
+ if (buf.st_mode & (S_IWGRP | S_IWOTH)) {
+ fprintf(stderr, "SECURITY ALERT: '%s' writable by group or other\n",
+ path);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**********************************************************************
+ *%FUNCTION: CleanEnvironment
+ *%ARGUMENTS:
+ * envp -- environment passed to main
+ *%RETURNS:
+ * Nothing
+ *%DESCRIPTION:
+ * Deletes all environment variables; makes safe environment
+ **********************************************************************/
+static void
+CleanEnvironment(char *envp[])
+{
+ envp[0] = NULL;
+ putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin");
+}
+
+/**********************************************************************
+ *%FUNCTION: main
+ *%ARGUMENTS:
+ * argc, argv -- usual suspects
+ * Usage: pppoe-wrapper {start|stop|status} {connection_name}
+ *%RETURNS:
+ * Whatever adsl-start, adsl-stop or adsl-status returns.
+ *%DESCRIPTION:
+ * Runs adsl-start, adsl-stop or adsl-status on given connection if
+ * non-root users are allowed to do it.
+ **********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int amRoot;
+ char *cp;
+ char fname[64+CONN_NAME_LEN];
+ char line[LINELEN+1];
+ int allowed = 0;
+
+ FILE *fp;
+
+ extern char **environ;
+
+ /* Clean out environment */
+ CleanEnvironment(environ);
+
+ /* Are we root? */
+ amRoot = (getuid() == 0);
+
+ /* Validate arguments */
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n",
+ argv[0]);
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "start") &&
+ strcmp(argv[1], "stop") &&
+ strcmp(argv[1], "status")) {
+ fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n",
+ argv[0]);
+ exit(1);
+ }
+
+ /* Connection name can be at most CONN_NAME_LEN chars; alpha, num, underscore */
+ if (strlen(argv[2]) > CONN_NAME_LEN) {
+ fprintf(stderr, "%s: Connection name '%s' too long.\n",
+ argv[0], argv[2]);
+ exit(1);
+ }
+
+ for (cp = argv[2]; *cp; cp++) {
+ if (!strchr("abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789_-", *cp)) {
+ fprintf(stderr, "%s: Connection name '%s' contains illegal character '%c'\n", argv[0], argv[2], *cp);
+ exit(1);
+ }
+ }
+
+ /* Open the connection file */
+ sprintf(fname, "/etc/ppp/rp-pppoe-gui/conf.%s", argv[2]);
+ /* Check path sanity */
+ if (!PathOK(fname)) {
+ exit(1);
+ }
+
+ fp = fopen(fname, "r");
+ if (!fp) {
+ fprintf(stderr, "%s: Could not open '%s': %s\n",
+ argv[0], fname, strerror(errno));
+ exit(1);
+ }
+
+ /* Check if non-root users can control it */
+ if (amRoot) {
+ allowed = 1;
+ } else {
+ while (!feof(fp)) {
+ if (!fgets(line, LINELEN, fp)) {
+ break;
+ }
+ if (!strcmp(line, "NONROOT=OK\n")) {
+ allowed = 1;
+ break;
+ }
+ }
+ }
+ fclose(fp);
+
+ if (!allowed) {
+ fprintf(stderr, "%s: Non-root users are not permitted to control connection '%s'\n", argv[0], argv[2]);
+ exit(1);
+ }
+
+ /* Become root with setuid() to defeat is-root checks in shell scripts */
+ if (setreuid(0, 0) < 0) {
+ perror("setreuid");
+ exit(1);
+ }
+
+ /* It's OK -- do it. */
+ if (!strcmp(argv[1], "start")) {
+ if (!PathOK(adsl_start)) exit(1);
+ execl(adsl_start, "adsl-start", fname, NULL);
+ } else if (!strcmp(argv[1], "stop")) {
+ if (!PathOK(adsl_stop)) exit(1);
+ execl(adsl_stop, "adsl-stop", fname, NULL);
+ } else {
+ if (!PathOK(adsl_status)) exit(1);
+ execl(adsl_status, "adsl-status", fname, NULL);
+ }
+ fprintf(stderr, "%s: execl: %s\n", argv[0], strerror(errno));
+ exit(1);
+}
diff --git a/mdk-stage1/rp-pppoe/man/adsl-connect.8 b/mdk-stage1/rp-pppoe/man/adsl-connect.8
new file mode 100644
index 000000000..1b34a74e5
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-connect.8
@@ -0,0 +1,66 @@
+.\" $Id$
+.TH ADSL-CONNECT 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-connect \- Shell script to manage a PPPoE link
+
+.SH SYNOPSIS
+.B adsl-connect \fR[\fIconfig_file\fR]
+.P
+.B adsl-connect \fR\fIinterface user\fR [\fIconfig_file\fR]
+
+
+.SH DESCRIPTION
+\fBadsl-connect\fR is a shell script which manages an ADSL connection
+using the Roaring Penguin user-space PPPoE client. If you omit
+\fIconfig_file\fR, the default file \fB/etc/ppp/pppoe.conf\fR is used.
+If you supply \fIinterface\fR and \fIuser\fR, then they override the
+Ethernet interface and user-name settings in the configuration file.
+.P
+Note that normally, you should \fInot\fR invoke \fBadsl-connect\fR
+directly. Instead, use \fBadsl-start\fR to bring up the ADSL connection.
+.P
+\fBadsl-connect\fR first reads a configuration file. It then brings
+up a PPPoE connection. If the connection ever drops, a message is logged
+to syslog, and \fBadsl-connect\fR re-establishes the connection. In addition,
+each time the connection is dropped or cannot be established,
+\fBadsl-connect\fR executes the script \fB/etc/ppp/adsl-lost\fR if it
+exists and is executable.
+
+.P
+The shell script \fBadsl-stop\fR causes \fBadsl-connect\fR to break out
+of its loop, bring the connection down, and exit.
+
+.SH TECHNICAL DETAILS
+\fBadsl-connect\fR uses the following shell variables from the
+configuration file:
+
+.TP
+.B ETH
+The Ethernet interface connected to the ADSL modem (for example, eth0).
+
+.TP
+.B USER
+The ADSL user-id (for example, b1xxnxnx@sympatico.ca).
+
+.TP
+.B PIDFILE
+A file in which to write the process-ID of the adsl-connect process
+(for example, \fB/var/run/pppoe.pid\fR). Two additional files
+($PIDFILE.pppd and $PIDFILE.pppoe) hold the process-ID's of the
+\fBpppd\fR and \fBpppoe\fR processes, respectively.
+
+.P
+By using different configuration files with different PIDFILE
+settings, you can manage multiple PPPoE connections. Just specify the
+configuration file as an argument to \fBadsl-start\fR and
+\fBadsl-stop\fR.
+
+.SH AUTHOR
+\fBadsl-connect\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-stop(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-setup.8 b/mdk-stage1/rp-pppoe/man/adsl-setup.8
new file mode 100644
index 000000000..9e78fa547
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-setup.8
@@ -0,0 +1,23 @@
+.\" $Id$
+.TH ADSL-SETUP 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-setup \- Shell script to configure Roaring Penguin PPPoE client
+.SH SYNOPSIS
+.B adsl-setup
+
+.SH DESCRIPTION
+\fBadsl-setup\fR is a shell script which prompts you for various pieces
+of information and sets up an /etc/ppp/pppoe.conf configuration script
+for the \fBadsl-start\fR, \fBadsl-stop\fR and \fBadsl-connect\fR scripts.
+
+.SH AUTHOR
+\fBadsl-setup\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8),
+pppoe.conf(5), adsl-status(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-start.8 b/mdk-stage1/rp-pppoe/man/adsl-start.8
new file mode 100644
index 000000000..87250b381
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-start.8
@@ -0,0 +1,27 @@
+.\" $Id$
+.TH ADSL-START 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-start \- Shell script to bring up a PPPoE link
+.SH SYNOPSIS
+.B adsl-start \fR[\fIconfig_file\fR]
+.P
+.B adsl-start \fR\fIinterface user\fR [\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBadsl-start\fR is a shell script which starts the Roaring Penguin
+user-space PPPoE client. If you omit \fIconfig_file\fR, the default
+file \fB/etc/ppp/pppoe.conf\fR is used. If you supply
+\fIinterface\fR and \fIuser\fR, then they override the Ethernet interface
+and user-name settings in the configuration file.
+
+.SH AUTHOR
+\fBadsl-start\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-status.8 b/mdk-stage1/rp-pppoe/man/adsl-status.8
new file mode 100644
index 000000000..2114d461e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-status.8
@@ -0,0 +1,25 @@
+.\" $Id$
+.TH ADSL-STATUS 8 "16 March 2000"
+.UC 4
+.SH NAME
+adsl-status \- Shell script to report on status of PPPoE link
+.SH SYNOPSIS
+.B adsl-status \fR[\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBadsl-status\fR is a shell script which checks the status of the
+PPPoE link established by the Roaring Penguin user-space PPPoE client.
+If you omit \fIconfig_file\fR, the default file
+\fB/etc/ppp/pppoe.conf\fR is used.
+
+.SH AUTHOR
+\fBadsl-status\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+adsl-setup(8), adsl-stop(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-stop.8 b/mdk-stage1/rp-pppoe/man/adsl-stop.8
new file mode 100644
index 000000000..2ac7fef8e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-stop.8
@@ -0,0 +1,21 @@
+.\" $Id$
+.TH ADSL-STOP 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-stop \- Shell script to shut down a PPPoE link
+.SH SYNOPSIS
+.B adsl-stop \fR[\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBadsl-stop\fR is a shell script which stops the Roaring Penguin
+user-space PPPoE client. If you omit \fIconfig_file\fR, the default
+file \fB/etc/ppp/pppoe.conf\fR is used.
+
+.SH AUTHOR
+\fBadsl-stop\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-connect(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8), pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe-relay.8 b/mdk-stage1/rp-pppoe/man/pppoe-relay.8
new file mode 100644
index 000000000..5f79b09a1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe-relay.8
@@ -0,0 +1,124 @@
+.\" $Id$
+.TH PPPOE-RELAY 8 "26 January 2001"
+.\""
+.UC 4
+.SH NAME
+pppoe-relay \- user-space PPPoE relay agent.
+.SH SYNOPSIS
+.B pppoe-relay \fR[\fIoptions\fR]
+
+.SH DESCRIPTION
+\fBpppoe-relay\fR is a user-space relay agent for PPPoE
+(Point-to-Point Protocol over Ethernet) for Linux. \fBpppoe-relay\fR
+works in concert with the \fBpppoe\fR client and \fBpppoe-server\fR
+server. See the OPERATION section later in this manual for
+details on how \fBpppoe-relay\fR works.
+
+.SH OPTIONS
+.TP
+.B \-S \fIinterface\fR
+Adds the Ethernet interface \fIinterface\fR to the list of interfaces
+managed by \fBpppoe-relay\fR. Only PPPoE servers may be connected to
+this interface.
+
+.TP
+.B \-C \fIinterface\fR
+Adds the Ethernet interface \fIinterface\fR to the list of interfaces
+managed by \fBpppoe-relay\fR. Only PPPoE clients may be connected to
+this interface.
+
+.TP
+.B \-B \fIinterface\fR
+Adds the Ethernet interface \fIinterface\fR to the list of interfaces
+managed by \fBpppoe-relay\fR. Both PPPoE clients and servers may be
+connected to this interface.
+
+.TP
+.B \-n \fInum\fR
+Allows at most \fInum\fR concurrent PPPoE sessions. If not specified,
+the default is 5000. \fInum\fR can range from 1 to 65534.
+
+.TP
+.B \-i \fItimeout\fR
+Specifies the session idle timeout. If both peers in a session are idle
+for more than \fItimeout\fR seconds, the session is terminated.
+If \fItimeout\fR is specified as zero, sessions will never be terminated
+because of idleness.
+
+Note that the idle-session expiry routine is never run more frequently than
+every 30 seconds, so the timeout is approximate. The default value for
+\fItimeout\fR is 600 seconds (10 minutes.)
+
+.TP
+.B \-F
+The \fB\-F\fR option causes \fBpppoe-relay\fR \fInot\fR to fork into the
+background; instead, it remains in the foreground.
+
+.TP
+.B \-h
+The \fB\-h\fR option prints a brief usage message and exits.
+
+.SH OPERATION
+
+\fBpppoe-relay\fR listens for incoming PPPoE PADI frames on all interfaces
+specified with \fB-B\fR or \fB-C\fR options. When a PADI frame appears,
+\fBpppoe-relay\fR adds a Relay-Session-ID tag and broadcasts the PADI
+on all interfaces specified with \fB-B\fR or \fB-S\fR options (except the
+interface on which the frame arrived.)
+
+Any PADO frames received are relayed back to the client which sent the
+PADI (assuming they contain valid Relay-Session-ID tags.) Likewise,
+PADR frames from clients are relayed back to the matching access
+concentrator.
+
+When a PADS frame is received, \fBpppoe-relay\fR enters the two peers'
+MAC addresses and session-ID's into a hash table. (The session-ID seen
+by the access concentrator may be different from that seen by the client;
+\fBpppoe-relay\fR must renumber sessions to avoid the possibility of duplicate
+session-ID's.) Whenever either peer sends a session frame, \fBpppoe-relay\fR
+looks up the session entry in the hash table and relays the frame to
+the correct peer.
+
+When a PADT frame is received, \fBpppoe-relay\fR relays it to the peer
+and deletes the session entry from its hash table.
+
+If a client and server crash (or frames are lost), PADT frames may never
+be sent, and \fBpppoe-relay\fR's hash table can fill up with stale sessions.
+Therefore, a session-cleaning routine runs periodically, and removes old
+sessions from the hash table. A session is considered "old" if no traffic
+has been seen within \fItimeout\fR seconds. When a session is deleted because
+of a timeout, a PADT frame is sent to each peer to make certain that they
+are aware the session has been killed.
+
+.SH EXAMPLE INVOCATIONS
+
+.nf
+pppoe-relay -C eth0 -S eth1
+.fi
+
+The example above relays frames between PPPoE clients on the eth0 network
+and PPPoE servers on the eth1 network.
+
+.nf
+pppoe-relay -B eth0 -B eth1
+.fi
+
+This example is a transparent relay -- frames are relayed between any mix
+of clients and servers on the eth0 and eth1 networks.
+
+.nf
+pppoe-relay -S eth0 -C eth1 -C eth2 -C eth3
+.fi
+
+This example relays frames between servers on the eth0 network and
+clients on the eth1, eth2 and eth3 networks.
+
+.SH AUTHORS
+\fBpppoe-relay\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe-server.8 b/mdk-stage1/rp-pppoe/man/pppoe-server.8
new file mode 100644
index 000000000..aacf11f1f
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe-server.8
@@ -0,0 +1,123 @@
+.\" $Id$
+.TH PPPOE-SERVER 8 "3 July 2000"
+.\""
+.UC 4
+.SH NAME
+pppoe-server \- user-space PPPoE server
+.SH SYNOPSIS
+.B pppoe-server \fR[\fIoptions\fR]
+
+.SH DESCRIPTION
+\fBpppoe-server\fR is a user-space server for PPPoE (Point-to-Point Protocol
+over Ethernet) for Linux and other UNIX systems. \fBpppoe-server\fR works in
+concert with the \fBpppoe\fR client to respond to PPPoE discovery packets
+and set up PPPoE sessions.
+
+.SH OPTIONS
+.TP
+.B \-F
+The \fB\-F\fR option causes \fBpppoe-server\fR not to fork and become a
+daemon. The default is to fork and become a daemon.
+
+.TP
+.B \-I \fIinterface\fR
+The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
+it is typically \fIeth0\fR or \fIeth1\fR. The interface should be "up"
+before you start \fBpppoe-server\fR, but should \fInot\fR be configured to have
+an IP address.
+
+.TP
+.B \-T \fItimeout\fR
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details.
+
+.TP
+.B \-C \fIac_name\fR
+Specifies which name to report as the access concentrator name. If not
+supplied, the host name is used.
+
+.TP
+.B \-m \fIMSS\fR
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details.
+
+.TP
+.B \-s
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details. In addition, it causes \fBpppd\fR to be invoked with the
+\fIsync\fR option.
+
+.TP
+.B \-L \fIip\fR
+Sets the local IP address. This is passed to spawned \fBpppd\fR processes.
+If not specified, the default is 10.0.0.1.
+
+.TP
+.B \-R \fIip\fR
+Sets the starting remote IP address. As sessions are established,
+IP addresses are assigned starting from \fIip\fR. \fBpppoe-server\fR
+automatically keeps track of the pool of addresses and passes a
+valid remote IP address to \fBpppd\fR. If not specified, a starting address
+of 10.67.15.1 is used.
+
+.TP
+.B \-N \fInum\fR
+Allows at most \fInum\fR concurrent PPPoE sessions. If not specified,
+the default is 64.
+
+.TP
+.B \-p \fIfname\fR
+Reads the specified file \fIfname\fR which is a text file consisting of
+one IP address per line. These IP addresses will be assigned to clients.
+The number of sessions allowed will equal the number of addresses found
+in the file. The \fB\-p\fR option overrides both \fB\-R\fR and \fB\-N\fR.
+
+.TP
+.B \-o \fIoffset\fR
+Instead of numbering PPPoE sessions starting at 1, they will be numbered
+starting at \fIoffset\fR+1. This allows you to run multiple servers on
+a given machine; just make sure that their session numbers do not
+overlap.
+
+.TP
+.B \-f disc:sess
+The \fB\-f\fR option sets the Ethernet frame types for PPPoE discovery
+and session frames. The types are specified as hexadecimal numbers
+separated by a colon. Standard PPPoE uses frame types 8863:8864.
+\fIYou should not use this option\fR unless you are absolutely sure
+the peer you are dealing with uses non-standard frame types.
+
+.TP
+.B \-h
+The \fB\-h\fR option prints a brief usage message and exits.
+
+.SH OPERATION
+
+\fBpppoe-server\fR listens for incoming PPPoE discovery packets. When
+a session is established, it spawns a \fBpppd\fR process. The following
+options are passed to \fBpppd\fR:
+
+.nf
+nodetach noaccomp nobsdcom nodeflate nopcomp novj novjccomp
+default-asyncmap
+.fi
+
+In addition, the local and remote IP address are set based on the
+\fB\-L\fR and \fB\-R\fR options. The \fBpty\fR option is supplied along
+with a \fBpppoe\fR command to initiate the PPPoE session. Finally,
+additional \fBpppd\fR options can be placed in the file
+\fB/etc/ppp/pppoe-server-options\fR (which must exist, even if it is just
+empty!)
+
+Note that \fBpppoe-server\fR is meant mainly for testing PPPoE clients.
+It is \fInot\fR a high-performance server meant for production use.
+
+.SH AUTHORS
+\fBpppoe-server\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe-sniff.8 b/mdk-stage1/rp-pppoe/man/pppoe-sniff.8
new file mode 100644
index 000000000..431830a22
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe-sniff.8
@@ -0,0 +1,77 @@
+.\" $Id$
+.TH PPPOE-SNIFF 8 "3 July 2000"
+.\""
+.UC 4
+.SH NAME
+pppoe-sniff \- examine network for non-standard PPPoE frames
+.SH SYNOPSIS
+.B pppoe-sniff \fR[\fIoptions\fR]
+
+.SH DESCRIPTION
+\fBpppoe-sniff\fR listens for likely-looking PPPoE PADR and session frames
+and deduces extra options required for \fBpppoe(8)\fR to work.
+
+Some DSL providers seem to use non-standard frame types for PPPoE frames,
+and/or require a certain value in the Service-Name field. It is often
+easier to sniff those values from a machine which can successfully connect
+rather than try to pry them out of the DSL provider.
+
+To use \fBpppoe-sniff\fR, you need two computers, a DSL modem and
+an Ethernet hub (\fInot\fR an Ethernet switch.)
+
+If the DSL modem normally connects directly to your computer's
+Ethernet card, connect it to the "uplink" port on the Ethernet hub.
+Plug two computers into normal ports on the hub. On one computer, run
+whatever software the DSL provider gave you on whatever operating
+system the DSL provider supports. On the other computer, run Linux and
+log in as root.
+
+On the Linux machine, put the Ethernet interface into promiscuous mode
+and start \fBpppoe-sniff\fR. If the ethernet interface is \fIeth0\fR,
+for example, type these commands:
+
+.nf
+ ifconfig eth0 promisc
+ pppoe-sniff -I eth0
+.fi
+
+On the other machine, start your DSL connection as usual. After a short
+time, \fBpppoe-sniff\fR should print recommendations for the value
+of \fBPPPOE_EXTRA\fR. Set this value in \fB/etc/ppp/pppoe.conf\fR.
+If \fBpppoe-sniff\fR indicates that something special is required in
+\fBPPPOE_EXTRA\fR, please e-mail this to \fBpppoe@roaringpenguin.com\fR
+along with the name of your ISP and the manufacturer and model number of
+your DSL modem. This information will be collated and provided on the
+PPPoE web page for users who do not have two computers.
+
+After \fBpppoe-sniff\fR finishes (or you stop it if it seems hung),
+remember to turn off promiscuous mode:
+
+.nf
+ ifconfig eth0 -promisc
+.fi
+
+.SH OPTIONS
+.TP
+.B \-I \fIinterface\fR
+The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
+it is typically \fIeth0\fR or \fIeth1\fR. The interface should be "up"
+and in promiscuous mode before you start \fBpppoe-sniff\fR.
+
+.TP
+.B \-V
+The \fB\-V\fR option causes \fBpppoe-sniff\fR to print its version number and
+exit.
+
+.SH BUGS
+\fBpppoe-sniff\fR only works on Linux.
+
+.SH AUTHORS
+\fBpppoe-sniff\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), adsl-setup(8), adsl-status(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe.8 b/mdk-stage1/rp-pppoe/man/pppoe.8
new file mode 100644
index 000000000..999c3d2ed
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe.8
@@ -0,0 +1,236 @@
+.\" $Id$
+.TH PPPOE 8 "3 July 2000"
+.UC 4
+.SH NAME
+pppoe \- user-space PPPoE client.
+.SH SYNOPSIS
+.B pppd pty 'pppoe \fR[\fIpppoe_options\fR]\fB' \fR[\fIpppd_options\fR]
+.P
+.B pppoe -A \fR[\fIpppoe_options\fR]
+.SH DESCRIPTION
+\fBpppoe\fR is a user-space client for PPPoE (Point-to-Point Protocol
+over Ethernet) for Linux and other UNIX systems. \fBpppoe\fR works in
+concert with the \fBpppd\fR PPP daemon to provide a PPP connection
+over Ethernet, as is used by many ADSL service providers.
+
+.SH OPTIONS
+.TP
+.B \-I \fIinterface\fR
+The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
+it is typically \fIeth0\fR or \fIeth1\fR. The interface should be "up"
+before you start \fBpppoe\fR, but should \fInot\fR be configured to have
+an IP address.
+
+.TP
+.B \-T \fItimeout\fR
+The \fB\-T\fR option causes \fBpppoe\fR to exit if no session traffic
+is detected for \fItimeout\fR seconds. I recommend that you use this
+option as an extra safety measure, but if you do, you should make sure
+that PPP generates enough traffic so the timeout will normally not be
+triggered. The best way to do this is to use the
+\fIlcp-echo-interval\fR option to \fBpppd\fR. You should set the
+PPPoE timeout to be about four times the LCP echo interval.
+
+.TP
+.B \-D \fIfile_name\fR
+The \fB\-D\fR option causes every packet to be dumped to the specified
+\fIfile_name\fR. This is intended for debugging only; it produces huge
+amounts of output and greatly reduces performance.
+
+.TP
+.B \-V
+The \fB\-V\fR option causes \fBpppoe\fR to print its version number and
+exit.
+
+.TP
+.B \-A
+The \fB\-A\fR option causes \fBpppoe\fR to send a PADI packet and then print
+the names of access concentrators in each PADO packet it receives. Do not
+use this option in conjunction with \fBpppd\fR; the \fB\-A\fR option is
+meant to be used interactively to give interesting information about the
+access concentrator.
+
+.TP
+.B \-S \fIservice_name\fR
+Specifies the desired service name. \fBpppoe\fR will only initiate sessions
+with access concentrators which can provide the specified service. In
+most cases, you should \fInot\fR specify this option. Use it only if you
+know that there are multiple access concentrators or know that you need a
+specific service name.
+
+.TP
+.B \-C \fIac_name\fR
+Specifies the desired access concentrator name. \fBpppoe\fR will only
+initiate sessions with the specified access concentrator. In
+most cases, you should \fInot\fR specify this option. Use it only if you
+know that there are multiple access concentrators. If both the
+\fB\-S\fR and \fB\-C\fR options are specified, they must \fIboth\fR match
+for \fBpppoe\fR to initiate a session.
+
+.TP
+.B \-U
+Causes \fBpppoe\fR to use the Host-Uniq tag in its discovery packets. This
+lets you run multiple \fBpppoe\fR daemons without having their discovery
+packets interfere with one another. You must supply this option to
+\fIall\fR \fBpppoe\fR daemons if you intend to run multiple daemons
+simultaneously.
+
+.TP
+.B \-s
+Causes \fBpppoe\fR to use \fIsynchronous\fR PPP encapsulation. If you
+use this option, then you \fImust\fR use the \fBsync\fR option with
+\fBpppd\fR. You are encouraged to use this option if it works, because
+it greatly reduces the CPU overhead of \fBpppoe\fR. However, it
+MAY be unreliable on slow machines -- there is a race condition between
+pppd writing data and pppoe reading it. For this reason, the default
+setting is asynchronous. If you encounter bugs or crashes with Synchronous
+PPP, turn it off -- don't e-mail me for support!
+
+.TP
+.B \-m \fIMSS\fR
+Causes \fBpppoe\fR to \fIclamp\fR the TCP maximum segment size at the specified
+value. Because of PPPoE overhead, the maximum segment size for PPPoE is
+smaller than for normal Ethernet encapsulation. This could cause problems
+for machines on a LAN behind a gateway using PPPoE. If you have a LAN
+behind a gateway, and the gateway connects to the Internet using PPPoE,
+you are strongly recommended to use a \fB\-m 1412\fR option. This avoids
+having to set the MTU on all the hosts on the LAN.
+
+.TP
+.B \-p \fIfile\fR
+Causes \fBpppoe\fR to write its process-ID to the specified file. This
+can be used to locate and kill \fBpppoe\fR processes.
+
+.TP
+.B \-e \fIsess:mac\fR
+Causes \fBpppoe\fR to skip the discovery phase and move directly to the
+session phase. The session is given by \fIsess\fR and the MAC address of
+the peer by \fImac\fR. This mode is \fInot\fR meant for normal use; it
+is designed only for \fBpppoe-server\fR(8).
+
+.TP
+.B \-n
+Causes \fBpppoe\fR not to open a discovery socket. This mode is
+\fInot\fR meant for normal use; it is designed only for
+\fBpppoe-server\fR(8).
+
+.TP
+.B \-k
+Causes \fBpppoe\fR to terminate an existing session by sending a PADT frame,
+and then exit. You must use the \fB\-e\fR option in conjunction with this
+option to specify the session to kill. This may be useful for killing
+sessions when a buggy peer does not realize the session has ended.
+
+.TP
+.B \-d
+Causes \fBpppoe\fR to perform discovery and then exit, after printing
+session information to standard output. The session information is printed
+in exactly the format expected by the \fB\-e\fR option. This option lets
+you initiate a PPPoE discovery, perform some other work, and then start
+the actual PPP session. \fIBe careful\fR; if you use this option in a loop,
+you can create many sessions, which may annoy your peer.
+
+.TP
+.B \-f disc:sess
+The \fB\-f\fR option sets the Ethernet frame types for PPPoE discovery
+and session frames. The types are specified as hexadecimal numbers
+separated by a colon. Standard PPPoE uses frame types 8863:8864.
+\fIYou should not use this option\fR unless you are absolutely sure
+the peer you are dealing with uses non-standard frame types. If your
+ISP uses non-standard frame types, complain!
+
+.TP
+.B \-h
+The \fB\-h\fR option causes \fBpppoe\fR to print usage information and
+exit.
+
+.SH PPPOE BACKGROUND
+
+PPPoE (Point-to-Point Protocol over Ethernet) is described in RFC 2516
+and is a protocol which allows the session abstraction to be maintained
+over bridged Ethernet networks.
+
+PPPoE works by encapsulating PPP frames in Ethernet frames. The protocol
+has two distinct stages: The \fIdiscovery\fR and the \fIsession\fR stage.
+
+In the discovery stage, the host broadcasts a special PADI (PPPoE
+Active Discovery Initiation) frame to discover any \fIaccess
+concentrators\fR. The access concentrators (typically, only one
+access concentrator) reply with PADO (PPPoE Active Discovery Offer)
+packets, announcing their presence and the services they offer. The
+host picks one of the access concentrators and transmits a PADR (PPPoE
+Active Discovery Request) packet, asking for a session. The access
+concentrator replies with a PADS (PPPoE Active Discovery
+Session-Confirmation) packet. The protocol then moves to the session stage.
+
+In the session stage, the host and access concentrator exchange PPP frames
+embedded in Ethernet frames. The normal Ethernet MTU is 1500 bytes, but
+the PPPoE overhead plus two bytes of overhead for the encapsulated PPP
+frame mean that the MTU of the PPP interface is at most 1492 bytes.
+This causes \fIall kinds of problems\fR if you are using a Linux machine
+as a firewall and interfaces behind the firewall have an MTU greater than
+1492. In fact, to be safe, I recommend setting the MTU of machines
+behind the firewall to 1412, to allow for worst-case TCP and IP options
+in their respective headers.
+
+Normally, PPP uses the Link Control Protocol (LCP) to shut down a PPP
+link. However, the PPPoE specification allows the link to be shut down
+with a special PADT (PPPoE Active Discovery Terminate) packet. This client
+recognizes this packet and will correctly terminate if a terminate request
+is received for the PPP session.
+
+.SH DESIGN GOALS
+
+My design goals for this PPPoE client were as follows, in descending order
+of importance:
+
+.TP
+.B o
+It must work.
+
+.TP
+.B o
+It must be a user-space program and not a kernel patch.
+
+.TP
+.B o
+The code must be easy to read and maintain.
+
+.TP
+.B o
+It must be fully compliant with RFC 2516, the proposed PPPoE standard.
+
+.TP
+.B o
+It must never hang up forever -- if the connection is broken, it must
+detect this and exit, allowing a wrapper script to restart the connection.
+
+.TP
+.B o
+It must be fairly efficient.
+
+.P
+I believe I have achieved all of these goals, but (of course) am open
+to suggestions, patches and ideas. See my home page,
+http://www.roaringpenguin.com, for contact information.
+
+.SH NOTES
+
+For best results, you must give \fBpppd\fR an mtu option of
+1492. I have observed problems with excessively-large frames
+unless I set this option. Also, if \fBpppoe\fR is running on a firewall
+machine, all machines behind the firewall should have MTU's of 1412.
+
+If you have problems, check your system logs. \fBpppoe\fR logs interesting
+things to syslog. You may have to turn on logging of \fIdebug\fR-level
+messages for complete diagnosis.
+
+.SH AUTHORS
+\fBpppoe\fR was written by David F. Skoll <dfs@roaringpenguin.com>,
+with much inspiration from an earlier version by Luke Stras.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe.conf.5 b/mdk-stage1/rp-pppoe/man/pppoe.conf.5
new file mode 100644
index 000000000..731fd98d4
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe.conf.5
@@ -0,0 +1,168 @@
+.\" $Id$
+.\""
+.TH PPPOE.CONF 5 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe.conf \- Configuration file used by \fBadsl-start\fR(8),
+\fBadsl-stop\fR(8), \fBadsl-status(8)\fR and \fBadsl-connect\fR(8).
+
+.SH DESCRIPTION
+\fB/etc/ppp/pppoe.conf\fR is a shell script which contains configuration
+information for Roaring Penguin's ADSL scripts. Note that \fBpppoe.conf\fR
+is used only by the various adsl-* shell scripts, not by \fBpppoe\fR
+itself.
+
+\fBpppoe.conf\fR consists of a sequence of shell variable assignments.
+The variables and their meanings are:
+
+.TP
+.B ETH
+The Ethernet interface connected to the ADSL modem (for example, eth0).
+
+.TP
+.B USER
+The ADSL user-id (for example, b1xxnxnx@sympatico.ca).
+
+.TP
+.B SERVICENAME
+If this is not blank, then it is passed with the \fB\-S\fR option to
+\fBpppoe\fR. It specifies a service name to ask for. Usually, you
+should leave it blank.
+
+.TP
+.B ACNAME
+If this is not blank, then it is passed with the \fB\-C\fR option to
+\fBpppoe\fR. It specifies the name of the access concentrator to connect
+to. Usually, you should leave it blank.
+
+.TP
+.B DEMAND
+If set to a number, the link is activated on demand and brought down
+after after \fBDEMAND\fR seconds. If set to \fBno\fR, the link is kept
+up all the time rather than being activated on demand.
+
+.TP
+.B DNSTYPE
+One of \fBNOCHANGE\fR, \fBSPECIFY\fR or \fBSERVER\fR. If
+set to NOCHANGE, \fBadsl-connect\fR will not adjust the DNS setup in
+any way. If set to SPECIFY, it will re-write /etc/resolv.conf with
+the values of DNS1 and DNS2. If set to \fBSERVER\fR, it will
+supply the \fIusepeerdns\fR option to \fBpppd\fR, and make a symlink
+from /etc/resolv.conf to /etc/ppp/resolv.conf.
+
+.TP
+.B DNS1, DNS2
+IP addresses of DNS servers if you use DNSTYPE=SPECIFY.
+
+.TP
+.B NONROOT
+If the line \fBNONROOT=OK\fR (exactly like that; no whitespace or comments)
+appears in the configuration file, then \fBpppoe-wrapper\fR will allow
+non-root users to bring the conneciton up or down. The wrapper is installed
+only if you installed the rp-pppoe-gui package.
+
+.TP
+.B USEPEERDNS
+If set to "yes", then \fBadsl-connect\fR will supply the \fIusepeerdns\fR
+option to \fBpppd\fR, which causes it to obtain DNS server addresses
+from the peer and create a new \fB/etc/resolv.conf\fR file. Otherwise,
+\fBadsl-connect\fR will not supply this option, and \fBpppd\fR will not
+modify \fB/etc/resolv.conf\fR.
+
+.TP
+.B CONNECT_POLL
+How often (in seconds) \fBadsl-start\fR should check to see if a new PPP
+interface has come up. If this is set to 0, the \fBadsl-start\fR simply
+initiates the PPP session, but does not wait to see if it comes up
+successfully.
+
+.TP
+.B CONNECT_TIMEOUT
+How long (in seconds) \fBadsl-start\fR should wait for a new PPP interface
+to come up before concluding that \fBadsl-connect\fR has failed and killing
+the session.
+
+.TP
+.B PING
+A character which is echoed every \fBCONNECT_POLL\fR seconds while
+\fBadsl-start\fR is waiting for the PPP interface to come up.
+
+.TP
+.B FORCEPING
+A character which is echoed every \fBCONNECT_POLL\fR seconds while
+\fBadsl-start\fR is waiting for the PPP interface to come up. Similar
+to \fBPING\fR, but the character is echoed even if \fBadsl-start\fR's
+standard output is not a tty.
+
+.TP
+.B PIDFILE
+A file in which to write the process-ID of the adsl-connect process
+(for example, \fB/var/run/pppoe.pid\fR). Two additional files
+($PIDFILE.pppd and $PIDFILE.pppoe) hold the process-ID's of the
+\fBpppd\fR and \fBpppoe\fR processes, respectively.
+
+.TP
+.B SYNCHRONOUS
+An indication of whether or not to use synchronous PPP (\fByes\fR or
+\fBno\fR). Synchronous PPP is safe on Linux machines with the n_hdlc
+line discipline. (If you have a file called "n_hdlc.o" in your
+modules directory, you have the line discipline.) It is \fInot
+recommended\fR on other machines or on Linux machines without the
+n_hdlc line discipline due to some known and unsolveable race
+conditions in a user-mode client.
+
+.TP
+.B CLAMPMSS
+The value at which to "clamp" the advertised MSS for TCP sessions. The
+default of 1412 should be fine.
+
+.TP
+.B LCP_INTERVAL
+How often (in seconds) \fBpppd\fR sends out LCP echo-request packets.
+
+.TP
+.B LCP_FAILURE
+How many unanswered LCP echo-requests must occur before \fBpppd\fR
+concludes the link is dead.
+
+.TP
+.B PPPOE_TIMEOUT
+If this many seconds elapse without any activity seen by \fBpppoe\fR,
+then \fBpppoe\fR exits.
+
+.TP
+.B FIREWALL
+One of NONE, STANDALONE or MASQUERADE. If NONE, then \fBadsl-connect\fR does
+not add any firewall rules. If STANDALONE, then it clears existing firewall
+rules and sets up basic rules for a standalone machine. If MASQUERADE, then
+it clears existing firewall rules and sets up basic rules for an Internet
+gateway. If you run services on your machine, these simple firewall scripts
+are inadequate; you'll have to make your own firewall rules and set FIREWALL
+to NONE.
+
+.TP
+.B PPPOE_EXTRA
+Any extra arguments to pass to \fBpppoe\fR
+
+.TP
+.B PPPD_EXTRA
+Any extra arguments to pass to \fBpppd\fR
+
+.TP
+.B LINUX_PLUGIN
+If non-blank, the full path of the Linux kernel-mode PPPoE plugin
+(typically \fB/etc/ppp/plugins/rp-pppoe.so\fR.) This forces
+\fBadsl-connect\fR to use kernel-mode PPPoE on Linux 2.4.x systems.
+This code is experimental and unsupported. Use of the plugin causes
+\fBadsl-connect\fR to ignore CLAMPMSS, PPPOE_EXTRA, SYNCHRONOUS and
+PPPOE_TIMEOUT.
+
+.P
+By using different configuration files with different PIDFILE
+settings, you can manage multiple PPPoE connections. Just specify the
+configuration file as an argument to \fBadsl-start\fR and \fBadsl-stop\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-connect(8), adsl-start(8), adsl-stop(8), pppd(8), adsl-setup(8),
+pppoe-wrapper(8)
+
diff --git a/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec b/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec
new file mode 100644
index 000000000..3222a602e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec
@@ -0,0 +1,98 @@
+Summary: PPP Over Ethernet (xDSL support)
+Name: rp-pppoe-gui
+Version: 3.0
+%if %(%{expand:test %{_vendor} != mandrake ; echo $?})
+Release: 1mdk
+%else
+Release: 1
+%endif
+Copyright: GPL
+Group: System Environment/Daemons
+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz
+Url: http://www.roaringpenguin.com/pppoe/
+Packager: David F. Skoll <dfs@roaringpenguin.com>
+BuildRoot: /tmp/pppoe-build
+Vendor: Roaring Penguin Software Inc.
+Requires: ppp >= 2.3.7
+Requires: rp-pppoe >= 3.0
+
+%description
+This is a graphical wrapper around the rp-pppoe PPPoE client. PPPoE is
+a protocol used by many DSL Internet Service Providers.
+
+%prep
+umask 022
+mkdir -p $RPM_BUILD_ROOT
+cd $RPM_BUILD_ROOT
+rm -rf $RPM_BUILD_ROOT/rp-pppoe-%{version}
+zcat $RPM_SOURCE_DIR/rp-pppoe-%{version}.tar.gz | tar xvf -
+cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/src
+./configure --mandir=%{_mandir}
+
+%build
+cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/gui
+make
+
+%install
+cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/gui
+make install RPM_INSTALL_ROOT=$RPM_BUILD_ROOT
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+# Install entry in KDE menu
+if test -n "$KDEDIR" ; then
+ mkdir -p "$KDEDIR/share/applnk/Internet"
+ cat <<EOF > "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+# KDE Config File
+[KDE Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+
+# Install entry in GNOME menus
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+ mkdir -p "$GNOMEDIR/gnome/apps/Internet"
+cat <<EOF > "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+[Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+
+%postun
+# Remove KDE menu entry
+if test -n "$KDEDIR" ; then
+ rm -f "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+fi
+
+# Remove GNOME menu entry
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+ rm -f "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+fi
+
+%files
+%defattr(-,root,root)
+%dir /etc/ppp/rp-pppoe-gui
+/usr/sbin/pppoe-wrapper
+/usr/bin/tkpppoe
+%{_mandir}/man1/tkpppoe.1*
+%{_mandir}/man1/pppoe-wrapper.1*
+/usr/share/rp-pppoe-gui/tkpppoe.html
+/usr/share/rp-pppoe-gui/mainwin-busy.png
+/usr/share/rp-pppoe-gui/mainwin-nonroot.png
+/usr/share/rp-pppoe-gui/mainwin.png
+/usr/share/rp-pppoe-gui/props-advanced.png
+/usr/share/rp-pppoe-gui/props-basic.png
+/usr/share/rp-pppoe-gui/props-nic.png
+/usr/share/rp-pppoe-gui/props-options.png
diff --git a/mdk-stage1/rp-pppoe/rp-pppoe.spec b/mdk-stage1/rp-pppoe/rp-pppoe.spec
new file mode 100644
index 000000000..622e3bb80
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/rp-pppoe.spec
@@ -0,0 +1,71 @@
+Summary: PPP Over Ethernet (xDSL support)
+Name: rp-pppoe
+Version: 3.0
+%if %(%{expand:test %{_vendor} != mandrake ; echo $?})
+Release: 1mdk
+%else
+Release: 1
+%endif
+Copyright: GPL
+Group: System Environment/Daemons
+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz
+Url: http://www.roaringpenguin.com/pppoe/
+Packager: David F. Skoll <dfs@roaringpenguin.com>
+BuildRoot: /tmp/pppoe-build
+Vendor: Roaring Penguin Software Inc.
+Requires: ppp >= 2.3.7
+
+%description
+PPPoE (Point-to-Point Protocol over Ethernet) is a protocol used by
+many ADSL Internet Service Providers. Roaring Penguin has a free
+client for Linux systems to connect to PPPoE service providers.
+
+The client is a user-mode program and does not require any kernel
+modifications. It is fully compliant with RFC 2516, the official PPPoE
+specification.
+
+%prep
+%setup
+cd src
+./configure --mandir=%{_mandir}
+
+%build
+cd src
+make
+
+%install
+cd src
+make install RPM_INSTALL_ROOT=$RPM_BUILD_ROOT
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc doc/CHANGES doc/HOW-TO-CONNECT doc/LICENSE doc/KERNEL-MODE-PPPOE README
+%config /etc/ppp/pppoe.conf
+%config /etc/ppp/pppoe-server-options
+%config /etc/ppp/firewall-masq
+%config /etc/ppp/firewall-standalone
+/etc/ppp/plugins/*
+/usr/sbin/pppoe
+/usr/sbin/pppoe-server
+/usr/sbin/pppoe-sniff
+/usr/sbin/pppoe-relay
+/usr/sbin/adsl-connect
+/usr/sbin/adsl-start
+/usr/sbin/adsl-stop
+/usr/sbin/adsl-setup
+/usr/sbin/adsl-status
+%{_mandir}/man5/pppoe.conf.5*
+%{_mandir}/man8/pppoe.8*
+%{_mandir}/man8/pppoe-server.8*
+%{_mandir}/man8/pppoe-relay.8*
+%{_mandir}/man8/pppoe-sniff.8*
+%{_mandir}/man8/adsl-connect.8*
+%{_mandir}/man8/adsl-start.8*
+%{_mandir}/man8/adsl-stop.8*
+%{_mandir}/man8/adsl-status.8*
+%{_mandir}/man8/adsl-setup.8*
+/etc/rc.d/init.d/adsl
+
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-connect.in b/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
new file mode 100755
index 000000000..85dfb3d8d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
@@ -0,0 +1,278 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# adsl-connect
+#
+# Shell script to connect to an ADSL provider using PPPoE
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-connect [config_file]
+# adsl-connect interface user [config_file]
+# Second form overrides USER and ETH from config file.
+# If config_file is omitted, defaults to /etc//ppp/pppoe.conf
+#
+#***********************************************************************
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+localstatedir=/var
+
+# Paths to programs
+IFCONFIG=/sbin/ifconfig
+PPPD=@PPPD@
+SETSID=@SETSID@
+PPPOE=@sbindir@/pppoe
+LOGGER="/usr/bin/logger -t `basename $0`"
+
+# Must be root
+if test "`@ID@ -u`" != 0 ; then
+ echo "$0: You must be root to run this script" >& 2
+ exit 1
+fi
+
+if test "$SETSID" != "" -a ! -x "$SETSID"; then
+ SETSID=""
+fi
+
+CONFIG=/etc//ppp/pppoe.conf
+USER=""
+ETH=""
+
+# Sort out command-line arguments
+case "$#" in
+ 1)
+ CONFIG="$1"
+ ;;
+ 3)
+ CONFIG="$3"
+ ;;
+esac
+
+if test ! -f "$CONFIG" -o ! -r "$CONFIG" ; then
+ echo "$0: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+
+# Check for command-line overriding of ETH and USER
+case "$#" in
+ 2|3)
+ ETH="$1"
+ USER="$2"
+ ;;
+esac
+
+# Check that config file is sane
+if test "$USER" = "" ; then
+ echo "$0: Check '$CONFIG' -- no setting for USER" >& 2
+ exit 1
+fi
+if test "$ETH" = "" ; then
+ echo "$0: Check '$CONFIG' -- no setting for ETH" >& 2
+ exit 1
+fi
+
+PPPD_PID=0
+
+# Catch common error
+if test "$DEBUG" = "1" ; then
+ echo "*** If you want to use DEBUG, invoke adsl-start, not adsl-connect."
+ exit 1
+fi
+
+if test "$DEBUG" != "" ; then
+ if test "$LINUX_PLUGIN" != "" ; then
+ echo "Cannot use DEBUG mode and LINUX_PLUGIN at the same time."
+ echo "Kernel-mode PPPoE is experimental and unsupported."
+ exit 1
+ fi
+ echo "* The following section identifies your Ethernet interface" >> $DEBUG
+ echo "* and user name. Some ISP's need 'username'; others" >> $DEBUG
+ echo "* need 'username@isp.com'. Try both" >> $DEBUG
+ echo "ETH=$ETH; USER=$USER" >> $DEBUG
+ echo "---------------------------------------------" >> $DEBUG
+fi
+
+# MTU of Ethernet card attached to modem MUST be 1500. This apparently
+# fails on some *BSD's, so we'll only do it under Linux
+
+if test `uname -s` = Linux ; then
+ $IFCONFIG $ETH up mtu 1500
+ # For 2.4 kernels. Will fail on 2.2.x, but who cares?
+ modprobe ppp_generic > /dev/null 2>&1
+ modprobe ppp_async > /dev/null 2>&1
+ modprobe ppp_synctty > /dev/null 2>&1
+ if test -n "$LINUX_PLUGIN" ; then
+ modprobe pppox > /dev/null 2>&1
+ modprobe pppoe > /dev/null 2>&1
+ fi
+fi
+
+if test "$SYNCHRONOUS" = "yes" ; then
+ PPPOE_SYNC=-s
+ PPPD_SYNC=sync
+ # Increase the chances of it working on Linux...
+ if test `uname -s` = Linux ; then
+ modprobe n_hdlc > /dev/null 2>&1
+ fi
+else
+ PPPOE_SYNC=""
+ PPPD_SYNC=""
+fi
+
+if test -n "$ACNAME" ; then
+ ACNAME="-C $ACNAME"
+fi
+
+if test -n "$SERVICENAME" ; then
+ SERVICENAME="-S $SERVICENAME"
+fi
+
+if test "$CLAMPMSS" = "no" ; then
+ CLAMPMSS=""
+else
+ CLAMPMSS="-m $CLAMPMSS"
+fi
+
+# If DNSTYPE is SERVER, we must use "usepeerdns" option to pppd.
+if test "$DNSTYPE" = "SERVER" ; then
+ USEPEERDNS=yes
+fi
+
+if test "$USEPEERDNS" = "yes" ; then
+ USEPEERDNS="usepeerdns"
+else
+ USEPEERDNS=""
+fi
+
+# Backward config file compatibility
+if test "$DEMAND" = "" ; then
+ DEMAND=no
+fi
+
+if test "$DEMAND" = "no" ; then
+ DEMAND=""
+else
+ DEMAND="demand persist idle $DEMAND 10.112.112.112:10.112.112.113 ipcp-accept-remote ipcp-accept-local connect true noipdefault ktune"
+fi
+
+case "$FIREWALL" in
+ STANDALONE)
+ . /etc/ppp/firewall-standalone
+ ;;
+ MASQUERADE)
+ . /etc/ppp/firewall-masq
+ ;;
+esac
+
+# If we're using kernel-mode PPPoE on Linux...
+if test "$LINUX_PLUGIN" != "" ; then
+ PLUGIN_OPTS="plugin $LINUX_PLUGIN $ETH"
+ modprobe pppoe > /dev/null 2>&1
+fi
+
+# Standard PPP options we always use
+PPP_STD_OPTIONS="$PLUGIN_OPTS noipdefault noauth default-asyncmap defaultroute hide-password nodetach $USEPEERDNS local mtu 1492 mru 1492 noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp user $USER lcp-echo-interval $LCP_INTERVAL lcp-echo-failure $LCP_FAILURE $PPPD_EXTRA"
+
+# Jigger DNS if required...
+if test "$DNSTYPE" = "SERVER" ; then
+ # Sorry, dude...
+ rm -f /etc/resolv.conf
+ ln -s /etc/ppp/resolv.conf /etc/resolv.conf
+elif test "$DNSTYPE" = "SPECIFY" ; then
+ # Sorry, dude...
+ rm -f /etc/resolv.conf
+ echo "nameserver $DNS1" > /etc/resolv.conf
+ if test -n "$DNS2" ; then
+ echo "nameserver $DNS2" >> /etc/resolv.conf
+ fi
+fi
+
+# PPPoE invocation
+PPPOE_CMD="$PPPOE -p $PPPOE_PIDFILE -I $ETH -T $PPPOE_TIMEOUT -U $PPPOE_SYNC $CLAMPMSS $ACNAME $SERVICENAME $PPPOE_EXTRA"
+if test "$DEBUG" != "" ; then
+ if test "$DEMAND" != "" ; then
+ echo "(Turning off DEMAND for debugging purposes)"
+ DEMAND=""
+ fi
+ echo "* The following section shows the pppd command we will invoke" >> $DEBUG
+ echo "pppd invocation" >> $DEBUG
+ echo "$SETSID $PPPD pty '$PPPOE_CMD' $PPP_STD_OPTIONS $PPPD_SYNC debug" >> $DEBUG
+ echo "---------------------------------------------" >> $DEBUG
+ $SETSID $PPPD pty "$PPPOE_CMD -D $DEBUG-0" \
+ $PPP_STD_OPTIONS \
+ $PPPD_SYNC \
+ debug >> $DEBUG 2>&1
+ echo "---------------------------------------------" >> $DEBUG
+ echo "* The following section is an extract from your log." >> $DEBUG
+ echo "* Look for error messages from pppd, such as" >> $DEBUG
+ echo "* a lack of kernel support for PPP, authentication failure" >> $DEBUG
+ echo "* etc." >> $DEBUG
+ echo "Extract from /var/log/messages" >> $DEBUG
+ grep 'ppp' /var/log/messages | tail -150 >> $DEBUG
+ date >> $DEBUG
+ echo "---------------------------------------------" >> $DEBUG
+ echo "* The following section is a dump of the packets" >> $DEBUG
+ echo "* sent and received by rp-pppoe. If you don't see" >> $DEBUG
+ echo "* any output, it's an Ethernet driver problem. If you only" >> $DEBUG
+ echo "* see three PADI packets and nothing else, check your cables" >> $DEBUG
+ echo "* and modem. Make sure the modem lights flash when you try" >> $DEBUG
+ echo "* to connect. Check that your Ethernet card is in" >> $DEBUG
+ echo "* half-duplex, 10Mb/s mode. If all else fails," >> $DEBUG
+ echo "* try using pppoe-sniff." >> $DEBUG
+ echo "rp-pppoe debugging dump" >> $DEBUG
+ cat $DEBUG-0 >> $DEBUG
+ rm -f $DEBUG-0
+ for i in 1 2 3 4 5 6 7 8 9 10 ; do
+ echo ""
+ echo ""
+ echo ""
+ done
+ echo "*** Finished debugging run. Please review the file"
+ echo "*** '$DEBUG' and try to"
+ echo "*** figure out what is going on."
+ echo "***"
+ echo "*** Unfortunately, we can NO LONGER accept debugging"
+ echo "*** output for analysis. Please do not send this to"
+ echo "*** Roaring Penguin; it is too time-consuming for"
+ echo "*** us to deal with all the analyses we have been sent."
+ exit 0
+fi
+
+echo $$ > $PIDFILE
+
+while [ true ] ; do
+ if test "$LINUX_PLUGIN" != "" ; then
+ $SETSID $PPPD $PPP_STD_OPTIONS $DEMAND &
+ echo "$!" > $PPPD_PIDFILE
+ else
+ $SETSID $PPPD pty "$PPPOE_CMD" \
+ $PPP_STD_OPTIONS \
+ $DEMAND \
+ $PPPD_SYNC &
+ echo "$!" > $PPPD_PIDFILE
+ fi
+ wait
+
+ # Run /etc/ppp/adsl-lost if it exists
+ test -x /etc/ppp/adsl-lost && /etc/ppp/adsl-lost
+
+ # Re-establish the connection
+ $LOGGER -p daemon.notice \
+ "ADSL connection lost; attempting re-connection."
+
+ # Wait a bit in case a problem causes tons of log messages :-)
+ sleep 5
+done
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in b/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
new file mode 100755
index 000000000..936f5fba7
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# adsl This script starts or stops an ADSL connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to ADSL provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+# Modifed to work with SuSE 6.4 linux by Gary Cameron.
+#
+# Source function library.
+#. /etc/rc.d/init.d/functions # For red hat?
+. /etc/rc.config # For SuSE, enables setting from /etc/rc.config
+
+#Tweak this
+restart_time=120
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+START=@sbindir@/adsl-start
+STOP=@sbindir@/adsl-stop
+STATUS=@sbindir@/adsl-status
+
+test "$ADSL_START" = "yes" || exit 0
+
+# The echo return value for success (defined in /etc/rc.config).
+return=$rc_done
+case "$1" in
+ start)
+ echo -n "Bringing up ADSL link"
+ $START > /dev/null 2>&1 || return=$rc_failed
+ echo -e "$return"
+ ;;
+
+ stop)
+ echo -n "Shutting down ADSL link"
+ $STOP > /dev/null 2>&1 || return=$rc_failed
+ echo -e "$return"
+ ;;
+
+ restart)
+ $0 stop
+ echo "Waiting" $restart_time "seconds for the host to reset itself"
+ sleep $restart_time #Note: Need time for host to reset itself
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: adsl {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in b/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
new file mode 100755
index 000000000..3b22f1345
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# adsl This script starts or stops an ADSL connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to ADSL provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Source function library if it exists
+test -r /etc/rc.d/init.d/functions && . /etc/rc.d/init.d/functions
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+START=@sbindir@/adsl-start
+STOP=@sbindir@/adsl-stop
+STATUS=@sbindir@/adsl-status
+case "$1" in
+ start)
+ echo -n "Bringing up ADSL link: "
+
+ $START
+ if [ $? = 0 ] ; then
+ echo success
+ touch /var/lock/subsys/adsl
+ else
+ echo failure
+ fi
+ ;;
+
+ stop)
+ echo -n "Shutting down ADSL link: "
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ echo success
+ rm -f /var/lock/subsys/adsl
+ else
+ echo failure
+ fi
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: adsl {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-init.in b/mdk-stage1/rp-pppoe/scripts/adsl-init.in
new file mode 100755
index 000000000..ab9146fd3
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-init.in
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# adsl This script starts or stops an ADSL connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to ADSL provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Source function library if it exists
+test -r /etc/rc.d/init.d/functions && . /etc/rc.d/init.d/functions
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+START=@sbindir@/adsl-start
+STOP=@sbindir@/adsl-stop
+STATUS=@sbindir@/adsl-status
+case "$1" in
+ start)
+ echo -n "Bringing up ADSL link"
+
+ $START
+ if [ $? = 0 ] ; then
+ touch /var/lock/subsys/adsl
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ stop)
+ echo -n "Shutting down ADSL link"
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ rm -f /var/lock/subsys/adsl
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: adsl {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-setup.in b/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
new file mode 100755
index 000000000..a8c7fa039
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
@@ -0,0 +1,346 @@
+#!/bin/sh
+#***********************************************************************
+#
+# adsl-setup
+#
+# All-purpose slicing/dicing shell script to configure rp-pppoe.
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#***********************************************************************
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+IFCONFIG=/sbin/ifconfig
+PPPD=@PPPD@
+PPPOE=@sbindir@/pppoe
+ECHO=@ECHO@
+LOGGER="/usr/bin/logger -t `basename $0`"
+
+CONFIG=/etc/ppp/pppoe.conf
+
+# Protect created files
+umask 077
+
+copy() {
+ cp $1 $2
+ if [ "$?" != 0 ] ; then
+ $ECHO "*** Error copying $1 to $2"
+ $ECHO "*** Quitting."
+ exit 1
+ fi
+}
+
+$ECHO "Welcome to the Roaring Penguin ADSL client setup. First, I will run"
+$ECHO "some checks on your system to make sure the PPPoE client is installed"
+$ECHO "properly..."
+$ECHO ""
+
+# Must be root
+if [ "`@ID@ -u`" != 0 ] ; then
+ $ECHO "$0: Sorry, you must be root to run this script"
+ exit 1
+fi
+
+# Prototype config file must exist
+if [ ! -r "$CONFIG" ] ; then
+ $ECHO "Oh, dear, I don't see the file '$CONFIG' anywhere. Please"
+ $ECHO "re-install the PPPoE client."
+ exit 1
+fi
+
+# Must have pppd
+if [ ! -x $PPPD ] ; then
+ $ECHO "Oops, I can't execute the program '$PPPD'. You"
+ $ECHO "must install the PPP software suite, version 2.3.10 or later."
+ exit 1
+fi
+
+. $CONFIG
+
+if [ "$DEMAND" = "" ] ; then
+ DEMAND=no
+fi
+
+# pppoe must exist
+if [ ! -x "$PPPOE" ] ; then
+ $ECHO "Oh, dear, I can't execute the program '$PPPOE'. Please"
+ $ECHO "re-install the rp-pppoe client."
+ exit 1
+fi
+
+$ECHO "Looks good! Now, please enter some information:"
+
+while [ true ] ; do
+ $ECHO ""
+ $ECHO "USER NAME"
+ $ECHO ""
+ $ECHO -n ">>> Enter your PPPoE user name (default $USER): "
+ read U
+
+ if [ "$U" = "" ] ; then
+ U="$USER"
+ fi
+
+ # Under Linux, "fix" the default interface if eth1 is not available
+ if test `uname -s` = "Linux" ; then
+ $IFCONFIG $ETH > /dev/null 2>&1 || ETH=eth0
+ fi
+ $ECHO ""
+ $ECHO "INTERFACE"
+ $ECHO ""
+ $ECHO ">>> Enter the Ethernet interface connected to the ADSL modem"
+ $ECHO "For Solaris, this is likely to be something like /dev/hme0."
+ $ECHO "For Linux, it will be ethn, where 'n' is a number."
+ $ECHO -n "(default $ETH): "
+ read E
+
+ if [ "$E" = "" ] ; then
+ E="$ETH"
+ fi
+
+ $ECHO ""
+ $ECHO "Do you want the link to come up on demand, or stay up continuously?"
+ $ECHO "If you want it to come up on demand, enter the idle time in seconds"
+ $ECHO "after which the link should be dropped. If you want the link to"
+ $ECHO "stay up permanently, enter 'no' (two letters, lower-case.)"
+ $ECHO "NOTE: Demand-activated links do not interact well with dynamic IP"
+ $ECHO "addresses. You may have some problems with demand-activated links."
+ $ECHO -n ">>> Enter the demand value (default $DEMAND): "
+ read D
+ if [ "$D" = "" ] ; then
+ D=$DEMAND
+ fi
+
+ $ECHO ""
+ $ECHO "DNS"
+ $ECHO ""
+ $ECHO "Please enter the IP address of your ISP's primary DNS server."
+ $ECHO "If your ISP claims that 'the server will provide DNS addresses',"
+ $ECHO "enter 'server' (all lower-case) here."
+ $ECHO "If you just press enter, I will assume you know what you are"
+ $ECHO "doing and not modify your DNS setup."
+ $ECHO -n ">>> Enter the DNS information here: "
+
+ read DNS1
+
+
+ if [ "$DNS1" != "" ] ; then
+ if [ "$DNS1" != "server" ] ; then
+ $ECHO "Please enter the IP address of your ISP's secondary DNS server."
+ $ECHO "If you just press enter, I will assume there is only one DNS server."
+ $ECHO -n ">>> Enter the secondary DNS server address here: "
+ read DNS2
+ fi
+ fi
+
+ while [ true ] ; do
+ $ECHO ""
+ $ECHO "PASSWORD"
+ $ECHO ""
+ stty -echo
+ $ECHO -n ">>> Please enter your PPPoE password: "
+ read PWD1
+ $ECHO ""
+ $ECHO -n ">>> Please re-enter your PPPoE password: "
+ read PWD2
+ $ECHO ""
+ stty echo
+ if [ "$PWD1" = "$PWD2" ] ; then
+ break
+ fi
+
+ $ECHO -n ">>> Sorry, the passwords do not match. Try again? (y/n)"
+ read ANS
+ case "$ANS" in
+ N|No|NO|Non|n|no|non)
+ $ECHO "OK, quitting. Bye."
+ exit 1
+ esac
+ done
+
+ # Firewalling
+ $ECHO ""
+ $ECHO "FIREWALLING"
+ $ECHO ""
+ if test `uname -s` != "Linux" ; then
+ $ECHO "Sorry, firewalling is only supported under Linux. Consult"
+ $ECHO "your operating system manuals for details on setting up"
+ $ECHO "packet filters for your system."
+ FIREWALL=NONE
+ else
+ $ECHO "Please choose the firewall rules to use. Note that these rules are"
+ $ECHO "very basic. You are strongly encouraged to use a more sophisticated"
+ $ECHO "firewall setup; however, these will provide basic security. If you"
+ $ECHO "are running any servers on your machine, you must choose 'NONE' and"
+ $ECHO "set up firewalling yourself. Otherwise, the firewall rules will deny"
+ $ECHO "access to all standard servers like Web, e-mail, ftp, etc. If you"
+ $ECHO "are using SSH, the rules will block outgoing SSH connections which"
+ $ECHO "allocate a privileged source port."
+ $ECHO ""
+ while [ true ] ; do
+ $ECHO "The firewall choices are:"
+ $ECHO "0 - NONE: This script will not set any firewall rules. You are responsible"
+ $ECHO " for ensuring the security of your machine. You are STRONGLY"
+ $ECHO " recommended to use some kind of firewall rules."
+ $ECHO "1 - STANDALONE: Appropriate for a basic stand-alone web-surfing workstation"
+ $ECHO "2 - MASQUERADE: Appropriate for a machine acting as an Internet gateway"
+ $ECHO " for a LAN"
+ $ECHO -n ">>> Choose a type of firewall (0-2): "
+ read a
+ if [ "$a" = 0 -o "$a" = 1 -o "$a" = 2 ] ; then
+ break
+ fi
+ $ECHO "Please enter a number from 0 to 2"
+ done
+
+ case "$a" in
+ 0)
+ FIREWALL=NONE
+ ;;
+ 1)
+ FIREWALL=STANDALONE
+ ;;
+ 2)
+ FIREWALL=MASQUERADE
+ ;;
+ esac
+ fi
+
+ $ECHO ""
+ $ECHO "** Summary of what you entered **"
+ $ECHO ""
+ $ECHO "Ethernet Interface: $E"
+ $ECHO "User name: $U"
+ if [ "$D" = "no" ] ; then
+ $ECHO "Activate-on-demand: No"
+ else
+ $ECHO "Activate-on-demand: Yes; idle timeout = $D seconds"
+ fi
+
+ if [ "$DNS1" != "" ] ; then
+ if [ "$DNS1" = "server" ] ; then
+ $ECHO "DNS addresses: Supplied by ISP's server"
+ else
+ $ECHO "Primary DNS: $DNS1"
+ if [ "$DNS2" != "" ] ; then
+ $ECHO "Secondary DNS: $DNS2"
+ fi
+ fi
+ else
+ $ECHO "DNS: Do not adjust"
+ fi
+ $ECHO "Firewalling: $FIREWALL"
+ $ECHO ""
+ while [ true ] ; do
+ $ECHO -n '>>> Accept these settings and adjust configuration files (y/n)? '
+ read ANS
+ case "ANS" in
+ Y|y|yes|Yes|oui|Oui)
+ ANS=y
+ ;;
+ N|n|no|No|non|Non)
+ ANS=n
+ ;;
+ esac
+ if [ "$ANS" = "y" -o "$ANS" = "n" ] ; then
+ break
+ fi
+ done
+ if [ "$ANS" = "y" ] ; then
+ break
+ fi
+done
+
+# Adjust configuration files. First to $CONFIG
+
+$ECHO "Adjusting $CONFIG"
+
+copy $CONFIG $CONFIG-bak
+if [ "$DNS1" = "server" ] ; then
+ DNSTYPE=SERVER
+ DNS1=""
+ USEPEERDNS=yes
+else
+ USEPEERDNS=no
+ if [ "$DNS1" = "" ] ; then
+ DNSTYPE=NOCHANGE
+ else
+ DNSTYPE=SPECIFY
+ fi
+fi
+
+# Where is pppd likely to put its pid?
+if [ -d /var/run ] ; then
+ VARRUN=/var/run
+else
+ VARRUN=/etc/ppp
+fi
+
+# Some #$(*& ISP's use a slash in the user name...
+sed -e "s&^USER=.*&USER='$U'&" \
+ -e "s&^ETH=.*&ETH='$E'&" \
+ -e "s&^PIDFILE=.*&PIDFILE=\"$VARRUN/\$CF_BASE-adsl.pid\"&" \
+ -e "s/^FIREWALL=.*/FIREWALL=$FIREWALL/" \
+ -e "s/^DEMAND=.*/DEMAND=$D/" \
+ -e "s/^DNSTYPE=.*/DNSTYPE=$DNSTYPE/" \
+ -e "s/^DNS1=.*/DNS1=$DNS1/" \
+ -e "s/^DNS2=.*/DNS2=$DNS2/" \
+ -e "s/^USEPEERDNS=.*/USEPEERDNS=$USEPEERDNS/" \
+ < $CONFIG-bak > $CONFIG
+
+if [ $? != 0 ] ; then
+ $ECHO "** Error modifying $CONFIG"
+ $ECHO "** Quitting"
+ exit 1
+fi
+
+if [ "$DNS1" != "" ] ; then
+ if [ "$DNS1" != "server" ] ; then
+ $ECHO "Adjusting /etc/resolv.conf"
+ if [ -r /etc/resolv.conf ] ; then
+ grep -s "MADE-BY-RP-PPPOE" /etc/resolv.conf > /dev/null 2>&1
+ if [ "$?" != 0 ] ; then
+ $ECHO " (But first backing it up to /etc/resolv.conf-bak)"
+ copy /etc/resolv.conf /etc/resolv.conf-bak
+ fi
+ fi
+ $ECHO "# MADE-BY-RP-PPPOE" > /etc/resolv.conf
+ $ECHO "nameserver $DNS1" >> /etc/resolv.conf
+ if [ "$DNS2" != "" ] ; then
+ $ECHO "nameserver $DNS2" >> /etc/resolv.conf
+ fi
+ fi
+fi
+
+$ECHO "Adjusting /etc/ppp/pap-secrets and /etc/ppp/chap-secrets"
+if [ -r /etc/ppp/pap-secrets ] ; then
+ $ECHO " (But first backing it up to /etc/ppp/pap-secrets-bak)"
+ copy /etc/ppp/pap-secrets /etc/ppp/pap-secrets-bak
+else
+ cp /dev/null /etc/ppp/pap-secrets-bak
+fi
+if [ -r /etc/ppp/chap-secrets ] ; then
+ $ECHO " (But first backing it up to /etc/ppp/chap-secrets-bak)"
+ copy /etc/ppp/chap-secrets /etc/ppp/chap-secrets-bak
+else
+ cp /dev/null /etc/ppp/chap-secrets-bak
+fi
+
+egrep -v "^$U|^\"$U\"" /etc/ppp/pap-secrets-bak > /etc/ppp/pap-secrets
+$ECHO "\"$U\" * \"$PWD1\"" >> /etc/ppp/pap-secrets
+egrep -v "^$U|^\"$U\"" /etc/ppp/chap-secrets-bak > /etc/ppp/chap-secrets
+$ECHO "\"$U\" * \"$PWD1\"" >> /etc/ppp/chap-secrets
+
+$ECHO ""
+$ECHO ""
+$ECHO ""
+$ECHO "Congratulations, it should be all set up!"
+$ECHO ""
+$ECHO "Type 'adsl-start' to bring up your ADSL link and 'adsl-stop' to bring"
+$ECHO "it down. Type 'adsl-status' to see the link status."
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-start.in b/mdk-stage1/rp-pppoe/scripts/adsl-start.in
new file mode 100755
index 000000000..33251a851
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-start.in
@@ -0,0 +1,186 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# adsl-start
+#
+# Shell script to bring up an ADSL connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-start [config_file]
+# adsl-start interface user [config_file]
+# Second form overrides USER and ETH from config file.
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+CONNECT=@sbindir@/adsl-connect
+ECHO=@ECHO@
+IFCONFIG=/sbin/ifconfig
+
+# Defaults
+CONFIG=/etc/ppp/pppoe.conf
+USER=""
+ETH=""
+ME=`basename $0`
+# Must be root
+if [ "`@ID@ -u`" != 0 ] ; then
+ $ECHO "$ME: You must be root to run this script" >& 2
+ exit 1
+fi
+
+# Debugging
+if [ "$DEBUG" = "1" ] ; then
+ $ECHO "*** Running in debug mode... please be patient..."
+ DEBUG=/tmp/pppoe-debug-$$
+ export DEBUG
+ mkdir $DEBUG
+ if [ "$?" != 0 ] ; then
+ $ECHO "Could not create directory $DEBUG... exiting"
+ exit 1
+ fi
+ DEBUG=$DEBUG/pppoe-debug.txt
+
+ # Initial debug output
+ $ECHO "---------------------------------------------" > $DEBUG
+ $ECHO "* The following section contains information about your system" >> $DEBUG
+ date >> $DEBUG
+ $ECHO "Output of uname -a" >> $DEBUG
+ uname -a >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ $ECHO "* The following section contains information about your network" >> $DEBUG
+ $ECHO "* interfaces. The one you chose for PPPoE should contain the words:" >> $DEBUG
+ $ECHO "* 'UP' and 'RUNNING'. If it does not, you probably have an Ethernet" >> $DEBUG
+ $ECHO "* driver problem." >> $DEBUG
+ $ECHO "Output of ifconfig -a" >> $DEBUG
+ $IFCONFIG -a >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ if [ "`uname -s`" = "Linux" ] ; then
+ $ECHO "* The following section contains information about kernel modules" >> $DEBUG
+ $ECHO "* If the module for your Ethernet card is 'tulip', you might" >> $DEBUG
+ $ECHO "* want to look for an updated version at http://www.scyld.com" >> $DEBUG
+ $ECHO "Output of lsmod" >> $DEBUG
+ lsmod >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ fi
+ $ECHO "* The following section lists your routing table." >> $DEBUG
+ $ECHO "* If you have an entry which starts with '0.0.0.0', you probably" >> $DEBUG
+ $ECHO "* have defined a default route and gateway, and pppd will" >> $DEBUG
+ $ECHO "* not create a default route using your ISP. Try getting" >> $DEBUG
+ $ECHO "* rid of this route." >> $DEBUG
+ $ECHO "Output of netstat -n -r" >> $DEBUG
+ netstat -n -r >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ $ECHO "Contents of /etc/resolv.conf" >> $DEBUG
+ $ECHO "* The following section lists DNS setup." >> $DEBUG
+ $ECHO "* If you can browse by IP address, but not name, suspect" >> $DEBUG
+ $ECHO "* a DNS problem." >> $DEBUG
+ cat /etc/resolv.conf >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ $ECHO "* The following section lists /etc/ppp/options." >> $DEBUG
+ $ECHO "* You should have NOTHING in that file." >> $DEBUG
+ $ECHO "Contents of /etc/ppp/options" >> $DEBUG
+ cat /etc/ppp/options >> $DEBUG 2>/dev/null
+ $ECHO "---------------------------------------------" >> $DEBUG
+else
+ DEBUG=""
+fi
+
+# Sort out command-line arguments
+case "$#" in
+ 1)
+ CONFIG="$1"
+ ;;
+ 3)
+ CONFIG="$3"
+ ;;
+esac
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+ $ECHO "$ME: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+# Check for command-line overriding of ETH and USER
+case "$#" in
+ 2|3)
+ ETH="$1"
+ USER="$2"
+ ;;
+esac
+
+# Check for pidfile
+if [ -r "$PIDFILE" ] ; then
+ PID=`cat "$PIDFILE"`
+ # Check if still running
+ kill -0 $PID > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ $ECHO "$ME: There already seems to be an ADSL connection up (PID $PID)" >& 2
+ exit 1
+ fi
+ # Delete bogus PIDFILE
+ rm -f "$PIDFILE" "$PIDFILE.pppd" "$PIDFILE.pppoe" "$PIDFILE.start"
+fi
+
+echo $$ > $PIDFILE.start
+
+# Start the connection in the background unless we're debugging
+if [ "$DEBUG" != "" ] ; then
+ $CONNECT "$@"
+ exit 0
+fi
+
+$CONNECT "$@" > /dev/null 2>&1 &
+CONNECT_PID=$!
+
+if [ "$CONNECT_TIMEOUT" = "" -o "$CONNECT_TIMEOUT" = 0 ] ; then
+ exit 0
+fi
+
+# Don't monitor connection if dial-on-demand
+if [ "$DEMAND" != "" -a "$DEMAND" != "no" ] ; then
+ exit 0
+fi
+
+# Monitor connection
+TIME=0
+while [ true ] ; do
+ @sbindir@/adsl-status $CONFIG > /dev/null 2>&1
+
+ # Looks like the interface came up
+ if [ $? = 0 ] ; then
+ # Print newline if standard input is a TTY
+ tty -s && $ECHO " Connected!"
+ exit 0
+ fi
+
+ if test -n "$FORCEPING" ; then
+ $ECHO -n "$FORCEPING"
+ else
+ tty -s && $ECHO -n "$PING"
+ fi
+ sleep $CONNECT_POLL
+ TIME=`expr $TIME + $CONNECT_POLL`
+ if [ $TIME -gt $CONNECT_TIMEOUT ] ; then
+ break
+ fi
+done
+
+$ECHO "TIMED OUT" >& 2
+# Timed out! Kill the adsl-connect process and quit
+kill $CONNECT_PID > /dev/null 2>&1
+exit 1
+
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-status b/mdk-stage1/rp-pppoe/scripts/adsl-status
new file mode 100755
index 000000000..18b100ab2
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-status
@@ -0,0 +1,82 @@
+#!/bin/sh
+#***********************************************************************
+#
+# adsl-status
+#
+# Shell script to report on status of ADSL connection
+#
+# Copyright (C) 2000-2001 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-status [config_file]
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+# Defaults
+CONFIG=/etc/ppp/pppoe.conf
+
+case "$#" in
+ 1)
+ CONFIG="$1"
+ ;;
+esac
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+ echo "$0: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+
+if [ "$DEMAND" != "no" ] ; then
+ echo "Note: You have enabled demand-connection; adsl-status may be inaccurate."
+fi
+
+# If no PPPOE_PIDFILE, connection is down, unless we're using the Linux plugin
+if [ "$LINUX_PLUGIN" = "" ] ; then
+ if [ ! -r "$PPPOE_PIDFILE" ] ; then
+ echo "adsl-status: Link is down (can't read pppoe PID file $PPPOE_PIDFILE)"
+ exit 1
+ fi
+fi
+
+# If no PPPD_PIDFILE, something fishy!
+if [ ! -r "$PPPD_PIDFILE" ] ; then
+ echo "adsl-status: Link is down (can't read pppd PID file $PPPD_PIDFILE)"
+ exit 1
+fi
+
+PPPD_PID=`cat "$PPPD_PIDFILE"`
+
+# Sigh. Some versions of pppd put PID files in /var/run; others put them
+# in /etc/ppp. Since it's too messy to figure out what pppd does, we
+# try both locations.
+for i in /etc/ppp/ppp*.pid /var/run/ppp*.pid ; do
+ if [ -r $i ] ; then
+ PID=`cat $i`
+ if [ "$PID" = "$PPPD_PID" ] ; then
+ IF=`basename $i .pid`
+ netstat -rn | grep " ${IF}\$" > /dev/null
+ # /sbin/ifconfig $IF | grep "UP.*POINTOPOINT" > /dev/null
+ if [ "$?" != "0" ] ; then
+ echo "adsl-status: Link is attached to $IF, but $IF is down"
+ exit 1
+ fi
+ echo "adsl-status: Link is up and running on interface $IF"
+ /sbin/ifconfig $IF
+ exit 0
+ fi
+ fi
+done
+
+echo "adsl-status: Link is down -- could not find interface corresponding to"
+echo "pppd pid $PPPD_PID"
+exit 1 \ No newline at end of file
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-stop.in b/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
new file mode 100755
index 000000000..af0867573
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
@@ -0,0 +1,84 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# adsl-stop
+#
+# Shell script to bring down an ADSL connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-stop [config_file]
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+ME="`basename $0`"
+LOGGER="/usr/bin/logger -t $ME"
+CONFIG="$1"
+if [ "$CONFIG" = "" ] ; then
+ CONFIG=/etc/ppp/pppoe.conf
+fi
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+ echo "$ME: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+STARTPID="$PIDFILE.start"
+
+# Backward config file compatibility
+if test "$DEMAND" = "" ; then
+ DEMAND=no
+fi
+
+# Ignore SIGTERM
+trap "" 15
+
+# Check for pidfile
+if [ -r "$PIDFILE" ] ; then
+ PID=`cat $PIDFILE`
+
+ # Check if still running
+ kill -0 $PID > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "$ME: The adsl-connect script (PID $PID) appears to have died" >& 2
+ fi
+
+ # Kill pppd, which should in turn kill pppoe
+ if [ -r "$PPPD_PIDFILE" ] ; then
+ PPPD_PID=`cat "$PPPD_PIDFILE"`
+ $LOGGER -p daemon.notice "Killing pppd"
+ echo "Killing pppd ($PPPD_PID)"
+ kill $PPPD_PID > /dev/null 2>&1 || exit 1
+ fi
+
+ # Kill adsl-start
+ PIDS=`cat $STARTPID`
+ kill -0 $PIDS > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ $LOGGER -p daemon.notice "Killing adsl-connect"
+ kill $PIDS > /dev/null 2>&1
+ fi
+
+ # Kill adsl-connect
+ $LOGGER -p daemon.notice "Killing adsl-connect"
+ echo "Killing adsl-connect ($PID)"
+ kill $PID > /dev/null 2>&1
+
+ rm -f "$PIDFILE" "$PPPD_PIDFILE" "$PPPOE_PIDFILE" "$STARTPID"
+else
+ echo "$ME: No ADSL connection appears to be running" >&2
+ exit 1
+fi
+
+exit 0
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