Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: man/pppoe-server.8
===================================================================
--- man/pppoe-server.8	(nonexistent)
+++ man/pppoe-server.8	(revision 5)
@@ -0,0 +1,236 @@
+.\" 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 need not 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 \-X \fIpidfile\fR
+This option causes \fBpppoe-server\fR to write its process ID to
+\fIpidfile\fR.  Additionally, it keeps the file locked so that only
+a single process may be started for a given \fIpidfile\fR.
+
+.TP
+.B \-q \fI/path/to/pppd\fR
+Specifies the full path to the \fBpppd\fR program.  The default is determined
+at compile time.  One use of this option is to supply a wrapper program that
+modifies the arguments passed to pppd.  This lets you do things not directly
+supported by the server (for example, specify IPv6 addresses.)
+
+.TP
+.B \-Q \fI/path/to/pppoe\fR
+Specifies the full path to the \fBpppoe\fR program.  The default is determined
+at compile time.  This option is only relevant if you are \fInot\fR
+using kernel-mode PPPoE.
+
+.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 \-P
+Check pool file for correctness and exit.
+
+.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
+Increment local IP address for each session.
+
+.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 \-D
+Delegate the allocation of IP addresses to \fBpppd\fR.  If specified, no
+local and remote addresses passed to pppd.
+
+.TP
+.B \-N \fInum\fR
+Allows at most \fInum\fR concurrent PPPoE sessions.  If not specified,
+the default is 64.
+
+.TP
+.B \-M \fIstring\fR
+Sends \fIstring\fR in a MOTM tag in a PADM packet right after sending
+the PADS to a client.
+
+.TP
+.B \-H \fIurl\fR
+Sends \fIurl\fR in a HURL tag in a PADM packet right after sending the
+PADS to a client.  Note that \fIurl\fR must start with either
+\fBhttp://\fR or \fBhttps://\fR.
+
+.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 \-d
+Debug session creation.
+
+.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 \-i
+The \fB\-i\fR option tells the server to completely ignore PADI frames
+if there are no free session slots.
+
+.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 Dianne Skoll <dianne@skoll.ca>.
+
+The \fBpppoe\fR home page is \fIhttps://dianne.skoll.ca/projects/rp-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)
+
Index: man/pppoe.8
===================================================================
--- man/pppoe.8	(nonexistent)
+++ man/pppoe.8	(revision 5)
@@ -0,0 +1,251 @@
+.\" LIC: GPL
+.TH PPPOE 8 "5 October 2015"
+.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 \-t \fItimeout\fR
+The \fB\-t\fR option sets the initial timeout for discovery packets in seconds.
+
+.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.  The specific Host-Uniq value used is the hexadecimal
+representation of the \fBpppoe\fR process's PID.
+
+.TP
+.B \-W value
+Causes \fBpppoe\fR to use the Host-Uniq tag in its discovery packets,
+and furthermore to set the value of Host-Uniq to \fIvalue\fR.  Use with
+caution.  Note that \fB\-W\fR and \fB\-U\fR are mutually-incompatible.
+
+.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 \-F numfloods
+The \fB\-F\fR option sets the discovery flood, only used for stress-testing.
+
+.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,
+https://dianne.skoll.ca/projects/rp-pppoe/, 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 Dianne Skoll <dianne@skoll.ca>,
+with much inspiration from an earlier version by Luke Stras.
+
+The \fBpppoe\fR home page is \fIhttps://dianne.skoll.ca/projects/rp-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)
+
Index: man
===================================================================
--- man	(nonexistent)
+++ man	(revision 5)

