diff options
Diffstat (limited to 'mdk-stage1')
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=.*Ð='$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 |