summaryrefslogtreecommitdiff
authorkejun.gao <kejun.gao@amlogic.com>2011-08-22 08:02:05 (GMT)
committer kejun.gao <kejun.gao@amlogic.com>2011-08-22 08:02:05 (GMT)
commit621ec676857e70fcd29bad9be0c54f394fc14194 (patch)
treeb979204114346fdc6f6b33734d6cb3956535c3d9
parent3866cc7c2fe39b8385d93f62303eb363db61773d (diff)
downloadpppoe-621ec676857e70fcd29bad9be0c54f394fc14194.zip
pppoe-621ec676857e70fcd29bad9be0c54f394fc14194.tar.gz
pppoe-621ec676857e70fcd29bad9be0c54f394fc14194.tar.bz2
PPPoE: lib + jni + java.jar
Diffstat
-rwxr-xr-xAndroid.mk75
-rwxr-xr-xjni/README89
-rwxr-xr-xjni/SERVPOET18
-rwxr-xr-xjni/configs/firewall-masq71
-rwxr-xr-xjni/configs/firewall-standalone34
-rwxr-xr-xjni/configs/pap-secrets10
-rwxr-xr-xjni/configs/pppoe-server-options6
-rwxr-xr-xjni/configs/pppoe.conf140
-rwxr-xr-xjni/doc/CHANGES339
-rwxr-xr-xjni/doc/HOW-TO-CONNECT268
-rwxr-xr-xjni/doc/KERNEL-MODE-PPPOE98
-rwxr-xr-xjni/doc/LICENSE341
-rwxr-xr-xjni/doc/PROBLEMS5
-rwxr-xr-xjni/man/pppoe-connect.866
-rwxr-xr-xjni/man/pppoe-relay.8124
-rwxr-xr-xjni/man/pppoe-server.8184
-rwxr-xr-xjni/man/pppoe-setup.823
-rwxr-xr-xjni/man/pppoe-sniff.877
-rwxr-xr-xjni/man/pppoe-start.827
-rwxr-xr-xjni/man/pppoe-status.825
-rwxr-xr-xjni/man/pppoe-stop.821
-rwxr-xr-xjni/man/pppoe.8236
-rwxr-xr-xjni/man/pppoe.conf.5167
-rwxr-xr-xjni/pppoe_jni.cpp223
-rwxr-xr-xjni/pstart3
-rwxr-xr-xjni/pstop21
-rwxr-xr-xjni/scripts/pppoe-connect319
-rwxr-xr-xjni/scripts/pppoe-connect.in319
-rwxr-xr-xjni/scripts/pppoe-init66
-rwxr-xr-xjni/scripts/pppoe-init-suse64
-rwxr-xr-xjni/scripts/pppoe-init-suse.in64
-rwxr-xr-xjni/scripts/pppoe-init-turbolinux64
-rwxr-xr-xjni/scripts/pppoe-init-turbolinux.in64
-rwxr-xr-xjni/scripts/pppoe-init.in66
-rwxr-xr-xjni/scripts/pppoe-setup352
-rwxr-xr-xjni/scripts/pppoe-setup.in352
-rwxr-xr-xjni/scripts/pppoe-start196
-rwxr-xr-xjni/scripts/pppoe-start.in196
-rwxr-xr-xjni/scripts/pppoe-status84
-rwxr-xr-xjni/scripts/pppoe-stop96
-rwxr-xr-xjni/scripts/pppoe-stop.in96
-rwxr-xr-xjni/src/common.c651
-rwxr-xr-xjni/src/config.h146
-rwxr-xr-xjni/src/debug.c152
-rwxr-xr-xjni/src/discovery.c736
-rwxr-xr-xjni/src/if.c352
-rwxr-xr-xjni/src/libevent/Makefile42
-rwxr-xr-xjni/src/libevent/Makefile.in42
-rwxr-xr-xjni/src/libevent/event.c645
-rwxr-xr-xjni/src/libevent/event.h114
-rwxr-xr-xjni/src/libevent/event_sig.c265
-rwxr-xr-xjni/src/libevent/event_tcp.c577
-rwxr-xr-xjni/src/libevent/event_tcp.h87
-rwxr-xr-xjni/src/libevent/eventpriv.h46
-rwxr-xr-xjni/src/libevent/hash.c266
-rwxr-xr-xjni/src/libevent/hash.h54
-rwxr-xr-xjni/src/md5.c249
-rwxr-xr-xjni/src/md5.h34
-rwxr-xr-xjni/src/plugin.c469
-rwxr-xr-xjni/src/ppp.c262
-rwxr-xr-xjni/src/pppoe-server.c2137
-rwxr-xr-xjni/src/pppoe-server.h156
-rwxr-xr-xjni/src/pppoe-sniff.c266
-rwxr-xr-xjni/src/pppoe.c964
-rwxr-xr-xjni/src/pppoe.h347
-rwxr-xr-xjni/src/pppoe_cli.c58
-rwxr-xr-xjni/src/pppoe_ctrl.c129
-rwxr-xr-xjni/src/pppoe_ctrl.h30
-rwxr-xr-xjni/src/pppoe_status.c118
-rwxr-xr-xjni/src/pppoe_status.h20
-rwxr-xr-xjni/src/pppoe_wrapper.c154
-rwxr-xr-xjni/src/relay.c1559
-rwxr-xr-xjni/src/relay.h99
-rw-r--r--pppoe.xml8
-rwxr-xr-xsrc/com/amlogic/pppoe/PppoeOperation.java15
75 files changed, 16338 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100755
index 0000000..cba8d60
--- a/dev/null
+++ b/Android.mk
@@ -0,0 +1,75 @@
+LOCAL_PATH:= $(call my-dir)
+
+PPPOE_VERSION="\"3.0\""
+
+#MAKE_JAR
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+#LOCAL_JNI_SHARED_LIBRARIES := libpppoejni
+LOCAL_MODULE := pppoe
+include $(BUILD_JAVA_LIBRARY)
+
+#MAKE_XML
+include $(CLEAR_VARS)
+LOCAL_MODULE := pppoe.xml
+#LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := jni/src/pppoe.c \
+ jni/src/if.c \
+ jni/src/debug.c \
+ jni/src/common.c \
+ jni/src/ppp.c \
+ jni/src/discovery.c
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MODULE = pppoe
+LOCAL_CFLAGS := -DVERSION=$(PPPOE_VERSION)
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= jni/src/pppoe_ctrl.c\
+ jni/src/pppoe_status.c \
+ jni/pppoe_jni.cpp
+
+LOCAL_SHARED_LIBRARIES := libandroid_runtime libnativehelper
+LOCAL_SHARED_LIBRARIES += libc libcutils
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) $(LOCAL_PATH)/jni/src
+
+LOCAL_MODULE := libpppoejni
+LOCAL_MODULE_TAGS := optional
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+
+#include $(CLEAR_VARS)
+#LOCAL_SRC_FILES:= jni/src/pppoe_cli.c\
+# jni/src/pppoe_ctrl.c
+#
+#LOCAL_MODULE := pcli
+#LOCAL_CFLAGS += -O2
+#LOCAL_LDLIBS += -llog
+#LOCAL_SHARED_LIBRARIES := libcutils
+#include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= jni/src/pppoe_wrapper.c
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils libcrypto
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS := -DANDROID_CHANGES
+
+LOCAL_MODULE:= pppoe_wrapper
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/jni/README b/jni/README
new file mode 100755
index 0000000..2df6b47
--- a/dev/null
+++ b/jni/README
@@ -0,0 +1,89 @@
+# LIC: GPL
+
+pppoe: a PPP-over-Ethernet redirector for pppd
+Copyright (C) 2001-2005 Roaring Penguin Software Inc.
+
+Some 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
+DSL 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
+DSL 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
diff --git a/jni/SERVPOET b/jni/SERVPOET
new file mode 100755
index 0000000..b6fd5f7
--- a/dev/null
+++ b/jni/SERVPOET
@@ -0,0 +1,18 @@
+# LIC: GPL
+
+ServPoET
+--------
+
+ServPoET is a commercial version of the PPPoE server. While everything
+you received in this package is licensed under the GNU General Public
+License, ServPoET is not free software and is licensed under a traditional
+commercial license.
+
+ServPoET features RADIUS support, support for different realms,
+real-time server status reporting and a friendly curses-based GUI for
+administration. For information on ServPoET:
+
+Contact Fine Point Technologies, Inc. (http://www.finepoint.com/)
+
+--
+David F. Skoll <dfs@roaringpenguin.com>
diff --git a/jni/configs/firewall-masq b/jni/configs/firewall-masq
new file mode 100755
index 0000000..14b9971
--- a/dev/null
+++ b/jni/configs/firewall-masq
@@ -0,0 +1,71 @@
+#!/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.
+# LIC: GPL
+
+# Interface to Internet
+EXTIF=ppp+
+
+# NAT-Tables are different, so we can use ACCEPT everywhere (?)
+iptables -t nat -P PREROUTING ACCEPT
+iptables -t nat -P OUTPUT ACCEPT
+iptables -t nat -P POSTROUTING ACCEPT
+
+# Flush the NAT-Table
+iptables -t nat -F
+
+iptables -t filter -P INPUT DROP
+iptables -t filter -F
+
+# Allow incoming SSH
+#iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 22 -j ACCEPT
+
+# Log & Deny the rest of the privileged ports
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 0:1023 -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p udp --dport 0:1023 -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 0:1023 -j DROP
+iptables -t filter -A INPUT -i $EXTIF -p udp --dport 0:1023 -j DROP
+
+# Log & Deny NFS
+iptables -t filter -A INPUT -i $EXTIF -p udp --dport 2049 -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 2049 -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p udp --dport 2049 -j DROP
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 2049 -j DROP
+
+# Log & Deny X11
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 6000:6063 -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 6000:6063 -j DROP
+
+# Log & Deny XFS
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 7100 -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p tcp --dport 7100 -j DROP
+
+# Deny TCP connection attempts
+iptables -t filter -A INPUT -i $EXTIF -p tcp --syn -j LOG
+iptables -t filter -A INPUT -i $EXTIF -p tcp --syn -j DROP
+
+# Deny ICMP echo-requests
+iptables -t filter -A INPUT -i $EXTIF -p icmp --icmp-type echo-request -j DROP
+
+# Do masquerading
+iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
+
+# Enable forwarding
+echo 1 > /proc/sys/net/ipv4/ip_forward
+
+# no IP spoofing
+if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ] ; then
+ for i in /proc/sys/net/ipv4/conf/*/rp_filter; do
+ echo 1 > $i
+ done
+fi
+
+# Disable Source Routed Packets
+for i in /proc/sys/net/ipv4/conf/*/accept_source_route; do
+ echo 0 > $i
+done
diff --git a/jni/configs/firewall-standalone b/jni/configs/firewall-standalone
new file mode 100755
index 0000000..15b310e
--- a/dev/null
+++ b/jni/configs/firewall-standalone
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# firewall-standalone This script sets up firewall rules for a standalone
+# machine
+#
+# Copyright (C) 2005 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+# LIC: GPL
+
+# Interface to Internet
+EXTIF=ppp+
+
+iptables -P INPUT ACCEPT
+iptables -P OUTPUT ACCEPT
+iptables -P FORWARD DROP
+
+iptables -F FORWARD
+iptables -F INPUT
+iptables -F OUTPUT
+
+# Deny TCP and UDP packets to privileged ports
+iptables -A INPUT -p udp -i $EXTIF --dport 0:1023 -j LOG
+iptables -A INPUT -p tcp -i $EXTIF --dport 0:1023 -j LOG
+iptables -A INPUT -p udp -i $EXTIF --dport 0:1023 -j DROP
+iptables -A INPUT -p tcp -i $EXTIF --dport 0:1023 -j DROP
+
+# Deny TCP connection attempts
+iptables -A INPUT -i $EXTIF -p tcp --syn -j LOG
+iptables -A INPUT -i $EXTIF -p tcp --syn -j DROP
+
+# Deny ICMP echo-requests
+iptables -A INPUT -i $EXTIF -p icmp --icmp-type echo-request -j DROP
+
diff --git a/jni/configs/pap-secrets b/jni/configs/pap-secrets
new file mode 100755
index 0000000..e1bcaff
--- a/dev/null
+++ b/jni/configs/pap-secrets
@@ -0,0 +1,10 @@
+# LIC: GPL
+# 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/jni/configs/pppoe-server-options b/jni/configs/pppoe-server-options
new file mode 100755
index 0000000..b442db4
--- a/dev/null
+++ b/jni/configs/pppoe-server-options
@@ -0,0 +1,6 @@
+# PPP options for the PPPoE server
+# LIC: GPL
+require-pap
+login
+lcp-echo-interval 10
+lcp-echo-failure 2
diff --git a/jni/configs/pppoe.conf b/jni/configs/pppoe.conf
new file mode 100755
index 0000000..c222b2f
--- a/dev/null
+++ b/jni/configs/pppoe.conf
@@ -0,0 +1,140 @@
+#***********************************************************************
+#
+# pppoe.conf
+#
+# Configuration file for rp-pppoe. Edit as appropriate and install in
+# /etc/ppp/pppoe.conf
+#
+# NOTE: This file is used by the pppoe-start, pppoe-stop, pppoe-connect and
+# pppoe-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.
+#
+# LIC: GPL
+# $Id$
+#***********************************************************************
+
+# When you configure a variable, DO NOT leave spaces around the "=" sign.
+
+# Ethernet card connected to DSL modem
+ETH=eth1
+
+# PPPoE 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)
+# In old config files, this used to be called USEPEERDNS. Changed to
+# PEERDNS for better Red Hat compatibility
+PEERDNS=yes
+
+DNS1=
+DNS2=
+
+# Make the PPPoE connection your default route. Set to
+# DEFAULTROUTE=no if you don't want this.
+DEFAULTROUTE=yes
+
+### ONLY TOUCH THE FOLLOWING SETTINGS IF YOU'RE AN EXPERT
+
+# How long pppoe-start waits for a new PPP interface to appear before
+# concluding something went wrong. If you use 0, then pppoe-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 pppoe-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 pppoe-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 pppoe-connect script writes its process-ID.
+# Three files are actually used:
+# $PIDFILE contains PID of pppoe-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-pppoe.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 DSL 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 DSL 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=""
+
+
+########## DON'T CHANGE BELOW UNLESS YOU KNOW WHAT YOU ARE DOING
+# If you wish to COMPLETELY overrride the pppd invocation:
+# Example:
+# OVERRIDE_PPPD_COMMAND="pppd call dsl"
+
+# If you want pppoe-connect to exit when connection drops:
+# RETRY_ON_FAILURE=no
diff --git a/jni/doc/CHANGES b/jni/doc/CHANGES
new file mode 100755
index 0000000..fe315f4
--- a/dev/null
+++ b/jni/doc/CHANGES
@@ -0,0 +1,339 @@
+# LIC: GPL
+
+Changes from Version 3.9 to 3.10: (30 June 2008)
+
+- Fixed compilation problems on various platforms.
+
+- The Makefiles now use (standard) DESTDIR instead of (non-standard)
+ RPM_INSTALL_ROOT to relocate installed files.
+
+- Spec file has been updated (it had languished since 3.6.)
+
+Changes from Version 3.8 to 3.9: (21 June 2008)
+
+- pppoe-server has new "-x" option to limit the number of sessions per
+ MAC address.
+
+- Added proper timeout handling while waiting for PADO/PADS.
+
+- Fix race condition with some access concentrators that move very quickly
+ into session mode (problem noted by Luigi Sgro)
+
+- Fixed compilation problem on BSD.
+
+- Fixed compilation problems with old versions of gcc
+
+- Remove superfluous options in scripts/pppoe-connect.in
+
+Changes from Version 3.7 to 3.8: (2 April 2006)
+
+- Adjusted code and made it possible to disable debugging code to shrink
+ size of pppoe executable.
+
+- Fixed bug in MD5 code that caused pppoe-server to segfault on 64-bit
+ machines.
+
+- Made various functions and variables static that didn't need to be visible
+ outside their source files.
+
+Changes from Version 3.6 to 3.7:
+
+- Fixed typo in the firewall-standalone sample firewall script.
+ Fix courtesy of Robert Vogelgesang <vogel@users.sourceforge.net>
+
+- Added -O option to pppoe-server to let you specify a different default
+ options file for pppd instead of /etc/ppp/pppoe-server-options
+ Feature courtesy of Robert Vogelgesang <vogel@users.sourceforge.net>
+
+- Fixed some silliness and incorrectness in configure.in.
+ Feature courtesy of Robert Vogelgesang <vogel@users.sourceforge.net>
+
+- Fixed a typo in pppoe-connect.in that made it fail if used with the
+ kernel-mode plugin.
+
+- Make pppoe-server prepend "nic-" to interface name if used with
+ kernel-mode plugin. This lets you use interfaces that don't start
+ with "eth" more easily.
+
+
+Changes from Version 3.5 to 3.6:
+
+- Changed the names of commands from adsl-* to pppoe-* to more logically
+ name the scripts. NOTE INCOMPATIBILITY:
+
+ OLD NAME NEW NAME
+ adsl-start pppoe-start
+ adsl-stop pppoe-stop
+ adsl-status pppoe-status
+ adsl-connect pppoe-connect
+ adsl-setup pppoe-setup
+
+- Changed sample firewall scripts to use iptables instead of the old ipchains
+ command.
+
+- Updated KERNEL-MODE-PPPOE instructions to reflect more modern pppd that
+ is commonly distributed.
+
+- Make the userland pppoe daemon run as "nobody" if possible, once session
+ has started.
+
+- Make userland pppoe program somewhat safe if it is installed SUID or
+ SGID. Note that I still do *NOT* recommend a SUID/SGID pppoe.
+
+- Fix long-standing bug in pppoe-server that passed arguments to pppd in the
+ wrong order.
+
+- Fix kernel-mode plugin. It was broken by changes to pppd. The pppd
+ maintainers fixed their version of the plugin, but neglected to inform me.
+ Thanks a lot, guys!
+
+- Make plugin accept argument of the form "nix-XXXX" to force it to use
+ device "XXXX" as the Ethernet interface. This allows the use of devices
+ whose names do not start with "eth"
+
+
+Changes from Version 3.4 to 3.5:
+
+- Fixes for compilation on Solaris.
+
+
+Changes from Version 3.3 to 3.4:
+
+- INCOMPATIBILITY WITH EARLIER VERSIONS:
+ Kernel-mode plugin now is built against latest CVS ppp source rather than
+ Michal Ostrowski's patched version. If you use kernel-mode PPPoE, you
+ MUST use the CVS version of the ppp source code with rp-pppoe 3.4.
+
+- Print PPPoE session number when connection terminates. Thanks to
+ Alexander Dalloz for suggesting this.
+
+- Fixed a bug in MSS clamping -- it now works with protocol-field compression.
+ Thanks to Gerd v. Egidy for the patch.
+
+- Ignore SIGINT and SIGTERM so LCP termination packets make it out.
+
+
+Changes from Version 3.2 to 3.3:
+
+- Client works on Solaris again. It was broken in 3.2.
+
+- Added DEFAULTROUTE=yes|no option to configuration file.
+
+- Server parses address pool file better.
+
+- Server address pool allows ranges of addresses on a line: a.b.c.d-e
+
+- Added "-d" (=debug) and "-P" (=check pool file syntax) options to
+ pppoe-server.
+
+
+Changes from Version 3.1 to 3.2:
+
+- Client now ignores PADT's if they are from the wrong source MAC address
+ or to the wrong destination MAC address.
+
+- Minor fixes to Makefile.in for Turbolinux.
+
+
+Changes from Version 3.0 to 3.1:
+
+- Improved KERNEL-MODE-PPPOE instructions
+
+- Works with patched pppd 2.4.1
+
+- Many improvements to server: Added "-u" and "-r" options; server can
+ now respond to request on multiple Ethernet interfaces.
+
+- SECURITY BUG FIX: Server now ignores PADT's if they are from the wrong
+ source MAC address. You are STRONGLY RECOMMENDED to upgrade to 3.1
+ if you use pppoe-server in production.
+
+
+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/jni/doc/HOW-TO-CONNECT b/jni/doc/HOW-TO-CONNECT
new file mode 100755
index 0000000..f0d7185
--- a/dev/null
+++ b/jni/doc/HOW-TO-CONNECT
@@ -0,0 +1,268 @@
+# LIC: GPL
+
+$Id$
+
+This package lets you connect a Linux machine to an ISP that uses PPPoE.
+PPPoE is used by many DSL providers and some wireless providers.
+
+Follow these steps and you should have your PPPoE 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:
+
+ pppoe-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
+DSL 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 DSL 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/pppoe. To bring up the connection
+at boot time, just type this command as root:
+
+ chkconfig --add pppoe
+
+On non-Red-Hat systems, add this line to the end
+of /etc/rc.d/rc.local:
+
+ /usr/sbin/pppoe-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 PPPoE link
+-------------------------------------
+
+As root, bring up the link by typing: pppoe-start
+As root, bring down the link by typing: pppoe-stop
+
+That's it!
+
+--
+David F. Skoll <dfs@roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com |
+
+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
+
+Make sure you have "make", the C compiler and all development header
+files installed. I only test rp-pppoe on Linux. It might not work on
+*BSD and probably won't work on any other version of UNIX.
+
+-----------------------------------------------------------------------------
+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 DSL 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 "pppoe-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:
+
+ pppoe-stop; pppoe-start
+
+This should work around buggy routers which do not support Path MTU discovery.
+
+-----------------------------------------------------------------------------
+J) Whenever I connect using DSL, 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 pppoe-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 DSL 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 DSL modem. You might want to add these lines in
+pppoe-connect:
+
+ ifconfig ethx down
+ ifconfig ethx up mtu 1500
+
+which should reset things to sane values.
diff --git a/jni/doc/KERNEL-MODE-PPPOE b/jni/doc/KERNEL-MODE-PPPOE
new file mode 100755
index 0000000..03e6d2a
--- a/dev/null
+++ b/jni/doc/KERNEL-MODE-PPPOE
@@ -0,0 +1,98 @@
+# LIC: GPL
+
+RP-PPPoE now supports kernel-mode PPPoE on Linux kernels 2.4 or newer.
+However, the default "./go" build procedure does not make kernel-mode
+support.
+
+Here's what you need to do:
+
+0) Make sure you are running kernel 2.4 or newer on the machine you
+will build rp-pppoe on. You must have the following kernel
+configuration settings:
+
+ CONFIG_PPP=m or CONFIG_PPP=y
+ CONFIG_PPP_ASYNC=m or CONFIG_PPP_ASYNC=y
+ CONFIG_PPP_SYNC_TTY=m or CONFIG_PPP_SYNC_TTY=y
+ CONFIG_PPP_DEFLATE=m or CONFIG_PPP_DEFLATE=y
+ CONFIG_PPP_BSDCOMP=m or CONFIG_PPP_BSDCOMP=y
+ CONFIG_PPPOE=m or CONFIG_PPPOE=y
+ CONFIG_N_HDLC=m or CONFIG_N_HDLC=y
+ CONFIG_UNIX98_PTYS=y
+
+You also need a /dev/ppp file:
+
+ mknod --mode=664 /dev/ppp c 108 0
+
+You might want to add these lines to /etc/modules.conf:
+
+ alias char-major-108 ppp_generic
+ alias tty-ldisc-3 ppp_async
+ alias tty-ldisc-13 n_hdlc
+ alias tty-ldisc-14 ppp_synctty
+ alias net-pf-24 pppoe
+
+1) If you are running pppd older than 2.4.0, check out the latest
+version of the PPP software from the CVS repository at cvs.samba.org.
+Here's how to do this:
+
+ cvs -d :pserver:cvs@pserver.samba.org:/cvsroot login
+ # When prompted for a password, type "cvs"
+
+ # Change to the directory in which you want to store the PPP source
+ # code.
+ cd /path/to/checked/out/sources
+
+ # Check out the source
+ cvs -z5 -d :pserver:cvs@pserver.samba.org:/cvsroot co ppp
+
+If you are running pppd 2.4.0 or newer, and have the pppd development
+headers installed, you can skip steps 1 and 2.
+
+2) The source gets checked out into a subdirectory called ppp. If
+the source ends up in /path/to/checked/out/sources/ppp, then call
+that path $PPPDIR.
+
+Build and install the checked-out ppp code according to its instructions.
+
+3) Unpack rp-pppoe.
+
+4) In the rp-pppoe directory, change to src/ and type:
+
+ ./configure --enable-plugin=$PPPDIR
+
+where $PPPDIR, of course, refers to the checked-out "ppp" directory
+from cvs.samba.org.
+
+If you didn't check out the PPP software from cvs.samba.org, use:
+
+ ./configure --enable-plugin
+
+This will work if the header pppd/pppd.h is located in /usr/include
+or /usr/local/include.
+
+4) Type make; make install
+
+5) Edit /etc/ppp/pppoe.conf to include this line:
+
+ LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
+
+After that, pppoe-start should use kernel-mode PPPoE.
+
+The rp-pppoe.so plugin adds the following command-line options to pppd:
+
+ethXXX -- Use interface ethXXX as Ethernet interface
+brXXX -- Use interface brXXX as Ethernet interface
+nic-XXXX -- Use interface XXXX as the Ethernet interface
+
+rp_pppoe_service SERVICE_NAME -- Specify desired service name
+rp_pppoe_ac NAME -- Specify desired access concentrator name
+rp_pppoe_verbose 0|1 -- Print names of access concentrators
+
+rp_pppoe_sess nnnn:aa:bb:cc:dd:ee:ff -- Attach to existing session 'nnnn'
+ on AC with Ethernet address aa:bb:cc:dd:ee:ff
+ This skips the discovery phase.
+
+
+--
+David F. Skoll <dfs@roaringpenguin.com>
+
diff --git a/jni/doc/LICENSE b/jni/doc/LICENSE
new file mode 100755
index 0000000..c9fc902
--- a/dev/null
+++ b/jni/doc/LICENSE
@@ -0,0 +1,341 @@
+# LIC: GPL
+
+ 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/jni/doc/PROBLEMS b/jni/doc/PROBLEMS
new file mode 100755
index 0000000..0f77d61
--- a/dev/null
+++ b/jni/doc/PROBLEMS
@@ -0,0 +1,5 @@
+# LIC: GPL
+
+Problems?
+
+See the last section of HOW-TO-CONNECT.
diff --git a/jni/man/pppoe-connect.8 b/jni/man/pppoe-connect.8
new file mode 100755
index 0000000..cbb7a6b
--- a/dev/null
+++ b/jni/man/pppoe-connect.8
@@ -0,0 +1,66 @@
+.\" LIC: GPL
+.TH PPPOE-CONNECT 8 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe-connect \- Shell script to manage a PPPoE link
+
+.SH SYNOPSIS
+.B pppoe-connect \fR[\fIconfig_file\fR]
+.P
+.B pppoe-connect \fR\fIinterface user\fR [\fIconfig_file\fR]
+
+
+.SH DESCRIPTION
+\fBpppoe-connect\fR is a shell script which manages a PPPoE 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 \fBpppoe-connect\fR
+directly. Instead, use \fBpppoe-start\fR to bring up the PPPoE connection.
+.P
+\fBpppoe-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 \fBpppoe-connect\fR re-establishes the connection. In addition,
+each time the connection is dropped or cannot be established,
+\fBpppoe-connect\fR executes the script \fB/etc/ppp/pppoe-lost\fR if it
+exists and is executable.
+
+.P
+The shell script \fBpppoe-stop\fR causes \fBpppoe-connect\fR to break out
+of its loop, bring the connection down, and exit.
+
+.SH TECHNICAL DETAILS
+\fBpppoe-connect\fR uses the following shell variables from the
+configuration file:
+
+.TP
+.B ETH
+The Ethernet interface connected to the DSL modem (for example, eth0).
+
+.TP
+.B USER
+The PPPoE user-id (for example, b1xxnxnx@sympatico.ca).
+
+.TP
+.B PIDFILE
+A file in which to write the process-ID of the pppoe-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 \fBpppoe-start\fR and
+\fBpppoe-stop\fR.
+
+.SH AUTHOR
+\fBpppoe-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), pppoe-start(8), pppoe-stop(8), pppd(8), pppoe.conf(5), pppoe-setup(8), pppoe-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/jni/man/pppoe-relay.8 b/jni/man/pppoe-relay.8
new file mode 100755
index 0000000..9e52a30
--- a/dev/null
+++ b/jni/man/pppoe-relay.8
@@ -0,0 +1,124 @@
+.\" LIC: GPL
+.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
+pppoe-start(8), pppoe-stop(8), pppoe-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), pppoe-setup(8), pppoe-status(8), pppoe-sniff(8), pppoe-server(8)
+
diff --git a/jni/man/pppoe-server.8 b/jni/man/pppoe-server.8
new file mode 100755
index 0000000..b24c10b
--- a/dev/null
+++ b/jni/man/pppoe-server.8
@@ -0,0 +1,184 @@
+.\" LIC: GPL
+.TH PPPOE-SERVER 8 "21 June 2008"
+.\""
+.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. You can supply multiple \fB\-I\fR options if you want the
+server to respond on more than one interface.
+
+.TP
+.B \-T \fItimeout\fR
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details. If you are using kernel-mode PPPoE, this option has \fIno effect\fR.
+
+.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 \-S \fIname\fR
+Offer a service named \fIname\fR. Multiple \fB\-S\fR options may
+be specified; each one causes the named service to be advertised
+in a Service-Name tag in the PADO frame. The first \fB\-S\fR option
+specifies the default service, and is used if the PPPoE client
+requests a Service-Name of length zero.
+
+.TP
+.B \-m \fIMSS\fR
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details. If you are using kernel-mode PPPoE, this option has \fIno effect\fR.
+
+.TP
+.B \-x \fIn\fR
+Limit the number of sessions per peer MAC address to \fIn\fR. If a given
+MAC address attempts to create more than \fIn\fR sessions, then its
+PADI and PADR packets are ignored. If you set \fIn\fR to 0 (the default),
+then no limit is imposed on the number of sessions per peer MAC address.
+
+.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 \-O \fIfname\fR
+This option causes \fBpppoe-server\fR to tell \fBpppd\fR to use the option
+file \fIfname\fR instead of the default \fI/etc/ppp/pppoe-server-options\fR.
+
+.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.
+
+In addition to containing IP addresses, the pool file can contain lines
+of the form:
+
+.nf
+ a.b.c.d-e
+.fi
+
+which includes all IP addresses from a.b.c.d to a.b.c.e. For example,
+the line:
+
+.nf
+ 1.2.3.4-7
+.fi
+
+is equivalent to:
+
+.nf
+ 1.2.3.4
+ 1.2.3.5
+ 1.2.3.6
+ 1.2.3.7
+.fi
+
+.TP
+.B \-r
+Tells the PPPoE server to randomly permute session numbers. Instead of
+handing out sessions in order, the session numbers are assigned in an
+unpredictable order.
+
+.TP
+.B \-u
+Tells the server to invoke \fBpppd\fR with the \fIunit\fR option. Note
+that this option only works for \fBpppd\fR version 2.4.0 or newer.
+
+.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 \-k
+The \fB\-k\fR option tells the server to use kernel-mode PPPoE on Linux.
+This option is available only on Linux kernels 2.4.0 and later, and
+only if the server was built with kernel-mode support.
+
+.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
+pppoe-start(8), pppoe-stop(8), pppoe-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), pppoe-setup(8), pppoe-status(8), pppoe-sniff(8), pppoe-relay(8)
+
diff --git a/jni/man/pppoe-setup.8 b/jni/man/pppoe-setup.8
new file mode 100755
index 0000000..636cd56
--- a/dev/null
+++ b/jni/man/pppoe-setup.8
@@ -0,0 +1,23 @@
+.\" LIC: GPL
+.TH PPPOE-SETUP 8 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe-setup \- Shell script to configure Roaring Penguin PPPoE client
+.SH SYNOPSIS
+.B pppoe-setup
+
+.SH DESCRIPTION
+\fBpppoe-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 \fBpppoe-start\fR, \fBpppoe-stop\fR and \fBpppoe-connect\fR scripts.
+
+.SH AUTHOR
+\fBpppoe-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), pppoe-start(8), pppoe-stop(8), pppoe-connect(8), pppd(8),
+pppoe.conf(5), pppoe-status(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
diff --git a/jni/man/pppoe-sniff.8 b/jni/man/pppoe-sniff.8
new file mode 100755
index 0000000..95c9e24
--- a/dev/null
+++ b/jni/man/pppoe-sniff.8
@@ -0,0 +1,77 @@
+.\" LIC: GPL
+.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
+pppoe-start(8), pppoe-stop(8), pppoe-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), pppoe-setup(8), pppoe-status(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/jni/man/pppoe-start.8 b/jni/man/pppoe-start.8
new file mode 100755
index 0000000..aa2ce95
--- a/dev/null
+++ b/jni/man/pppoe-start.8
@@ -0,0 +1,27 @@
+.\" LIC: GPL
+.TH PPPOE-START 8 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe-start \- Shell script to bring up a PPPoE link
+.SH SYNOPSIS
+.B pppoe-start \fR[\fIconfig_file\fR]
+.P
+.B pppoe-start \fR\fIinterface user\fR [\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBpppoe-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
+\fBpppoe-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), pppoe-stop(8), pppoe-connect(8), pppd(8), pppoe.conf(5),
+pppoe-setup(8), pppoe-status(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
diff --git a/jni/man/pppoe-status.8 b/jni/man/pppoe-status.8
new file mode 100755
index 0000000..65ba874
--- a/dev/null
+++ b/jni/man/pppoe-status.8
@@ -0,0 +1,25 @@
+.\" LIC: GPL
+.TH PPPOE-STATUS 8 "16 March 2000"
+.UC 4
+.SH NAME
+pppoe-status \- Shell script to report on status of PPPoE link
+.SH SYNOPSIS
+.B pppoe-status \fR[\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBpppoe-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
+\fBpppoe-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), pppoe-start(8), pppoe-connect(8), pppd(8), pppoe.conf(5),
+pppoe-setup(8), pppoe-stop(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
+
diff --git a/jni/man/pppoe-stop.8 b/jni/man/pppoe-stop.8
new file mode 100755
index 0000000..123ca1b
--- a/dev/null
+++ b/jni/man/pppoe-stop.8
@@ -0,0 +1,21 @@
+.\" LIC: GPL
+.TH PPPOE-STOP 8 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe-stop \- Shell script to shut down a PPPoE link
+.SH SYNOPSIS
+.B pppoe-stop \fR[\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBpppoe-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
+\fBpppoe-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), pppoe-start(8), pppoe-connect(8), pppd(8), pppoe.conf(5), pppoe-setup(8), pppoe-status(8), pppoe-sniff(8), pppoe-relay(8), pppoe-server(8)
+
diff --git a/jni/man/pppoe.8 b/jni/man/pppoe.8
new file mode 100755
index 0000000..6ef60c6
--- a/dev/null
+++ b/jni/man/pppoe.8
@@ -0,0 +1,236 @@
+.\" LIC: GPL
+.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 DSL 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
+pppoe-start(8), pppoe-stop(8), pppoe-connect(8), pppd(8), pppoe.conf(5), pppoe-setup(8), pppoe-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/jni/man/pppoe.conf.5 b/jni/man/pppoe.conf.5
new file mode 100755
index 0000000..58f77ca
--- a/dev/null
+++ b/jni/man/pppoe.conf.5
@@ -0,0 +1,167 @@
+.\" LIC: GPL
+.TH PPPOE.CONF 5 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe.conf \- Configuration file used by \fBpppoe-start\fR(8),
+\fBpppoe-stop\fR(8), \fBpppoe-status(8)\fR and \fBpppoe-connect\fR(8).
+
+.SH DESCRIPTION
+\fB/etc/ppp/pppoe.conf\fR is a shell script which contains configuration
+information for Roaring Penguin's PPPoE scripts. Note that \fBpppoe.conf\fR
+is used only by the various pppoe-* 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 DSL modem (for example, eth0).
+
+.TP
+.B USER
+The PPPoE 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, \fBpppoe-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 \fBpppoe-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,
+\fBpppoe-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) \fBpppoe-start\fR should check to see if a new PPP
+interface has come up. If this is set to 0, the \fBpppoe-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) \fBpppoe-start\fR should wait for a new PPP interface
+to come up before concluding that \fBpppoe-connect\fR has failed and killing
+the session.
+
+.TP
+.B PING
+A character which is echoed every \fBCONNECT_POLL\fR seconds while
+\fBpppoe-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
+\fBpppoe-start\fR is waiting for the PPP interface to come up. Similar
+to \fBPING\fR, but the character is echoed even if \fBpppoe-start\fR's
+standard output is not a tty.
+
+.TP
+.B PIDFILE
+A file in which to write the process-ID of the pppoe-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 \fBpppoe-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
+\fBpppoe-connect\fR to use kernel-mode PPPoE on Linux 2.4.x systems.
+This code is experimental and unsupported. Use of the plugin causes
+\fBpppoe-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 \fBpppoe-start\fR and \fBpppoe-stop\fR.
+
+.SH SEE ALSO
+pppoe(8), pppoe-connect(8), pppoe-start(8), pppoe-stop(8), pppd(8), pppoe-setup(8),
+pppoe-wrapper(8)
+
diff --git a/jni/pppoe_jni.cpp b/jni/pppoe_jni.cpp
new file mode 100755
index 0000000..5c91401
--- a/dev/null
+++ b/jni/pppoe_jni.cpp
@@ -0,0 +1,223 @@
+#define LOG_NDEBUG 0
+#define LOCAL_TAG "PPPOE_JNI"
+
+
+//$as/dalvik/libnativehelper/include/nativehelper/jni.h
+#include <jni.h>
+
+#include <JNIHelp.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/Log.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sys/un.h>
+#include "pppoe_ctrl.h"
+#include "pppoe_status.h"
+#include <android/log.h>
+
+#define PPPOE_PLUGIN_CMD_LEN_MAX 256
+#define PPPOE_CONNECT_CMD_LEN_MAX 512
+
+#define TRACE() LOGI("[%s::%d]\n",__FUNCTION__,__LINE__)
+using namespace android;
+
+
+struct fields_t {
+ JavaVM *gJavaVM ;
+ JNIEnv* env;
+ jmethodID post_event;
+};
+
+static struct fields_t fields;
+
+extern int get_pppoe_status( const char *ether_if_name);
+
+static char pppoe_connect_cmd[PPPOE_CONNECT_CMD_LEN_MAX];
+
+static char pppoe_disconnect_cmd[512] = {"ppp-stop"};
+
+
+static char pppoe_plugin_cmd[PPPOE_PLUGIN_CMD_LEN_MAX];
+
+static char pppd_options[] = {"debug logfd 1 noipdefault noauth default-asyncmap defaultroute nodetach mtu 1492 mru 1492 noaccomp nodeflate nopcomp novj novjccomp lcp-echo-interval 20 lcp-echo-failure 3"};
+
+
+
+static char* create_pppoe_plugin_cmd(char *pid_file, char *ether_if)
+{
+ int len;
+ len = snprintf(pppoe_plugin_cmd, PPPOE_PLUGIN_CMD_LEN_MAX,
+ "'pppoe -p %s -I %s -T 80 - U -m 1412'",
+ pid_file, ether_if);
+ if ( len < 0 || len >= PPPOE_PLUGIN_CMD_LEN_MAX ) {
+ return NULL;
+ }
+
+ return pppoe_plugin_cmd;
+}
+
+
+static char* create_pppoe_connect_cmd
+(char *plugin_cmd, char *options, char *username, char *pwd)
+{
+ int len;
+ len = snprintf(pppoe_connect_cmd, PPPOE_CONNECT_CMD_LEN_MAX,
+ "pppd pty %s %s user %s password %s &",
+ plugin_cmd, options, username, pwd);
+ if ( len < 0 || len >= PPPOE_CONNECT_CMD_LEN_MAX ) {
+ return NULL;
+ }
+
+ return pppoe_connect_cmd;
+}
+
+
+static jboolean com_amlogic_PppoeOperation_connect
+(JNIEnv *env, jobject obj, jstring jstr_account, jstring jstr_passwd)
+{
+ char *p_user;
+ char *p_passwd;
+ struct pppoe_ctrl * ctrl;
+ char *p;
+
+ p_user = (char *)env->GetStringUTFChars(jstr_account, NULL);
+ p_passwd = (char *)env->GetStringUTFChars(jstr_passwd, NULL);
+
+ p = create_pppoe_plugin_cmd((char*)PPPOE_PIDFILE, (char*)"eth0");
+ if (!p) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"failed to create plug_in command\n");
+ return -1;
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"plug_in command: %s\n", p);
+
+ p = create_pppoe_connect_cmd(p, pppd_options, p_user, p_passwd);
+ if (!p) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"failed to create connect command\n");
+ return -1;
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"connect command: %s\n", p);
+
+
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"ppp.connect\n");
+
+ ctrl = pppoe_ctrl_open("/dev/socket/pppd");
+ if (ctrl == NULL) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG, "Failed to connect to pppd\n");
+ return -1;
+ }
+
+ pppoe_ctrl_request(ctrl, pppoe_connect_cmd, strlen(pppoe_connect_cmd));
+
+ pppoe_ctrl_close(ctrl);
+
+ env->ReleaseStringUTFChars(jstr_account, p_user);
+ env->ReleaseStringUTFChars(jstr_passwd, p_passwd);
+
+ return 1;
+}
+
+
+
+jboolean com_amlogic_PppoeOperation_disconnect
+(JNIEnv *env, jobject obj)
+{
+ struct pppoe_ctrl * ctrl;
+
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"ppp.disconnect\n");
+
+ ctrl = pppoe_ctrl_open("/dev/socket/pppd");
+ if (ctrl == NULL) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG, "Failed to connect to pppd\n");
+ return -1;
+ }
+
+ pppoe_ctrl_request(ctrl, pppoe_disconnect_cmd, strlen(pppoe_disconnect_cmd));
+
+ pppoe_ctrl_close(ctrl);
+
+ return 1;
+}
+
+
+jint com_amlogic_PppoeOperation_status
+(JNIEnv *env, jobject obj)
+{
+ int status;
+
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"ppp.status\n");
+
+ status = get_pppoe_status("eth0");
+ return status;
+}
+
+
+static JNINativeMethod gPppoeJNIMethods[] = {
+ /* name, signature, funcPtr */
+ { "connect", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*) com_amlogic_PppoeOperation_connect },
+ { "disconnect", "()Z", (void*) com_amlogic_PppoeOperation_disconnect },
+ { "status", "()I", (void*) com_amlogic_PppoeOperation_status },
+};
+
+
+#define PPPOE_CLASS_NAME "com/amlogic/pppoe/PppoeOperation"
+
+
+int register_pppoe_jni(JNIEnv* env)
+{
+ int ret;
+ jclass pppoe = env->FindClass(PPPOE_CLASS_NAME);
+ if (NULL == pppoe) {
+ LOGI("%s:Unable to find class %s", __FUNCTION__, PPPOE_CLASS_NAME);
+ return -1;
+ }
+ else {
+ LOGI("%s:class %s FOUND", __FUNCTION__, PPPOE_CLASS_NAME);
+ }
+
+ TRACE();
+ ret = android::AndroidRuntime::registerNativeMethods(env,
+ PPPOE_CLASS_NAME, gPppoeJNIMethods, NELEM(gPppoeJNIMethods));
+ return ret;
+}
+
+
+JNIEXPORT jint
+JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ jint ret;
+ JNIEnv* env = NULL;
+ TRACE();
+ if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env) {
+ LOGE("GetEnv failed!");
+ return -1;
+ }
+ fields.gJavaVM = vm;
+ fields.env = env;
+ TRACE();
+ ret = register_pppoe_jni(env);
+ LOGI("register_pppoe_jni=%d\n", ret);
+ if (ret == 0) {
+ return JNI_VERSION_1_4;
+ } else {
+ return -1;
+ }
+}
+
+
+JNIEXPORT void
+JNI_OnUnload(JavaVM* vm, void* reserved)
+{
+ return;
+}
+
+
diff --git a/jni/pstart b/jni/pstart
new file mode 100755
index 0000000..029e405
--- a/dev/null
+++ b/jni/pstart
@@ -0,0 +1,3 @@
+#! /system/bin/sh
+pppd pty 'pppoe -p /var/run/pppoe.pid -I eth0 -T 80 -U -m 1412' debug logfd 1 noipdefault noauth default-asyncmap defaultroute nodetach mtu 1492 mru 1492 noaccomp nodeflate nopcomp novj novjccomp user gaokj password fatpig lcp-echo-interval 20 lcp-echo-failure 3 &
+
diff --git a/jni/pstop b/jni/pstop
new file mode 100755
index 0000000..2ff6a00
--- a/dev/null
+++ b/jni/pstop
@@ -0,0 +1,21 @@
+#!/system/bin/sh
+
+PPPOE_PIDFILE="/var/run/pppoe.pid"
+
+# Check for pidfile
+ PPPOE_PID=`cat $PPPOE_PIDFILE`
+ echo "$PPPOE_PIDFILE"
+ echo "$PPPOE_PID"
+ # Check if still running
+ kill -0 $PPPOE_PID > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "The pppoe(PID $PPPOE_PID) appears to have died" >& 2
+ fi
+
+ # Kill pppoe, which should in turn kill pppd
+ echo "Killing pppoe (PID $PPPOE_PID)"
+ kill -9 $PPPOE_PID > /dev/null 2>&1 || exit 1
+
+ rm "$PPPOE_PIDFILE"
+
+exit 0
diff --git a/jni/scripts/pppoe-connect b/jni/scripts/pppoe-connect
new file mode 100755
index 0000000..88dd15c
--- a/dev/null
+++ b/jni/scripts/pppoe-connect
@@ -0,0 +1,319 @@
+#!/bin/sh
+# ../scripts/pppoe-connect. Generated from pppoe-connect.in by configure.
+#***********************************************************************
+#
+# pppoe-connect
+#
+# Shell script to connect to a PPPoE provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-connect [config_file]
+# pppoe-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=/usr
+exec_prefix=${prefix}
+localstatedir=/var
+
+# Paths to programs
+IFCONFIG=/sbin/ifconfig
+PPPD=pppd
+SETSID=/usr/bin/setsid
+PPPOE=${exec_prefix}/sbin/pppoe
+LOGGER="/usr/bin/logger -t `basename $0`"
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+# Must be root
+if test "`/usr/bin/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
+export CONFIG
+. $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 pppoe-start, not pppoe-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
+ SERVICENAMEOPT="-S $SERVICENAME"
+else
+ SERVICENAMEOPT=""
+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
+ PEERDNS=yes
+ USEPEERDNS=yes
+fi
+
+if test "$PEERDNS" = "yes" ; then
+ PEERDNS="usepeerdns"
+else
+ PEERDNS=""
+fi
+
+# Backward config file compatibility -- PEERDNS used to be USEPEERDNS
+if test "$USEPEERDNS" = "yes" ; then
+ PEERDNS="usepeerdns"
+fi
+if test "$USEPEERDNS" = "no" ; then
+ PEERDNS=""
+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 nic-$ETH"
+ if test -n "$SERVICENAME" ; then
+ PLUGIN_OPTS="$PLUGIN_OPTS rp_pppoe_service $SERVICENAME"
+ fi
+ modprobe pppoe > /dev/null 2>&1
+fi
+
+if test "$DEFAULTROUTE" != "no" ; then
+ DEFAULTROUTE="defaultroute"
+else
+ DEFAULTROUTE=""
+fi
+
+# Standard PPP options we always use
+PPP_STD_OPTIONS="$PLUGIN_OPTS noipdefault noauth default-asyncmap $DEFAULTROUTE hide-password nodetach $PEERDNS mtu 1492 mru 1492 noaccomp 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 $SERVICENAMEOPT $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
+ if test -f "/var/log/messages" ; then
+ echo "Extract from /var/log/messages" >> $DEBUG
+ grep 'ppp' /var/log/messages | tail -150 >> $DEBUG
+ elif test -f "/var/adm/messages"; then
+ echo "Extract from /var/adm/messages" >> $DEBUG
+ grep 'ppp' /var/adm/messages | tail -150 >> $DEBUG
+ else
+ echo "Can't find messages file (looked for /var/{log,adm}/messages" >> $DEBUG
+ fi
+ 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 "$OVERRIDE_PPPD_COMMAND" != "" ; then
+ $SETSID $OVERRIDE_PPPD_COMMAND &
+ echo "$!" > $PPPD_PIDFILE
+ elif 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
+
+ if test "$RETRY_ON_FAILURE" = "no" ; then
+ exit
+ fi
+
+ # Run /etc/ppp/pppoe-lost if it exists
+ test -x /etc/ppp/pppoe-lost && /etc/ppp/pppoe-lost
+
+ # Re-establish the connection
+ $LOGGER -p daemon.notice \
+ "PPPoE connection lost; attempting re-connection."
+
+ # Wait a bit in case a problem causes tons of log messages :-)
+ sleep 5
+done
diff --git a/jni/scripts/pppoe-connect.in b/jni/scripts/pppoe-connect.in
new file mode 100755
index 0000000..635cffe
--- a/dev/null
+++ b/jni/scripts/pppoe-connect.in
@@ -0,0 +1,319 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# pppoe-connect
+#
+# Shell script to connect to a PPPoE provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-connect [config_file]
+# pppoe-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`"
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+# 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
+export CONFIG
+. $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 pppoe-start, not pppoe-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
+ SERVICENAMEOPT="-S $SERVICENAME"
+else
+ SERVICENAMEOPT=""
+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
+ PEERDNS=yes
+ USEPEERDNS=yes
+fi
+
+if test "$PEERDNS" = "yes" ; then
+ PEERDNS="usepeerdns"
+else
+ PEERDNS=""
+fi
+
+# Backward config file compatibility -- PEERDNS used to be USEPEERDNS
+if test "$USEPEERDNS" = "yes" ; then
+ PEERDNS="usepeerdns"
+fi
+if test "$USEPEERDNS" = "no" ; then
+ PEERDNS=""
+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 nic-$ETH"
+ if test -n "$SERVICENAME" ; then
+ PLUGIN_OPTS="$PLUGIN_OPTS rp_pppoe_service $SERVICENAME"
+ fi
+ modprobe pppoe > /dev/null 2>&1
+fi
+
+if test "$DEFAULTROUTE" != "no" ; then
+ DEFAULTROUTE="defaultroute"
+else
+ DEFAULTROUTE=""
+fi
+
+# Standard PPP options we always use
+PPP_STD_OPTIONS="$PLUGIN_OPTS noipdefault noauth default-asyncmap $DEFAULTROUTE hide-password nodetach $PEERDNS mtu 1492 mru 1492 noaccomp 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 $SERVICENAMEOPT $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
+ if test -f "/var/log/messages" ; then
+ echo "Extract from /var/log/messages" >> $DEBUG
+ grep 'ppp' /var/log/messages | tail -150 >> $DEBUG
+ elif test -f "/var/adm/messages"; then
+ echo "Extract from /var/adm/messages" >> $DEBUG
+ grep 'ppp' /var/adm/messages | tail -150 >> $DEBUG
+ else
+ echo "Can't find messages file (looked for /var/{log,adm}/messages" >> $DEBUG
+ fi
+ 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 "$OVERRIDE_PPPD_COMMAND" != "" ; then
+ $SETSID $OVERRIDE_PPPD_COMMAND &
+ echo "$!" > $PPPD_PIDFILE
+ elif 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
+
+ if test "$RETRY_ON_FAILURE" = "no" ; then
+ exit
+ fi
+
+ # Run /etc/ppp/pppoe-lost if it exists
+ test -x /etc/ppp/pppoe-lost && /etc/ppp/pppoe-lost
+
+ # Re-establish the connection
+ $LOGGER -p daemon.notice \
+ "PPPoE connection lost; attempting re-connection."
+
+ # Wait a bit in case a problem causes tons of log messages :-)
+ sleep 5
+done
diff --git a/jni/scripts/pppoe-init b/jni/scripts/pppoe-init
new file mode 100755
index 0000000..0d61565
--- a/dev/null
+++ b/jni/scripts/pppoe-init
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# pppoe This script starts or stops a PPPoE connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to PPPoE provider
+#
+# LIC: GPL
+#
+# 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=/usr
+exec_prefix=${prefix}
+
+# Paths to programs
+START=${exec_prefix}/sbin/pppoe-start
+STOP=${exec_prefix}/sbin/pppoe-stop
+STATUS=${exec_prefix}/sbin/pppoe-status
+case "$1" in
+ start)
+ echo -n "Bringing up PPPoE link"
+
+ $START
+ if [ $? = 0 ] ; then
+ touch /var/lock/subsys/pppoe
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ stop)
+ echo -n "Shutting down PPPoE link"
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ rm -f /var/lock/subsys/pppoe
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: pppoe {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/jni/scripts/pppoe-init-suse b/jni/scripts/pppoe-init-suse
new file mode 100755
index 0000000..64f6998
--- a/dev/null
+++ b/jni/scripts/pppoe-init-suse
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# pppoe This script starts or stops a PPPoE connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to PPPoE provider
+#
+# LIC: GPL
+#
+# 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=/usr
+exec_prefix=${prefix}
+
+# Paths to programs
+START=${exec_prefix}/sbin/pppoe-start
+STOP=${exec_prefix}/sbin/pppoe-stop
+STATUS=${exec_prefix}/sbin/pppoe-status
+
+test "$PPPoE_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 PPPoE link"
+ $START > /dev/null 2>&1 || return=$rc_failed
+ echo -e "$return"
+ ;;
+
+ stop)
+ echo -n "Shutting down PPPoE 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: pppoe {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/jni/scripts/pppoe-init-suse.in b/jni/scripts/pppoe-init-suse.in
new file mode 100755
index 0000000..28376f4
--- a/dev/null
+++ b/jni/scripts/pppoe-init-suse.in
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# pppoe This script starts or stops a PPPoE connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to PPPoE provider
+#
+# LIC: GPL
+#
+# 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@/pppoe-start
+STOP=@sbindir@/pppoe-stop
+STATUS=@sbindir@/pppoe-status
+
+test "$PPPoE_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 PPPoE link"
+ $START > /dev/null 2>&1 || return=$rc_failed
+ echo -e "$return"
+ ;;
+
+ stop)
+ echo -n "Shutting down PPPoE 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: pppoe {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/jni/scripts/pppoe-init-turbolinux b/jni/scripts/pppoe-init-turbolinux
new file mode 100755
index 0000000..aad06d6
--- a/dev/null
+++ b/jni/scripts/pppoe-init-turbolinux
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# pppoe This script starts or stops a PPPoE connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to PPPoE provider
+#
+# LIC: GPL
+#
+# 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=/usr
+exec_prefix=${prefix}
+
+# Paths to programs
+START=${exec_prefix}/sbin/pppoe-start
+STOP=${exec_prefix}/sbin/pppoe-stop
+STATUS=${exec_prefix}/sbin/pppoe-status
+case "$1" in
+ start)
+ echo -n "Bringing up PPPoE link: "
+
+ $START
+ if [ $? = 0 ] ; then
+ echo success
+ touch /var/lock/subsys/pppoe
+ else
+ echo failure
+ fi
+ ;;
+
+ stop)
+ echo -n "Shutting down PPPoE link: "
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ echo success
+ rm -f /var/lock/subsys/pppoe
+ else
+ echo failure
+ fi
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: pppoe {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/jni/scripts/pppoe-init-turbolinux.in b/jni/scripts/pppoe-init-turbolinux.in
new file mode 100755
index 0000000..d35c801
--- a/dev/null
+++ b/jni/scripts/pppoe-init-turbolinux.in
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# pppoe This script starts or stops a PPPoE connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to PPPoE provider
+#
+# LIC: GPL
+#
+# 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@/pppoe-start
+STOP=@sbindir@/pppoe-stop
+STATUS=@sbindir@/pppoe-status
+case "$1" in
+ start)
+ echo -n "Bringing up PPPoE link: "
+
+ $START
+ if [ $? = 0 ] ; then
+ echo success
+ touch /var/lock/subsys/pppoe
+ else
+ echo failure
+ fi
+ ;;
+
+ stop)
+ echo -n "Shutting down PPPoE link: "
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ echo success
+ rm -f /var/lock/subsys/pppoe
+ else
+ echo failure
+ fi
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: pppoe {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/jni/scripts/pppoe-init.in b/jni/scripts/pppoe-init.in
new file mode 100755
index 0000000..26dbe0b
--- a/dev/null
+++ b/jni/scripts/pppoe-init.in
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# pppoe This script starts or stops a PPPoE connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to PPPoE provider
+#
+# LIC: GPL
+#
+# 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@/pppoe-start
+STOP=@sbindir@/pppoe-stop
+STATUS=@sbindir@/pppoe-status
+case "$1" in
+ start)
+ echo -n "Bringing up PPPoE link"
+
+ $START
+ if [ $? = 0 ] ; then
+ touch /var/lock/subsys/pppoe
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ stop)
+ echo -n "Shutting down PPPoE link"
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ rm -f /var/lock/subsys/pppoe
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: pppoe {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/jni/scripts/pppoe-setup b/jni/scripts/pppoe-setup
new file mode 100755
index 0000000..5665118
--- a/dev/null
+++ b/jni/scripts/pppoe-setup
@@ -0,0 +1,352 @@
+#!/bin/sh
+#***********************************************************************
+#
+# pppoe-setup
+#
+# All-purpose slicing/dicing shell script to configure rp-pppoe.
+#
+# LIC: GPL
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#***********************************************************************
+
+# From AUTOCONF
+prefix=/usr
+exec_prefix=${prefix}
+
+# Paths to programs
+IFCONFIG=/sbin/ifconfig
+PPPD=pppd
+PPPOE=${exec_prefix}/sbin/pppoe
+ECHO=/bin/echo
+LOGGER="/usr/bin/logger -t `basename $0`"
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+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 PPPoE 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 [ "`/usr/bin/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
+export CONFIG
+. $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 ""
+ printf "%s" ">>> 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 DSL 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."
+ printf "%s" "(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."
+ printf "%s" ">>> 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."
+ printf "%s" ">>> 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."
+ printf "%s" ">>> Enter the secondary DNS server address here: "
+ read DNS2
+ fi
+ fi
+
+ while [ true ] ; do
+ $ECHO ""
+ $ECHO "PASSWORD"
+ $ECHO ""
+ stty -echo
+ printf "%s" ">>> Please enter your PPPoE password: "
+ read PWD1
+ $ECHO ""
+ printf "%s" ">>> Please re-enter your PPPoE password: "
+ read PWD2
+ $ECHO ""
+ stty echo
+ if [ "$PWD1" = "$PWD2" ] ; then
+ break
+ fi
+
+ printf "%s" ">>> 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"
+ printf "%s" ">>> 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
+ printf "%s" '>>> 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=""
+ PEERDNS=yes
+else
+ PEERDNS=no
+ if [ "$DNS1" = "" ] ; then
+ DNSTYPE=NOCHANGE
+ else
+ DNSTYPE=SPECIFY
+ fi
+fi
+
+# Where is pppd likely to put its pid?
+if [ -d /var/run ] ; then
+ VARRUN=/var/run
+else
+ VARRUN=/etc/ppp
+fi
+
+# Some #$(*& ISP's use a slash in the user name...
+sed -e "s&^USER=.*&USER='$U'&" \
+ -e "s&^ETH=.*&ETH='$E'&" \
+ -e "s&^PIDFILE=.*&PIDFILE=\"$VARRUN/\$CF_BASE-pppoe.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/^PEERDNS=.*/PEERDNS=$PEERDNS/" \
+ < $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 'pppoe-start' to bring up your PPPoE link and 'pppoe-stop' to bring"
+$ECHO "it down. Type 'pppoe-status' to see the link status."
+exit 0
diff --git a/jni/scripts/pppoe-setup.in b/jni/scripts/pppoe-setup.in
new file mode 100755
index 0000000..b378479
--- a/dev/null
+++ b/jni/scripts/pppoe-setup.in
@@ -0,0 +1,352 @@
+#!/bin/sh
+#***********************************************************************
+#
+# pppoe-setup
+#
+# All-purpose slicing/dicing shell script to configure rp-pppoe.
+#
+# LIC: GPL
+#
+# 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`"
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+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 PPPoE 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
+export CONFIG
+. $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 ""
+ printf "%s" ">>> 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 DSL 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."
+ printf "%s" "(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."
+ printf "%s" ">>> 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."
+ printf "%s" ">>> 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."
+ printf "%s" ">>> Enter the secondary DNS server address here: "
+ read DNS2
+ fi
+ fi
+
+ while [ true ] ; do
+ $ECHO ""
+ $ECHO "PASSWORD"
+ $ECHO ""
+ stty -echo
+ printf "%s" ">>> Please enter your PPPoE password: "
+ read PWD1
+ $ECHO ""
+ printf "%s" ">>> Please re-enter your PPPoE password: "
+ read PWD2
+ $ECHO ""
+ stty echo
+ if [ "$PWD1" = "$PWD2" ] ; then
+ break
+ fi
+
+ printf "%s" ">>> 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"
+ printf "%s" ">>> 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
+ printf "%s" '>>> 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=""
+ PEERDNS=yes
+else
+ PEERDNS=no
+ if [ "$DNS1" = "" ] ; then
+ DNSTYPE=NOCHANGE
+ else
+ DNSTYPE=SPECIFY
+ fi
+fi
+
+# Where is pppd likely to put its pid?
+if [ -d /var/run ] ; then
+ VARRUN=/var/run
+else
+ VARRUN=/etc/ppp
+fi
+
+# Some #$(*& ISP's use a slash in the user name...
+sed -e "s&^USER=.*&USER='$U'&" \
+ -e "s&^ETH=.*&ETH='$E'&" \
+ -e "s&^PIDFILE=.*&PIDFILE=\"$VARRUN/\$CF_BASE-pppoe.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/^PEERDNS=.*/PEERDNS=$PEERDNS/" \
+ < $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 'pppoe-start' to bring up your PPPoE link and 'pppoe-stop' to bring"
+$ECHO "it down. Type 'pppoe-status' to see the link status."
+exit 0
diff --git a/jni/scripts/pppoe-start b/jni/scripts/pppoe-start
new file mode 100755
index 0000000..63501f6
--- a/dev/null
+++ b/jni/scripts/pppoe-start
@@ -0,0 +1,196 @@
+#!/bin/sh
+# ../scripts/pppoe-start. Generated from pppoe-start.in by configure.
+#***********************************************************************
+#
+# pppoe-start
+#
+# Shell script to bring up a PPPoE connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-start [config_file]
+# pppoe-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=/usr
+exec_prefix=${prefix}
+
+# Paths to programs
+CONNECT=${exec_prefix}/sbin/pppoe-connect
+ECHO=/bin/echo
+IFCONFIG=/sbin/ifconfig
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+# Defaults
+CONFIG=/etc/ppp/pppoe.conf
+USER=""
+ETH=""
+ME=`basename $0`
+# Must be root
+if [ "`/usr/bin/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
+export CONFIG
+. $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 a PPPoE 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
+ ${exec_prefix}/sbin/pppoe-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
+ printf "%s" "$FORCEPING"
+ else
+ tty -s && printf "%s" "$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 pppoe-connect process and quit
+kill $CONNECT_PID > /dev/null 2>&1
+
+# Clean up PIDFILE(s)
+rm -f "$PIDFILE" "$PIDFILE.pppd" "$PIDFILE.pppoe" "$PIDFILE.start"
+
+exit 1
+
diff --git a/jni/scripts/pppoe-start.in b/jni/scripts/pppoe-start.in
new file mode 100755
index 0000000..7e15804
--- a/dev/null
+++ b/jni/scripts/pppoe-start.in
@@ -0,0 +1,196 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# pppoe-start
+#
+# Shell script to bring up a PPPoE connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-start [config_file]
+# pppoe-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@/pppoe-connect
+ECHO=@ECHO@
+IFCONFIG=/sbin/ifconfig
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+# 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
+export CONFIG
+. $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 a PPPoE 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@/pppoe-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
+ printf "%s" "$FORCEPING"
+ else
+ tty -s && printf "%s" "$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 pppoe-connect process and quit
+kill $CONNECT_PID > /dev/null 2>&1
+
+# Clean up PIDFILE(s)
+rm -f "$PIDFILE" "$PIDFILE.pppd" "$PIDFILE.pppoe" "$PIDFILE.start"
+
+exit 1
+
diff --git a/jni/scripts/pppoe-status b/jni/scripts/pppoe-status
new file mode 100755
index 0000000..9fe89cd
--- a/dev/null
+++ b/jni/scripts/pppoe-status
@@ -0,0 +1,84 @@
+#!/bin/sh
+#***********************************************************************
+#
+# pppoe-status
+#
+# Shell script to report on status of PPPoE connection
+#
+# Copyright (C) 2000-2001 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-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; pppoe-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 "pppoe-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 "pppoe-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 "pppoe-status: Link is attached to $IF, but $IF is down"
+ exit 1
+ fi
+ echo "pppoe-status: Link is up and running on interface $IF"
+ /sbin/ifconfig $IF
+ exit 0
+ fi
+ fi
+done
+
+echo "pppoe-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/jni/scripts/pppoe-stop b/jni/scripts/pppoe-stop
new file mode 100755
index 0000000..5880377
--- a/dev/null
+++ b/jni/scripts/pppoe-stop
@@ -0,0 +1,96 @@
+#!/bin/sh
+# ../scripts/pppoe-stop. Generated from pppoe-stop.in by configure.
+#***********************************************************************
+#
+# pppoe-stop
+#
+# Shell script to bring down a PPPoE connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-stop [config_file]
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+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
+export CONFIG
+. $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 pppoe-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 pppoe-start
+ PIDS=`cat $STARTPID`
+ kill -0 $PIDS > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ $LOGGER -p daemon.notice "Killing pppoe-connect"
+ kill $PIDS > /dev/null 2>&1
+ fi
+
+ # Kill pppoe-connect
+ $LOGGER -p daemon.notice "Killing pppoe-connect"
+ echo "Killing pppoe-connect ($PID)"
+ kill -9 $PID > /dev/null 2>&1
+
+ # Kill pppd again, in case it's still hanging around
+ if [ -r "$PPPD_PIDFILE" ] ; then
+ PPPD_PID=`cat "$PPPD_PIDFILE"`
+ kill -9 $PPPD_PID > /dev/null 2>&1 || exit 1
+ fi
+
+ rm -f "$PIDFILE" "$PPPD_PIDFILE" "$PPPOE_PIDFILE" "$STARTPID"
+else
+ echo "$ME: No PPPoE connection appears to be running" >&2
+ exit 1
+fi
+
+exit 0
diff --git a/jni/scripts/pppoe-stop.in b/jni/scripts/pppoe-stop.in
new file mode 100755
index 0000000..1ba8756
--- a/dev/null
+++ b/jni/scripts/pppoe-stop.in
@@ -0,0 +1,96 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# pppoe-stop
+#
+# Shell script to bring down a PPPoE connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id$
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# LIC: GPL
+#
+# Usage: pppoe-stop [config_file]
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+# Set to "C" locale so we can parse messages from commands
+LANG=C
+export LANG
+
+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
+export CONFIG
+. $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 pppoe-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 pppoe-start
+ PIDS=`cat $STARTPID`
+ kill -0 $PIDS > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ $LOGGER -p daemon.notice "Killing pppoe-connect"
+ kill $PIDS > /dev/null 2>&1
+ fi
+
+ # Kill pppoe-connect
+ $LOGGER -p daemon.notice "Killing pppoe-connect"
+ echo "Killing pppoe-connect ($PID)"
+ kill -9 $PID > /dev/null 2>&1
+
+ # Kill pppd again, in case it's still hanging around
+ if [ -r "$PPPD_PIDFILE" ] ; then
+ PPPD_PID=`cat "$PPPD_PIDFILE"`
+ kill -9 $PPPD_PID > /dev/null 2>&1 || exit 1
+ fi
+
+ rm -f "$PIDFILE" "$PPPD_PIDFILE" "$PPPOE_PIDFILE" "$STARTPID"
+else
+ echo "$ME: No PPPoE connection appears to be running" >&2
+ exit 1
+fi
+
+exit 0
diff --git a/jni/src/common.c b/jni/src/common.c
new file mode 100755
index 0000000..b8c53fd
--- a/dev/null
+++ b/jni/src/common.c
@@ -0,0 +1,651 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+/* For vsnprintf prototype */
+#define _ISOC99_SOURCE 1
+
+/* For seteuid prototype */
+#define _BSD_SOURCE 1
+
+#include "pppoe.h"
+
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#include <android/log.h>
+#define syslog(prio, fmt...) \
+ __android_log_print(prio, "PPPOE", fmt)
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <pwd.h>
+
+/* Are we running SUID or SGID? */
+int IsSetID = 0;
+
+static uid_t saved_uid = -2;
+static uid_t saved_gid = -2;
+
+/**********************************************************************
+*%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: switchToRealID
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sets effective user-ID and group-ID to real ones. Aborts on failure
+***********************************************************************/
+void
+switchToRealID (void) {
+ if (IsSetID) {
+ if ((int)saved_uid < 0) saved_uid = geteuid();
+ if ((int)saved_gid < 0) saved_gid = getegid();
+ if (setegid(getgid()) < 0) {
+ printErr("setgid failed");
+ exit(EXIT_FAILURE);
+ }
+ if (seteuid(getuid()) < 0) {
+ printErr("seteuid failed");
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: switchToEffectiveID
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sets effective user-ID and group-ID back to saved gid/uid
+***********************************************************************/
+void
+switchToEffectiveID (void) {
+ if (IsSetID) {
+ if (setegid(saved_gid) < 0) {
+ printErr("setgid failed");
+ exit(EXIT_FAILURE);
+ }
+ if (seteuid(saved_uid) < 0) {
+ printErr("seteuid failed");
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: dropPrivs
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* If effective ID is root, try to become "nobody". If that fails and
+* we're SUID, switch to real user-ID
+***********************************************************************/
+void
+dropPrivs(void)
+{
+ struct passwd *pw = NULL;
+ int ok = 0;
+ if (geteuid() == 0) {
+ pw = getpwnam("nobody");
+ if (pw) {
+ if (setgid(pw->pw_gid) < 0) ok++;
+ if (setuid(pw->pw_uid) < 0) ok++;
+ }
+ }
+ if (ok < 2 && IsSetID) {
+ setegid(getgid());
+ seteuid(getuid());
+ }
+}
+
+/**********************************************************************
+*%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];
+ UINT16_t tmp;
+
+ 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) {
+ memcpy(&tmp, addr, sizeof(tmp));
+ sum += (UINT32_t) tmp;
+ addr += sizeof(tmp);
+ count -= sizeof(tmp);
+ }
+ if (count > 0) {
+ sum += (unsigned char) *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, minlen;
+
+ /* check PPP protocol type */
+ if (packet->payload[0] & 0x01) {
+ /* 8 bit protocol type */
+
+ /* Is it IPv4? */
+ if (packet->payload[0] != 0x21) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ ipHdr = packet->payload + 1;
+ minlen = 41;
+ } else {
+ /* 16 bit protocol type */
+
+ /* Is it IPv4? */
+ if (packet->payload[0] != 0x00 ||
+ packet->payload[1] != 0x21) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ ipHdr = packet->payload + 2;
+ minlen = 42;
+ }
+
+ /* Is it too short? */
+ len = (int) ntohs(packet->length);
+ if (len < minlen) {
+ /* 20 byte IP header; 20 byte TCP header; at least 1 or 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 <= (unsigned int)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((char *) 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));
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+ syslog(LOG_INFO,"Sent PADT");
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADTf
+*%ARGUMENTS:
+* conn -- PPPoE connection
+* msg -- printf-style format string
+* args -- arguments for msg
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADT packet with a formatted message
+***********************************************************************/
+void
+sendPADTf(PPPoEConnection *conn, char const *fmt, ...)
+{
+ char msg[512];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ msg[511] = 0;
+
+ sendPADT(conn, msg);
+}
+
+/**********************************************************************
+*%FUNCTION: pktLogErrs
+*%ARGUMENTS:
+* pkt -- packet type (a string)
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Logs error tags
+***********************************************************************/
+void
+pktLogErrs(char const *pkt,
+ UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ char const *str;
+ char const *fmt = "%s: %s: %.*s";
+ switch(type) {
+ case TAG_SERVICE_NAME_ERROR:
+ str = "Service-Name-Error";
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ str = "System-Error";
+ break;
+ default:
+ str = "Generic-Error";
+ }
+
+ syslog(LOG_ERR, fmt, pkt, str, (int) len, data);
+ fprintf(stderr, fmt, pkt, str, (int) len, data);
+ fprintf(stderr, "\n");
+}
+
+/**********************************************************************
+*%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)
+{
+ pktLogErrs("PADT", type, len, data, extra);
+}
diff --git a/jni/src/config.h b/jni/src/config.h
new file mode 100755
index 0000000..b75a298
--- a/dev/null
+++ b/jni/src/config.h
@@ -0,0 +1,146 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* LIC: GPL */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* 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. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if your <sys/time.h> declares struct tm. */
+/* #undef TM_IN_SYS_TIME */
+
+#define HAVE_STRUCT_SOCKADDR_LL 1
+
+/* The number of bytes in a unsigned int. */
+#define SIZEOF_UNSIGNED_INT 4
+
+/* The number of bytes in a unsigned long. */
+#define SIZEOF_UNSIGNED_LONG 4
+
+/* The number of bytes in a unsigned short. */
+#define SIZEOF_UNSIGNED_SHORT 2
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strtol function. */
+#define HAVE_STRTOL 1
+
+/* Define if you have the <asm/types.h> header file. */
+#define HAVE_ASM_TYPES_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define if you have the <linux/if_ether.h> header file. */
+#define HAVE_LINUX_IF_ETHER_H 1
+
+/* 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. */
+#define HAVE_LINUX_IF_PACKET_H 1
+
+/* Define if you have the <linux/if_pppox.h> header file. */
+#define HAVE_LINUX_IF_PPPOX_H 1
+
+/* 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. */
+#define HAVE_NET_IF_ARP_H 1
+
+/* Define if you have the <net/ethernet.h> header file. */
+#define HAVE_NET_ETHERNET_H 1
+
+/* Define if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define if you have the <linux/if.h> header file. */
+#define HAVE_LINUX_IF_H 1
+
+/* 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. */
+#define HAVE_NETINET_IF_ETHER_H 1
+
+/* Define if you have the <netpacket/packet.h> header file. */
+#define HAVE_NETPACKET_PACKET_H 1
+
+/* Define if you have the <sys/cdefs.h> header file. */
+#define HAVE_SYS_CDEFS_H 1
+
+/* 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. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/uio.h> header file. */
+#ifndef HAVE_SYS_UIO_H
+#define HAVE_SYS_UIO_H 1
+#endif
+
+/* Define if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* 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 */
+#define PACK_BITFIELDS_REVERSED 1
+
+/* Define to include debugging code */
+#define DEBUGGING_ENABLED 1
+
+/* Solaris moans if we don't do this... */
+#ifdef __sun
+#define __EXTENSIONS__ 1
+#endif
diff --git a/jni/src/debug.c b/jni/src/debug.c
new file mode 100755
index 0000000..b606272
--- a/dev/null
+++ b/jni/src/debug.c
@@ -0,0 +1,152 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef DEBUGGING_ENABLED
+
+#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_PADM: fprintf(fp, "PADM "); break;
+ case CODE_PADN: fprintf(fp, "PADN "); 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));
+}
+
+#endif /* DEBUGGING_ENABLED */
diff --git a/jni/src/discovery.c b/jni/src/discovery.c
new file mode 100755
index 0000000..c92ceef
--- a/dev/null
+++ b/jni/src/discovery.c
@@ -0,0 +1,736 @@
+/***********************************************************************
+*
+* discovery.c
+*
+* Perform PPPoE discovery
+*
+* Copyright (C) 1999 by Roaring Penguin Software Inc.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#include <android/log.h>
+#define syslog(prio, fmt...) \
+ __android_log_print(prio, "PPPOE", fmt)
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#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>
+
+/* Supplied by pppd if we're a plugin */
+extern int persist;
+
+/**********************************************************************
+*%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.
+***********************************************************************/
+static 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.
+***********************************************************************/
+static int
+packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ int forMe = 0;
+
+ /* If packet is not directed to our MAC address, forget it */
+ if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 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
+***********************************************************************/
+static 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:
+ pc->seenACName = 1;
+ 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:
+ pc->seenServiceName = 1;
+ 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 {
+ pktLogErrs("PADO", type, len, data, extra);
+ exit(1);
+ }
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ if (conn->printACNames) {
+ printf("Got a System-Error tag: %.*s\n", (int) len, data);
+ } else {
+ pktLogErrs("PADO", type, len, data, extra);
+ exit(1);
+ }
+ break;
+ case TAG_GENERIC_ERROR:
+ if (conn->printACNames) {
+ printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
+ } else {
+ pktLogErrs("PADO", type, len, data, extra);
+ 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
+***********************************************************************/
+static 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_GENERIC_ERROR:
+ case TAG_AC_SYSTEM_ERROR:
+ case TAG_SERVICE_NAME_ERROR:
+ pktLogErrs("PADS", type, len, data, extra);
+ conn->PADSHadError = 1;
+ break;
+ 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
+***********************************************************************/
+static void
+sendPADI(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ unsigned char *cursor = packet.payload;
+ PPPoETag *svc = (PPPoETag *) (&packet.payload);
+ UINT16_t namelen = 0;
+ UINT16_t plen;
+ int omit_service_name = 0;
+
+ if (conn->serviceName) {
+ namelen = (UINT16_t) strlen(conn->serviceName);
+ if (!strcmp(conn->serviceName, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
+ omit_service_name = 1;
+ }
+ }
+
+ /* 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;
+
+ if (!omit_service_name) {
+ plen = TAG_HDR_SIZE + namelen;
+ CHECK_ROOM(cursor, packet.payload, plen);
+
+ svc->type = TAG_SERVICE_NAME;
+ svc->length = htons(namelen);
+
+ if (conn->serviceName) {
+ memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
+ }
+ cursor += namelen + TAG_HDR_SIZE;
+ } else {
+ plen = 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));
+ 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));
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+}
+
+/**********************************************************************
+*%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
+***********************************************************************/
+static void
+waitForPADO(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ struct timeval expire_at;
+ struct timeval now;
+
+ PPPoEPacket packet;
+ int len;
+
+ struct PacketCriteria pc;
+ pc.conn = conn;
+ pc.acNameOK = (conn->acName) ? 0 : 1;
+ pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
+ pc.seenACName = 0;
+ pc.seenServiceName = 0;
+
+ if (gettimeofday(&expire_at, NULL) < 0) {
+ fatalSys("gettimeofday (waitForPADO)");
+ }
+ expire_at.tv_sec += timeout;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ if (gettimeofday(&now, NULL) < 0) {
+ fatalSys("gettimeofday (waitForPADO)");
+ }
+ tv.tv_sec = expire_at.tv_sec - now.tv_sec;
+ tv.tv_usec = expire_at.tv_usec - now.tv_usec;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1000000;
+ if (tv.tv_sec) {
+ tv.tv_sec--;
+ } else {
+ /* Timed out */
+ return;
+ }
+ }
+ if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
+ /* Timed out */
+ return;
+ }
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR) {
+ syslog( LOG_INFO, "waitForPADO: (r >= 0 || errno != EINTR)\n");
+ break;
+ }
+ }
+
+ if (r < 0) {
+ fatalSys("select (waitForPADO)");
+ }
+ if (r == 0) {
+ /* Timed out */
+ return;
+ }
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > (unsigned int)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
+
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+ /* 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;
+ }
+ parsePacket(&packet, parsePADOTags, &pc);
+ if (!pc.seenACName) {
+ printErr("Ignoring PADO packet with no AC-Name tag");
+ continue;
+ }
+ if (!pc.seenServiceName) {
+ printErr("Ignoring PADO packet with no Service-Name tag");
+ continue;
+ }
+ conn->numPADOs++;
+ 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]);
+ printf("--------------------------------------------------\n");
+ 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
+***********************************************************************/
+static 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));
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+}
+
+/**********************************************************************
+*%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
+***********************************************************************/
+static void
+waitForPADS(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ struct timeval expire_at;
+ struct timeval now;
+
+ PPPoEPacket packet;
+ int len;
+
+ if (gettimeofday(&expire_at, NULL) < 0) {
+ fatalSys("gettimeofday (waitForPADS)");
+ }
+ expire_at.tv_sec += timeout;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ if (gettimeofday(&now, NULL) < 0) {
+ fatalSys("gettimeofday (waitForPADS)");
+ }
+ tv.tv_sec = expire_at.tv_sec - now.tv_sec;
+ tv.tv_usec = expire_at.tv_usec - now.tv_usec;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1000000;
+ if (tv.tv_sec) {
+ tv.tv_sec--;
+ } else {
+ /* Timed out */
+ return;
+ }
+ }
+ if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
+ /* Timed out */
+ return;
+ }
+
+ 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) {
+ /* Timed out */
+ return;
+ }
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > (unsigned int)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
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+ /* 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 */
+ conn->PADSHadError = 0;
+ parsePacket(&packet, parsePADSTags, conn);
+ if (!conn->PADSHadError) {
+ 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 (0x%x)", (int) ntohs(conn->session),
+ (unsigned 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
+***********************************************************************/
+static struct timeval current_time;
+
+static int g_padi_sent = 0;
+void
+discovery(PPPoEConnection *conn)
+{
+ int padiAttempts = 0;
+ int padrAttempts = 0;
+ int timeout = conn->discoveryTimeout;
+
+ fprintf(stderr, "discovery: timeout = %d\n", timeout);
+
+ /* 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) {
+ if (persist) {
+ padiAttempts = 0;
+ timeout = conn->discoveryTimeout;
+ printErr("Timeout waiting for PADO packets");
+ } else {
+ rp_fatal("Timeout waiting for PADO packets");
+ }
+ }
+ fprintf(stderr, "sendPADI\n");
+ syslog( LOG_INFO, "sendPADI\n");
+ sendPADI(conn);
+
+ conn->discoveryState = STATE_SENT_PADI;
+ gettimeofday(&current_time, NULL);
+ fprintf(stderr, "before: sec = %d, usec = %d\n", (int)current_time.tv_sec, (int)current_time.tv_usec);
+ waitForPADO(conn, timeout);
+ gettimeofday(&current_time, NULL);
+ fprintf(stderr, "after: sec = %d, usec = %d\n", (int)current_time.tv_sec, (int)current_time.tv_usec);
+ /* 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) {
+ exit(0);
+ }
+
+ timeout = conn->discoveryTimeout;
+ do {
+ padrAttempts++;
+ if (padrAttempts > MAX_PADI_ATTEMPTS) {
+ if (persist) {
+ padrAttempts = 0;
+ timeout = conn->discoveryTimeout;
+ printErr("Timeout waiting for PADS packets");
+ } else {
+ rp_fatal("Timeout waiting for PADS packets");
+ }
+ }
+ fprintf(stderr, "sendPADR\n");
+ syslog( LOG_INFO, "sendPADR\n");
+ 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/jni/src/if.c b/jni/src/if.c
new file mode 100755
index 0000000..d076b69
--- a/dev/null
+++ b/jni/src/if.c
@@ -0,0 +1,352 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+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 <android/log.h>
+#include <syslog.h>
+#define syslog(prio, fmt...) \
+ __android_log_print(prio, "PPPOE", fmt)
+#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 */
+
+static 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);
+static 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>
+
+static unsigned char *bpfBuffer; /* Packet filter buffer */
+static int bpfLength = 0; /* Packet filter buffer length */
+ int bpfSize = 0; /* Number of unread bytes in buffer */
+static 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_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;
+
+ struct sockaddr_ll sa;
+
+ memset(&sa, 0, sizeof(sa));
+
+ domain = PF_PACKET;
+ stype = SOCK_RAW;
+
+ 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);
+
+ 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);
+ }
+
+ /* 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;
+
+ /* 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 (send(sock, pkt, size, 0) < 0 && (errno != ENOBUFS)) {
+ sysErr("send (sendPacket)");
+ return -1;
+ }
+ 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;
+}
+
diff --git a/jni/src/libevent/Makefile b/jni/src/libevent/Makefile
new file mode 100755
index 0000000..6f0a5ed
--- a/dev/null
+++ b/jni/src/libevent/Makefile
@@ -0,0 +1,42 @@
+# Generated automatically from Makefile.in by configure.
+# $Id$
+#
+# Makefile for event-handling library
+#
+# Copyright 2002 Roaring Penguin Software Inc.
+#
+# This software may be distributed according to the terms of the GNU
+# General Public License, version 2 or (at your option) any later version.
+# LIC: GPL
+
+OBJS=event.o event_tcp.o hash.o event_sig.o
+SRCS=$(OBJS:.o=.c)
+HDRS=event.h event_tcp.h eventpriv.h hash.h
+CFLAGS=-g -O2 -Wall -Wstrict-prototypes -I.. $(DEFINES)
+AR=ar
+
+all: libevent.a
+
+libevent.a: $(OBJS)
+ rm -f libevent.a
+ $(AR) -cq libevent.a $(OBJS)
+ ranlib libevent.a
+
+event.o: event.c $(HDRS)
+ gcc $(CFLAGS) -c -o event.o event.c
+
+hash.o: hash.c $(HDRS)
+ gcc $(CFLAGS) -c -o hash.o hash.c
+
+event_sig.o: event_sig.c $(HDRS)
+ gcc $(CFLAGS) -c -o event_sig.o event_sig.c
+
+event_tcp.o: event_tcp.c $(HDRS)
+ gcc $(CFLAGS) -c -o event_tcp.o event_tcp.c
+
+clean: FORCE
+ rm -f *.a *.o *~
+
+FORCE:
+
+.phony: FORCE \ No newline at end of file
diff --git a/jni/src/libevent/Makefile.in b/jni/src/libevent/Makefile.in
new file mode 100755
index 0000000..7f7988c
--- a/dev/null
+++ b/jni/src/libevent/Makefile.in
@@ -0,0 +1,42 @@
+# Generated automatically from Makefile.in by configure.
+# $Id$
+#
+# Makefile for event-handling library
+#
+# Copyright 2002 Roaring Penguin Software Inc.
+#
+# This software may be distributed according to the terms of the GNU
+# General Public License, version 2 or (at your option) any later version.
+# LIC: GPL
+
+OBJS=event.o event_tcp.o hash.o event_sig.o
+SRCS=$(OBJS:.o=.c)
+HDRS=event.h event_tcp.h eventpriv.h hash.h
+CFLAGS=@CFLAGS@ -I.. $(DEFINES)
+AR=ar
+
+all: libevent.a
+
+libevent.a: $(OBJS)
+ rm -f libevent.a
+ $(AR) -cq libevent.a $(OBJS)
+ @RANLIB@ libevent.a
+
+event.o: event.c $(HDRS)
+ @CC@ $(CFLAGS) -c -o event.o event.c
+
+hash.o: hash.c $(HDRS)
+ @CC@ $(CFLAGS) -c -o hash.o hash.c
+
+event_sig.o: event_sig.c $(HDRS)
+ @CC@ $(CFLAGS) -c -o event_sig.o event_sig.c
+
+event_tcp.o: event_tcp.c $(HDRS)
+ @CC@ $(CFLAGS) -c -o event_tcp.o event_tcp.c
+
+clean: FORCE
+ rm -f *.a *.o *~
+
+FORCE:
+
+.phony: FORCE \ No newline at end of file
diff --git a/jni/src/libevent/event.c b/jni/src/libevent/event.c
new file mode 100755
index 0000000..d6514cb
--- a/dev/null
+++ b/jni/src/libevent/event.c
@@ -0,0 +1,645 @@
+/***********************************************************************
+*
+* event.c
+*
+* Abstraction of select call into "event-handling" to make programming
+* easier.
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "event.h"
+#include <stdlib.h>
+#include <errno.h>
+
+static void DestroySelector(EventSelector *es);
+static void DestroyHandler(EventHandler *eh);
+static void DoPendingChanges(EventSelector *es);
+
+/**********************************************************************
+* %FUNCTION: Event_CreateSelector
+* %ARGUMENTS:
+* None
+* %RETURNS:
+* A newly-allocated EventSelector, or NULL if out of memory.
+* %DESCRIPTION:
+* Creates a new EventSelector.
+***********************************************************************/
+EventSelector *
+Event_CreateSelector(void)
+{
+ EventSelector *es = malloc(sizeof(EventSelector));
+ if (!es) return NULL;
+ es->handlers = NULL;
+ es->nestLevel = 0;
+ es->destroyPending = 0;
+ es->opsPending = 0;
+ EVENT_DEBUG(("CreateSelector() -> %p\n", (void *) es));
+ return es;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_DestroySelector
+* %ARGUMENTS:
+* es -- EventSelector to destroy
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Destroys an EventSelector. Destruction may be delayed if we
+* are in the HandleEvent function.
+***********************************************************************/
+void
+Event_DestroySelector(EventSelector *es)
+{
+ if (es->nestLevel) {
+ es->destroyPending = 1;
+ es->opsPending = 1;
+ return;
+ }
+ DestroySelector(es);
+}
+
+/**********************************************************************
+* %FUNCTION: Event_HandleEvent
+* %ARGUMENTS:
+* es -- EventSelector
+* %RETURNS:
+* 0 if OK, non-zero on error. errno is set appropriately.
+* %DESCRIPTION:
+* Handles a single event (uses select() to wait for an event.)
+***********************************************************************/
+int
+Event_HandleEvent(EventSelector *es)
+{
+ fd_set readfds, writefds;
+ fd_set *rd, *wr;
+ unsigned int flags;
+
+ struct timeval abs_timeout, now;
+
+ struct timeval timeout;
+ struct timeval *tm;
+ EventHandler *eh;
+
+ int r = 0;
+ int errno_save = 0;
+ int foundTimeoutEvent = 0;
+ int foundReadEvent = 0;
+ int foundWriteEvent = 0;
+ int maxfd = -1;
+ int pastDue;
+
+ /* Avoid compiler warning */
+ abs_timeout.tv_sec = 0;
+ abs_timeout.tv_usec = 0;
+
+ EVENT_DEBUG(("Enter Event_HandleEvent(es=%p)\n", (void *) es));
+
+ /* Build the select sets */
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+
+ eh = es->handlers;
+ for (eh=es->handlers; eh; eh=eh->next) {
+ if (eh->flags & EVENT_FLAG_DELETED) continue;
+ if (eh->flags & EVENT_FLAG_READABLE) {
+ foundReadEvent = 1;
+ FD_SET(eh->fd, &readfds);
+ if (eh->fd > maxfd) maxfd = eh->fd;
+ }
+ if (eh->flags & EVENT_FLAG_WRITEABLE) {
+ foundWriteEvent = 1;
+ FD_SET(eh->fd, &writefds);
+ if (eh->fd > maxfd) maxfd = eh->fd;
+ }
+ if (eh->flags & EVENT_TIMER_BITS) {
+ if (!foundTimeoutEvent) {
+ abs_timeout = eh->tmout;
+ foundTimeoutEvent = 1;
+ } else {
+ if (eh->tmout.tv_sec < abs_timeout.tv_sec ||
+ (eh->tmout.tv_sec == abs_timeout.tv_sec &&
+ eh->tmout.tv_usec < abs_timeout.tv_usec)) {
+ abs_timeout = eh->tmout;
+ }
+ }
+ }
+ }
+ if (foundReadEvent) {
+ rd = &readfds;
+ } else {
+ rd = NULL;
+ }
+ if (foundWriteEvent) {
+ wr = &writefds;
+ } else {
+ wr = NULL;
+ }
+
+ if (foundTimeoutEvent) {
+ gettimeofday(&now, NULL);
+ /* Convert absolute timeout to relative timeout for select */
+ timeout.tv_usec = abs_timeout.tv_usec - now.tv_usec;
+ timeout.tv_sec = abs_timeout.tv_sec - now.tv_sec;
+ if (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
+ }
+ if (timeout.tv_sec < 0 ||
+ (timeout.tv_sec == 0 && timeout.tv_usec < 0)) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ }
+ tm = &timeout;
+ } else {
+ tm = NULL;
+ }
+
+ if (foundReadEvent || foundWriteEvent || foundTimeoutEvent) {
+ for(;;) {
+ r = select(maxfd+1, rd, wr, NULL, tm);
+ if (r < 0) {
+ if (errno == EINTR) continue;
+ }
+ break;
+ }
+ }
+
+ if (foundTimeoutEvent) gettimeofday(&now, NULL);
+ errno_save = errno;
+ es->nestLevel++;
+
+ if (r >= 0) {
+ /* Call handlers */
+ for (eh=es->handlers; eh; eh=eh->next) {
+
+ /* Pending delete for this handler? Ignore it */
+ if (eh->flags & EVENT_FLAG_DELETED) continue;
+
+ flags = 0;
+ if ((eh->flags & EVENT_FLAG_READABLE) &&
+ FD_ISSET(eh->fd, &readfds)) {
+ flags |= EVENT_FLAG_READABLE;
+ }
+ if ((eh->flags & EVENT_FLAG_WRITEABLE) &&
+ FD_ISSET(eh->fd, &writefds)) {
+ flags |= EVENT_FLAG_WRITEABLE;
+ }
+ if (eh->flags & EVENT_TIMER_BITS) {
+ pastDue = (eh->tmout.tv_sec < now.tv_sec ||
+ (eh->tmout.tv_sec == now.tv_sec &&
+ eh->tmout.tv_usec <= now.tv_usec));
+ if (pastDue) {
+ flags |= EVENT_TIMER_BITS;
+ if (eh->flags & EVENT_FLAG_TIMER) {
+ /* Timer events are only called once */
+ es->opsPending = 1;
+ eh->flags |= EVENT_FLAG_DELETED;
+ }
+ }
+ }
+ /* Do callback */
+ if (flags) {
+ EVENT_DEBUG(("Enter callback: eh=%p flags=%u\n", eh, flags));
+ eh->fn(es, eh->fd, flags, eh->data);
+ EVENT_DEBUG(("Leave callback: eh=%p flags=%u\n", eh, flags));
+ }
+ }
+ }
+
+ es->nestLevel--;
+
+ if (!es->nestLevel && es->opsPending) {
+ DoPendingChanges(es);
+ }
+ errno = errno_save;
+ return r;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_AddHandler
+* %ARGUMENTS:
+* es -- event selector
+* fd -- file descriptor to watch
+* flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE
+* fn -- callback function to call when event is triggered
+* data -- extra data to pass to callback function
+* %RETURNS:
+* A newly-allocated EventHandler, or NULL.
+***********************************************************************/
+EventHandler *
+Event_AddHandler(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ EventCallbackFunc fn,
+ void *data)
+{
+ EventHandler *eh;
+
+ /* Specifically disable timer and deleted flags */
+ flags &= (~(EVENT_TIMER_BITS | EVENT_FLAG_DELETED));
+
+ /* Bad file descriptor */
+ if (fd < 0) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ eh = malloc(sizeof(EventHandler));
+ if (!eh) return NULL;
+ eh->fd = fd;
+ eh->flags = flags;
+ eh->tmout.tv_usec = 0;
+ eh->tmout.tv_sec = 0;
+ eh->fn = fn;
+ eh->data = data;
+
+ /* Add immediately. This is safe even if we are in a handler. */
+ eh->next = es->handlers;
+ es->handlers = eh;
+
+ EVENT_DEBUG(("Event_AddHandler(es=%p, fd=%d, flags=%u) -> %p\n", es, fd, flags, eh));
+ return eh;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_AddHandlerWithTimeout
+* %ARGUMENTS:
+* es -- event selector
+* fd -- file descriptor to watch
+* flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE
+* t -- Timeout after which to call handler, even if not readable/writable.
+* If t.tv_sec < 0, calls normal Event_AddHandler with no timeout.
+* fn -- callback function to call when event is triggered
+* data -- extra data to pass to callback function
+* %RETURNS:
+* A newly-allocated EventHandler, or NULL.
+***********************************************************************/
+EventHandler *
+Event_AddHandlerWithTimeout(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ struct timeval t,
+ EventCallbackFunc fn,
+ void *data)
+{
+ EventHandler *eh;
+ struct timeval now;
+
+ /* If timeout is negative, just do normal non-timing-out event */
+ if (t.tv_sec < 0 || t.tv_usec < 0) {
+ return Event_AddHandler(es, fd, flags, fn, data);
+ }
+
+ /* Specifically disable timer and deleted flags */
+ flags &= (~(EVENT_FLAG_TIMER | EVENT_FLAG_DELETED));
+ flags |= EVENT_FLAG_TIMEOUT;
+
+ /* Bad file descriptor? */
+ if (fd < 0) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ /* Bad timeout? */
+ if (t.tv_usec >= 1000000) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ eh = malloc(sizeof(EventHandler));
+ if (!eh) return NULL;
+
+ /* Convert time interval to absolute time */
+ gettimeofday(&now, NULL);
+
+ t.tv_sec += now.tv_sec;
+ t.tv_usec += now.tv_usec;
+ if (t.tv_usec >= 1000000) {
+ t.tv_usec -= 1000000;
+ t.tv_sec++;
+ }
+
+ eh->fd = fd;
+ eh->flags = flags;
+ eh->tmout = t;
+ eh->fn = fn;
+ eh->data = data;
+
+ /* Add immediately. This is safe even if we are in a handler. */
+ eh->next = es->handlers;
+ es->handlers = eh;
+
+ EVENT_DEBUG(("Event_AddHandlerWithTimeout(es=%p, fd=%d, flags=%u, t=%d/%d) -> %p\n", es, fd, flags, t.tv_sec, t.tv_usec, eh));
+ return eh;
+}
+
+
+/**********************************************************************
+* %FUNCTION: Event_AddTimerHandler
+* %ARGUMENTS:
+* es -- event selector
+* t -- time interval after which to trigger event
+* fn -- callback function to call when event is triggered
+* data -- extra data to pass to callback function
+* %RETURNS:
+* A newly-allocated EventHandler, or NULL.
+***********************************************************************/
+EventHandler *
+Event_AddTimerHandler(EventSelector *es,
+ struct timeval t,
+ EventCallbackFunc fn,
+ void *data)
+{
+ EventHandler *eh;
+ struct timeval now;
+
+ /* Check time interval for validity */
+ if (t.tv_sec < 0 || t.tv_usec < 0 || t.tv_usec >= 1000000) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ eh = malloc(sizeof(EventHandler));
+ if (!eh) return NULL;
+
+ /* Convert time interval to absolute time */
+ gettimeofday(&now, NULL);
+
+ t.tv_sec += now.tv_sec;
+ t.tv_usec += now.tv_usec;
+ if (t.tv_usec >= 1000000) {
+ t.tv_usec -= 1000000;
+ t.tv_sec++;
+ }
+
+ eh->fd = -1;
+ eh->flags = EVENT_FLAG_TIMER;
+ eh->tmout = t;
+ eh->fn = fn;
+ eh->data = data;
+
+ /* Add immediately. This is safe even if we are in a handler. */
+ eh->next = es->handlers;
+ es->handlers = eh;
+
+ EVENT_DEBUG(("Event_AddTimerHandler(es=%p, t=%d/%d) -> %p\n", es, t.tv_sec,t.tv_usec, eh));
+ return eh;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_DelHandler
+* %ARGUMENTS:
+* es -- event selector
+* eh -- event handler
+* %RETURNS:
+* 0 if OK, non-zero if there is an error
+* %DESCRIPTION:
+* Deletes the event handler eh
+***********************************************************************/
+int
+Event_DelHandler(EventSelector *es,
+ EventHandler *eh)
+{
+ /* Scan the handlers list */
+ EventHandler *cur, *prev;
+ EVENT_DEBUG(("Event_DelHandler(es=%p, eh=%p)\n", es, eh));
+ for (cur=es->handlers, prev=NULL; cur; prev=cur, cur=cur->next) {
+ if (cur == eh) {
+ if (es->nestLevel) {
+ eh->flags |= EVENT_FLAG_DELETED;
+ es->opsPending = 1;
+ return 0;
+ } else {
+ if (prev) prev->next = cur->next;
+ else es->handlers = cur->next;
+
+ DestroyHandler(cur);
+ return 0;
+ }
+ }
+ }
+
+ /* Handler not found */
+ return 1;
+}
+
+/**********************************************************************
+* %FUNCTION: DestroySelector
+* %ARGUMENTS:
+* es -- an event selector
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Destroys selector and all associated handles.
+***********************************************************************/
+void
+DestroySelector(EventSelector *es)
+{
+ EventHandler *cur, *next;
+ for (cur=es->handlers; cur; cur=next) {
+ next = cur->next;
+ DestroyHandler(cur);
+ }
+
+ free(es);
+}
+
+/**********************************************************************
+* %FUNCTION: DestroyHandler
+* %ARGUMENTS:
+* eh -- an event handler
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Destroys handler
+***********************************************************************/
+void
+DestroyHandler(EventHandler *eh)
+{
+ EVENT_DEBUG(("DestroyHandler(eh=%p)\n", eh));
+ free(eh);
+}
+
+/**********************************************************************
+* %FUNCTION: DoPendingChanges
+* %ARGUMENTS:
+* es -- an event selector
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Makes all pending insertions and deletions happen.
+***********************************************************************/
+void
+DoPendingChanges(EventSelector *es)
+{
+ EventHandler *cur, *prev, *next;
+
+ es->opsPending = 0;
+
+ /* If selector is to be deleted, do it and skip everything else */
+ if (es->destroyPending) {
+ DestroySelector(es);
+ return;
+ }
+
+ /* Do deletions */
+ cur = es->handlers;
+ prev = NULL;
+ while(cur) {
+ if (!(cur->flags & EVENT_FLAG_DELETED)) {
+ prev = cur;
+ cur = cur->next;
+ continue;
+ }
+
+ /* Unlink from list */
+ if (prev) {
+ prev->next = cur->next;
+ } else {
+ es->handlers = cur->next;
+ }
+ next = cur->next;
+ DestroyHandler(cur);
+ cur = next;
+ }
+}
+
+/**********************************************************************
+* %FUNCTION: Event_GetCallback
+* %ARGUMENTS:
+* eh -- the event handler
+* %RETURNS:
+* The callback function
+***********************************************************************/
+EventCallbackFunc
+Event_GetCallback(EventHandler *eh)
+{
+ return eh->fn;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_GetData
+* %ARGUMENTS:
+* eh -- the event handler
+* %RETURNS:
+* The "data" field.
+***********************************************************************/
+void *
+Event_GetData(EventHandler *eh)
+{
+ return eh->data;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_SetCallbackAndData
+* %ARGUMENTS:
+* eh -- the event handler
+* fn -- new callback function
+* data -- new data value
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Sets the callback function and data fields.
+***********************************************************************/
+void
+Event_SetCallbackAndData(EventHandler *eh,
+ EventCallbackFunc fn,
+ void *data)
+{
+ eh->fn = fn;
+ eh->data = data;
+}
+
+#ifdef DEBUG_EVENT
+#include <stdarg.h>
+#include <stdio.h>
+FILE *Event_DebugFP = NULL;
+/**********************************************************************
+* %FUNCTION: Event_DebugMsg
+* %ARGUMENTS:
+* fmt, ... -- format string
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Writes a debug message to the debug file.
+***********************************************************************/
+void
+Event_DebugMsg(char const *fmt, ...)
+{
+ va_list ap;
+ struct timeval now;
+
+ if (!Event_DebugFP) return;
+
+ gettimeofday(&now, NULL);
+
+ fprintf(Event_DebugFP, "%03d.%03d ", (int) now.tv_sec % 1000,
+ (int) now.tv_usec / 1000);
+
+ va_start(ap, fmt);
+ vfprintf(Event_DebugFP, fmt, ap);
+ va_end(ap);
+ fflush(Event_DebugFP);
+}
+
+#endif
+
+/**********************************************************************
+* %FUNCTION: Event_EnableDebugging
+* %ARGUMENTS:
+* fname -- name of file to log debug messages to
+* %RETURNS:
+* 1 if debugging was enabled; 0 otherwise.
+***********************************************************************/
+int
+Event_EnableDebugging(char const *fname)
+{
+#ifndef DEBUG_EVENT
+ return 0;
+#else
+ Event_DebugFP = fopen(fname, "w");
+ return (Event_DebugFP != NULL);
+#endif
+}
+
+/**********************************************************************
+* %FUNCTION: Event_ChangeTimeout
+* %ARGUMENTS:
+* h -- event handler
+* t -- new timeout
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Changes timeout of event handler to be "t" seconds in the future.
+***********************************************************************/
+void
+Event_ChangeTimeout(EventHandler *h, struct timeval t)
+{
+ struct timeval now;
+
+ /* Check time interval for validity */
+ if (t.tv_sec < 0 || t.tv_usec < 0 || t.tv_usec >= 1000000) {
+ return;
+ }
+ /* Convert time interval to absolute time */
+ gettimeofday(&now, NULL);
+
+ t.tv_sec += now.tv_sec;
+ t.tv_usec += now.tv_usec;
+ if (t.tv_usec >= 1000000) {
+ t.tv_usec -= 1000000;
+ t.tv_sec++;
+ }
+
+ h->tmout = t;
+}
diff --git a/jni/src/libevent/event.h b/jni/src/libevent/event.h
new file mode 100755
index 0000000..fad5b95
--- a/dev/null
+++ b/jni/src/libevent/event.h
@@ -0,0 +1,114 @@
+/***********************************************************************
+*
+* event.h
+*
+* Abstraction of select call into "event-handling" to make programming
+* easier.
+*
+* 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$
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+#define DEBUG_EVENT
+
+#ifndef INCLUDE_EVENT_H
+#define INCLUDE_EVENT_H 1
+
+/* Solaris moans if we don't do this... */
+#ifdef __sun
+#define __EXTENSIONS__ 1
+#endif
+
+struct EventSelector_t;
+
+/* Callback function */
+typedef void (*EventCallbackFunc)(struct EventSelector_t *es,
+ int fd, unsigned int flags,
+ void *data);
+
+#include "eventpriv.h"
+
+/* Create an event selector */
+extern EventSelector *Event_CreateSelector(void);
+
+/* Destroy the event selector */
+extern void Event_DestroySelector(EventSelector *es);
+
+/* Handle one event */
+extern int Event_HandleEvent(EventSelector *es);
+
+/* Add a handler for a ready file descriptor */
+extern EventHandler *Event_AddHandler(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ EventCallbackFunc fn, void *data);
+
+/* Add a handler for a ready file descriptor with associated timeout*/
+extern EventHandler *Event_AddHandlerWithTimeout(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ struct timeval t,
+ EventCallbackFunc fn,
+ void *data);
+
+
+/* Add a timer handler */
+extern EventHandler *Event_AddTimerHandler(EventSelector *es,
+ struct timeval t,
+ EventCallbackFunc fn,
+ void *data);
+
+/* Change the timeout of a timer handler */
+void Event_ChangeTimeout(EventHandler *handler, struct timeval t);
+
+/* Delete a handler */
+extern int Event_DelHandler(EventSelector *es,
+ EventHandler *eh);
+
+/* Retrieve callback function from a handler */
+extern EventCallbackFunc Event_GetCallback(EventHandler *eh);
+
+/* Retrieve data field from a handler */
+extern void *Event_GetData(EventHandler *eh);
+
+/* Set callback and data to new values */
+extern void Event_SetCallbackAndData(EventHandler *eh,
+ EventCallbackFunc fn,
+ void *data);
+
+/* Handle a signal synchronously in event loop */
+int Event_HandleSignal(EventSelector *es, int sig, void (*handler)(int sig));
+
+/* Reap children synchronously in event loop */
+int Event_HandleChildExit(EventSelector *es, pid_t pid,
+ void (*handler)(pid_t, int, void *), void *data);
+
+extern int Event_EnableDebugging(char const *fname);
+
+#ifdef DEBUG_EVENT
+extern void Event_DebugMsg(char const *fmt, ...);
+#define EVENT_DEBUG(x) Event_DebugMsg x
+#else
+#define EVENT_DEBUG(x) ((void) 0)
+#endif
+
+/* Flags */
+#define EVENT_FLAG_READABLE 1
+#define EVENT_FLAG_WRITEABLE 2
+#define EVENT_FLAG_WRITABLE EVENT_FLAG_WRITEABLE
+
+/* This is strictly a timer event */
+#define EVENT_FLAG_TIMER 4
+
+/* This is a read or write event with an associated timeout */
+#define EVENT_FLAG_TIMEOUT 8
+
+#define EVENT_TIMER_BITS (EVENT_FLAG_TIMER | EVENT_FLAG_TIMEOUT)
+#endif
diff --git a/jni/src/libevent/event_sig.c b/jni/src/libevent/event_sig.c
new file mode 100755
index 0000000..e3b4e4b
--- a/dev/null
+++ b/jni/src/libevent/event_sig.c
@@ -0,0 +1,265 @@
+/***********************************************************************
+*
+* event_sig.c
+*
+* Code for handling signals nicely (synchronously) and for dealing
+* with reaping child processes.
+*
+* Copyright (C) 2002 by Roaring Penguin Software Inc.
+*
+* This software may be distributed under the terms of the GNU General
+* Public License, Version 2, or (at your option) any later version.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#define _POSIX_SOURCE 1 /* For sigaction defines */
+#define _BSD_SOURCE 1 /* For SA_RESTART */
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include "event.h"
+#include "hash.h"
+
+/* Kludge for figuring out NSIG */
+#ifdef NSIG
+#define MAX_SIGNALS NSIG
+#elif defined(_NSIG)
+#define MAX_SIGNALS _NSIG
+#else
+#define MAX_SIGNALS 256 /* Should be safe... */
+#endif
+
+/* A structure for a "synchronous" signal handler */
+struct SynchronousSignalHandler {
+ int fired; /* Have we received this signal? */
+ void (*handler)(int sig); /* Handler function */
+};
+
+/* A structure for calling back when a child dies */
+struct ChildEntry {
+ hash_bucket hash;
+ void (*handler)(pid_t pid, int status, void *data);
+ pid_t pid;
+ void *data;
+};
+
+static struct SynchronousSignalHandler SignalHandlers[MAX_SIGNALS];
+static int Pipe[2] = {-1, -1};
+static EventHandler *PipeHandler = NULL;
+static sig_atomic_t PipeFull = 0;
+static hash_table child_process_table;
+
+static unsigned int child_hash(void *data)
+{
+ return (unsigned int) ((struct ChildEntry *) data)->pid;
+}
+
+static int child_compare(void *d1, void *d2)
+{
+ return ((struct ChildEntry *)d1)->pid != ((struct ChildEntry *)d2)->pid;
+}
+
+/**********************************************************************
+* %FUNCTION: DoPipe
+* %ARGUMENTS:
+* es -- event selector
+* fd -- readable file descriptor
+* flags -- flags from event system
+* data -- ignored
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Called when an async signal handler wants attention. This function
+* fires all "synchronous" signal handlers.
+***********************************************************************/
+static void
+DoPipe(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ void *data)
+{
+ char buf[64];
+ int i;
+
+ /* Clear buffer */
+ read(fd, buf, 64);
+ PipeFull = 0;
+
+ /* Fire handlers */
+ for (i=0; i<MAX_SIGNALS; i++) {
+ if (SignalHandlers[i].fired &&
+ SignalHandlers[i].handler) {
+ SignalHandlers[i].handler(i);
+ }
+ SignalHandlers[i].fired = 0;
+ }
+}
+
+/**********************************************************************
+* %FUNCTION: sig_handler
+* %ARGUMENTS:
+* sig -- signal number
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Marks a signal as having "fired"; fills IPC pipe.
+***********************************************************************/
+static void
+sig_handler(int sig)
+{
+ if (sig <0 || sig > MAX_SIGNALS) {
+ /* Ooops... */
+ return;
+ }
+ SignalHandlers[sig].fired = 1;
+ if (!PipeFull) {
+ write(Pipe[1], &sig, 1);
+ PipeFull = 1;
+ }
+}
+
+/**********************************************************************
+* %FUNCTION: child_handler
+* %ARGUMENTS:
+* sig -- signal number (whoop-dee-doo)
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Called *SYNCHRONOUSLY* to reap dead children.
+***********************************************************************/
+static void
+child_handler(int sig)
+{
+ int status;
+ int pid;
+ struct ChildEntry *ce;
+ struct ChildEntry candidate;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ candidate.pid = (pid_t) pid;
+ ce = hash_find(&child_process_table, &candidate);
+ if (ce) {
+ if (ce->handler) {
+ ce->handler(pid, status, ce->data);
+ }
+ hash_remove(&child_process_table, ce);
+ free(ce);
+ }
+ }
+}
+
+/**********************************************************************
+* %FUNCTION: SetupPipes (static)
+* %ARGUMENTS:
+* es -- event selector
+* %RETURNS:
+* 0 on success; -1 on failure
+* %DESCRIPTION:
+* Sets up pipes with an event handler to handle IPC from a signal handler
+***********************************************************************/
+static int
+SetupPipes(EventSelector *es)
+{
+ /* If already done, do nothing */
+ if (PipeHandler) return 0;
+
+ /* Initialize the child-process hash table */
+ hash_init(&child_process_table,
+ offsetof(struct ChildEntry, hash),
+ child_hash,
+ child_compare);
+
+ /* Open pipe to self */
+ if (pipe(Pipe) < 0) {
+ return -1;
+ }
+
+ PipeHandler = Event_AddHandler(es, Pipe[0],
+ EVENT_FLAG_READABLE, DoPipe, NULL);
+ if (!PipeHandler) {
+ int old_errno = errno;
+ close(Pipe[0]);
+ close(Pipe[1]);
+ errno = old_errno;
+ return -1;
+ }
+ return 0;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_HandleSignal
+* %ARGUMENTS:
+* es -- event selector
+* sig -- signal number
+* handler -- handler to call when signal is raised. Handler is called
+* "synchronously" as events are processed by event loop.
+* %RETURNS:
+* 0 on success, -1 on error.
+* %DESCRIPTION:
+* Sets up a "synchronous" signal handler.
+***********************************************************************/
+int
+Event_HandleSignal(EventSelector *es,
+ int sig,
+ void (*handler)(int sig))
+{
+ struct sigaction act;
+
+ if (SetupPipes(es) < 0) return -1;
+
+ act.sa_handler = sig_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+#ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+#endif
+ if (sig == SIGCHLD) {
+ act.sa_flags |= SA_NOCLDSTOP;
+ }
+ if (sigaction(sig, &act, NULL) < 0) return -1;
+
+ SignalHandlers[sig].handler = handler;
+
+ return 0;
+}
+
+/**********************************************************************
+* %FUNCTION: Event_HandleChildExit
+* %ARGUMENTS:
+* es -- event selector
+* pid -- process-ID of child to wait for
+* handler -- function to call when child exits
+* data -- data to pass to handler when child exits
+* %RETURNS:
+* 0 on success, -1 on failure.
+* %DESCRIPTION:
+* Sets things up so that when a child exits, handler() will be called
+* with the pid of the child and "data" as arguments. The call will
+* be synchronous (part of the normal event loop on es).
+***********************************************************************/
+int
+Event_HandleChildExit(EventSelector *es,
+ pid_t pid,
+ void (*handler)(pid_t, int, void *),
+ void *data)
+{
+ struct ChildEntry *ce;
+
+ if (Event_HandleSignal(es, SIGCHLD, child_handler) < 0) return -1;
+ ce = malloc(sizeof(struct ChildEntry));
+ if (!ce) return -1;
+ ce->pid = pid;
+ ce->data = data;
+ ce->handler = handler;
+ hash_insert(&child_process_table, ce);
+ return 0;
+}
diff --git a/jni/src/libevent/event_tcp.c b/jni/src/libevent/event_tcp.c
new file mode 100755
index 0000000..679e06b
--- a/dev/null
+++ b/jni/src/libevent/event_tcp.c
@@ -0,0 +1,577 @@
+/***********************************************************************
+*
+* event_tcp.c -- implementation of event-driven socket I/O.
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "event_tcp.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+static void free_state(EventTcpState *state);
+
+typedef struct EventTcpConnectState_t {
+ int fd;
+ EventHandler *conn;
+ EventTcpConnectFunc f;
+ void *data;
+} EventTcpConnectState;
+
+/**********************************************************************
+* %FUNCTION: handle_accept
+* %ARGUMENTS:
+* es -- event selector
+* fd -- socket
+* flags -- ignored
+* data -- the accept callback function
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Calls accept; if a connection arrives, calls the accept callback
+* function with connected descriptor
+***********************************************************************/
+static void
+handle_accept(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ void *data)
+{
+ int conn;
+ EventTcpAcceptFunc f;
+
+ EVENT_DEBUG(("tcp_handle_accept(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
+ conn = accept(fd, NULL, NULL);
+ if (conn < 0) return;
+ f = (EventTcpAcceptFunc) data;
+
+ f(es, conn);
+}
+
+/**********************************************************************
+* %FUNCTION: handle_connect
+* %ARGUMENTS:
+* es -- event selector
+* fd -- socket
+* flags -- ignored
+* data -- the accept callback function
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Calls accept; if a connection arrives, calls the accept callback
+* function with connected descriptor
+***********************************************************************/
+static void
+handle_connect(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ void *data)
+{
+ int error = 0;
+ socklen_t len = sizeof(error);
+ EventTcpConnectState *state = (EventTcpConnectState *) data;
+
+ EVENT_DEBUG(("tcp_handle_connect(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
+
+ /* Cancel writable event */
+ Event_DelHandler(es, state->conn);
+ state->conn = NULL;
+
+ /* Timeout? */
+ if (flags & EVENT_FLAG_TIMEOUT) {
+ errno = ETIMEDOUT;
+ state->f(es, fd, EVENT_TCP_FLAG_TIMEOUT, state->data);
+ free(state);
+ return;
+ }
+
+ /* Check for pending error */
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+ state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);
+ free(state);
+ return;
+ }
+ if (error) {
+ errno = error;
+ state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);
+ free(state);
+ return;
+ }
+
+ /* It looks cool! */
+ state->f(es, fd, EVENT_TCP_FLAG_COMPLETE, state->data);
+ free(state);
+}
+
+/**********************************************************************
+* %FUNCTION: EventTcp_CreateAcceptor
+* %ARGUMENTS:
+* es -- event selector
+* socket -- listening socket
+* f -- function to call when a connection is accepted
+* data -- extra data to pass to f.
+* %RETURNS:
+* An event handler on success, NULL on failure.
+* %DESCRIPTION:
+* Sets up an accepting socket and calls "f" whenever a new
+* connection arrives.
+***********************************************************************/
+EventHandler *
+EventTcp_CreateAcceptor(EventSelector *es,
+ int socket,
+ EventTcpAcceptFunc f)
+{
+ int flags;
+
+ EVENT_DEBUG(("EventTcp_CreateAcceptor(es=%p, socket=%d)\n", es, socket));
+ /* Make sure socket is non-blocking */
+ flags = fcntl(socket, F_GETFL, 0);
+ if (flags == -1) {
+ return NULL;
+ }
+ if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+ return NULL;
+ }
+
+ return Event_AddHandler(es, socket, EVENT_FLAG_READABLE,
+ handle_accept, (void *) f);
+
+}
+
+/**********************************************************************
+* %FUNCTION: free_state
+* %ARGUMENTS:
+* state -- EventTcpState to free
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Frees all state associated with the TcpEvent.
+***********************************************************************/
+static void
+free_state(EventTcpState *state)
+{
+ if (!state) return;
+ EVENT_DEBUG(("tcp_free_state(state=%p)\n", state));
+ if (state->buf) free(state->buf);
+ if (state->eh) Event_DelHandler(state->es, state->eh);
+ free(state);
+}
+
+/**********************************************************************
+* %FUNCTION: handle_readable
+* %ARGUMENTS:
+* es -- event selector
+* fd -- the readable socket
+* flags -- ignored
+* data -- the EventTcpState object
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Continues to fill buffer. Calls callback when done.
+***********************************************************************/
+static void
+handle_readable(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ void *data)
+{
+ EventTcpState *state = (EventTcpState *) data;
+ int done = state->cur - state->buf;
+ int togo = state->len - done;
+ int nread = 0;
+ int flag;
+
+ EVENT_DEBUG(("tcp_handle_readable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
+
+ /* Timed out? */
+ if (flags & EVENT_FLAG_TIMEOUT) {
+ errno = ETIMEDOUT;
+ (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,
+ state->data);
+ free_state(state);
+ return;
+ }
+ if (state->delim < 0) {
+ /* Not looking for a delimiter */
+ /* togo had better not be zero here! */
+ nread = read(fd, state->cur, togo);
+ if (nread <= 0) {
+ /* Change connection reset to EOF if we have read at least
+ one char */
+ if (nread < 0 && errno == ECONNRESET && done > 0) {
+ nread = 0;
+ }
+ flag = (nread) ? EVENT_TCP_FLAG_IOERROR : EVENT_TCP_FLAG_EOF;
+ /* error or EOF */
+ (state->f)(es, state->socket, state->buf, done, flag, state->data);
+ free_state(state);
+ return;
+ }
+ state->cur += nread;
+ done += nread;
+ if (done >= state->len) {
+ /* Read enough! */
+ (state->f)(es, state->socket, state->buf, done,
+ EVENT_TCP_FLAG_COMPLETE, state->data);
+ free_state(state);
+ return;
+ }
+ } else {
+ /* Looking for a delimiter */
+ while ( (togo > 0) && (nread = read(fd, state->cur, 1)) == 1) {
+ togo--;
+ done++;
+ state->cur++;
+ if (*(state->cur - 1) == state->delim) break;
+ }
+
+ if (nread <= 0) {
+ /* Error or EOF -- check for EAGAIN */
+ if (nread < 0 && errno == EAGAIN) return;
+ }
+
+ /* Some other error, or EOF, or delimiter, or read enough */
+ if (nread < 0) {
+ flag = EVENT_TCP_FLAG_IOERROR;
+ } else if (nread == 0) {
+ flag = EVENT_TCP_FLAG_EOF;
+ } else {
+ flag = EVENT_TCP_FLAG_COMPLETE;
+ }
+ (state->f)(es, state->socket, state->buf, done, flag, state->data);
+ free_state(state);
+ return;
+ }
+}
+
+/**********************************************************************
+* %FUNCTION: handle_writeable
+* %ARGUMENTS:
+* es -- event selector
+* fd -- the writeable socket
+* flags -- ignored
+* data -- the EventTcpState object
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Continues to fill buffer. Calls callback when done.
+***********************************************************************/
+static void
+handle_writeable(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ void *data)
+{
+ EventTcpState *state = (EventTcpState *) data;
+ int done = state->cur - state->buf;
+ int togo = state->len - done;
+ int n;
+
+ /* Timed out? */
+ if (flags & EVENT_FLAG_TIMEOUT) {
+ errno = ETIMEDOUT;
+ (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,
+ state->data);
+ free_state(state);
+ return;
+ }
+
+ /* togo had better not be zero here! */
+ n = write(fd, state->cur, togo);
+
+ EVENT_DEBUG(("tcp_handle_writeable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
+ if (n <= 0) {
+ /* error */
+ if (state->f) {
+ (state->f)(es, state->socket, state->buf, done,
+ EVENT_TCP_FLAG_IOERROR,
+ state->data);
+ } else {
+ close(fd);
+ }
+ free_state(state);
+ return;
+ }
+ state->cur += n;
+ done += n;
+ if (done >= state->len) {
+ /* Written enough! */
+ if (state->f) {
+ (state->f)(es, state->socket, state->buf, done,
+ EVENT_TCP_FLAG_COMPLETE, state->data);
+ } else {
+ close(fd);
+ }
+ free_state(state);
+ return;
+ }
+
+}
+
+/**********************************************************************
+* %FUNCTION: EventTcp_ReadBuf
+* %ARGUMENTS:
+* es -- event selector
+* socket -- socket to read from
+* len -- maximum number of bytes to read
+* delim -- delimiter at which to stop reading, or -1 if we should
+* read exactly len bytes
+* f -- function to call on EOF or when all bytes have been read
+* timeout -- if non-zero, timeout in seconds after which we cancel
+* operation.
+* data -- extra data to pass to function f.
+* %RETURNS:
+* A new EventTcpState token or NULL on error
+* %DESCRIPTION:
+* Sets up a handler to fill a buffer from a socket.
+***********************************************************************/
+EventTcpState *
+EventTcp_ReadBuf(EventSelector *es,
+ int socket,
+ int len,
+ int delim,
+ EventTcpIOFinishedFunc f,
+ int timeout,
+ void *data)
+{
+ EventTcpState *state;
+ int flags;
+ struct timeval t;
+
+ EVENT_DEBUG(("EventTcp_ReadBuf(es=%p, socket=%d, len=%d, delim=%d, timeout=%d)\n", es, socket, len, delim, timeout));
+ if (len <= 0) return NULL;
+ if (socket < 0) return NULL;
+
+ /* Make sure socket is non-blocking */
+ flags = fcntl(socket, F_GETFL, 0);
+ if (flags == -1) {
+ return NULL;
+ }
+ if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+ return NULL;
+ }
+
+ state = malloc(sizeof(EventTcpState));
+ if (!state) return NULL;
+
+ memset(state, 0, sizeof(EventTcpState));
+
+ state->socket = socket;
+
+ state->buf = malloc(len);
+ if (!state->buf) {
+ free_state(state);
+ return NULL;
+ }
+
+ state->cur = state->buf;
+ state->len = len;
+ state->f = f;
+ state->es = es;
+
+ if (timeout <= 0) {
+ t.tv_sec = -1;
+ t.tv_usec = -1;
+ } else {
+ t.tv_sec = timeout;
+ t.tv_usec = 0;
+ }
+
+ state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_READABLE,
+ t, handle_readable,
+ (void *) state);
+ if (!state->eh) {
+ free_state(state);
+ return NULL;
+ }
+ state->data = data;
+ state->delim = delim;
+ EVENT_DEBUG(("EventTcp_ReadBuf() -> %p\n", state));
+
+ return state;
+}
+
+/**********************************************************************
+* %FUNCTION: EventTcp_WriteBuf
+* %ARGUMENTS:
+* es -- event selector
+* socket -- socket to read from
+* buf -- buffer to write
+* len -- number of bytes to write
+* f -- function to call on EOF or when all bytes have been read
+* timeout -- timeout after which to cancel operation
+* data -- extra data to pass to function f.
+* %RETURNS:
+* A new EventTcpState token or NULL on error
+* %DESCRIPTION:
+* Sets up a handler to fill a buffer from a socket.
+***********************************************************************/
+EventTcpState *
+EventTcp_WriteBuf(EventSelector *es,
+ int socket,
+ char *buf,
+ int len,
+ EventTcpIOFinishedFunc f,
+ int timeout,
+ void *data)
+{
+ EventTcpState *state;
+ int flags;
+ struct timeval t;
+
+ EVENT_DEBUG(("EventTcp_WriteBuf(es=%p, socket=%d, len=%d, timeout=%d)\n", es, socket, len, timeout));
+ if (len <= 0) return NULL;
+ if (socket < 0) return NULL;
+
+ /* Make sure socket is non-blocking */
+ flags = fcntl(socket, F_GETFL, 0);
+ if (flags == -1) {
+ return NULL;
+ }
+ if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+ return NULL;
+ }
+
+ state = malloc(sizeof(EventTcpState));
+ if (!state) return NULL;
+
+ memset(state, 0, sizeof(EventTcpState));
+
+ state->socket = socket;
+
+ state->buf = malloc(len);
+ if (!state->buf) {
+ free_state(state);
+ return NULL;
+ }
+ memcpy(state->buf, buf, len);
+
+ state->cur = state->buf;
+ state->len = len;
+ state->f = f;
+ state->es = es;
+
+ if (timeout <= 0) {
+ t.tv_sec = -1;
+ t.tv_usec = -1;
+ } else {
+ t.tv_sec = timeout;
+ t.tv_usec = 0;
+ }
+
+ state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_WRITEABLE,
+ t, handle_writeable,
+ (void *) state);
+ if (!state->eh) {
+ free_state(state);
+ return NULL;
+ }
+
+ state->data = data;
+ state->delim = -1;
+ EVENT_DEBUG(("EventTcp_WriteBuf() -> %p\n", state));
+ return state;
+}
+
+/**********************************************************************
+* %FUNCTION: EventTcp_Connect
+* %ARGUMENTS:
+* es -- event selector
+* fd -- descriptor to connect
+* addr -- address to connect to
+* addrlen -- length of address
+* f -- function to call with connected socket
+* data -- extra data to pass to f
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Does a non-blocking connect on fd
+***********************************************************************/
+void
+EventTcp_Connect(EventSelector *es,
+ int fd,
+ struct sockaddr const *addr,
+ socklen_t addrlen,
+ EventTcpConnectFunc f,
+ int timeout,
+ void *data)
+{
+ int flags;
+ int n;
+ EventTcpConnectState *state;
+ struct timeval t;
+
+ /* Make sure socket is non-blocking */
+ flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
+ return;
+ }
+
+ n = connect(fd, addr, addrlen);
+ if (n < 0) {
+ if (errno != EINPROGRESS) {
+ f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
+ return;
+ }
+ }
+
+ if (n == 0) { /* Connect succeeded immediately */
+ f(es, fd, EVENT_TCP_FLAG_COMPLETE, data);
+ return;
+ }
+
+ state = malloc(sizeof(*state));
+ if (!state) {
+ f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
+ return;
+ }
+ state->f = f;
+ state->fd = fd;
+ state->data = data;
+
+ if (timeout <= 0) {
+ t.tv_sec = -1;
+ t.tv_usec = -1;
+ } else {
+ t.tv_sec = timeout;
+ t.tv_usec = 0;
+ }
+
+ state->conn = Event_AddHandlerWithTimeout(es, fd, EVENT_FLAG_WRITEABLE,
+ t, handle_connect,
+ (void *) state);
+ if (!state->conn) {
+ free(state);
+ f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
+ return;
+ }
+}
+
+/**********************************************************************
+* %FUNCTION: EventTcp_CancelPending
+* %ARGUMENTS:
+* s -- an EventTcpState
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Cancels the pending event handler
+***********************************************************************/
+void
+EventTcp_CancelPending(EventTcpState *s)
+{
+ free_state(s);
+}
diff --git a/jni/src/libevent/event_tcp.h b/jni/src/libevent/event_tcp.h
new file mode 100755
index 0000000..7e281d0
--- a/dev/null
+++ b/jni/src/libevent/event_tcp.h
@@ -0,0 +1,87 @@
+/***********************************************************************
+*
+* event-tcp.h
+*
+* Event-driven TCP functions to allow for single-threaded "concurrent"
+* server.
+*
+* Copyright (C) 2001 Roaring Penguin Software Inc.
+*
+* $Id$
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+#ifndef INCLUDE_EVENT_TCP_H
+#define INCLUDE_EVENT_TCP_H 1
+
+#include "event.h"
+#include <sys/socket.h>
+
+typedef void (*EventTcpAcceptFunc)(EventSelector *es,
+ int fd);
+
+typedef void (*EventTcpConnectFunc)(EventSelector *es,
+ int fd,
+ int flag,
+ void *data);
+
+typedef void (*EventTcpIOFinishedFunc)(EventSelector *es,
+ int fd,
+ char *buf,
+ int len,
+ int flag,
+ void *data);
+
+#define EVENT_TCP_FLAG_COMPLETE 0
+#define EVENT_TCP_FLAG_IOERROR 1
+#define EVENT_TCP_FLAG_EOF 2
+#define EVENT_TCP_FLAG_TIMEOUT 3
+
+typedef struct EventTcpState_t {
+ int socket;
+ char *buf;
+ char *cur;
+ int len;
+ int delim;
+ EventTcpIOFinishedFunc f;
+ EventSelector *es;
+ EventHandler *eh;
+ void *data;
+} EventTcpState;
+
+extern EventHandler *EventTcp_CreateAcceptor(EventSelector *es,
+ int socket,
+ EventTcpAcceptFunc f);
+
+extern void EventTcp_Connect(EventSelector *es,
+ int fd,
+ struct sockaddr const *addr,
+ socklen_t addrlen,
+ EventTcpConnectFunc f,
+ int timeout,
+ void *data);
+
+extern EventTcpState *EventTcp_ReadBuf(EventSelector *es,
+ int socket,
+ int len,
+ int delim,
+ EventTcpIOFinishedFunc f,
+ int timeout,
+ void *data);
+
+extern EventTcpState *EventTcp_WriteBuf(EventSelector *es,
+ int socket,
+ char *buf,
+ int len,
+ EventTcpIOFinishedFunc f,
+ int timeout,
+ void *data);
+
+extern void EventTcp_CancelPending(EventTcpState *s);
+
+#endif
diff --git a/jni/src/libevent/eventpriv.h b/jni/src/libevent/eventpriv.h
new file mode 100755
index 0000000..7be7654
--- a/dev/null
+++ b/jni/src/libevent/eventpriv.h
@@ -0,0 +1,46 @@
+/***********************************************************************
+*
+* eventpriv.h
+*
+* Abstraction of select call into "event-handling" to make programming
+* easier. This header includes "private" definitions which users
+* of the event-handling code should not care about.
+*
+* 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$
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+#ifndef INCLUDE_EVENTPRIV_H
+#define INCLUDE_EVENTPRIV_H 1
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Handler structure */
+typedef struct EventHandler_t {
+ struct EventHandler_t *next; /* Link in list */
+ int fd; /* File descriptor for select */
+ unsigned int flags; /* Select on read or write; enable timeout */
+ struct timeval tmout; /* Absolute time for timeout */
+ EventCallbackFunc fn; /* Callback function */
+ void *data; /* Extra data to pass to callback */
+} EventHandler;
+
+/* Selector structure */
+typedef struct EventSelector_t {
+ EventHandler *handlers; /* Linked list of EventHandlers */
+ int nestLevel; /* Event-handling nesting level */
+ int opsPending; /* True if operations are pending */
+ int destroyPending; /* If true, a destroy is pending */
+} EventSelector;
+
+/* Private flags */
+#define EVENT_FLAG_DELETED 256
+#endif
diff --git a/jni/src/libevent/hash.c b/jni/src/libevent/hash.c
new file mode 100755
index 0000000..cc58ef0
--- a/dev/null
+++ b/jni/src/libevent/hash.c
@@ -0,0 +1,266 @@
+/***********************************************************************
+*
+* hash.c
+*
+* Implementation of hash tables. Each item inserted must include
+* a hash_bucket member.
+*
+* Copyright (C) 2002 Roaring Penguin Software Inc.
+*
+* This software may be distributed under the terms of the GNU General
+* Public License, Version 2 or (at your option) any later version.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "hash.h"
+
+#include <limits.h>
+#define BITS_IN_int ( sizeof(int) * CHAR_BIT )
+#define THREE_QUARTERS ((int) ((BITS_IN_int * 3) / 4))
+#define ONE_EIGHTH ((int) (BITS_IN_int / 8))
+#define HIGH_BITS ( ~((unsigned int)(~0) >> ONE_EIGHTH ))
+
+#define GET_BUCKET(tab, data) ((hash_bucket *) ((char *) (data) + (tab)->hash_offset))
+
+#define GET_ITEM(tab, bucket) ((void *) (((char *) (void *) bucket) - (tab)->hash_offset))
+
+static void *hash_next_cursor(hash_table *tab, hash_bucket *b);
+
+/**********************************************************************
+* %FUNCTION: hash_init
+* %ARGUMENTS:
+* tab -- hash table
+* hash_offset -- offset of hash_bucket data member in inserted items
+* compute -- pointer to function to compute hash value
+* compare -- pointer to comparison function. Returns 0 if items are equal,
+* non-zero otherwise.
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Initializes a hash table.
+***********************************************************************/
+void
+hash_init(hash_table *tab,
+ size_t hash_offset,
+ unsigned int (*compute)(void *data),
+ int (*compare)(void *item1, void *item2))
+{
+ size_t i;
+
+ tab->hash_offset = hash_offset;
+ tab->compute_hash = compute;
+ tab->compare = compare;
+ for (i=0; i<HASHTAB_SIZE; i++) {
+ tab->buckets[i] = NULL;
+ }
+ tab->num_entries = 0;
+}
+
+/**********************************************************************
+* %FUNCTION: hash_insert
+* %ARGUMENTS:
+* tab -- hash table to insert into
+* item -- the item we're inserting
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Inserts an item into the hash table. It must not currently be in any
+* hash table.
+***********************************************************************/
+void
+hash_insert(hash_table *tab,
+ void *item)
+{
+ hash_bucket *b = GET_BUCKET(tab, item);
+ unsigned int val = tab->compute_hash(item);
+ b->hashval = val;
+ val %= HASHTAB_SIZE;
+ b->prev = NULL;
+ b->next = tab->buckets[val];
+ if (b->next) {
+ b->next->prev = b;
+ }
+ tab->buckets[val] = b;
+ tab->num_entries++;
+}
+
+/**********************************************************************
+* %FUNCTION: hash_remove
+* %ARGUMENTS:
+* tab -- hash table
+* item -- item in hash table
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Removes item from hash table
+***********************************************************************/
+void
+hash_remove(hash_table *tab,
+ void *item)
+{
+ hash_bucket *b = GET_BUCKET(tab, item);
+ unsigned int val = b->hashval % HASHTAB_SIZE;
+
+ if (b->prev) {
+ b->prev->next = b->next;
+ } else {
+ tab->buckets[val] = b->next;
+ }
+ if (b->next) {
+ b->next->prev = b->prev;
+ }
+ tab->num_entries--;
+}
+
+/**********************************************************************
+* %FUNCTION: hash_find
+* %ARGUMENTS:
+* tab -- hash table
+* item -- item equal to one we're seeking (in the compare-function sense)
+* %RETURNS:
+* A pointer to the item in the hash table, or NULL if no such item
+* %DESCRIPTION:
+* Searches hash table for item.
+***********************************************************************/
+void *
+hash_find(hash_table *tab,
+ void *item)
+{
+ unsigned int val = tab->compute_hash(item) % HASHTAB_SIZE;
+ hash_bucket *b;
+ for (b = tab->buckets[val]; b; b = b->next) {
+ void *item2 = GET_ITEM(tab, b);
+ if (!tab->compare(item, item2)) return item2;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+* %FUNCTION: hash_find_next
+* %ARGUMENTS:
+* tab -- hash table
+* item -- an item returned by hash_find or hash_find_next
+* %RETURNS:
+* A pointer to the next equal item in the hash table, or NULL if no such item
+* %DESCRIPTION:
+* Searches hash table for anoter item equivalent to this one. Search
+* starts from item.
+***********************************************************************/
+void *
+hash_find_next(hash_table *tab,
+ void *item)
+{
+ hash_bucket *b = GET_BUCKET(tab, item);
+ for (b = b->next; b; b = b->next) {
+ void *item2 = GET_ITEM(tab, b);
+ if (!tab->compare(item, item2)) return item2;
+ }
+ return NULL;
+}
+/**********************************************************************
+* %FUNCTION: hash_start
+* %ARGUMENTS:
+* tab -- hash table
+* cursor -- a void pointer to keep track of location
+* %RETURNS:
+* "first" entry in hash table, or NULL if table is empty
+* %DESCRIPTION:
+* Starts an iterator -- sets cursor so hash_next will return next entry.
+***********************************************************************/
+void *
+hash_start(hash_table *tab, void **cursor)
+{
+ int i;
+ for (i=0; i<HASHTAB_SIZE; i++) {
+ if (tab->buckets[i]) {
+ /* Point cursor to NEXT item so it is valid
+ even if current item is free'd */
+ *cursor = hash_next_cursor(tab, tab->buckets[i]);
+ return GET_ITEM(tab, tab->buckets[i]);
+ }
+ }
+ *cursor = NULL;
+ return NULL;
+}
+
+/**********************************************************************
+* %FUNCTION: hash_next
+* %ARGUMENTS:
+* tab -- hash table
+* cursor -- cursor into hash table
+* %RETURNS:
+* Next item in table, or NULL.
+* %DESCRIPTION:
+* Steps cursor to next item in table.
+***********************************************************************/
+void *
+hash_next(hash_table *tab, void **cursor)
+{
+ hash_bucket *b;
+
+ if (!*cursor) return NULL;
+
+ b = (hash_bucket *) *cursor;
+ *cursor = hash_next_cursor(tab, b);
+ return GET_ITEM(tab, b);
+}
+
+/**********************************************************************
+* %FUNCTION: hash_next_cursor
+* %ARGUMENTS:
+* tab -- a hash table
+* b -- a hash bucket
+* %RETURNS:
+* Cursor value for bucket following b in hash table.
+***********************************************************************/
+static void *
+hash_next_cursor(hash_table *tab, hash_bucket *b)
+{
+ unsigned int i;
+ if (!b) return NULL;
+ if (b->next) return b->next;
+
+ i = b->hashval % HASHTAB_SIZE;
+ for (++i; i<HASHTAB_SIZE; ++i) {
+ if (tab->buckets[i]) return tab->buckets[i];
+ }
+ return NULL;
+}
+
+size_t
+hash_num_entries(hash_table *tab)
+{
+ return tab->num_entries;
+}
+
+/**********************************************************************
+* %FUNCTION: hash_pjw
+* %ARGUMENTS:
+* str -- a zero-terminated string
+* %RETURNS:
+* A hash value using the hashpjw algorithm
+* %DESCRIPTION:
+* An adaptation of Peter Weinberger's (PJW) generic hashing
+* algorithm based on Allen Holub's version. Accepts a pointer
+* to a datum to be hashed and returns an unsigned integer.
+***********************************************************************/
+unsigned int
+hash_pjw(char const * str)
+{
+ unsigned int hash_value, i;
+
+ for (hash_value = 0; *str; ++str) {
+ hash_value = ( hash_value << ONE_EIGHTH ) + *str;
+ if (( i = hash_value & HIGH_BITS ) != 0 ) {
+ hash_value =
+ ( hash_value ^ ( i >> THREE_QUARTERS )) &
+ ~HIGH_BITS;
+ }
+ }
+ return hash_value;
+}
diff --git a/jni/src/libevent/hash.h b/jni/src/libevent/hash.h
new file mode 100755
index 0000000..6169c6e
--- a/dev/null
+++ b/jni/src/libevent/hash.h
@@ -0,0 +1,54 @@
+/***********************************************************************
+*
+* hash.h
+*
+* Hash table utilities
+*
+* Copyright (C) 2002 Roaring Penguin Software Inc.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+#ifndef HASH_H
+#define HASH_H
+
+#include <stdlib.h>
+/* Fixed-size hash tables for now */
+#define HASHTAB_SIZE 67
+
+/* A hash bucket */
+typedef struct hash_bucket_t {
+ struct hash_bucket_t *next;
+ struct hash_bucket_t *prev;
+ unsigned int hashval;
+} hash_bucket;
+
+/* A hash table */
+typedef struct hash_table_t {
+ hash_bucket *buckets[HASHTAB_SIZE];
+ size_t hash_offset;
+ unsigned int (*compute_hash)(void *data);
+ int (*compare)(void *item1, void *item2);
+ size_t num_entries;
+} hash_table;
+
+/* Functions */
+void hash_init(hash_table *tab,
+ size_t hash_offset,
+ unsigned int (*compute)(void *data),
+ int (*compare)(void *item1, void *item2));
+void hash_insert(hash_table *tab, void *item);
+void hash_remove(hash_table *tab, void *item);
+void *hash_find(hash_table *tab, void *item);
+void *hash_find_next(hash_table *tab, void *item);
+size_t hash_num_entries(hash_table *tab);
+
+/* Iteration functions */
+void *hash_start(hash_table *tab, void **cursor);
+void *hash_next(hash_table *tab, void **cursor);
+
+/* Utility function: hashpjw for strings */
+unsigned int hash_pjw(char const *str);
+
+#endif
diff --git a/jni/src/md5.c b/jni/src/md5.c
new file mode 100755
index 0000000..a379cf5
--- a/dev/null
+++ b/jni/src/md5.c
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ * LIC: GPL
+ *
+ * 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"
+
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static 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/jni/src/md5.h b/jni/src/md5.h
new file mode 100755
index 0000000..525a45e
--- a/dev/null
+++ b/jni/src/md5.h
@@ -0,0 +1,34 @@
+#ifndef MD5_H
+#define MD5_H
+/*
+ * LIC: GPL
+ */
+
+#include "config.h"
+
+#if SIZEOF_UNSIGNED_INT == 4
+typedef unsigned int uint32;
+#elif SIZEOF_UNSIGNED_LONG == 4
+typedef unsigned long uint32;
+#else
+# error Could not find a 32-bit integer type
+#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/jni/src/plugin.c b/jni/src/plugin.c
new file mode 100755
index 0000000..83978f0
--- a/dev/null
+++ b/jni/src/plugin.c
@@ -0,0 +1,469 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+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/ppp_defs.h>
+#include <linux/if_pppox.h>
+
+#ifndef _ROOT_PATH
+#define _ROOT_PATH ""
+#endif
+
+#define _PATH_ETHOPT _ROOT_PATH "/etc/ppp/options."
+
+char pppd_version[] = VERSION;
+
+/* From sys-linux.c in pppd -- MUST FIX THIS! */
+extern int new_style_driver;
+
+char *pppd_pppoe_service = NULL;
+static char *acName = NULL;
+static char *existingSession = NULL;
+static int printACNames = 0;
+
+static int PPPoEDevnameHook(char *cmd, char **argv, int doit);
+static option_t Options[] = {
+ { "device name", o_wild, (void *) &PPPoEDevnameHook,
+ "PPPoE device name",
+ OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC,
+ devnam},
+ { "rp_pppoe_service", o_string, &pppd_pppoe_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)" },
+ { "rp_pppoe_verbose", o_int, &printACNames,
+ "Be verbose about discovered access concentrators"},
+ { NULL }
+};
+int (*OldDevnameHook)(char *cmd, char **argv, int doit) = 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 (pppd_pppoe_service) {
+ SET_STRING(conn->serviceName, pppd_pppoe_service);
+ }
+ SET_STRING(conn->ifName, devnam);
+ conn->discoverySocket = -1;
+ conn->sessionSocket = -1;
+ conn->useHostUniq = 1;
+ conn->printACNames = printACNames;
+ conn->discoveryTimeout = PADI_TIMEOUT;
+ 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;
+
+ /* Open session socket before discovery phase, to avoid losing session */
+ /* packets sent by peer just after PADS packet (noted on some Cisco */
+ /* server equipment). */
+ /* Opening this socket just before waitForPADS in the discovery() */
+ /* function would be more appropriate, but it would mess-up the code */
+ conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
+ if (conn->sessionSocket < 0) {
+ error("Failed to create PPPoE socket: %m");
+ return -1;
+ }
+
+ 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 {
+ conn->discoverySocket =
+ openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+ discovery(conn);
+ if (conn->discoveryState != STATE_SESSION) {
+ error("Unable to complete PPPoE Discovery");
+ return -1;
+ }
+ }
+
+ /* Set PPPoE session-number for further consumption */
+ ppp_session_number = ntohs(conn->session);
+
+ 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);
+
+ /* Set remote_number for ServPoET */
+ sprintf(remote_number, "%02X:%02X:%02X:%02X:%02X:%02X",
+ (unsigned) conn->peerEth[0],
+ (unsigned) conn->peerEth[1],
+ (unsigned) conn->peerEth[2],
+ (unsigned) conn->peerEth[3],
+ (unsigned) conn->peerEth[4],
+ (unsigned) conn->peerEth[5]);
+
+ warn("Connected to %02X:%02X:%02X:%02X:%02X:%02X via interface %s",
+ (unsigned) conn->peerEth[0],
+ (unsigned) conn->peerEth[1],
+ (unsigned) conn->peerEth[2],
+ (unsigned) conn->peerEth[3],
+ (unsigned) conn->peerEth[4],
+ (unsigned) conn->peerEth[5],
+ conn->ifName);
+
+ script_setenv("MACREMOTE", remote_number, 0);
+
+ if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+ sizeof(struct sockaddr_pppox)) < 0) {
+ error("Failed to connect PPPoE socket: %d %m", errno);
+ return -1;
+ }
+
+ return conn->sessionSocket;
+}
+
+static void
+PPPOESendConfig(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);
+ mtu = MAX_PPPOE_MTU;
+ }
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ warn("Couldn't create IP socket: %m");
+ return;
+ }
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) {
+ warn("ioctl(SIOCSIFMTU): %m");
+ return;
+ }
+ (void) close (sock);
+}
+
+
+static void
+PPPOERecvConfig(int mru,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ if (mru > MAX_PPPOE_MTU) {
+ warn("Couldn't increase MRU to %d", mru);
+ }
+}
+
+/**********************************************************************
+ * %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);
+ close(conn->discoverySocket);
+
+}
+
+static void
+PPPOEDeviceOptions(void)
+{
+ char buf[256];
+ snprintf(buf, 256, _PATH_ETHOPT "%s",devnam);
+ if(!options_from_file(buf, 0, 0, 1))
+ exit(EXIT_OPTION_ERROR);
+
+}
+
+struct channel pppoe_channel;
+
+/**********************************************************************
+ * %FUNCTION: PPPoEDevnameHook
+ * %ARGUMENTS:
+ * cmd -- the command (actually, the device name
+ * argv -- argument vector
+ * doit -- if non-zero, set device name. Otherwise, just check if possible
+ * %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).
+ ***********************************************************************/
+static int
+PPPoEDevnameHook(char *cmd, char **argv, int doit)
+{
+ int r = 1;
+ int fd;
+ struct ifreq ifr;
+
+ /* Only do it if name is "ethXXX" or "brXXX" or what was specified
+ by rp_pppoe_dev option (ugh). */
+ /* Can also specify nic-XXXX in which case the nic- is stripped off. */
+ if (!strncmp(cmd, "nic-", 4)) {
+ cmd += 4;
+ } else {
+ if (strncmp(cmd, "eth", 3) &&
+ strncmp(cmd, "br", 2)) {
+ if (OldDevnameHook) return OldDevnameHook(cmd, argv, doit);
+ return 0;
+ }
+ }
+
+ /* Open a socket */
+ if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
+ r = 0;
+ }
+
+ /* Try getting interface index */
+ if (r) {
+ strncpy(ifr.ifr_name, cmd, IFNAMSIZ);
+ 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", cmd);
+ r=0;
+ }
+ }
+ }
+ }
+
+ /* Close socket */
+ close(fd);
+ if (r) {
+ strncpy(devnam, cmd, sizeof(devnam));
+ if (the_channel != &pppoe_channel) {
+
+ the_channel = &pppoe_channel;
+ 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;
+
+ ipcp_allowoptions[0].neg_vj=0;
+ ipcp_wantoptions[0].neg_vj=0;
+
+ ccp_allowoptions[0].deflate = 0 ;
+ ccp_wantoptions[0].deflate = 0 ;
+
+ ccp_allowoptions[0].bsd_compress = 0;
+ ccp_wantoptions[0].bsd_compress = 0;
+
+
+ PPPOEInitDevice();
+ }
+ return 1;
+ }
+
+ if (OldDevnameHook) r = OldDevnameHook(cmd, argv, doit);
+ return r;
+}
+
+/**********************************************************************
+ * %FUNCTION: plugin_init
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Nothing
+ * %DESCRIPTION:
+ * Initializes hooks for pppd plugin
+ ***********************************************************************/
+void
+plugin_init(void)
+{
+ if (!ppp_available() && !new_style_driver) {
+ fatal("Linux kernel does not support PPPoE -- are you running 2.4.x?");
+ }
+
+ add_options(Options);
+
+ info("RP-PPPoE plugin version %s compiled against pppd %s",
+ RP_VERSION, VERSION);
+}
+
+/**********************************************************************
+*%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)
+{
+ printErr(str);
+ sendPADTf(conn, "RP-PPPoE: %.256s", str);
+ 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);
+}
+
+
+struct channel pppoe_channel = {
+ .options = Options,
+ .process_extra_options = &PPPOEDeviceOptions,
+ .check_options = NULL,
+ .connect = &PPPOEConnectDevice,
+ .disconnect = &PPPOEDisconnectDevice,
+ .establish_ppp = &generic_establish_ppp,
+ .disestablish_ppp = &generic_disestablish_ppp,
+ .send_config = &PPPOESendConfig,
+ .recv_config = &PPPOERecvConfig,
+ .close = NULL,
+ .cleanup = NULL
+};
diff --git a/jni/src/ppp.c b/jni/src/ppp.c
new file mode 100755
index 0000000..543ba71
--- a/dev/null
+++ b/jni/src/ppp.c
@@ -0,0 +1,262 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#include <android/log.h>
+#define syslog(prio, fmt...) \
+ __android_log_print(prio, "PPPOE", fmt)
+#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
+
+static int PPPState;
+static int PPPPacketSize;
+static unsigned char PPPXorValue;
+
+static UINT16_t const 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/jni/src/pppoe-server.c b/jni/src/pppoe-server.c
new file mode 100755
index 0000000..b59cd3c
--- a/dev/null
+++ b/jni/src/pppoe-server.c
@@ -0,0 +1,2137 @@
+/***********************************************************************
+*
+* pppoe-server.c
+*
+* 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$
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+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-server.h"
+#include "md5.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.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 <time.h>
+
+#include <signal.h>
+
+#ifdef HAVE_LICENSE
+#include "license.h"
+#include "licensed-only/servfuncs.h"
+static struct License const *ServerLicense;
+static struct License const *ClusterLicense;
+#else
+#define control_session_started(x) (void) 0
+#define control_session_terminated(x) (void) 0
+#define control_exit() (void) 0
+#define realpeerip peerip
+#endif
+
+#ifdef HAVE_L2TP
+extern PppoeSessionFunctionTable L2TPSessionFunctionTable;
+extern void pppoe_to_l2tp_add_interface(EventSelector *es,
+ Interface *interface);
+#endif
+
+static void InterfaceHandler(EventSelector *es,
+ int fd, unsigned int flags, void *data);
+static void startPPPD(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)
+
+static void PppoeStopSession(ClientSession *ses, char const *reason);
+static int PppoeSessionIsActive(ClientSession *ses);
+
+/* Service-Names we advertise */
+#define MAX_SERVICE_NAMES 64
+static int NumServiceNames = 0;
+static char const *ServiceNames[MAX_SERVICE_NAMES];
+
+PppoeSessionFunctionTable DefaultSessionFunctionTable = {
+ PppoeStopSession,
+ PppoeSessionIsActive,
+ NULL
+};
+
+/* An array of client sessions */
+ClientSession *Sessions = NULL;
+ClientSession *FreeSessions = NULL;
+ClientSession *LastFreeSession = NULL;
+ClientSession *BusySessions = NULL;
+
+/* Interfaces we're listening on */
+Interface interfaces[MAX_INTERFACES];
+int NumInterfaces = 0;
+
+/* The number of session slots */
+size_t NumSessionSlots;
+
+/* Maximum number of sessions per MAC address */
+int MaxSessionsPerMac;
+
+/* Number of active sessions */
+size_t NumActiveSessions = 0;
+
+/* Offset of first session */
+size_t SessOffset = 0;
+
+/* Event Selector */
+EventSelector *event_selector;
+
+/* Use Linux kernel-mode PPPoE? */
+static int UseLinuxKernelModePPPoE = 0;
+
+/* File with PPPD options */
+static char *pppoptfile = NULL;
+
+static int Debug = 0;
+static int CheckPoolSyntax = 0;
+
+/* Synchronous mode */
+static 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 */
+
+static unsigned char CookieSeed[SEED_LEN];
+
+#define MAXLINE 512
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+
+/* 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}; /* Counter optionally STARTS here */
+unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */
+
+/* Do we increment local IP for each connection? */
+int IncrLocalIP = 0;
+
+/* Do we randomize session numbers? */
+int RandomizeSessionNumbers = 0;
+
+/* Do we pass the "unit" option to pppd? (2.4 or greater) */
+int PassUnitOptionToPPPD = 0;
+
+static PPPoETag hostUniq;
+static PPPoETag relayId;
+static PPPoETag receivedCookie;
+static PPPoETag requestedService;
+
+#define HOSTNAMELEN 256
+
+static int
+count_sessions_from_mac(unsigned char *eth)
+{
+ int n=0;
+ ClientSession *s = BusySessions;
+ while(s) {
+ if (!memcmp(eth, s->eth, ETH_ALEN)) n++;
+ s = s->next;
+ }
+ return n;
+}
+
+/**********************************************************************
+*%FUNCTION: childHandler
+*%ARGUMENTS:
+* pid -- pid of child
+* status -- exit status
+* ses -- which session terminated
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Called synchronously when a child dies. Remove from busy list.
+***********************************************************************/
+static void
+childHandler(pid_t pid, int status, void *s)
+{
+ ClientSession *session = s;
+
+ /* Temporary structure for sending PADT's. */
+ PPPoEConnection conn;
+
+#ifdef HAVE_L2TP
+ /* We're acting as LAC, so when child exits, become a PPPoE <-> L2TP
+ relay */
+ if (session->flags & FLAG_ACT_AS_LAC) {
+ syslog(LOG_INFO, "Session %u for client "
+ "%02x:%02x:%02x:%02x:%02x:%02x handed off to LNS %s",
+ (unsigned int) ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ inet_ntoa(session->tunnel_endpoint.sin_addr));
+ session->pid = 0;
+ session->funcs = &L2TPSessionFunctionTable;
+ return;
+ }
+#endif
+
+ memset(&conn, 0, sizeof(conn));
+ conn.useHostUniq = 0;
+
+ syslog(LOG_INFO,
+ "Session %u closed for client "
+ "%02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s",
+ (unsigned int) ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->realpeerip[0], (int) session->realpeerip[1],
+ (int) session->realpeerip[2], (int) session->realpeerip[3],
+ session->ethif->name);
+ memcpy(conn.myEth, session->ethif->mac, ETH_ALEN);
+ conn.discoverySocket = session->ethif->sock;
+ conn.session = session->sess;
+ memcpy(conn.peerEth, session->eth, ETH_ALEN);
+ if (!(session->flags & FLAG_SENT_PADT)) {
+ if (session->flags & FLAG_RECVD_PADT) {
+ sendPADT(&conn, "RP-PPPoE: Received PADT from peer");
+ } else {
+ sendPADT(&conn, "RP-PPPoE: Child pppd process terminated");
+ }
+ session->flags |= FLAG_SENT_PADT;
+ }
+
+ session->serviceName = "";
+ control_session_terminated(session);
+ if (pppoe_free_session(session) < 0) {
+ return;
+ }
+
+}
+
+/**********************************************************************
+*%FUNCTION: incrementIPAddress (static)
+*%ARGUMENTS:
+* addr -- a 4-byte array representing IP address
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Increments addr in-place
+***********************************************************************/
+static void
+incrementIPAddress(unsigned char ip[IPV4ALEN])
+{
+ ip[3]++;
+ if (!ip[3]) {
+ ip[2]++;
+ if (!ip[2]) {
+ ip[1]++;
+ if (!ip[1]) {
+ ip[0]++;
+ }
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: killAllSessions
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Kills all pppd processes (and hence all PPPoE sessions)
+***********************************************************************/
+void
+killAllSessions(void)
+{
+ ClientSession *sess = BusySessions;
+ while(sess) {
+ sess->funcs->stop(sess, "Shutting Down");
+ sess = sess->next;
+ }
+#ifdef HAVE_L2TP
+ pppoe_close_l2tp_tunnels();
+#endif
+}
+
+/**********************************************************************
+*%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;
+ unsigned int e, f, g, h;
+ char line[MAXLINE];
+
+ if (!fp) {
+ sysErr("Cannot open address pool file");
+ exit(1);
+ }
+
+ while (!feof(fp)) {
+ if (!fgets(line, MAXLINE, fp)) {
+ break;
+ }
+ if ((sscanf(line, "%u.%u.%u.%u:%u.%u.%u.%u",
+ &a, &b, &c, &d, &e, &f, &g, &h) == 8) &&
+ a < 256 && b < 256 && c < 256 && d < 256 &&
+ e < 256 && f < 256 && g < 256 && h < 256) {
+
+ /* Both specified (local:remote) */
+ if (install) {
+ Sessions[numAddrs].myip[0] = (unsigned char) a;
+ Sessions[numAddrs].myip[1] = (unsigned char) b;
+ Sessions[numAddrs].myip[2] = (unsigned char) c;
+ Sessions[numAddrs].myip[3] = (unsigned char) d;
+ Sessions[numAddrs].peerip[0] = (unsigned char) e;
+ Sessions[numAddrs].peerip[1] = (unsigned char) f;
+ Sessions[numAddrs].peerip[2] = (unsigned char) g;
+ Sessions[numAddrs].peerip[3] = (unsigned char) h;
+#ifdef HAVE_LICENSE
+ memcpy(Sessions[numAddrs].realpeerip,
+ Sessions[numAddrs].peerip, IPV4ALEN);
+#endif
+ }
+ numAddrs++;
+ } else if ((sscanf(line, "%u.%u.%u.%u-%u", &a, &b, &c, &d, &e) == 5) &&
+ a < 256 && b < 256 && c < 256 && d < 256 && e < 256) {
+ /* Remote specied as a.b.c.d-e. Example: 1.2.3.4-8 yields:
+ 1.2.3.4, 1.2.3.5, 1.2.3.6, 1.2.3.7, 1.2.3.8 */
+ /* Swap d and e so that e >= d */
+ if (e < d) {
+ f = d;
+ d = e;
+ e = f;
+ }
+ if (install) {
+ while (d <= e) {
+ Sessions[numAddrs].peerip[0] = (unsigned char) a;
+ Sessions[numAddrs].peerip[1] = (unsigned char) b;
+ Sessions[numAddrs].peerip[2] = (unsigned char) c;
+ Sessions[numAddrs].peerip[3] = (unsigned char) d;
+#ifdef HAVE_LICENSE
+ memcpy(Sessions[numAddrs].realpeerip,
+ Sessions[numAddrs].peerip, IPV4ALEN);
+#endif
+ d++;
+ numAddrs++;
+ }
+ } else {
+ numAddrs += (e-d) + 1;
+ }
+ } else if ((sscanf(line, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) &&
+ a < 256 && b < 256 && c < 256 && d < 256) {
+ /* Only remote specified */
+ if (install) {
+ Sessions[numAddrs].peerip[0] = (unsigned char) a;
+ Sessions[numAddrs].peerip[1] = (unsigned char) b;
+ Sessions[numAddrs].peerip[2] = (unsigned char) c;
+ Sessions[numAddrs].peerip[3] = (unsigned char) d;
+#ifdef HAVE_LICENSE
+ memcpy(Sessions[numAddrs].realpeerip,
+ Sessions[numAddrs].peerip, IPV4ALEN);
+#endif
+ }
+ numAddrs++;
+ }
+ }
+ fclose(fp);
+ 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:
+ /* Copy requested service name */
+ requestedService.type = htons(type);
+ requestedService.length = htons(len);
+ memcpy(requestedService.payload, data, len);
+ 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: 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);
+ control_exit();
+ 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);
+ control_exit();
+ 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:
+* ethif -- Interface
+* packet -- PPPoE PADI packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADO packet back to client
+***********************************************************************/
+void
+processPADI(Interface *ethif, PPPoEPacket *packet, int len)
+{
+ PPPoEPacket pado;
+ PPPoETag acname;
+ PPPoETag servname;
+ PPPoETag cookie;
+ size_t acname_len;
+ unsigned char *cursor = pado.payload;
+ UINT16_t plen;
+
+ int sock = ethif->sock;
+ int i;
+ int ok = 0;
+ unsigned char *myAddr = ethif->mac;
+
+ /* 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;
+ }
+
+ /* If number of sessions per MAC is limited, check here and don't
+ send PADO if already max number of sessions. */
+ if (MaxSessionsPerMac) {
+ if (count_sessions_from_mac(packet->ethHdr.h_source) >= MaxSessionsPerMac) {
+ syslog(LOG_INFO, "PADI: Client %02x:%02x:%02x:%02x:%02x:%02x attempted to create more than %d session(s)",
+ 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],
+ MaxSessionsPerMac);
+ return;
+ }
+ }
+
+ acname.type = htons(TAG_AC_NAME);
+ acname_len = strlen(ACName);
+ acname.length = htons(acname_len);
+ memcpy(acname.payload, ACName, acname_len);
+
+ relayId.type = 0;
+ hostUniq.type = 0;
+ requestedService.type = 0;
+ parsePacket(packet, parsePADITags, NULL);
+
+ /* If PADI specified non-default service name, and we do not offer
+ that service, DO NOT send PADO */
+ if (requestedService.type) {
+ int slen = ntohs(requestedService.length);
+ if (slen) {
+ for (i=0; i<NumServiceNames; i++) {
+ if (slen == strlen(ServiceNames[i]) &&
+ !memcmp(ServiceNames[i], &requestedService.payload, slen)) {
+ ok = 1;
+ break;
+ }
+ }
+ } else {
+ ok = 1; /* Default service requested */
+ }
+ } else {
+ ok = 1; /* No Service-Name tag in PADI */
+ }
+
+ if (!ok) {
+ /* PADI asked for unsupported service */
+ return;
+ }
+
+ /* 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;
+
+ /* If no service-names specified on command-line, just send default
+ zero-length name. Otherwise, add all service-name tags */
+ servname.type = htons(TAG_SERVICE_NAME);
+ if (!NumServiceNames) {
+ servname.length = 0;
+ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
+ memcpy(cursor, &servname, TAG_HDR_SIZE);
+ cursor += TAG_HDR_SIZE;
+ plen += TAG_HDR_SIZE;
+ } else {
+ for (i=0; i<NumServiceNames; i++) {
+ int slen = strlen(ServiceNames[i]);
+ servname.length = htons(slen);
+ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE+slen);
+ memcpy(cursor, &servname, TAG_HDR_SIZE);
+ memcpy(cursor+TAG_HDR_SIZE, ServiceNames[i], slen);
+ cursor += TAG_HDR_SIZE+slen;
+ plen += TAG_HDR_SIZE+slen;
+ }
+ }
+
+ 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:
+* ethif -- interface
+* packet -- PPPoE PADT packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Kills session whose session-ID is in PADT packet.
+***********************************************************************/
+void
+processPADT(Interface *ethif, PPPoEPacket *packet, int len)
+{
+ size_t i;
+
+ unsigned char *myAddr = ethif->mac;
+
+ /* 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 source MAC does not match, do not kill session */
+ if (memcmp(packet->ethHdr.h_source, Sessions[i].eth, ETH_ALEN)) {
+ syslog(LOG_WARNING, "PADT for session %u received from "
+ "%02X:%02X:%02X:%02X:%02X:%02X; should be from "
+ "%02X:%02X:%02X:%02X:%02X:%02X",
+ (unsigned int) ntohs(packet->session),
+ 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],
+ Sessions[i].eth[0],
+ Sessions[i].eth[1],
+ Sessions[i].eth[2],
+ Sessions[i].eth[3],
+ Sessions[i].eth[4],
+ Sessions[i].eth[5]);
+ return;
+ }
+ Sessions[i].flags |= FLAG_RECVD_PADT;
+ parsePacket(packet, parseLogErrs, NULL);
+ Sessions[i].funcs->stop(&Sessions[i], "Received PADT");
+}
+
+/**********************************************************************
+*%FUNCTION: processPADR
+*%ARGUMENTS:
+* ethif -- Ethernet interface
+* 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(Interface *ethif, PPPoEPacket *packet, int len)
+{
+ unsigned char cookieBuffer[COOKIE_LEN];
+ ClientSession *cliSession;
+ pid_t child;
+ PPPoEPacket pads;
+ unsigned char *cursor = pads.payload;
+ UINT16_t plen;
+ int i;
+ int sock = ethif->sock;
+ unsigned char *myAddr = ethif->mac;
+ int slen = 0;
+ char const *serviceName = NULL;
+
+#ifdef HAVE_LICENSE
+ int freemem;
+#endif
+
+ /* 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;
+ }
+
+ /* If number of sessions per MAC is limited, check here and don't
+ send PADS if already max number of sessions. */
+ if (MaxSessionsPerMac) {
+ if (count_sessions_from_mac(packet->ethHdr.h_source) >= MaxSessionsPerMac) {
+ syslog(LOG_INFO, "PADR: Client %02x:%02x:%02x:%02x:%02x:%02x attempted to create more than %d session(s)",
+ 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],
+ MaxSessionsPerMac);
+ 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 */
+ 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;
+ }
+
+ slen = ntohs(requestedService.length);
+ if (slen) {
+ /* Check supported services */
+ for(i=0; i<NumServiceNames; i++) {
+ if (slen == strlen(ServiceNames[i]) &&
+ !memcmp(ServiceNames[i], &requestedService.payload, slen)) {
+ serviceName = ServiceNames[i];
+ break;
+ }
+ }
+
+ if (!serviceName) {
+ 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;
+ }
+ } else {
+ serviceName = "";
+ }
+
+
+#ifdef HAVE_LICENSE
+ /* Are we licensed for this many sessions? */
+ if (License_NumLicenses("PPPOE-SESSIONS") <= NumActiveSessions) {
+ syslog(LOG_ERR, "Insufficient session licenses (%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 session licenses available");
+ return;
+ }
+#endif
+ /* Enough free memory? */
+#ifdef HAVE_LICENSE
+ freemem = getFreeMem();
+ if (freemem < MIN_FREE_MEMORY) {
+ syslog(LOG_WARNING,
+ "Insufficient free memory to create session: Want %d, have %d",
+ MIN_FREE_MEMORY, freemem);
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Insufficient free RAM");
+ return;
+ }
+#endif
+ /* Looks cool... find a slot for the session */
+ cliSession = pppoe_alloc_session();
+ 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->ethif = ethif;
+ cliSession->flags = 0;
+ cliSession->funcs = &DefaultSessionFunctionTable;
+ cliSession->startTime = time(NULL);
+ cliSession->serviceName = serviceName;
+
+ /* 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");
+ pppoe_free_session(cliSession);
+ return;
+ }
+ if (child != 0) {
+ /* In the parent process. Mark pid in session slot */
+ cliSession->pid = child;
+ Event_HandleChildExit(event_selector, child,
+ childHandler, cliSession);
+ control_session_started(cliSession);
+ return;
+ }
+
+ /* In the child process. */
+
+ /* Close all file descriptors except for socket */
+ closelog();
+ for (i=0; i<CLOSEFD; i++) {
+ if (i != sock) {
+ close(i);
+ }
+ }
+
+ openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+ /* 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;
+
+ /* Copy requested service name tag back in. If requested-service name
+ length is zero, and we have non-zero services, use first service-name
+ as default */
+ if (!slen && NumServiceNames) {
+ slen = strlen(ServiceNames[0]);
+ memcpy(&requestedService.payload, ServiceNames[0], slen);
+ requestedService.length = htons(slen);
+ }
+ memcpy(cursor, &requestedService, TAG_HDR_SIZE+slen);
+ cursor += TAG_HDR_SIZE+slen;
+ plen += TAG_HDR_SIZE+slen;
+
+ 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));
+
+ /* Close sock; don't need it any more */
+ close(sock);
+
+ startPPPD(cliSession);
+}
+
+/**********************************************************************
+*%FUNCTION: termHandler
+*%ARGUMENTS:
+* sig -- signal number
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Called by SIGTERM or SIGINT. Causes all sessions to be killed!
+***********************************************************************/
+static void
+termHandler(int sig)
+{
+ syslog(LOG_INFO,
+ "Terminating on signal %d -- killing all PPPoE sessions",
+ sig);
+ killAllSessions();
+ control_exit();
+ exit(0);
+}
+
+/**********************************************************************
+*%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, " -l -- Increment local IP address for each session.\n");
+ fprintf(stderr, " -R ip -- Set start address of remote IP pool.\n");
+ fprintf(stderr, " -S name -- Advertise specified service-name.\n");
+ fprintf(stderr, " -O fname -- Use PPPD options from specified file\n");
+ fprintf(stderr, " (default %s).\n", PPPOE_SERVER_OPTIONS);
+ 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, " -u -- Pass 'unit' option to pppd.\n");
+ fprintf(stderr, " -r -- Randomize session numbers.\n");
+ fprintf(stderr, " -d -- Debug session creation.\n");
+ fprintf(stderr, " -x n -- Limit to 'n' sessions/MAC address.\n");
+ fprintf(stderr, " -P -- Check pool file for correctness and exit.\n");
+#ifdef HAVE_LICENSE
+ fprintf(stderr, " -c secret:if:port -- Enable clustering on interface 'if'.\n");
+ fprintf(stderr, " -1 -- Allow only one session per user.\n");
+#endif
+
+ fprintf(stderr, " -h -- Print usage information.\n\n");
+ fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001-2006 Roaring Penguin Software Inc.\n", VERSION);
+
+#ifndef HAVE_LICENSE
+ 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");
+#endif
+ 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, j;
+ int opt;
+ int d[IPV4ALEN];
+ int beDaemon = 1;
+ int found;
+ unsigned int discoveryType, sessionType;
+ char *addressPoolFname = NULL;
+#ifdef HAVE_LICENSE
+ int use_clustering = 0;
+#endif
+
+#ifndef HAVE_LINUX_KERNEL_PPPOE
+ char *options = "x:hI:C:L:R:T:m:FN:f:O:o:sp:lrudPc:S:1";
+#else
+ char *options = "x:hI:C:L:R:T:m:FN:f:O:o:skp:lrudPc:S:1";
+#endif
+
+ if (getuid() != geteuid() ||
+ getgid() != getegid()) {
+ fprintf(stderr, "SECURITY WARNING: pppoe-server will NOT run suid or sgid. Fix your installation.\n");
+ exit(1);
+ }
+
+ memset(interfaces, 0, sizeof(interfaces));
+
+ /* Initialize syslog */
+ openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+
+ /* Default number of session slots */
+ NumSessionSlots = DEFAULT_MAX_SESSIONS;
+ MaxSessionsPerMac = 0; /* No limit */
+ NumActiveSessions = 0;
+
+ /* Parse command-line options */
+ while((opt = getopt(argc, argv, options)) != -1) {
+ switch(opt) {
+ case 'x':
+ if (sscanf(optarg, "%d", &MaxSessionsPerMac) != 1) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (MaxSessionsPerMac < 0) {
+ MaxSessionsPerMac = 0;
+ }
+ break;
+
+#ifdef HAVE_LINUX_KERNEL_PPPOE
+ case 'k':
+ UseLinuxKernelModePPPoE = 1;
+ break;
+#endif
+ case 'S':
+ if (NumServiceNames == MAX_SERVICE_NAMES) {
+ fprintf(stderr, "Too many '-S' options (%d max)",
+ MAX_SERVICE_NAMES);
+ exit(1);
+ }
+ ServiceNames[NumServiceNames] = strdup(optarg);
+ if (!ServiceNames[NumServiceNames]) {
+ fprintf(stderr, "Out of memory");
+ exit(1);
+ }
+ NumServiceNames++;
+ break;
+ case 'c':
+#ifndef HAVE_LICENSE
+ fprintf(stderr, "Clustering capability not available.\n");
+ exit(1);
+#else
+ cluster_handle_option(optarg);
+ use_clustering = 1;
+ break;
+#endif
+
+ case 'd':
+ Debug = 1;
+ break;
+ case 'P':
+ CheckPoolSyntax = 1;
+ break;
+ case 'u':
+ PassUnitOptionToPPPD = 1;
+ break;
+
+ case 'r':
+ RandomizeSessionNumbers = 1;
+ break;
+
+ case 'l':
+ IncrLocalIP = 1;
+ break;
+
+ case 'p':
+ SET_STRING(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':
+ SET_STRING(pppoptfile, optarg);
+ 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':
+ if (NumInterfaces >= MAX_INTERFACES) {
+ fprintf(stderr, "Too many -I options (max %d)\n",
+ MAX_INTERFACES);
+ exit(EXIT_FAILURE);
+ }
+ found = 0;
+ for (i=0; i<NumInterfaces; i++) {
+ if (!strncmp(interfaces[i].name, optarg, IFNAMSIZ)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ strncpy(interfaces[NumInterfaces].name, optarg, IFNAMSIZ);
+ NumInterfaces++;
+ }
+ 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);
+ case '1':
+#ifdef HAVE_LICENSE
+ MaxSessionsPerUser = 1;
+#else
+ fprintf(stderr, "-1 option not valid.\n");
+ exit(1);
+#endif
+ break;
+ }
+ }
+
+ if (!pppoptfile) {
+ pppoptfile = PPPOE_SERVER_OPTIONS;
+ }
+
+#ifdef HAVE_LICENSE
+ License_SetVersion(SERVPOET_VERSION);
+ License_ReadBundleFile("/etc/rp/bundle.txt");
+ License_ReadFile("/etc/rp/license.txt");
+ ServerLicense = License_GetFeature("PPPOE-SERVER");
+ if (!ServerLicense) {
+ fprintf(stderr, "License: GetFeature failed: %s\n",
+ License_ErrorMessage());
+ exit(1);
+ }
+#endif
+
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+ fprintf(stderr, "The PPPoE server does not work on Linux 2.0 kernels.\n");
+ exit(EXIT_FAILURE);
+#endif
+#endif
+
+ if (!NumInterfaces) {
+ strcpy(interfaces[0].name, DEFAULT_IF);
+ NumInterfaces = 1;
+ }
+
+ 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);
+ if (CheckPoolSyntax) {
+ printf("%lu\n", (unsigned long) NumSessionSlots);
+ exit(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(ClientSession));
+ if (!Sessions) {
+ rp_fatal("Cannot allocate memory for session slots");
+ }
+
+ /* Fill in local addresses first (let pool file override later */
+ for (i=0; i<NumSessionSlots; i++) {
+ memcpy(Sessions[i].myip, LocalIP, sizeof(LocalIP));
+ if (IncrLocalIP) {
+ incrementIPAddress(LocalIP);
+ }
+ }
+
+ /* Fill in remote IP addresses from pool (may also overwrite local ips) */
+ 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].funcs = &DefaultSessionFunctionTable;
+ Sessions[i].sess = htons(i+1+SessOffset);
+
+ if (!addressPoolFname) {
+ memcpy(Sessions[i].peerip, RemoteIP, sizeof(RemoteIP));
+#ifdef HAVE_LICENSE
+ memcpy(Sessions[i].realpeerip, RemoteIP, sizeof(RemoteIP));
+#endif
+ incrementIPAddress(RemoteIP);
+ }
+ }
+
+ /* Initialize our random cookie. Try /dev/urandom; if that fails,
+ use PID and rand() */
+ fp = fopen("/dev/urandom", "r");
+ if (fp) {
+ unsigned int x;
+ fread(&x, 1, sizeof(x), fp);
+ srand(x);
+ fread(&CookieSeed, 1, SEED_LEN, fp);
+ fclose(fp);
+ } else {
+ srand((unsigned int) getpid() * (unsigned int) time(NULL));
+ CookieSeed[0] = getpid() & 0xFF;
+ CookieSeed[1] = (getpid() >> 8) & 0xFF;
+ for (i=2; i<SEED_LEN; i++) {
+ CookieSeed[i] = (rand() >> (i % 9)) & 0xFF;
+ }
+ }
+
+ if (RandomizeSessionNumbers) {
+ int *permutation;
+ int tmp;
+ permutation = malloc(sizeof(int) * NumSessionSlots);
+ if (!permutation) {
+ fprintf(stderr, "Could not allocate memory to randomize session numbers\n");
+ exit(EXIT_FAILURE);
+ }
+ for (i=0; i<NumSessionSlots; i++) {
+ permutation[i] = i;
+ }
+ for (i=0; i<NumSessionSlots-1; i++) {
+ j = i + rand() % (NumSessionSlots - i);
+ if (j != i) {
+ tmp = permutation[j];
+ permutation[j] = permutation[i];
+ permutation[i] = tmp;
+ }
+ }
+ /* Link sessions together */
+ FreeSessions = &Sessions[permutation[0]];
+ LastFreeSession = &Sessions[permutation[NumSessionSlots-1]];
+ for (i=0; i<NumSessionSlots-1; i++) {
+ Sessions[permutation[i]].next = &Sessions[permutation[i+1]];
+ }
+ Sessions[permutation[NumSessionSlots-1]].next = NULL;
+ free(permutation);
+ } else {
+ /* Link sessions together */
+ FreeSessions = &Sessions[0];
+ LastFreeSession = &Sessions[NumSessionSlots - 1];
+ for (i=0; i<NumSessionSlots-1; i++) {
+ Sessions[i].next = &Sessions[i+1];
+ }
+ Sessions[NumSessionSlots-1].next = NULL;
+ }
+
+ if (Debug) {
+ /* Dump session array and exit */
+ ClientSession *ses = FreeSessions;
+ while(ses) {
+ printf("Session %u local %d.%d.%d.%d remote %d.%d.%d.%d\n",
+ (unsigned int) (ntohs(ses->sess)),
+ ses->myip[0], ses->myip[1],
+ ses->myip[2], ses->myip[3],
+ ses->peerip[0], ses->peerip[1],
+ ses->peerip[2], ses->peerip[3]);
+ ses = ses->next;
+ }
+ exit(0);
+ }
+
+ /* Open all the interfaces */
+ for (i=0; i<NumInterfaces; i++) {
+ interfaces[i].sock = openInterface(interfaces[i].name, Eth_PPPOE_Discovery, interfaces[i].mac);
+ }
+
+ /* Ignore SIGPIPE */
+ signal(SIGPIPE, SIG_IGN);
+
+ /* Create event selector */
+ event_selector = Event_CreateSelector();
+ if (!event_selector) {
+ rp_fatal("Could not create EventSelector -- probably out of memory");
+ }
+
+ /* Set signal handlers for SIGTERM and SIGINT */
+ if (Event_HandleSignal(event_selector, SIGTERM, termHandler) < 0 ||
+ Event_HandleSignal(event_selector, SIGINT, termHandler) < 0) {
+ fatalSys("Event_HandleSignal");
+ }
+
+ /* Control channel */
+#ifdef HAVE_LICENSE
+ if (control_init(argc, argv, event_selector)) {
+ rp_fatal("control_init failed");
+ }
+#endif
+
+ /* Create event handler for each interface */
+ for (i = 0; i<NumInterfaces; i++) {
+ interfaces[i].eh = Event_AddHandler(event_selector,
+ interfaces[i].sock,
+ EVENT_FLAG_READABLE,
+ InterfaceHandler,
+ &interfaces[i]);
+#ifdef HAVE_L2TP
+ interfaces[i].session_sock = -1;
+#endif
+ if (!interfaces[i].eh) {
+ rp_fatal("Event_AddHandler failed");
+ }
+ }
+
+#ifdef HAVE_LICENSE
+ if (use_clustering) {
+ ClusterLicense = License_GetFeature("PPPOE-CLUSTER");
+ if (!ClusterLicense) {
+ fprintf(stderr, "License: GetFeature failed: %s\n",
+ License_ErrorMessage());
+ exit(1);
+ }
+ if (!License_Expired(ClusterLicense)) {
+ if (cluster_init(event_selector) < 0) {
+ rp_fatal("cluster_init failed");
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_L2TP
+ for (i=0; i<NumInterfaces; i++) {
+ pppoe_to_l2tp_add_interface(event_selector,
+ &interfaces[i]);
+ }
+#endif
+
+ /* 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("/");
+
+ /* Point stdin/stdout/stderr to /dev/null */
+ for (i=0; i<3; i++) {
+ close(i);
+ }
+ i = open("/dev/null", O_RDWR);
+ if (i >= 0) {
+ dup2(i, 0);
+ dup2(i, 1);
+ dup2(i, 2);
+ if (i > 2) close(i);
+ }
+ }
+
+ for(;;) {
+ i = Event_HandleEvent(event_selector);
+ if (i < 0) {
+ fatalSys("Event_HandleEvent");
+ }
+
+#ifdef HAVE_LICENSE
+ if (License_Expired(ServerLicense)) {
+ syslog(LOG_INFO, "Server license has expired -- killing all PPPoE sessions");
+ killAllSessions();
+ control_exit();
+ exit(0);
+ }
+#endif
+ }
+ return 0;
+}
+
+void
+serverProcessPacket(Interface *i)
+{
+ int len;
+ PPPoEPacket packet;
+ int sock = i->sock;
+
+ 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;
+ }
+
+ /* Sanity check on packet */
+ if (packet.ver != 1 || packet.type != 1) {
+ /* Syslog an error */
+ return;
+ }
+ switch(packet.code) {
+ case CODE_PADI:
+ processPADI(i, &packet, len);
+ break;
+ case CODE_PADR:
+ processPADR(i, &packet, len);
+ break;
+ case CODE_PADT:
+ /* Kill the child */
+ processPADT(i, &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;
+ }
+}
+
+/**********************************************************************
+*%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(ClientSession *session)
+{
+ /* Leave some room */
+ char *argv[32];
+
+ char buffer[SMALLBUF];
+
+ int c = 0;
+
+ argv[c++] = "pppd";
+ argv[c++] = "pty";
+
+ /* Let's hope service-name does not have ' in it... */
+ snprintf(buffer, SMALLBUF, "%s -n -I %s -e %u:%02x:%02x:%02x:%02x:%02x:%02x%s -S '%s'",
+ PPPOE_PATH, session->ethif->name,
+ (unsigned int) ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ PppoeOptions, session->serviceName);
+ argv[c++] = strdup(buffer);
+ if (!argv[c-1]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+
+ argv[c++] = "file";
+ argv[c++] = pppoptfile;
+
+ snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+ (int) session->myip[0], (int) session->myip[1],
+ (int) session->myip[2], (int) session->myip[3],
+ (int) session->peerip[0], (int) session->peerip[1],
+ (int) session->peerip[2], (int) session->peerip[3]);
+ syslog(LOG_INFO,
+ "Session %u created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
+ (unsigned int) ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->peerip[0], (int) session->peerip[1],
+ (int) session->peerip[2], (int) session->peerip[3],
+ session->ethif->name,
+ session->serviceName);
+ argv[c++] = strdup(buffer);
+ if (!argv[c-1]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+ argv[c++] = "nodetach";
+ argv[c++] = "noaccomp";
+ argv[c++] = "nobsdcomp";
+ argv[c++] = "nodeflate";
+ argv[c++] = "nopcomp";
+ argv[c++] = "novj";
+ argv[c++] = "novjccomp";
+ argv[c++] = "default-asyncmap";
+ if (Synchronous) {
+ argv[c++] = "sync";
+ }
+ if (PassUnitOptionToPPPD) {
+ argv[c++] = "unit";
+ sprintf(buffer, "%u", (unsigned int) (ntohs(session->sess) - 1 - SessOffset));
+ argv[c++] = buffer;
+ }
+ argv[c++] = 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(ClientSession *session)
+{
+ /* Leave some room */
+ char *argv[32];
+
+ int c = 0;
+
+ char buffer[SMALLBUF];
+
+ argv[c++] = "pppd";
+ argv[c++] = "plugin";
+ argv[c++] = PLUGIN_PATH;
+
+ /* Add "nic-" to interface name */
+ snprintf(buffer, SMALLBUF, "nic-%s", session->ethif->name);
+ argv[c++] = strdup(buffer);
+ if (!argv[c-1]) {
+ exit(EXIT_FAILURE);
+ }
+
+ snprintf(buffer, SMALLBUF, "%u:%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned int) ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5]);
+ argv[c++] = "rp_pppoe_sess";
+ argv[c++] = strdup(buffer);
+ if (!argv[c-1]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+ argv[c++] = "rp_pppoe_service";
+ argv[c++] = (char *) session->serviceName;
+ argv[c++] = "file";
+ argv[c++] = pppoptfile;
+
+ snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+ (int) session->myip[0], (int) session->myip[1],
+ (int) session->myip[2], (int) session->myip[3],
+ (int) session->peerip[0], (int) session->peerip[1],
+ (int) session->peerip[2], (int) session->peerip[3]);
+ syslog(LOG_INFO,
+ "Session %u created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
+ (unsigned int) ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->peerip[0], (int) session->peerip[1],
+ (int) session->peerip[2], (int) session->peerip[3],
+ session->ethif->name,
+ session->serviceName);
+ argv[c++] = strdup(buffer);
+ if (!argv[c-1]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+ argv[c++] = "nodetach";
+ argv[c++] = "noaccomp";
+ argv[c++] = "nobsdcomp";
+ argv[c++] = "nodeflate";
+ argv[c++] = "nopcomp";
+ argv[c++] = "novj";
+ argv[c++] = "novjccomp";
+ argv[c++] = "default-asyncmap";
+ if (PassUnitOptionToPPPD) {
+ argv[c++] = "unit";
+ sprintf(buffer, "%u", (unsigned int) (ntohs(session->sess) - 1 - SessOffset));
+ argv[c++] = buffer;
+ }
+ argv[c++] = NULL;
+ execv(PPPD_PATH, argv);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: startPPPD
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD
+***********************************************************************/
+void
+startPPPD(ClientSession *session)
+{
+ if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
+ else startPPPDUserMode(session);
+}
+
+/**********************************************************************
+* %FUNCTION: InterfaceHandler
+* %ARGUMENTS:
+* es -- event selector (ignored)
+* fd -- file descriptor which is readable
+* flags -- ignored
+* data -- Pointer to the Interface structure
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Handles a packet ready at an interface
+***********************************************************************/
+void
+InterfaceHandler(EventSelector *es,
+ int fd,
+ unsigned int flags,
+ void *data)
+{
+ serverProcessPacket((Interface *) data);
+}
+
+/**********************************************************************
+* %FUNCTION: PppoeStopSession
+* %ARGUMENTS:
+* ses -- the session
+* reason -- reason session is being stopped.
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Kills pppd.
+***********************************************************************/
+static void
+PppoeStopSession(ClientSession *ses,
+ char const *reason)
+{
+ /* Temporary structure for sending PADT's. */
+ PPPoEConnection conn;
+
+ memset(&conn, 0, sizeof(conn));
+ conn.useHostUniq = 0;
+
+ memcpy(conn.myEth, ses->ethif->mac, ETH_ALEN);
+ conn.discoverySocket = ses->ethif->sock;
+ conn.session = ses->sess;
+ memcpy(conn.peerEth, ses->eth, ETH_ALEN);
+ sendPADT(&conn, reason);
+ ses->flags |= FLAG_SENT_PADT;
+
+ if (ses->pid) {
+ kill(ses->pid, SIGTERM);
+ }
+ ses->funcs = &DefaultSessionFunctionTable;
+}
+
+/**********************************************************************
+* %FUNCTION: PppoeSessionIsActive
+* %ARGUMENTS:
+* ses -- the session
+* %RETURNS:
+* True if session is active, false if not.
+***********************************************************************/
+static int
+PppoeSessionIsActive(ClientSession *ses)
+{
+ return (ses->pid != 0);
+}
+
+#ifdef HAVE_LICENSE
+/**********************************************************************
+* %FUNCTION: getFreeMem
+* %ARGUMENTS:
+* None
+* %RETURNS:
+* The amount of free RAM in kilobytes, or -1 if it could not be
+* determined
+* %DESCRIPTION:
+* Reads Linux-specific /proc/meminfo file and extracts free RAM
+***********************************************************************/
+int
+getFreeMem(void)
+{
+ char buf[512];
+ int memfree=0, buffers=0, cached=0;
+ FILE *fp = fopen("/proc/meminfo", "r");
+ if (!fp) return -1;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!strncmp(buf, "MemFree:", 8)) {
+ if (sscanf(buf, "MemFree: %d", &memfree) != 1) {
+ fclose(fp);
+ return -1;
+ }
+ } else if (!strncmp(buf, "Buffers:", 8)) {
+ if (sscanf(buf, "Buffers: %d", &buffers) != 1) {
+ fclose(fp);
+ return -1;
+ }
+ } else if (!strncmp(buf, "Cached:", 7)) {
+ if (sscanf(buf, "Cached: %d", &cached) != 1) {
+ fclose(fp);
+ return -1;
+ }
+ }
+ }
+ fclose(fp);
+ /* return memfree + buffers + cached; */
+ return memfree;
+}
+#endif
+
+/**********************************************************************
+* %FUNCTION: pppoe_alloc_session
+* %ARGUMENTS:
+* None
+* %RETURNS:
+* NULL if no session is available, otherwise a ClientSession structure.
+* %DESCRIPTION:
+* Allocates a ClientSession structure and removes from free list, puts
+* on busy list
+***********************************************************************/
+ClientSession *
+pppoe_alloc_session(void)
+{
+ ClientSession *ses = FreeSessions;
+ if (!ses) return NULL;
+
+ /* Remove from free sessions list */
+ if (ses == LastFreeSession) {
+ LastFreeSession = NULL;
+ }
+ FreeSessions = ses->next;
+
+ /* Put on busy sessions list */
+ ses->next = BusySessions;
+ BusySessions = ses;
+
+ /* Initialize fields to sane values */
+ ses->funcs = &DefaultSessionFunctionTable;
+ ses->pid = 0;
+ ses->ethif = NULL;
+ memset(ses->eth, 0, ETH_ALEN);
+ ses->flags = 0;
+ ses->startTime = time(NULL);
+ ses->serviceName = "";
+#ifdef HAVE_LICENSE
+ memset(ses->user, 0, MAX_USERNAME_LEN+1);
+ memset(ses->realm, 0, MAX_USERNAME_LEN+1);
+ memset(ses->realpeerip, 0, IPV4ALEN);
+#endif
+#ifdef HAVE_L2TP
+ ses->l2tp_ses = NULL;
+#endif
+ NumActiveSessions++;
+ return ses;
+}
+
+/**********************************************************************
+* %FUNCTION: pppoe_free_session
+* %ARGUMENTS:
+* ses -- session to free
+* %RETURNS:
+* 0 if OK, -1 if error
+* %DESCRIPTION:
+* Places a ClientSession on the free list.
+***********************************************************************/
+int
+pppoe_free_session(ClientSession *ses)
+{
+ ClientSession *cur, *prev;
+
+ cur = BusySessions;
+ prev = NULL;
+ while (cur) {
+ if (ses == cur) break;
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (!cur) {
+ syslog(LOG_ERR, "pppoe_free_session: Could not find session %p on busy list", (void *) ses);
+ return -1;
+ }
+
+ /* Remove from busy sessions list */
+ if (prev) {
+ prev->next = ses->next;
+ } else {
+ BusySessions = ses->next;
+ }
+
+ /* Add to end of free sessions */
+ ses->next = NULL;
+ if (LastFreeSession) {
+ LastFreeSession->next = ses;
+ LastFreeSession = ses;
+ } else {
+ FreeSessions = ses;
+ LastFreeSession = ses;
+ }
+
+ /* Initialize fields to sane values */
+ ses->funcs = &DefaultSessionFunctionTable;
+ ses->pid = 0;
+ ses->flags = 0;
+#ifdef HAVE_L2TP
+ ses->l2tp_ses = NULL;
+#endif
+ NumActiveSessions--;
+ return 0;
+}
+
+/**********************************************************************
+* %FUNCTION: sendHURLorMOTM
+* %ARGUMENTS:
+* conn -- PPPoE connection
+* url -- a URL, which *MUST* begin with "http://" or it won't be sent, or
+* a message.
+* tag -- one of TAG_HURL or TAG_MOTM
+* %RETURNS:
+* Nothing
+* %DESCRIPTION:
+* Sends a PADM packet contaning a HURL or MOTM tag to the victim...er, peer.
+***********************************************************************/
+void
+sendHURLorMOTM(PPPoEConnection *conn, char const *url, UINT16_t tag)
+{
+ PPPoEPacket packet;
+ PPPoETag hurl;
+ size_t elen;
+ unsigned char *cursor = packet.payload;
+ UINT16_t plen = 0;
+
+ if (!conn->session) return;
+ if (conn->discoverySocket < 0) return;
+
+ if (tag == TAG_HURL) {
+ if (strncmp(url, "http://", 7)) {
+ syslog(LOG_WARNING, "sendHURL(%s): URL must begin with http://", url);
+ return;
+ }
+ } else {
+ tag = TAG_MOTM;
+ }
+
+ 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_PADM;
+ packet.session = conn->session;
+
+ elen = strlen(url);
+ if (elen > 256) {
+ syslog(LOG_WARNING, "MOTM or HURL too long: %d", (int) elen);
+ return;
+ }
+
+ hurl.type = htons(tag);
+ hurl.length = htons(elen);
+ strcpy((char *) hurl.payload, url);
+ memcpy(cursor, &hurl, elen + TAG_HDR_SIZE);
+ cursor += elen + TAG_HDR_SIZE;
+ plen += elen + TAG_HDR_SIZE;
+
+ packet.length = htons(plen);
+
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+}
diff --git a/jni/src/pppoe-server.h b/jni/src/pppoe-server.h
new file mode 100755
index 0000000..ba4635f
--- a/dev/null
+++ b/jni/src/pppoe-server.h
@@ -0,0 +1,156 @@
+/**********************************************************************
+*
+* pppoe-server.h
+*
+* Definitions for PPPoE server
+*
+* Copyright (C) 2001-2006 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.
+*
+* LIC: GPL
+*
+* $Id$
+*
+***********************************************************************/
+
+#include "pppoe.h"
+#include "event.h"
+
+#ifdef HAVE_L2TP
+#include "l2tp/l2tp.h"
+#endif
+
+#define MAX_USERNAME_LEN 31
+/* An Ethernet interface */
+typedef struct {
+ char name[IFNAMSIZ+1]; /* Interface name */
+ int sock; /* Socket for discovery frames */
+ unsigned char mac[ETH_ALEN]; /* MAC address */
+ EventHandler *eh; /* Event handler for this interface */
+
+ /* Next fields are used only if we're an L2TP LAC */
+#ifdef HAVE_L2TP
+ int session_sock; /* Session socket */
+ EventHandler *lac_eh; /* LAC's event-handler */
+#endif
+} Interface;
+
+#define FLAG_RECVD_PADT 1
+#define FLAG_USER_SET 2
+#define FLAG_IP_SET 4
+#define FLAG_SENT_PADT 8
+
+/* Only used if we are an L2TP LAC or LNS */
+#define FLAG_ACT_AS_LAC 256
+#define FLAG_ACT_AS_LNS 512
+
+/* Forward declaration */
+struct ClientSessionStruct;
+
+/* Dispatch table for session-related functions. We call different
+ functions for L2TP-terminated sessions than for locally-terminated
+ sessions. */
+typedef struct PppoeSessionFunctionTable_t {
+ /* Stop the session */
+ void (*stop)(struct ClientSessionStruct *ses, char const *reason);
+
+ /* Return 1 if session is active, 0 otherwise */
+ int (*isActive)(struct ClientSessionStruct *ses);
+
+ /* Describe a session in human-readable form */
+ char const * (*describe)(struct ClientSessionStruct *ses);
+} PppoeSessionFunctionTable;
+
+extern PppoeSessionFunctionTable DefaultSessionFunctionTable;
+
+/* A client session */
+typedef struct ClientSessionStruct {
+ struct ClientSessionStruct *next; /* In list of free or active sessions */
+ PppoeSessionFunctionTable *funcs; /* Function table */
+ pid_t pid; /* PID of child handling session */
+ Interface *ethif; /* Ethernet interface */
+ unsigned char myip[IPV4ALEN]; /* Local IP address */
+ unsigned char peerip[IPV4ALEN]; /* Desired IP address of peer */
+ UINT16_t sess; /* Session number */
+ unsigned char eth[ETH_ALEN]; /* Peer's Ethernet address */
+ unsigned int flags; /* Various flags */
+ time_t startTime; /* When session started */
+ char const *serviceName; /* Service name */
+#ifdef HAVE_LICENSE
+ char user[MAX_USERNAME_LEN+1]; /* Authenticated user-name */
+ char realm[MAX_USERNAME_LEN+1]; /* Realm */
+ unsigned char realpeerip[IPV4ALEN]; /* Actual IP address -- may be assigned
+ by RADIUS server */
+ int maxSessionsPerUser; /* Max sessions for this user */
+#endif
+#ifdef HAVE_L2TP
+ l2tp_session *l2tp_ses; /* L2TP session */
+ struct sockaddr_in tunnel_endpoint; /* L2TP endpoint */
+#endif
+} ClientSession;
+
+/* Hack for daemonizing */
+#define CLOSEFD 64
+
+/* Max. number of interfaces to listen on */
+#define MAX_INTERFACES 64
+
+/* Max. 64 sessions by default */
+#define DEFAULT_MAX_SESSIONS 64
+
+/* An array of client sessions */
+extern ClientSession *Sessions;
+
+/* Interfaces we're listening on */
+extern Interface interfaces[MAX_INTERFACES];
+extern int NumInterfaces;
+
+/* The number of session slots */
+extern size_t NumSessionSlots;
+
+/* The number of active sessions */
+extern size_t NumActiveSessions;
+
+/* Offset of first session */
+extern size_t SessOffset;
+
+/* Access concentrator name */
+extern char *ACName;
+
+extern unsigned char LocalIP[IPV4ALEN];
+extern unsigned char RemoteIP[IPV4ALEN];
+
+/* Do not create new sessions if free RAM < 10MB (on Linux only!) */
+#define MIN_FREE_MEMORY 10000
+
+/* Do we increment local IP for each connection? */
+extern int IncrLocalIP;
+
+/* Free sessions */
+extern ClientSession *FreeSessions;
+
+/* When a session is freed, it is added to the end of the free list */
+extern ClientSession *LastFreeSession;
+
+/* Busy sessions */
+extern ClientSession *BusySessions;
+
+extern EventSelector *event_selector;
+extern int GotAlarm;
+
+extern void setAlarm(unsigned int secs);
+extern void killAllSessions(void);
+extern void serverProcessPacket(Interface *i);
+extern void processPADT(Interface *ethif, PPPoEPacket *packet, int len);
+extern void processPADR(Interface *ethif, PPPoEPacket *packet, int len);
+extern void processPADI(Interface *ethif, PPPoEPacket *packet, int len);
+extern void usage(char const *msg);
+extern ClientSession *pppoe_alloc_session(void);
+extern int pppoe_free_session(ClientSession *ses);
+extern void sendHURLorMOTM(PPPoEConnection *conn, char const *url, UINT16_t tag);
+
+#ifdef HAVE_LICENSE
+extern int getFreeMem(void);
+#endif
diff --git a/jni/src/pppoe-sniff.c b/jni/src/pppoe-sniff.c
new file mode 100755
index 0000000..1569857
--- a/dev/null
+++ b/jni/src/pppoe-sniff.c
@@ -0,0 +1,266 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+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
+
+ if (getuid() != geteuid() ||
+ getgid() != getegid()) {
+ fprintf(stderr, "SECURITY WARNING: pppoe-sniff will NOT run suid or sgid. Fix your installation.\n");
+ exit(1);
+ }
+
+ 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 > (unsigned int)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 > (unsigned int)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/jni/src/pppoe.c b/jni/src/pppoe.c
new file mode 100755
index 0000000..58e0046
--- a/dev/null
+++ b/jni/src/pppoe.c
@@ -0,0 +1,964 @@
+/***********************************************************************
+*
+* pppoe.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Copyright (C) 2000-2006 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.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id$";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#include <android/log.h>
+#define syslog(prio, fmt...) \
+ __android_log_print(prio, "PPPOE", fmt)
+#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 */
+int optFloodDiscovery = 0; /* Flood server with discovery requests.
+ USED FOR STRESS-TESTING ONLY. DO NOT
+ USE THE -F OPTION AGAINST A REAL ISP */
+
+PPPoEConnection *Connection = NULL; /* Must be global -- used
+ in signal handler */
+
+int persist = 0; /* We are not a pppd plugin */
+/***********************************************************************
+*%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) {
+ if (errno == ENOBUFS) {
+ /* No buffer space is a transient error */
+ return;
+ }
+ exit(EXIT_FAILURE);
+ }
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+
+}
+
+#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.
+***********************************************************************/
+static 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;
+ }
+ if (memcmp(packet->ethHdr.h_dest, Connection->myEth, ETH_ALEN)) {
+ return;
+ }
+
+ if (memcmp(packet->ethHdr.h_source, Connection->peerEth, ETH_ALEN)) {
+ return;
+ }
+
+ syslog(LOG_INFO,
+ "Session %d terminated -- received PADT from peer",
+ (int) ntohs(packet->session));
+ parsePacket(packet, parseLogErrs, NULL);
+ sendPADT(Connection, "Received PADT from peer");
+ 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.
+***********************************************************************/
+static void
+sessionDiscoveryPacket(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ int len;
+
+ if (receivePacket(conn->discoverySocket, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > (unsigned int)len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ 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;
+ }
+
+ if (memcmp(packet.ethHdr.h_dest, conn->myEth, ETH_ALEN)) {
+ return;
+ }
+
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {
+ return;
+ }
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+ syslog(LOG_INFO,
+ "Session %d terminated -- received PADT from peer",
+ (int) ntohs(packet.session));
+ parsePacket(&packet, parseLogErrs, NULL);
+ sendPADT(conn, "Received PADT from peer");
+ 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;
+
+ /* Drop privileges */
+ dropPrivs();
+
+ /* 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 on session %d",
+ (int) ntohs(conn->session));
+ 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
+***********************************************************************/
+static void
+sigPADT(int src)
+{
+ syslog(LOG_DEBUG,"Received signal %d on session %d.",
+ (int)src, (int) ntohs(Connection->session));
+ sendPADTf(Connection, "RP-PPPoE: Received signal %d", src);
+ 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
+#ifdef DEBUGGING_ENABLED
+ fprintf(stderr, " -D filename -- Log debugging information in filename.\n");
+#endif
+ fprintf(stderr,
+ " -T timeout -- Specify inactivity timeout in seconds.\n"
+ " -t timeout -- Initial timeout for discovery packets in seconds\n"
+ " -V -- Print version and exit.\n"
+ " -A -- Print access concentrator names and exit.\n"
+ " -S name -- Set desired service name.\n"
+ " -C name -- Set desired access concentrator name.\n"
+ " -U -- Use Host-Unique to allow multiple PPPoE sessions.\n"
+ " -s -- Use synchronous PPP encapsulation.\n"
+ " -m MSS -- Clamp incoming and outgoing MSS options.\n"
+ " -p pidfile -- Write process-ID to pidfile.\n"
+ " -e sess:mac -- Skip discovery phase; use existing session.\n"
+ " -n -- Do not open discovery socket.\n"
+ " -k -- Kill a session with PADT (requires -e)\n"
+ " -d -- Perform discovery, print session info and exit.\n"
+ " -f disc:sess -- Set Ethernet frame types (hex).\n"
+ " -h -- Print usage information.\n\n"
+ "PPPoE Version %s, Copyright (C) 2001-2006 Roaring Penguin Software Inc.\n"
+ "PPPoE comes with ABSOLUTELY NO WARRANTY.\n"
+ "This is free software, and you are welcome to redistribute it under the terms\n"
+ "of the GNU General Public License, version 2 or any later version.\n"
+ "http://www.roaringpenguin.com\n", VERSION);
+ 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;
+ char const *options;
+
+ PPPoEConnection conn;
+
+#ifdef HAVE_N_HDLC
+ int disc = N_HDLC;
+ long flags;
+#endif
+
+ if (getuid() != geteuid() ||
+ getgid() != getegid()) {
+ IsSetID = 1;
+ }
+
+ /* Initialize connection info */
+ memset(&conn, 0, sizeof(conn));
+ conn.discoverySocket = -1;
+ conn.sessionSocket = -1;
+ conn.discoveryTimeout = PADI_TIMEOUT;
+
+ /* For signal handler */
+ Connection = &conn;
+
+ /* Initialize syslog */
+ openlog("pppoe", LOG_PID, LOG_DAEMON);
+
+#ifdef DEBUGGING_ENABLED
+ options = "I:VAT:D:hS:C:Usm:np:e:kdf:F:t:";
+#else
+ options = "I:VAT:hS:C:Usm:np:e:kdf:F:t:";
+#endif
+ while((opt = getopt(argc, argv, options)) != -1) {
+ switch(opt) {
+ case 't':
+ if (sscanf(optarg, "%d", &conn.discoveryTimeout) != 1) {
+ fprintf(stderr, "Illegal argument to -t: Should be -t timeout\n");
+ exit(EXIT_FAILURE);
+ }
+ if (conn.discoveryTimeout < 1) {
+ conn.discoveryTimeout = 1;
+ }
+ break;
+ case 'F':
+ if (sscanf(optarg, "%d", &optFloodDiscovery) != 1) {
+ fprintf(stderr, "Illegal argument to -F: Should be -F numFloods\n");
+ exit(EXIT_FAILURE);
+ }
+ if (optFloodDiscovery < 1) optFloodDiscovery = 1;
+ fprintf(stderr,
+ "WARNING: DISCOVERY FLOOD IS MEANT FOR STRESS-TESTING\n"
+ "A PPPOE SERVER WHICH YOU OWN. DO NOT USE IT AGAINST\n"
+ "A REAL ISP. YOU HAVE 5 SECONDS TO ABORT.\n");
+ sleep(5);
+ 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;
+ 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':
+ switchToRealID();
+ pidfile = fopen(optarg, "w");
+ if (pidfile) {
+ syslog( LOG_INFO, "open %s OK\n", optarg);
+ fprintf(pidfile, "%lu\n", (unsigned long) getpid());
+ fclose(pidfile);
+ }
+ else {
+ syslog( LOG_INFO, "Could not open %s: %s\n",
+ optarg, strerror(errno));
+ }
+ switchToEffectiveID();
+ 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;
+#ifdef DEBUGGING_ENABLED
+ case 'D':
+ switchToRealID();
+ conn.debugFile = fopen(optarg, "w");
+ switchToEffectiveID();
+ 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;
+#endif
+ 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
+ }
+
+ if (!conn.printACNames) {
+
+#ifdef HAVE_N_HDLC
+ if (conn.synchronous) {
+ if (ioctl(0, TIOCSETD, &disc) < 0) {
+ printErr("Unable to set line discipline to N_HDLC. Make sure your kernel supports the N_HDLC line discipline, or do not use the SYNCHRONOUS option. Quitting.");
+ exit(EXIT_FAILURE);
+ } 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
+
+ }
+
+ if (optFloodDiscovery) {
+ for (n=0; n < optFloodDiscovery; n++) {
+ if (conn.printACNames) {
+ fprintf(stderr, "Sending discovery flood %d\n", n+1);
+ }
+ conn.discoverySocket =
+ openInterface(conn.ifName, Eth_PPPOE_Discovery, conn.myEth);
+ discovery(&conn);
+ conn.discoveryState = STATE_SENT_PADI;
+ close(conn.discoverySocket);
+ }
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Open session socket before discovery phase, to avoid losing session */
+ /* packets sent by peer just after PADS packet (noted on some Cisco */
+ /* server equipment). */
+ /* Opening this socket just before waitForPADS in the discovery() */
+ /* function would be more appropriate, but it would mess-up the code */
+ if (!optSkipSession)
+ conn.sessionSocket = openInterface(conn.ifName, Eth_PPPOE_Session, conn.myEth);
+
+ /* Skip discovery and don't open discovery socket? */
+ if (conn.skipDiscovery && conn.noDiscoverySocket) {
+ conn.discoveryState = STATE_SESSION;
+ } else {
+ conn.discoverySocket =
+ openInterface(conn.ifName, Eth_PPPOE_Discovery, conn.myEth);
+ syslog( LOG_INFO, "discovery\n");
+ 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);
+ }
+
+ /* Set signal handlers: send PADT on HUP; ignore TERM and INT */
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, sigPADT);
+ 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: Session %d: %.256s",
+ str, (int) ntohs(Connection->session), strerror(errno));
+ printErr(buf);
+ sendPADTf(Connection, "RP-PPPoE: System call error: %s",
+ strerror(errno));
+ 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);
+ sendPADTf(Connection, "RP-PPPoE: Session %d: %.256s",
+ (int) ntohs(Connection->session), str);
+ 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 > (unsigned int)len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+
+#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_dest, conn->myEth, ETH_ALEN)) {
+ 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 > (unsigned int)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 > (unsigned int)len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+#ifdef DEBUGGING_ENABLED
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+#endif
+
+#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_dest, conn->myEth, ETH_ALEN)) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ 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 > (unsigned int)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/jni/src/pppoe.h b/jni/src/pppoe.h
new file mode 100755
index 0000000..77f2a2d
--- a/dev/null
+++ b/jni/src/pppoe.h
@@ -0,0 +1,347 @@
+/***********************************************************************
+*
+* 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.
+*
+* LIC: GPL
+*
+* $Id$
+*
+***********************************************************************/
+
+#include "config.h"
+
+extern int IsSetID;
+
+#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_SYS_DLPI_H)
+#define USE_DLPI
+#elif defined(HAVE_NET_BPF_H)
+#define USE_BPF 1
+#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 32-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;
+
+extern void switchToRealID(void);
+extern void switchToEffectiveID(void);
+extern void dropPrivs(void);
+
+/* PPPoE codes */
+#define CODE_PADI 0x09
+#define CODE_PADO 0x07
+#define CODE_PADR 0x19
+#define CODE_PADS 0x65
+#define CODE_PADT 0xA7
+
+/* Extensions from draft-carrel-info-pppoe-ext-00 */
+/* I do NOT like PADM or PADN, but they are here for completeness */
+#define CODE_PADM 0xD3
+#define CODE_PADN 0xD4
+
+#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
+
+/* Extensions from draft-carrel-info-pppoe-ext-00 */
+/* I do NOT like these tags one little bit */
+#define TAG_HURL 0x111
+#define TAG_MOTM 0x112
+#define TAG_IP_ROUTE_ADD 0x121
+
+/* 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);
+
+#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 */
+ int PADSHadError; /* If PADS had an error tag */
+ int discoveryTimeout; /* Timeout for discovery packets */
+} PPPoEConnection;
+
+/* Structure used to determine acceptable PADO or PADS packet */
+struct PacketCriteria {
+ PPPoEConnection *conn;
+ int acNameOK;
+ int serviceNameOK;
+ int seenACName;
+ int seenServiceName;
+};
+
+/* 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);
+#ifdef DEBUGGING_ENABLED
+void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir);
+void dumpHex(FILE *fp, unsigned char const *buf, int len);
+#endif
+int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra);
+void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra);
+void pktLogErrs(char const *pkt, 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 sendPADTf(PPPoEConnection *conn, char const *fmt, ...);
+
+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/jni/src/pppoe_cli.c b/jni/src/pppoe_cli.c
new file mode 100755
index 0000000..e10f2f3
--- a/dev/null
+++ b/jni/src/pppoe_cli.c
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sys/un.h>
+#include "pppoe_ctrl.h"
+
+
+static char pppd_connect_cmd[512];
+static char pppoe_plugin_cmd[] = {"'pppoe -p /system/etc/ppp/pppoe.pid -I eth0 -T 80 -U -m 1412'" };
+static char pppd_options[] = {"debug logfd 1 noipdefault noauth default-asyncmap defaultroute nodetach mtu 1492 mru 1492 noaccomp nodeflate nopcomp novj novjccomp lcp-echo-interval 20 lcp-echo-failure 3"};
+
+static int usage()
+{
+ fprintf(stderr,"ppp_cli connect <user> <pwd>\n");
+ fprintf(stderr,"ppp_cli disconnect\n");
+
+ return -1;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct pppoe_ctrl * ctrl;
+
+ ctrl = pppoe_ctrl_open("/dev/socket/pppd");
+ if (ctrl == NULL) {
+ printf("Failed to connect to pppd\n");
+ return -1;
+ }
+
+ if (0 == strcmp( "connect", argv[1])) {
+ sprintf(pppd_connect_cmd, "pppd pty %s %s user %s password %s &",
+ pppoe_plugin_cmd, pppd_options, argv[2], argv[3] );
+
+ }
+ else if (0 == strcmp( "disconnect", argv[1])) {
+ }
+ else {
+ usage();
+ return -2;
+ }
+
+ pppoe_ctrl_request(ctrl, pppd_connect_cmd, strlen(pppd_connect_cmd));
+
+ pppoe_ctrl_close(ctrl);
+ exit(0);
+}
diff --git a/jni/src/pppoe_ctrl.c b/jni/src/pppoe_ctrl.c
new file mode 100755
index 0000000..a1ef844
--- a/dev/null
+++ b/jni/src/pppoe_ctrl.c
@@ -0,0 +1,129 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sys/un.h>
+#include <android/log.h>
+#include "pppoe_ctrl.h"
+
+
+#define LOCAL_TAG "PPPOE_CTRL"
+
+struct pppoe_ctrl * pppoe_ctrl_open(const char *ctrl_path)
+{
+ struct pppoe_ctrl *ctrl;
+ static int counter = 0;
+ int ret;
+ size_t res;
+ int tries = 0;
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"%s(ctrl_path = %s)\n", __FUNCTION__, ctrl_path);
+ ctrl = malloc(sizeof(*ctrl));
+ if (ctrl == NULL)
+ return NULL;
+ memset(ctrl, 0, sizeof(*ctrl));
+
+ ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (ctrl->s < 0) {
+ free(ctrl);
+ return NULL;
+ }
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"%s(ctrl->s = %d)\n", __FUNCTION__, ctrl->s);
+
+ ctrl->local.sun_family = AF_UNIX;
+ counter++;
+try_again:
+ ret = snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+ "/dev/socket/ppp_cli-%d", getpid());
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"%s: ctrl->local.sun_path: %s\n", __FUNCTION__, ctrl->local.sun_path);
+ if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+ tries++;
+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+ sizeof(ctrl->local)) < 0) {
+#if 0
+ if (errno == EADDRINUSE && tries < 2) {
+ /*
+ * getpid() returns unique identifier for this instance
+ * of pppoe_ctrl, so the existing socket file must have
+ * been left by unclean termination of an earlier run.
+ * Remove the file and try again.
+ */
+ unlink(ctrl->local.sun_path);
+ goto try_again;
+ }
+
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"%s: bind failed(%s)\n", __FUNCTION__, strerror(errno));
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+#endif
+ }
+
+ ctrl->dest.sun_family = AF_UNIX;
+ res = strlcpy(ctrl->dest.sun_path, ctrl_path,
+ sizeof(ctrl->dest.sun_path));
+ if (res >= sizeof(ctrl->dest.sun_path)) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"%s: ctrl->dest.sun_path: %s\n", __FUNCTION__, ctrl->dest.sun_path);
+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+ sizeof(ctrl->dest)) < 0) {
+ close(ctrl->s);
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"%s: connection failed\n", __FUNCTION__);
+ unlink(ctrl->local.sun_path);
+ free(ctrl);
+ return NULL;
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"connection to ppp_wrapper OK\n");
+ return ctrl;
+}
+
+
+void pppoe_ctrl_close(struct pppoe_ctrl *ctrl)
+{
+ if (ctrl == NULL)
+ return;
+ unlink(ctrl->local.sun_path);
+ if (ctrl->s >= 0)
+ close(ctrl->s);
+ free(ctrl);
+}
+
+
+
+int pppoe_ctrl_request(struct pppoe_ctrl *ctrl, const char *cmd, size_t cmd_len)
+{
+ if (send(ctrl->s, cmd, cmd_len, 0) < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"send command[%s] failed\n", cmd);
+ return -1;
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,"send command[%s] OK\n", cmd);
+ return 0;
+}
+
+
+int pppoe_ctrl_get_fd(struct pppoe_ctrl *ctrl)
+{
+ return ctrl->s;
+}
+
+
diff --git a/jni/src/pppoe_ctrl.h b/jni/src/pppoe_ctrl.h
new file mode 100755
index 0000000..22d5ce7
--- a/dev/null
+++ b/jni/src/pppoe_ctrl.h
@@ -0,0 +1,30 @@
+#ifndef PPPOE_CTRL_H
+#define PPPOE_CTRL_H
+
+#define PPPOE_PIDFILE "/data/misc/ppp/pppoe.pid"
+
+struct pppoe_ctrl {
+ int s;
+ struct sockaddr_un local;
+ struct sockaddr_un dest;
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct pppoe_ctrl * pppoe_ctrl_open(const char *ctrl_path);
+
+void pppoe_ctrl_close(struct pppoe_ctrl *ctrl);
+
+int pppoe_ctrl_request(struct pppoe_ctrl *ctrl, const char *cmd, size_t cmd_len);
+
+int pppoe_ctrl_get_fd(struct pppoe_ctrl *ctrl);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/jni/src/pppoe_status.c b/jni/src/pppoe_status.c
new file mode 100755
index 0000000..e1f14e3
--- a/dev/null
+++ b/jni/src/pppoe_status.c
@@ -0,0 +1,118 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+
+#include <sys/un.h>
+#include <android/log.h>
+#include "pppoe_status.h"
+
+
+#define LOCAL_TAG "PPPOE_STATUS"
+//#define PRINTF printf
+#define PRINTF
+
+static int if_is_up(const char *if_name)
+{
+ struct ifreq ifr;
+ int s, ret;
+
+ strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"if_is_up(%s): failed to create socket\n", if_name);
+
+ return -1;
+ }
+ ret = ioctl(s, SIOCGIFFLAGS, &ifr);
+ if (ret < 0) {
+ ret = -errno;
+ //perror(ifr.ifr_name);
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,"if_is_up(%s): failed to ioctl()\n", if_name);
+ goto done;
+ }
+
+ ret = (ifr.ifr_flags &= IFF_UP) ? 1 : 0;
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "if_is_up(%s) is %s\n", if_name, ret ? "UP" : "DOWN");
+
+done:
+ close(s);
+ return ret;
+}
+
+#define PPP_IF_NAME "ppp0"
+
+int get_pppoe_status( const char *ether_if_name)
+{
+ int ret;
+
+ ret = if_is_up(ether_if_name);
+ if (ret < 0){
+ if ( ENODEV == -ret )
+ PRINTF( "No such device(%s)\n", ether_if_name );
+
+ PRINTF("ppp_status: DISCONNECTED\n");
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "ppp_status: DISCONNECTED\n");
+
+ return PPP_STATUS_DISCONNECTED;
+ }
+
+ if (0 == ret ) {
+ PRINTF( "%s is DOWN\n", ether_if_name );
+
+ PRINTF("ppp_status: DISCONNECTED\n");
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "ppp_status: DISCONNECTED\n");
+ return PPP_STATUS_DISCONNECTED;
+ }
+
+ ret = if_is_up(PPP_IF_NAME);
+ if (ret < 0){
+ if ( ENODEV == -ret )
+ PRINTF( "No such device(%s)\n", PPP_IF_NAME );
+
+ PRINTF("ppp_status: DISCONNECTED\n");
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "ppp_status: DISCONNECTED\n");
+ return PPP_STATUS_DISCONNECTED;
+ }
+
+ if (0 == ret ) {
+ PRINTF("ppp_status: CONNECTING\n");
+
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "ppp_status: CONNECTING\n");
+ return PPP_STATUS_CONNECTING;
+ }
+ else {
+ PRINTF("ppp_status: CONNECTED\n");
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "ppp_status: CONNECTED\n");
+ return PPP_STATUS_CONNECTED;
+ }
+
+
+}
+
+/*
+int
+main(int argc, char **argv)
+{
+ get_pppoe_status(( 1 == argc ) ? "eth0" : argv[1]);
+
+ return 0;
+}
+*/
diff --git a/jni/src/pppoe_status.h b/jni/src/pppoe_status.h
new file mode 100755
index 0000000..7e48ef8
--- a/dev/null
+++ b/jni/src/pppoe_status.h
@@ -0,0 +1,20 @@
+#ifndef PPPOE_STATUS_H
+#define PPPOE_STATUS_H
+
+#define PPP_STATUS_CONNECTED 0x10
+#define PPP_STATUS_DISCONNECTED 0x20
+#define PPP_STATUS_CONNECTING 0x40
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int get_pppoe_status( const char *ether_if_name);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/jni/src/pppoe_wrapper.c b/jni/src/pppoe_wrapper.c
new file mode 100755
index 0000000..672e00f
--- a/dev/null
+++ b/jni/src/pppoe_wrapper.c
@@ -0,0 +1,154 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <cutils/properties.h>
+#include <sys/un.h>
+
+#include <android/log.h>
+
+#include "pppoe_ctrl.h"
+
+#define LOCAL_TAG "PPPOE_WRAPPER"
+
+#define PPP_CMD_LEN_MAX 512
+
+static char ppp_cmd[PPP_CMD_LEN_MAX];
+
+
+static pid_t read_pid(const char *pidfile)
+{
+ FILE *fp;
+ pid_t pid;
+
+ if ((fp = fopen(pidfile, "r")) == NULL) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "failed to open %s (%s)\n", pidfile, strerror(errno));
+ errno = ENOENT;
+ return 0;
+ }
+
+ if (fscanf(fp, "%d", &pid) != 1) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "failed to read pid, make pid as 0\n");
+ pid = 0;
+ }
+ fclose(fp);
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,
+ "read_pid: %d\n", pid);
+
+ return pid;
+}
+
+static int ppp_stop()
+{
+ pid_t pid;
+ int ret;
+
+ pid = read_pid(PPPOE_PIDFILE);
+ if ( 0 == pid ) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "failed to stop ppp for no pid got\n" );
+ return -1;
+ }
+
+ ret = kill(pid, 0);
+ if ( 0 != ret ) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "process(#%d) died already???\n", pid );
+ return -1;
+ }
+
+ ret = kill(pid, SIGKILL);
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,
+ "Send SIGKILL to pid(#%d), ret = %d\n", pid, ret );
+
+ unlink(PPPOE_PIDFILE);
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,
+ "removed %s\n", PPPOE_PIDFILE );
+
+ return 0;
+}
+
+
+int main(int argc, char * argv[])
+{
+ int socket_fd;
+ struct sockaddr_un name;
+ int i, len;
+ int ppp_cmd_len;
+
+ socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "failed to create socket(%s)\n", strerror(errno));
+ exit(-1);
+ }
+
+ memset(&name,0,sizeof(name));
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,
+ "create AF_UNIX socket:%d OK\n",socket_fd);
+
+ unlink("/dev/socket/pppd");
+ name.sun_family = AF_UNIX;
+ strncpy(name.sun_path, "/dev/socket/pppd", sizeof(name.sun_path) - 1);
+
+ if (bind(socket_fd, (struct sockaddr *)&name, sizeof(struct sockaddr_un)) < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, LOCAL_TAG,
+ "failed to bind socket(%s)\n", strerror(errno));
+ exit(-1);
+ }
+
+ {
+ struct timeval tv;
+ int res;
+ fd_set rfds;
+
+ for (;;) {
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(socket_fd, &rfds);
+ res = select(socket_fd + 1, &rfds, NULL, NULL, &tv);
+ if (FD_ISSET(socket_fd, &rfds)) {
+ res = recv(socket_fd, ppp_cmd, PPP_CMD_LEN_MAX-1, 0);
+ if (res < 0)
+ return res;
+ ppp_cmd[res] = '\0';
+ ppp_cmd_len = res;
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG,
+ "recv cmd: [%s]\n",ppp_cmd);
+ if ( 0 == strcmp(ppp_cmd, "ppp-stop") ) {
+ ppp_stop();
+ }
+ else {
+ system(ppp_cmd);
+ }
+ }
+ }
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, LOCAL_TAG, "EXIT\n");
+ close(socket_fd);
+ return 0;
+}
+
diff --git a/jni/src/relay.c b/jni/src/relay.c
new file mode 100755
index 0000000..2dad044
--- a/dev/null
+++ b/jni/src/relay.c
@@ -0,0 +1,1559 @@
+/***********************************************************************
+*
+* relay.c
+*
+* Implementation of PPPoE relay
+*
+* Copyright (C) 2001-2006 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.
+*
+* LIC: GPL
+*
+* $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-2006 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;
+
+ if (getuid() != geteuid() ||
+ getgid() != getegid()) {
+ fprintf(stderr, "SECURITY WARNING: pppoe-relay will NOT run suid or sgid. Fix your installation.\n");
+ exit(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;
+ int j;
+ for (j=0; j<NumInterfaces; j++) {
+ if (!strncmp(Interfaces[j].name, ifname, IFNAMSIZ)) {
+ fprintf(stderr, "Interface %s specified more than once.\n", ifname);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ 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 > (unsigned int)size) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ /* Drop Ethernet frame padding */
+ if ((unsigned int)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 > (unsigned int)size) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ /* Drop Ethernet frame padding */
+ if ((unsigned int)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((char *) 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/jni/src/relay.h b/jni/src/relay.h
new file mode 100755
index 0000000..36d89a7
--- a/dev/null
+++ b/jni/src/relay.h
@@ -0,0 +1,99 @@
+/**********************************************************************
+*
+* relay.h
+*
+* Definitions for PPPoE relay
+*
+* Copyright (C) 2001-2006 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.
+*
+* LIC: GPL
+*
+* $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
diff --git a/pppoe.xml b/pppoe.xml
new file mode 100644
index 0000000..0e8c499
--- a/dev/null
+++ b/pppoe.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<permissions>
+<library
+name="com.amlogic.pppoe"
+file="/system/framework/pppoe.jar"
+/>
+</permissions>
+
diff --git a/src/com/amlogic/pppoe/PppoeOperation.java b/src/com/amlogic/pppoe/PppoeOperation.java
new file mode 100755
index 0000000..9419cee
--- a/dev/null
+++ b/src/com/amlogic/pppoe/PppoeOperation.java
@@ -0,0 +1,15 @@
+package com.amlogic.pppoe;
+
+public class PppoeOperation
+{
+ public static final int PPP_STATUS_CONNECTED = 0x10;
+ public static final int PPP_STATUS_DISCONNECTED = 0x20;
+ public static final int PPP_STATUS_CONNECTING = 0x40;
+
+ public native boolean connect(String account, String passwd);
+ public native boolean disconnect();
+ public native int status();
+ static {
+ System.loadLibrary("pppoejni");
+ }
+}