Property changes on: man
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: src/pppoe.c
===================================================================
--- src/pppoe.c	(nonexistent)
+++ src/pppoe.c	(revision 5)
@@ -0,0 +1,978 @@
+/***********************************************************************
+*
+* pppoe.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Copyright (C) 2000-2015 by Roaring Penguin Software Inc.
+* Copyright (C) 2018-2020 Dianne Skoll
+*
+* 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
+*
+***********************************************************************/
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.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 <pty.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 */
+
+/***********************************************************************
+*%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 > len) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+
+    /* Is it for our session? */
+    if (packet.session != conn->session) {
+	/* Nope, ignore it */
+	return;
+    }
+
+    /* Is it for our Ethernet interface? */
+    if (memcmp(packet.ethHdr.h_dest, conn->myEth, ETH_ALEN)) {
+	/* Nope, ignore it */
+	return;
+    }
+
+    /* Is it from our peer's Ethernet interface? */
+    if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {
+	/* Nope, ignore it */
+	return;
+    }
+
+    if (packet.code != CODE_PADT) {
+	/* Not PADT; ignore it */
+	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.vertype = PPPOE_VER_TYPE(1, 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"
+	    "   -W value       -- Use Host-Unique set to 'value' specifically.\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"
+	    "   -F numfloods   -- Set the discovery flood, only used for stress-testing.\n"
+	    "   -h             -- Print usage information.\n\n"
+	    "RP-PPPoE Version %s, Copyright (C) 2001-2018 Roaring Penguin Software Inc.\n"
+	    "                 %*s  Copyright (C) 2018-2020 Dianne Skoll\n"
+	    "RP-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"
+	    "https://dianne.skoll.ca/projects/rp-pppoe/\n", RP_VERSION, (int) strlen(RP_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:UW:sm:np:e:kdf:F:t:";
+#else
+    options = "I:VAT:hS:C:UW:sm: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) {
+		fprintf(pidfile, "%lu\n", (unsigned long) getpid());
+		fclose(pidfile);
+	    }
+	    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':
+	    if (conn.hostUniq) {
+		fprintf(stderr, "-U and -W are mutually-exclusive and may only be used once.\n");
+		exit(EXIT_FAILURE);
+	    }
+	    /* Allows for a 64-bit PID */
+	    conn.hostUniq = malloc(17);
+	    if (!conn.hostUniq) {
+		fprintf(stderr, "Out of memory.\n");
+		exit(EXIT_FAILURE);
+	    }
+	    sprintf(conn.hostUniq, "%lx", (unsigned long) getpid());
+	    break;
+	case 'W':
+	    if (conn.hostUniq) {
+		fprintf(stderr, "-U and -W are mutually-exclusive and may only be used once.\n");
+		exit(EXIT_FAILURE);
+	    }
+	    SET_STRING(conn.hostUniq, optarg);
+	    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", RP_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("RP-PPPoE Version %s\n", RP_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, NULL);
+	    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, NULL);
+
+    /* 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, NULL);
+        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 > 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 (PPPOE_VER(packet.vertype) != 1) {
+	syslog(LOG_ERR, "Unexpected packet version %d", PPPOE_VER(packet.vertype));
+	return;
+    }
+    if (PPPOE_TYPE(packet.vertype) != 1) {
+	syslog(LOG_ERR, "Unexpected packet type %d", PPPOE_TYPE(packet.vertype));
+	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 > len) {
+	syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+	       (int) plen, (int) len);
+	return;
+    }
+
+    /* Clamp MSS */
+    if (clampMss) {
+	clampMSS(&packet, "incoming", clampMss);
+    }
+
+    /* Compute FCS */
+    fcs = pppFCS16(PPPINITFCS16, header, 2);
+    fcs = pppFCS16(fcs, packet.payload, plen) ^ 0xffff;
+    tail[0] = fcs & 0x00ff;
+    tail[1] = (fcs >> 8) & 0x00ff;
+
+    /* Build a buffer to send to PPP */
+    *ptr++ = FRAME_FLAG;
+    *ptr++ = FRAME_ADDR;
+    *ptr++ = FRAME_ESC;
+    *ptr++ = FRAME_CTRL ^ FRAME_ENC;
+
+    for (i=0; i<plen; i++) {
+	c = packet.payload[i];
+	if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+	    *ptr++ = FRAME_ESC;
+	    *ptr++ = c ^ FRAME_ENC;
+	} else {
+	    *ptr++ = c;
+	}
+    }
+    for (i=0; i<2; i++) {
+	c = tail[i];
+	if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+	    *ptr++ = FRAME_ESC;
+	    *ptr++ = c ^ FRAME_ENC;
+	} else {
+	    *ptr++ = c;
+	}
+    }
+    *ptr++ = FRAME_FLAG;
+
+    /* Ship it out */
+    if (write(1, pppBuf, (ptr-pppBuf)) < 0) {
+	fatalSys("asyncReadFromEth: write");
+    }
+}
+
+/**********************************************************************
+*%FUNCTION: syncReadFromEth
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* sock -- Ethernet socket
+* clampMss -- if true, clamp MSS.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads a packet from the Ethernet interface and sends it to sync PPP
+* device.
+***********************************************************************/
+void
+syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
+{
+    PPPoEPacket packet;
+    int len;
+    int plen;
+    struct iovec vec[2];
+    unsigned char dummy[2];
+#ifdef USE_BPF
+    int type;
+#endif
+
+    if (receivePacket(sock, &packet, &len) < 0) {
+	return;
+    }
+
+    /* Check length */
+    if (ntohs(packet.length) + HDR_SIZE > len) {
+	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+	       (unsigned int) ntohs(packet.length));
+	return;
+    }
+#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 (PPPOE_VER(packet.vertype) != 1) {
+	syslog(LOG_ERR, "Unexpected packet version %d", PPPOE_VER(packet.vertype));
+	return;
+    }
+    if (PPPOE_TYPE(packet.vertype) != 1) {
+	syslog(LOG_ERR, "Unexpected packet type %d", PPPOE_TYPE(packet.vertype));
+	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 > 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");
+    }
+}
Index: src
===================================================================
--- src	(nonexistent)
+++ src	(revision 5)

Property changes on: src
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~