4. Add the following line to /etc/ppp/options:
- plugin rp-pppoe.so
+ plugin pppoe.so
The effect of this line is simply to make "eth0", "eth1",
....,"ethx" all valid device names for pppd (just like ttyS0,
echo "Creating Makefiles."
mkmkf $ksrc/Makefile.top Makefile
mkmkf $ksrc/Makedefs$compiletype Makedefs.com
- for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/rp-pppoe \
+ for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/pppoe \
pppd/plugins/radius pppd/plugins/pppoatm \
pppd/plugins/pppol2tp; do
mkmkf $dir/Makefile.$makext $dir/Makefile
MANDIR = $(DESTDIR)/share/man/man8
LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
-SUBDIRS := rp-pppoe pppoatm pppol2tp
+SUBDIRS := pppoe pppoatm pppol2tp
# Uncomment the next line to include the radius authentication plugin
SUBDIRS += radius
PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so
--- /dev/null
+pppoe-discovery
--- /dev/null
+# Generated automatically from Makefile.in by configure.
+#***********************************************************************
+#
+# Makefile
+#
+# Makefile for Roaring Penguin's Linux PPPoE plugin.
+# Modified for integration with pppd sources by Paul Mackerras.
+#
+# 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: Makefile.linux,v 1.8 2008/06/09 08:34:23 paulus Exp $
+#***********************************************************************
+
+DESTDIR = $(INSTROOT)@DESTDIR@
+BINDIR = $(DESTDIR)/sbin
+LIBDIR = $(DESTDIR)/lib/pppd/$(PPPDVERSION)
+
+PPPDVERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
+
+INSTALL = install
+LN_S = ln -sf
+
+COPTS=-O2 -g
+CFLAGS=$(COPTS) -I../../../include
+all: pppoe.so pppoe-discovery
+
+pppoe-discovery: pppoe-discovery.o debug.o
+ $(CC) $(LDFLAGS) -o pppoe-discovery pppoe-discovery.o debug.o
+
+pppoe-discovery.o: pppoe-discovery.c
+ $(CC) $(CFLAGS) -I../../.. -c -o pppoe-discovery.o pppoe-discovery.c
+
+debug.o: debug.c
+ $(CC) $(CFLAGS) -I../../.. -c -o debug.o debug.c
+
+pppoe.so: plugin.o discovery.o if.o common.o
+ $(CC) $(LDFLAGS) -o pppoe.so -shared plugin.o discovery.o if.o common.o
+
+install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+ $(INSTALL) -c -m 4550 pppoe.so $(LIBDIR)
+ # Symlink for backward compatibility
+ $(LN_S) pppoe.so $(LIBDIR)/rp-pppoe.so
+ $(INSTALL) -d -m 755 $(BINDIR)
+ $(INSTALL) -c -m 555 pppoe-discovery $(BINDIR)
+
+clean:
+ rm -f *.o *.so pppoe-discovery
+
+plugin.o: plugin.c
+ $(CC) $(CFLAGS) -I../../.. -c -o plugin.o -fPIC plugin.c
+
+discovery.o: discovery.c
+ $(CC) $(CFLAGS) -I../../.. -c -o discovery.o -fPIC discovery.c
+
+if.o: if.c
+ $(CC) $(CFLAGS) -I../../.. -c -o if.o -fPIC if.c
+
+common.o: common.c
+ $(CC) $(CFLAGS) -I../../.. -c -o common.o -fPIC common.c
+
--- /dev/null
+/***********************************************************************
+*
+* common.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Common functions used by PPPoE client and server
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: common.c,v 1.3 2008/06/09 08:34:23 paulus Exp $";
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+#include "pppd/pppd.h"
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <syslog.h> /* for LOG_DEBUG */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/**********************************************************************
+*%FUNCTION: parsePacket
+*%ARGUMENTS:
+* packet -- the PPPoE discovery packet to parse
+* func -- function called for each tag in the packet
+* extra -- an opaque data pointer supplied to parsing function
+*%RETURNS:
+* 0 if everything went well; -1 if there was an error
+*%DESCRIPTION:
+* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
+* "func" is passed the additional argument "extra".
+***********************************************************************/
+int
+parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
+{
+ UINT16_t len = ntohs(packet->length);
+ unsigned char *curTag;
+ UINT16_t tagType, tagLen;
+
+ if (PPPOE_VER(packet->vertype) != 1) {
+ error("Invalid PPPoE version (%d)", PPPOE_VER(packet->vertype));
+ return -1;
+ }
+ if (PPPOE_TYPE(packet->vertype) != 1) {
+ error("Invalid PPPoE type (%d)", PPPOE_TYPE(packet->vertype));
+ return -1;
+ }
+
+ /* Do some sanity checks on packet */
+ if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
+ error("Invalid PPPoE packet length (%u)", len);
+ return -1;
+ }
+
+ /* Step through the tags */
+ curTag = packet->payload;
+ while (curTag - packet->payload + TAG_HDR_SIZE <= len) {
+ /* Alignment is not guaranteed, so do this by hand... */
+ tagType = (curTag[0] << 8) + curTag[1];
+ tagLen = (curTag[2] << 8) + curTag[3];
+ if (tagType == TAG_END_OF_LIST) {
+ return 0;
+ }
+ if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+ error("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: 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.vertype = PPPOE_VER_TYPE(1, 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->hostUniq.length) {
+ int len = ntohs(conn->hostUniq.length);
+ memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
+ cursor += len + TAG_HDR_SIZE;
+ plen += len + TAG_HDR_SIZE;
+ }
+
+ /* Copy error message */
+ if (msg) {
+ PPPoETag err;
+ size_t elen = strlen(msg);
+ err.type = htons(TAG_GENERIC_ERROR);
+ err.length = htons(elen);
+ strcpy(err.payload, msg);
+ memcpy(cursor, &err, elen + TAG_HDR_SIZE);
+ cursor += elen + TAG_HDR_SIZE;
+ plen += elen + TAG_HDR_SIZE;
+ }
+
+ /* Copy cookie and relay-ID if needed */
+ if (conn->cookie.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ }
+
+ if (conn->relayId.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ info("Sent PADT");
+}
+
+#define EH(x) (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5]
+
+/* Print out a PPPOE packet for debugging */
+void pppoe_printpkt(PPPoEPacket *packet,
+ void (*printer)(void *, char *, ...), void *arg)
+{
+ int len = ntohs(packet->length);
+ int i, tag, tlen, text;
+
+ switch (ntohs(packet->ethHdr.h_proto)) {
+ case ETH_PPPOE_DISCOVERY:
+ printer(arg, "PPPOE Discovery V%dT%d ", PPPOE_VER(packet->vertype),
+ PPPOE_TYPE(packet->vertype));
+ switch (packet->code) {
+ case CODE_PADI:
+ printer(arg, "PADI");
+ break;
+ case CODE_PADO:
+ printer(arg, "PADO");
+ break;
+ case CODE_PADR:
+ printer(arg, "PADR");
+ break;
+ case CODE_PADS:
+ printer(arg, "PADS");
+ break;
+ case CODE_PADT:
+ printer(arg, "PADT");
+ break;
+ default:
+ printer(arg, "unknown code %x", packet->code);
+ }
+ printer(arg, " session 0x%x length %d\n", ntohs(packet->session), len);
+ break;
+ case ETH_PPPOE_SESSION:
+ printer(arg, "PPPOE Session V%dT%d", PPPOE_VER(packet->vertype),
+ PPPOE_TYPE(packet->vertype));
+ printer(arg, " code 0x%x session 0x%x length %d\n", packet->code,
+ ntohs(packet->session), len);
+ break;
+ default:
+ printer(arg, "Unknown ethernet frame with proto = 0x%x\n",
+ ntohs(packet->ethHdr.h_proto));
+ }
+
+ printer(arg, " dst %02x:%02x:%02x:%02x:%02x:%02x ", EH(packet->ethHdr.h_dest));
+ printer(arg, " src %02x:%02x:%02x:%02x:%02x:%02x\n", EH(packet->ethHdr.h_source));
+ if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY)
+ return;
+
+ for (i = 0; i + TAG_HDR_SIZE <= len; i += tlen) {
+ tag = (packet->payload[i] << 8) + packet->payload[i+1];
+ tlen = (packet->payload[i+2] << 8) + packet->payload[i+3];
+ if (i + tlen + TAG_HDR_SIZE > len)
+ break;
+ text = 0;
+ i += TAG_HDR_SIZE;
+ printer(arg, " [");
+ switch (tag) {
+ case TAG_END_OF_LIST:
+ printer(arg, "end-of-list");
+ break;
+ case TAG_SERVICE_NAME:
+ printer(arg, "service-name");
+ text = 1;
+ break;
+ case TAG_AC_NAME:
+ printer(arg, "AC-name");
+ text = 1;
+ break;
+ case TAG_HOST_UNIQ:
+ printer(arg, "host-uniq");
+ break;
+ case TAG_AC_COOKIE:
+ printer(arg, "AC-cookie");
+ break;
+ case TAG_VENDOR_SPECIFIC:
+ printer(arg, "vendor-specific");
+ break;
+ case TAG_RELAY_SESSION_ID:
+ printer(arg, "relay-session-id");
+ break;
+ case TAG_PPP_MAX_PAYLOAD:
+ printer(arg, "PPP-max-payload");
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ printer(arg, "service-name-error");
+ text = 1;
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ printer(arg, "AC-system-error");
+ text = 1;
+ break;
+ case TAG_GENERIC_ERROR:
+ printer(arg, "generic-error");
+ text = 1;
+ break;
+ default:
+ printer(arg, "unknown tag 0x%x", tag);
+ }
+ if (tlen) {
+ if (text)
+ printer(arg, " %.*v", tlen, &packet->payload[i]);
+ else if (tlen <= 32)
+ printer(arg, " %.*B", tlen, &packet->payload[i]);
+ else
+ printer(arg, " %.32B... (length %d)",
+ &packet->payload[i], tlen);
+ }
+ printer(arg, "]");
+ }
+ printer(arg, "\n");
+}
+
+void pppoe_log_packet(const char *prefix, PPPoEPacket *packet)
+{
+ init_pr_log(prefix, LOG_DEBUG);
+ pppoe_printpkt(packet, pr_log, NULL);
+ end_pr_log();
+}
--- /dev/null
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#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. */
+#define HAVE_LINUX_KERNEL_PPPOE 1
+
+/* 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. */
+#define HAVE_NET_BPF_H 1
+
+/* 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/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. */
+#define HAVE_SYS_UIO_H 1
+
+/* 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 */
+#define HAVE_N_HDLC 1
--- /dev/null
+/***********************************************************************
+*
+* debug.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for printing debugging information
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: debug.c,v 1.2 2008/06/09 08:34:23 paulus Exp $";
+
+#include "pppoe.h"
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/**********************************************************************
+*%FUNCTION: dumpHex
+*%ARGUMENTS:
+* fp -- file to dump to
+* buf -- buffer to dump
+* len -- length of data
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Dumps buffer to fp in an easy-to-read format
+***********************************************************************/
+void
+dumpHex(FILE *fp, unsigned char const *buf, int len)
+{
+ int i;
+ int base;
+
+ if (!fp) return;
+
+ /* do NOT dump PAP packets */
+ if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
+ fprintf(fp, "(PAP Authentication Frame -- Contents not dumped)\n");
+ return;
+ }
+
+ for (base=0; base<len; base += 16) {
+ for (i=base; i<base+16; i++) {
+ if (i < len) {
+ fprintf(fp, "%02x ", (unsigned) buf[i]);
+ } else {
+ fprintf(fp, " ");
+ }
+ }
+ fprintf(fp, " ");
+ for (i=base; i<base+16; i++) {
+ if (i < len) {
+ if (isprint(buf[i])) {
+ fprintf(fp, "%c", buf[i]);
+ } else {
+ fprintf(fp, ".");
+ }
+ } else {
+ break;
+ }
+ }
+ fprintf(fp, "\n");
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: dumpPacket
+*%ARGUMENTS:
+* fp -- file to dump to
+* packet -- a PPPoE packet
+* dir -- either SENT or RCVD
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Dumps the PPPoE packet to fp in an easy-to-read format
+***********************************************************************/
+void
+dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir)
+{
+ int len = ntohs(packet->length);
+
+ /* Sheesh... printing times is a pain... */
+ struct timeval tv;
+ time_t now;
+ int millisec;
+ struct tm *lt;
+ char timebuf[256];
+
+ UINT16_t type = etherType(packet);
+ if (!fp) return;
+ gettimeofday(&tv, NULL);
+ now = (time_t) tv.tv_sec;
+ millisec = tv.tv_usec / 1000;
+ lt = localtime(&now);
+ strftime(timebuf, 256, "%H:%M:%S", lt);
+ fprintf(fp, "%s.%03d %s PPPoE ", timebuf, millisec, dir);
+ if (type == Eth_PPPOE_Discovery) {
+ fprintf(fp, "Discovery (%x) ", (unsigned) type);
+ } else if (type == Eth_PPPOE_Session) {
+ fprintf(fp, "Session (%x) ", (unsigned) type);
+ } else {
+ fprintf(fp, "Unknown (%x) ", (unsigned) type);
+ }
+
+ switch(packet->code) {
+ case CODE_PADI: fprintf(fp, "PADI "); break;
+ case CODE_PADO: fprintf(fp, "PADO "); break;
+ case CODE_PADR: fprintf(fp, "PADR "); break;
+ case CODE_PADS: fprintf(fp, "PADS "); break;
+ case CODE_PADT: fprintf(fp, "PADT "); break;
+ case CODE_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));
+}
--- /dev/null
+/***********************************************************************
+*
+* discovery.c
+*
+* Perform PPPoE discovery
+*
+* Copyright (C) 1999 by Roaring Penguin Software Inc.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: discovery.c,v 1.6 2008/06/15 04:35:50 paulus Exp $";
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+#include "pppd/pppd.h"
+#include "pppd/fsm.h"
+#include "pppd/lcp.h"
+
+#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>
+
+/* Calculate time remaining until *exp, return 0 if now >= *exp */
+static int time_left(struct timeval *diff, struct timeval *exp)
+{
+ struct timeval now;
+
+ if (get_time(&now) < 0) {
+ error("get_time: %m");
+ return 0;
+ }
+
+ if (now.tv_sec > exp->tv_sec
+ || (now.tv_sec == exp->tv_sec && now.tv_usec >= exp->tv_usec))
+ return 0;
+
+ diff->tv_sec = exp->tv_sec - now.tv_sec;
+ diff->tv_usec = exp->tv_usec - now.tv_usec;
+ if (diff->tv_usec < 0) {
+ diff->tv_usec += 1000000;
+ --diff->tv_sec;
+ }
+
+ return 1;
+}
+
+/**********************************************************************
+*%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)
+{
+ PPPoETag *tag = extra;
+
+ if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
+ tag->length = memcmp(data, tag->payload, len);
+}
+
+/**********************************************************************
+*%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)
+{
+ PPPoETag hostUniq = conn->hostUniq;
+
+ /* 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->hostUniq.length) return 1;
+
+ parsePacket(packet, parseForHostUniq, &hostUniq);
+ return !hostUniq.length;
+}
+
+/**********************************************************************
+*%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;
+ UINT16_t mru;
+ int i;
+
+ switch(type) {
+ case TAG_AC_NAME:
+ pc->seenACName = 1;
+ if (conn->printACNames) {
+ info("Access-Concentrator: %.*s", (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->serviceName && len == strlen(conn->serviceName) &&
+ !strncmp((char *) data, conn->serviceName, len)) {
+ pc->serviceNameOK = 1;
+ }
+ break;
+ case TAG_AC_COOKIE:
+ conn->cookie.type = htons(type);
+ conn->cookie.length = htons(len);
+ memcpy(conn->cookie.payload, data, len);
+ break;
+ case TAG_RELAY_SESSION_ID:
+ conn->relayId.type = htons(type);
+ conn->relayId.length = htons(len);
+ memcpy(conn->relayId.payload, data, len);
+ break;
+ case TAG_PPP_MAX_PAYLOAD:
+ if (len == sizeof(mru)) {
+ memcpy(&mru, data, sizeof(mru));
+ mru = ntohs(mru);
+ if (mru >= ETH_PPPOE_MTU) {
+ if (lcp_allowoptions[0].mru > mru)
+ lcp_allowoptions[0].mru = mru;
+ if (lcp_wantoptions[0].mru > mru)
+ lcp_wantoptions[0].mru = mru;
+ conn->seenMaxPayload = 1;
+ }
+ }
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ error("PADO: Service-Name-Error: %.*s", (int) len, data);
+ conn->error = 1;
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ error("PADO: System-Error: %.*s", (int) len, data);
+ conn->error = 1;
+ break;
+ case TAG_GENERIC_ERROR:
+ error("PADO: Generic-Error: %.*s", (int) len, data);
+ conn->error = 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;
+ UINT16_t mru;
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
+ break;
+ case TAG_PPP_MAX_PAYLOAD:
+ if (len == sizeof(mru)) {
+ memcpy(&mru, data, sizeof(mru));
+ mru = ntohs(mru);
+ if (mru >= ETH_PPPOE_MTU) {
+ if (lcp_allowoptions[0].mru > mru)
+ lcp_allowoptions[0].mru = mru;
+ if (lcp_wantoptions[0].mru > mru)
+ lcp_wantoptions[0].mru = mru;
+ conn->seenMaxPayload = 1;
+ }
+ }
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ error("PADS: Service-Name-Error: %.*s", (int) len, data);
+ conn->error = 1;
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ error("PADS: System-Error: %.*s", (int) len, data);
+ conn->error = 1;
+ break;
+ case TAG_GENERIC_ERROR:
+ error("PADS: Generic-Error: %.*s", (int) len, data);
+ conn->error = 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.vertype = PPPOE_VER_TYPE(1, 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->hostUniq.length) {
+ int len = ntohs(conn->hostUniq.length);
+ CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
+ cursor += len + TAG_HDR_SIZE;
+ plen += len + TAG_HDR_SIZE;
+ }
+
+ /* Add our maximum MTU/MRU */
+ if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+ PPPoETag maxPayload;
+ UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+ maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
+ maxPayload.length = htons(sizeof(mru));
+ memcpy(maxPayload.payload, &mru, sizeof(mru));
+ CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
+ memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
+ cursor += sizeof(mru) + TAG_HDR_SIZE;
+ plen += sizeof(mru) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+}
+
+/**********************************************************************
+*%FUNCTION: waitForPADO
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* timeout -- how long to wait (in seconds)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Waits for a PADO packet and copies useful information
+***********************************************************************/
+void
+waitForPADO(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ struct timeval expire_at;
+
+ 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;
+ conn->seenMaxPayload = 0;
+ conn->error = 0;
+
+ if (get_time(&expire_at) < 0) {
+ error("get_time (waitForPADO): %m");
+ return;
+ }
+ expire_at.tv_sec += timeout;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ if (!time_left(&tv, &expire_at))
+ return; /* Timed out */
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR || got_sigterm) break;
+ }
+ if (r < 0) {
+ error("select (waitForPADO): %m");
+ return;
+ }
+ if (r == 0)
+ return; /* Timed out */
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ error("Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+
+ /* If it's not for us, loop again */
+ if (!packetIsForMe(conn, &packet)) continue;
+
+ if (packet.code == CODE_PADO) {
+ if (NOT_UNICAST(packet.ethHdr.h_source)) {
+ error("Ignoring PADO packet from non-unicast MAC address");
+ continue;
+ }
+ if (conn->req_peer
+ && memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
+ warn("Ignoring PADO packet from wrong MAC address");
+ continue;
+ }
+ if (parsePacket(&packet, parsePADOTags, &pc) < 0)
+ return;
+ if (conn->error)
+ return;
+ if (!pc.seenACName) {
+ error("Ignoring PADO packet with no AC-Name tag");
+ continue;
+ }
+ if (!pc.seenServiceName) {
+ error("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);
+ 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.vertype = PPPOE_VER_TYPE(1, 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->hostUniq.length) {
+ int len = ntohs(conn->hostUniq.length);
+ CHECK_ROOM(cursor, packet.payload, len+TAG_HDR_SIZE);
+ memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
+ cursor += len + TAG_HDR_SIZE;
+ plen += len + TAG_HDR_SIZE;
+ }
+
+ /* Add our maximum MTU/MRU */
+ if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+ PPPoETag maxPayload;
+ UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+ maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
+ maxPayload.length = htons(sizeof(mru));
+ memcpy(maxPayload.payload, &mru, sizeof(mru));
+ CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
+ memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
+ cursor += sizeof(mru) + TAG_HDR_SIZE;
+ plen += sizeof(mru) + 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));
+}
+
+/**********************************************************************
+*%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;
+
+ PPPoEPacket packet;
+ int len;
+
+ if (get_time(&expire_at) < 0) {
+ error("get_time (waitForPADS): %m");
+ return;
+ }
+ expire_at.tv_sec += timeout;
+
+ conn->error = 0;
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ if (!time_left(&tv, &expire_at))
+ return; /* Timed out */
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR || got_sigterm) break;
+ }
+ if (r < 0) {
+ error("select (waitForPADS): %m");
+ return;
+ }
+ if (r == 0)
+ return; /* Timed out */
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ error("Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+
+ /* If 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 */
+ if (parsePacket(&packet, parsePADSTags, conn) < 0)
+ return;
+ if (conn->error)
+ return;
+ 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;
+
+ info("PPP session is %d", (int) ntohs(conn->session));
+
+ /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
+ if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
+ error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: discovery
+*%ARGUMENTS:
+* conn -- PPPoE connection info structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Performs the PPPoE discovery phase
+***********************************************************************/
+void
+discovery(PPPoEConnection *conn)
+{
+ int padiAttempts = 0;
+ int padrAttempts = 0;
+ int timeout = conn->discoveryTimeout;
+
+ do {
+ padiAttempts++;
+ if (got_sigterm || padiAttempts > conn->discoveryAttempts) {
+ warn("Timeout waiting for PADO packets");
+ close(conn->discoverySocket);
+ conn->discoverySocket = -1;
+ return;
+ }
+ sendPADI(conn);
+ conn->discoveryState = STATE_SENT_PADI;
+ waitForPADO(conn, timeout);
+
+ timeout *= 2;
+ } while (conn->discoveryState == STATE_SENT_PADI);
+
+ timeout = conn->discoveryTimeout;
+ do {
+ padrAttempts++;
+ if (got_sigterm || padrAttempts > conn->discoveryAttempts) {
+ warn("Timeout waiting for PADS packets");
+ close(conn->discoverySocket);
+ conn->discoverySocket = -1;
+ return;
+ }
+ sendPADR(conn);
+ conn->discoveryState = STATE_SENT_PADR;
+ waitForPADS(conn, timeout);
+ timeout *= 2;
+ } while (conn->discoveryState == STATE_SENT_PADR);
+
+ if (!conn->seenMaxPayload) {
+ /* RFC 4638: MUST limit MTU/MRU to 1492 */
+ if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU)
+ lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
+ if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)
+ lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
+ }
+
+ /* We're done. */
+ close(conn->discoverySocket);
+ conn->discoverySocket = -1;
+ conn->discoveryState = STATE_SESSION;
+ return;
+}
--- /dev/null
+/***********************************************************************
+*
+* if.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for opening a raw socket and reading/writing raw Ethernet frames.
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: if.c,v 1.2 2008/06/09 08:34:23 paulus Exp $";
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+#include "pppd/pppd.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_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#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) {
+ error("Invalid ether type 0x%x", type);
+ }
+ return type;
+}
+
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A raw socket for talking to the Ethernet card. Exits on error.
+*%DESCRIPTION:
+* Opens a raw Ethernet socket
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ int optval=1;
+ int fd;
+ struct ifreq ifr;
+ int domain, stype;
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ struct sockaddr_ll sa;
+#else
+ struct sockaddr sa;
+#endif
+
+ memset(&sa, 0, sizeof(sa));
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ domain = PF_PACKET;
+ stype = SOCK_RAW;
+#else
+ domain = PF_INET;
+ stype = SOCK_PACKET;
+#endif
+
+ if ((fd = socket(domain, stype, htons(type))) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
+ error("Can't open socket for pppoe: %m");
+ return -1;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
+ error("Can't set socket options for pppoe: %m");
+ close(fd);
+ return -1;
+ }
+
+ /* Fill in hardware address */
+ if (hwaddr) {
+ strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ error("Can't get hardware address for %s: %m", ifname);
+ close(fd);
+ return -1;
+ }
+ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+#ifdef ARPHRD_ETHER
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ warn("Interface %.16s is not Ethernet", ifname);
+ }
+#endif
+ if (NOT_UNICAST(hwaddr)) {
+ fatal("Can't use interface %.16s: it has broadcast/multicast MAC address",
+ ifname);
+ }
+ }
+
+ /* Sanity check on MTU */
+ strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ error("Can't get MTU for %s: %m", ifname);
+ } else if (ifr.ifr_mtu < ETH_DATA_LEN) {
+ error("Interface %.16s has MTU of %d -- should be at least %d.",
+ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+ error("This may cause serious connection problems.");
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ /* Get interface index */
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons(type);
+
+ strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ error("Could not get interface index for %s: %m", ifname);
+ close(fd);
+ return -1;
+ }
+ sa.sll_ifindex = ifr.ifr_ifindex;
+
+#else
+ strcpy(sa.sa_data, ifname);
+#endif
+
+ /* We're only interested in packets on specified interface */
+ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ error("Failed to bind to interface %s: %m", ifname);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+
+/***********************************************************************
+*%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)
+{
+ int err;
+
+ if (debug)
+ pppoe_log_packet("Send ", pkt);
+#if defined(HAVE_STRUCT_SOCKADDR_LL)
+ err = send(sock, pkt, size, 0);
+#else
+ struct sockaddr sa;
+
+ strcpy(sa.sa_data, conn->ifName);
+ err = sendto(sock, pkt, size, 0, &sa, sizeof(sa));
+#endif
+ if (err < 0) {
+ error("error sending pppoe packet: %m");
+ return -1;
+ }
+ return 0;
+}
+
+/***********************************************************************
+*%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)
+{
+ if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+ error("error receiving pppoe packet: %m");
+ return -1;
+ }
+ if (debug)
+ pppoe_log_packet("Recv ", pkt);
+ return 0;
+}
--- /dev/null
+/***********************************************************************
+*
+* plugin.c
+*
+* pppd plugin for kernel-mode PPPoE on Linux
+*
+* Copyright (C) 2001 by Roaring Penguin Software Inc., Michal Ostrowski
+* and Jamal Hadi Salim.
+*
+* Much code and many ideas derived from pppoe plugin by Michal
+* Ostrowski and Jamal Hadi Salim, which carries this copyright:
+*
+* Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
+* Jamal Hadi Salim <hadi@cyberus.ca>
+* Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
+* which is based in part on work from Jens Axboe and Paul Mackerras.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version
+* 2 of the License, or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: plugin.c,v 1.17 2008/06/15 04:35:50 paulus Exp $";
+
+#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 <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/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 char *pppoe_reqd_mac = NULL;
+unsigned char pppoe_reqd_mac_addr[6];
+static char *host_uniq;
+static int pppoe_padi_timeout = PADI_TIMEOUT;
+static int pppoe_padi_attempts = MAX_PADI_ATTEMPTS;
+
+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"},
+ { "pppoe-mac", o_string, &pppoe_reqd_mac,
+ "Only connect to specified MAC address" },
+ { "host-uniq", o_string, &host_uniq,
+ "Set the Host-Uniq to the supplied hex string" },
+ { "pppoe-padi-timeout", o_int, &pppoe_padi_timeout,
+ "Initial timeout for discovery packets in seconds" },
+ { "pppoe-padi-attempts", o_int, &pppoe_padi_attempts,
+ "Number of discovery attempts" },
+ { 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) {
+ novm("PPPoE session data");
+ }
+ memset(conn, 0, sizeof(PPPoEConnection));
+ conn->ifName = devnam;
+ conn->discoverySocket = -1;
+ conn->sessionSocket = -1;
+ conn->printACNames = printACNames;
+ conn->discoveryTimeout = pppoe_padi_timeout;
+ conn->discoveryAttempts = pppoe_padi_attempts;
+ 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;
+ struct ifreq ifr;
+ int s;
+
+ /* 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;
+ }
+
+ /* Restore configuration */
+ lcp_allowoptions[0].mru = conn->mtu;
+ lcp_wantoptions[0].mru = conn->mru;
+
+ /* Update maximum MRU */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ error("Can't get MTU for %s: %m", conn->ifName);
+ goto errout;
+ }
+ strlcpy(ifr.ifr_name, conn->ifName, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
+ error("Can't get MTU for %s: %m", conn->ifName);
+ close(s);
+ goto errout;
+ }
+ close(s);
+
+ if (lcp_allowoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
+ lcp_allowoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+ if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
+ lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+
+ if (host_uniq) {
+ if (!parseHostUniq(host_uniq, &conn->hostUniq))
+ fatal("Illegal value for host-uniq option");
+ } else {
+ /* if a custom host-uniq is not supplied, use our PID */
+ pid_t pid = getpid();
+ conn->hostUniq.type = htons(TAG_HOST_UNIQ);
+ conn->hostUniq.length = htons(sizeof(pid));
+ memcpy(conn->hostUniq.payload, &pid, sizeof(pid));
+ }
+
+ conn->acName = acName;
+ conn->serviceName = pppd_pppoe_service;
+ 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");
+ goto errout;
+ }
+ }
+
+ /* 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);
+ goto errout;
+ }
+
+ return conn->sessionSocket;
+
+ errout:
+ if (conn->discoverySocket >= 0) {
+ sendPADT(conn, NULL);
+ close(conn->discoverySocket);
+ conn->discoverySocket = -1;
+ }
+ close(conn->sessionSocket);
+ return -1;
+}
+
+static void
+PPPOERecvConfig(int mru,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+#if 0 /* broken protocol, but no point harrassing the users I guess... */
+ if (mru > MAX_PPPOE_MTU)
+ warn("Couldn't increase MRU to %d", mru);
+#endif
+}
+
+/**********************************************************************
+ * %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 && errno != EALREADY)
+ error("Failed to disconnect PPPoE socket: %d %m", errno);
+ close(conn->sessionSocket);
+ if (conn->discoverySocket >= 0) {
+ sendPADT(conn, NULL);
+ close(conn->discoverySocket);
+ }
+}
+
+static void
+PPPOEDeviceOptions(void)
+{
+ char buf[MAXPATHLEN];
+
+ strlcpy(buf, _PATH_ETHOPT, MAXPATHLEN);
+ strlcat(buf, devnam, MAXPATHLEN);
+ 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;
+
+ /*
+ * Take any otherwise-unrecognized option as a possible device name,
+ * and test if it is the name of a network interface with a
+ * hardware address whose sa_family is ARPHRD_ETHER.
+ */
+ if (strlen(cmd) > 4 && !strncmp(cmd, "nic-", 4)) {
+ /* Strip off "nic-" */
+ cmd += 4;
+ }
+
+ /* Open a socket */
+ if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
+ r = 0;
+ }
+
+ /* Try getting interface index */
+ if (r) {
+ strlcpy(ifr.ifr_name, cmd, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ r = 0;
+ } else {
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ r = 0;
+ } else {
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ if (doit)
+ error("Interface %s not Ethernet", cmd);
+ r = 0;
+ }
+ }
+ }
+ }
+
+ /* Close socket */
+ close(fd);
+ if (r && doit) {
+ strlcpy(devnam, cmd, sizeof(devnam));
+ if (the_channel != &pppoe_channel) {
+
+ the_channel = &pppoe_channel;
+ modem = 0;
+
+ PPPOEInitDevice();
+ }
+ return 1;
+ }
+
+ 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("PPPoE plugin from pppd %s", VERSION);
+}
+
+void pppoe_check_options(void)
+{
+ unsigned int mac[6];
+ int i;
+
+ if (pppoe_reqd_mac != NULL) {
+ if (sscanf(pppoe_reqd_mac, "%x:%x:%x:%x:%x:%x",
+ &mac[0], &mac[1], &mac[2], &mac[3],
+ &mac[4], &mac[5]) != 6) {
+ option_error("cannot parse pppoe-mac option value");
+ exit(EXIT_OPTION_ERROR);
+ }
+ for (i = 0; i < 6; ++i)
+ conn->req_peer_mac[i] = mac[i];
+ conn->req_peer = 1;
+ }
+
+ 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;
+
+ if (lcp_allowoptions[0].mru > MAX_PPPOE_MTU)
+ lcp_allowoptions[0].mru = MAX_PPPOE_MTU;
+ if (lcp_wantoptions[0].mru > MAX_PPPOE_MTU)
+ lcp_wantoptions[0].mru = MAX_PPPOE_MTU;
+
+ /* Save configuration */
+ conn->mtu = lcp_allowoptions[0].mru;
+ conn->mru = lcp_wantoptions[0].mru;
+
+ ccp_allowoptions[0].deflate = 0;
+ ccp_wantoptions[0].deflate = 0;
+
+ ipcp_allowoptions[0].neg_vj = 0;
+ ipcp_wantoptions[0].neg_vj = 0;
+
+ ccp_allowoptions[0].bsd_compress = 0;
+ ccp_wantoptions[0].bsd_compress = 0;
+}
+
+struct channel pppoe_channel = {
+ .options = Options,
+ .process_extra_options = &PPPOEDeviceOptions,
+ .check_options = pppoe_check_options,
+ .connect = &PPPOEConnectDevice,
+ .disconnect = &PPPOEDisconnectDevice,
+ .establish_ppp = &generic_establish_ppp,
+ .disestablish_ppp = &generic_disestablish_ppp,
+ .send_config = NULL,
+ .recv_config = &PPPOERecvConfig,
+ .close = NULL,
+ .cleanup = NULL
+};
--- /dev/null
+/*
+ * Perform PPPoE discovery
+ *
+ * Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
+ * Copyright (C) 2004 Marco d'Itri <md@linux.it>
+ *
+ * This program may be distributed according to the terms of the GNU
+ * General Public License, version 2 or (at your option) any later version.
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+#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_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+
+char *xstrdup(const char *s);
+void usage(void);
+
+void die(int status)
+{
+ exit(status);
+}
+
+void error(char *fmt, ...)
+{
+ va_list pvar;
+ va_start(pvar, fmt);
+ vfprintf(stderr, fmt, pvar);
+ va_end(pvar);
+}
+
+/* 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) {
+ fprintf(stderr, "Invalid ether type 0x%x\n", type);
+ }
+ return type;
+}
+
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A raw socket for talking to the Ethernet card. Exits on error.
+*%DESCRIPTION:
+* Opens a raw Ethernet socket
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ int optval=1;
+ int fd;
+ struct ifreq ifr;
+ int domain, stype;
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ struct sockaddr_ll sa;
+#else
+ struct sockaddr sa;
+#endif
+
+ memset(&sa, 0, sizeof(sa));
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ domain = PF_PACKET;
+ stype = SOCK_RAW;
+#else
+ domain = PF_INET;
+ stype = SOCK_PACKET;
+#endif
+
+ if ((fd = socket(domain, stype, htons(type))) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
+ fatalSys("socket");
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
+ fatalSys("setsockopt");
+ }
+
+ /* Fill in hardware address */
+ if (hwaddr) {
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFHWADDR)");
+ }
+ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+#ifdef ARPHRD_ETHER
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
+ rp_fatal(buffer);
+ }
+#endif
+ if (NOT_UNICAST(hwaddr)) {
+ char buffer[256];
+ sprintf(buffer,
+ "Interface %.16s has broadcast/multicast MAC address??",
+ ifname);
+ rp_fatal(buffer);
+ }
+ }
+
+ /* Sanity check on MTU */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFMTU)");
+ }
+ if (ifr.ifr_mtu < ETH_DATA_LEN) {
+ fprintf(stderr, "Interface %.16s has MTU of %d -- should be %d.\n",
+ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+ fprintf(stderr, "You may have serious connection problems.\n");
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ /* Get interface index */
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons(type);
+
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ - 1] = 0;
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
+ }
+ sa.sll_ifindex = ifr.ifr_ifindex;
+
+#else
+ strcpy(sa.sa_data, ifname);
+#endif
+
+ /* We're only interested in packets on specified interface */
+ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ fatalSys("bind");
+ }
+
+ return fd;
+}
+
+
+/***********************************************************************
+*%FUNCTION: sendPacket
+*%ARGUMENTS:
+* sock -- socket to send to
+* pkt -- the packet to transmit
+* size -- size of packet (in bytes)
+*%RETURNS:
+* 0 on success; -1 on failure
+*%DESCRIPTION:
+* Transmits a packet
+***********************************************************************/
+int
+sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
+{
+#if defined(HAVE_STRUCT_SOCKADDR_LL)
+ if (send(sock, pkt, size, 0) < 0) {
+ sysErr("send (sendPacket)");
+ return -1;
+ }
+#else
+ struct sockaddr sa;
+
+ if (!conn) {
+ rp_fatal("relay and server not supported on Linux 2.0 kernels");
+ }
+ strcpy(sa.sa_data, conn->ifName);
+ if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
+ sysErr("sendto (sendPacket)");
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/***********************************************************************
+*%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)
+{
+ if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+ sysErr("recv (receivePacket)");
+ return -1;
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%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 (PPPOE_VER(packet->vertype) != 1) {
+ fprintf(stderr, "Invalid PPPoE version (%d)\n",
+ PPPOE_VER(packet->vertype));
+ return -1;
+ }
+ if (PPPOE_TYPE(packet->vertype) != 1) {
+ fprintf(stderr, "Invalid PPPoE type (%d)\n",
+ PPPOE_TYPE(packet->vertype));
+ return -1;
+ }
+
+ /* Do some sanity checks on packet */
+ if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
+ fprintf(stderr, "Invalid PPPoE packet length (%u)\n", 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 = (curTag[0] << 8) + curTag[1];
+ tagLen = (curTag[2] << 8) + curTag[3];
+ if (tagType == TAG_END_OF_LIST) {
+ return 0;
+ }
+ if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+ fprintf(stderr, "Invalid PPPoE tag length (%u)\n", tagLen);
+ return -1;
+ }
+ func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
+ curTag = curTag + TAG_HDR_SIZE + tagLen;
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: parseForHostUniq
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data.
+* extra -- user-supplied pointer. This is assumed to be a pointer to int.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* If a HostUnique tag is found which matches our PID, sets *extra to 1.
+***********************************************************************/
+void
+parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ PPPoETag *tag = extra;
+
+ if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
+ tag->length = memcmp(data, tag->payload, len);
+}
+
+/**********************************************************************
+*%FUNCTION: packetIsForMe
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* packet -- a received PPPoE packet
+*%RETURNS:
+* 1 if packet is for this PPPoE daemon; 0 otherwise.
+*%DESCRIPTION:
+* If we are using the Host-Unique tag, verifies that packet contains
+* our unique identifier.
+***********************************************************************/
+int
+packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ PPPoETag hostUniq = conn->hostUniq;
+
+ /* 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->hostUniq.length) return 1;
+
+ parsePacket(packet, parseForHostUniq, &hostUniq);
+ return !hostUniq.length;
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADOTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data. Should point to a PacketCriteria structure
+* which gets filled in according to selected AC name and service
+* name.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADO packet
+***********************************************************************/
+void
+parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ struct PacketCriteria *pc = (struct PacketCriteria *) extra;
+ PPPoEConnection *conn = pc->conn;
+ int i;
+
+ switch(type) {
+ case TAG_AC_NAME:
+ 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);
+ }
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ if (conn->printACNames) {
+ printf("Got a System-Error tag: %.*s\n", (int) len, data);
+ }
+ break;
+ case TAG_GENERIC_ERROR:
+ if (conn->printACNames) {
+ printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
+ }
+ break;
+ }
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADI
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADI packet
+***********************************************************************/
+void
+sendPADI(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ unsigned char *cursor = packet.payload;
+ PPPoETag *svc = (PPPoETag *) (&packet.payload);
+ UINT16_t namelen = 0;
+ UINT16_t plen;
+
+ if (conn->serviceName) {
+ namelen = (UINT16_t) strlen(conn->serviceName);
+ }
+ plen = TAG_HDR_SIZE + namelen;
+ CHECK_ROOM(cursor, packet.payload, plen);
+
+ /* Set destination to Ethernet broadcast address */
+ memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.vertype = PPPOE_VER_TYPE(1, 1);
+ packet.code = CODE_PADI;
+ packet.session = 0;
+
+ svc->type = TAG_SERVICE_NAME;
+ svc->length = htons(namelen);
+ CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
+
+ if (conn->serviceName) {
+ memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
+ }
+ cursor += namelen + TAG_HDR_SIZE;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->hostUniq.length) {
+ int len = ntohs(conn->hostUniq.length);
+ CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
+ cursor += len + TAG_HDR_SIZE;
+ plen += len + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: waitForPADO
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* timeout -- how long to wait (in seconds)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Waits for a PADO packet and copies useful information
+***********************************************************************/
+void
+waitForPADO(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ PPPoEPacket packet;
+ int len;
+
+ struct PacketCriteria pc;
+ pc.conn = conn;
+ pc.acNameOK = (conn->acName) ? 0 : 1;
+ pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
+ pc.seenACName = 0;
+ pc.seenServiceName = 0;
+ conn->error = 0;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ perror("select (waitForPADO)");
+ return;
+ }
+ if (r == 0) return; /* Timed out */
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ fprintf(stderr, "Bogus PPPoE length field (%u)\n",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+ /* If it's not for us, loop again */
+ if (!packetIsForMe(conn, &packet)) continue;
+
+ if (packet.code == CODE_PADO) {
+ if (BROADCAST(packet.ethHdr.h_source)) {
+ fprintf(stderr, "Ignoring PADO packet from broadcast MAC address\n");
+ continue;
+ }
+ parsePacket(&packet, parsePADOTags, &pc);
+ if (conn->error)
+ return;
+ if (!pc.seenACName) {
+ fprintf(stderr, "Ignoring PADO packet with no AC-Name tag\n");
+ continue;
+ }
+ if (!pc.seenServiceName) {
+ fprintf(stderr, "Ignoring PADO packet with no Service-Name tag\n");
+ 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: discovery
+*%ARGUMENTS:
+* conn -- PPPoE connection info structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Performs the PPPoE discovery phase
+***********************************************************************/
+void
+discovery(PPPoEConnection *conn)
+{
+ int padiAttempts = 0;
+ int timeout = conn->discoveryTimeout;
+
+ conn->discoverySocket =
+ openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+
+ do {
+ padiAttempts++;
+ if (padiAttempts > conn->discoveryAttempts) {
+ fprintf(stderr, "Timeout waiting for PADO packets\n");
+ close(conn->discoverySocket);
+ conn->discoverySocket = -1;
+ return;
+ }
+ sendPADI(conn);
+ conn->discoveryState = STATE_SENT_PADI;
+ waitForPADO(conn, timeout);
+ } while (!conn->numPADOs);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ PPPoEConnection *conn;
+
+ conn = malloc(sizeof(PPPoEConnection));
+ if (!conn)
+ fatalSys("malloc");
+
+ memset(conn, 0, sizeof(PPPoEConnection));
+
+ conn->printACNames = 1;
+ conn->discoveryTimeout = PADI_TIMEOUT;
+ conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
+
+ while ((opt = getopt(argc, argv, "I:D:VUQS:C:W:t:a:h")) > 0) {
+ switch(opt) {
+ case 'S':
+ conn->serviceName = xstrdup(optarg);
+ break;
+ case 'C':
+ conn->acName = xstrdup(optarg);
+ break;
+ 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 'a':
+ if (sscanf(optarg, "%d", &conn->discoveryAttempts) != 1) {
+ fprintf(stderr, "Illegal argument to -a: Should be -a attempts\n");
+ exit(EXIT_FAILURE);
+ }
+ if (conn->discoveryAttempts < 1) {
+ conn->discoveryAttempts = 1;
+ }
+ break;
+ case 'U':
+ if(conn->hostUniq.length) {
+ fprintf(stderr, "-U and -W are mutually exclusive\n");
+ exit(EXIT_FAILURE);
+ } else {
+ pid_t pid = getpid();
+ conn->hostUniq.type = htons(TAG_HOST_UNIQ);
+ conn->hostUniq.length = htons(sizeof(pid));
+ memcpy(conn->hostUniq.payload, &pid, sizeof(pid));
+ }
+ break;
+ case 'W':
+ if(conn->hostUniq.length) {
+ fprintf(stderr, "-U and -W are mutually exclusive\n");
+ exit(EXIT_FAILURE);
+ }
+ if (!parseHostUniq(optarg, &conn->hostUniq)) {
+ fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'D':
+ conn->debugFile = fopen(optarg, "w");
+ if (!conn->debugFile) {
+ fprintf(stderr, "Could not open %s: %s\n",
+ optarg, strerror(errno));
+ exit(1);
+ }
+ fprintf(conn->debugFile, "pppoe-discovery from pppd %s\n", VERSION);
+ break;
+ case 'I':
+ conn->ifName = xstrdup(optarg);
+ break;
+ case 'Q':
+ conn->printACNames = 0;
+ break;
+ case 'V':
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ /* default interface name */
+ if (!conn->ifName)
+ conn->ifName = strdup("eth0");
+
+ conn->discoverySocket = -1;
+ conn->sessionSocket = -1;
+
+ discovery(conn);
+
+ if (!conn->numPADOs)
+ exit(1);
+ else
+ exit(0);
+}
+
+void rp_fatal(char const *str)
+{
+ fprintf(stderr, "%s\n", str);
+ exit(1);
+}
+
+void fatalSys(char const *str)
+{
+ perror(str);
+ exit(1);
+}
+
+void sysErr(char const *str)
+{
+ rp_fatal(str);
+}
+
+char *xstrdup(const char *s)
+{
+ register char *ret = strdup(s);
+ if (!ret)
+ sysErr("strdup");
+ return ret;
+}
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: pppoe-discovery [options]\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -I if_name -- Specify interface (default eth0)\n");
+ fprintf(stderr, " -D filename -- Log debugging information in filename.\n");
+ fprintf(stderr,
+ " -t timeout -- Initial timeout for discovery packets in seconds\n"
+ " -a attempts -- Number of discovery attempts\n"
+ " -V -- Print version and exit.\n"
+ " -Q -- Quit Mode: Do not print access concentrator names\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 hexvalue -- Set the Host-Unique to the supplied hex string.\n"
+ " -h -- Print usage information.\n");
+ fprintf(stderr, "\npppoe-discovery from pppd " VERSION "\n");
+}
--- /dev/null
+/***********************************************************************
+*
+* pppoe.h
+*
+* Declaration of various PPPoE constants
+*
+* Copyright (C) 2000 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id: pppoe.h,v 1.4 2008/06/15 04:35:50 paulus Exp $
+*
+***********************************************************************/
+
+#include "config.h"
+
+#include <stdio.h> /* For FILE */
+#include <sys/types.h> /* For pid_t */
+#include <ctype.h>
+#include <string.h>
+
+#include "pppd/pppd.h" /* For error */
+
+/* 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_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+/* This has to be included before Linux 4.8's linux/in.h
+ * gets dragged in. */
+#include <netinet/in.h>
+
+/* 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
+
+#define BPF_BUFFER_IS_EMPTY 1
+#define BPF_BUFFER_HAS_DATA 0
+
+/* 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>
+#else
+
+#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
+#endif
+
+/* Ethernet frame types according to RFC 2516 */
+#define ETH_PPPOE_DISCOVERY 0x8863
+#define ETH_PPPOE_SESSION 0x8864
+
+/* But some brain-dead peers disobey the RFC, so frame types are variables */
+extern UINT16_t Eth_PPPOE_Discovery;
+extern UINT16_t Eth_PPPOE_Session;
+
+/* PPPoE codes */
+#define CODE_PADI 0x09
+#define CODE_PADO 0x07
+#define CODE_PADR 0x19
+#define CODE_PADS 0x65
+#define CODE_PADT 0xA7
+
+/* 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_PPP_MAX_PAYLOAD 0x0120
+#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
+
+/* There are other fixed-size buffers preventing
+ this from being increased to 16110. The buffer
+ sizes would need to be properly de-coupled from
+ the default MRU. For now, getting up to 1500 is
+ enough. */
+#define ETH_JUMBO_LEN 1508
+
+/* A PPPoE Packet, including Ethernet headers */
+typedef struct PPPoEPacketStruct {
+ struct ethhdr ethHdr; /* Ethernet header */
+ unsigned int vertype:8; /* PPPoE Version and Type (must both be 1) */
+ unsigned int code:8; /* PPPoE code */
+ unsigned int session:16; /* PPPoE session */
+ unsigned int length:16; /* Payload length */
+ unsigned char payload[ETH_JUMBO_LEN]; /* A bit of room to spare */
+} PPPoEPacket;
+
+#define PPPOE_VER(vt) ((vt) >> 4)
+#define PPPOE_TYPE(vt) ((vt) & 0xf)
+#define PPPOE_VER_TYPE(v, t) (((v) << 4) | (t))
+
+/* 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_JUMBO_LEN - PPPOE_OVERHEAD)
+#define PPP_OVERHEAD 2 /* protocol */
+#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - PPP_OVERHEAD)
+#define TOTAL_OVERHEAD (PPPOE_OVERHEAD + PPP_OVERHEAD)
+#define ETH_PPPOE_MTU (ETH_DATA_LEN - TOTAL_OVERHEAD)
+
+/* PPPoE Tag */
+
+typedef struct PPPoETagStruct {
+ unsigned int type:16; /* tag type */
+ unsigned int length:16; /* Length of payload */
+ unsigned char payload[ETH_JUMBO_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 */
+ unsigned char req_peer_mac[ETH_ALEN]; /* required peer MAC address */
+ unsigned char req_peer; /* require mac addr to match req_peer_mac */
+ 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 */
+ PPPoETag hostUniq; /* Use Host-Uniq tag */
+ int printACNames; /* Just print AC names */
+ 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 error; /* Error packet received */
+ int debug; /* Set to log packets sent and received */
+ int discoveryTimeout; /* Timeout for discovery packets */
+ int discoveryAttempts; /* Number of discovery attempts */
+ int seenMaxPayload;
+ int mtu; /* Stored MTU */
+ int mru; /* Stored MRU */
+} 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);
+void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir);
+void dumpHex(FILE *fp, unsigned char const *buf, int len);
+int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra);
+void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra);
+void syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
+void asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
+void asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+char *strDup(char const *str);
+void sendPADT(PPPoEConnection *conn, char const *msg);
+void sendSessionPacket(PPPoEConnection *conn,
+ PPPoEPacket *packet, int len);
+void initPPP(void);
+void clampMSS(PPPoEPacket *packet, char const *dir, int clampMss);
+UINT16_t computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr);
+UINT16_t pppFCS16(UINT16_t fcs, unsigned char *cp, int len);
+void discovery(PPPoEConnection *conn);
+unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
+ PPPoETag *tag);
+
+void pppoe_printpkt(PPPoEPacket *packet,
+ void (*printer)(void *, char *, ...), void *arg);
+void pppoe_log_packet(const char *prefix, PPPoEPacket *packet);
+
+static inline int parseHostUniq(const char *uniq, PPPoETag *tag)
+{
+ unsigned i, len = strlen(uniq);
+
+#define hex(x) \
+ (((x) <= '9') ? ((x) - '0') : \
+ (((x) <= 'F') ? ((x) - 'A' + 10) : \
+ ((x) - 'a' + 10)))
+
+ if (!len || len % 2 || len / 2 > sizeof(tag->payload))
+ return 0;
+
+ for (i = 0; i < len; i += 2) {
+ if (!isxdigit(uniq[i]) || !isxdigit(uniq[i+1]))
+ return 0;
+
+ tag->payload[i / 2] = (char)(hex(uniq[i]) << 4 | hex(uniq[i+1]));
+ }
+
+#undef hex
+
+ tag->type = htons(TAG_HOST_UNIQ);
+ tag->length = htons(len / 2);
+ return 1;
+}
+
+#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) { \
+ error("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)
+++ /dev/null
-pppoe-discovery
+++ /dev/null
-# Generated automatically from Makefile.in by configure.
-#***********************************************************************
-#
-# Makefile
-#
-# Makefile for Roaring Penguin's Linux PPPoE plugin.
-# Modified for integration with pppd sources by Paul Mackerras.
-#
-# 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: Makefile.linux,v 1.8 2008/06/09 08:34:23 paulus Exp $
-#***********************************************************************
-
-DESTDIR = $(INSTROOT)@DESTDIR@
-BINDIR = $(DESTDIR)/sbin
-LIBDIR = $(DESTDIR)/lib/pppd/$(PPPDVERSION)
-
-PPPDVERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
-
-INSTALL = install
-
-# Version is set ONLY IN THE MAKEFILE! Don't delete this!
-RP_VERSION=3.8p
-
-COPTS=-O2 -g
-CFLAGS=$(COPTS) -I../../../include '-DRP_VERSION="$(RP_VERSION)"'
-all: rp-pppoe.so pppoe-discovery
-
-pppoe-discovery: pppoe-discovery.o debug.o
- $(CC) $(LDFLAGS) -o pppoe-discovery pppoe-discovery.o debug.o
-
-pppoe-discovery.o: pppoe-discovery.c
- $(CC) $(CFLAGS) -I../../.. -c -o pppoe-discovery.o pppoe-discovery.c
-
-debug.o: debug.c
- $(CC) $(CFLAGS) -I../../.. -c -o debug.o debug.c
-
-rp-pppoe.so: plugin.o discovery.o if.o common.o
- $(CC) $(LDFLAGS) -o rp-pppoe.so -shared plugin.o discovery.o if.o common.o
-
-install: all
- $(INSTALL) -d -m 755 $(LIBDIR)
- $(INSTALL) -c -m 4550 rp-pppoe.so $(LIBDIR)
- $(INSTALL) -d -m 755 $(BINDIR)
- $(INSTALL) -c -m 555 pppoe-discovery $(BINDIR)
-
-clean:
- rm -f *.o *.so pppoe-discovery
-
-plugin.o: plugin.c
- $(CC) $(CFLAGS) -I../../.. -c -o plugin.o -fPIC plugin.c
-
-discovery.o: discovery.c
- $(CC) $(CFLAGS) -I../../.. -c -o discovery.o -fPIC discovery.c
-
-if.o: if.c
- $(CC) $(CFLAGS) -I../../.. -c -o if.o -fPIC if.c
-
-common.o: common.c
- $(CC) $(CFLAGS) -I../../.. -c -o common.o -fPIC common.c
-
+++ /dev/null
-/***********************************************************************
-*
-* common.c
-*
-* Implementation of user-space PPPoE redirector for Linux.
-*
-* Common functions used by PPPoE client and server
-*
-* Copyright (C) 2000 by Roaring Penguin Software Inc.
-*
-* This program may be distributed according to the terms of the GNU
-* General Public License, version 2 or (at your option) any later version.
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: common.c,v 1.3 2008/06/09 08:34:23 paulus Exp $";
-
-#define _GNU_SOURCE 1
-#include "pppoe.h"
-#include "pppd/pppd.h"
-
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <syslog.h> /* for LOG_DEBUG */
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-/**********************************************************************
-*%FUNCTION: parsePacket
-*%ARGUMENTS:
-* packet -- the PPPoE discovery packet to parse
-* func -- function called for each tag in the packet
-* extra -- an opaque data pointer supplied to parsing function
-*%RETURNS:
-* 0 if everything went well; -1 if there was an error
-*%DESCRIPTION:
-* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
-* "func" is passed the additional argument "extra".
-***********************************************************************/
-int
-parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
-{
- UINT16_t len = ntohs(packet->length);
- unsigned char *curTag;
- UINT16_t tagType, tagLen;
-
- if (PPPOE_VER(packet->vertype) != 1) {
- error("Invalid PPPoE version (%d)", PPPOE_VER(packet->vertype));
- return -1;
- }
- if (PPPOE_TYPE(packet->vertype) != 1) {
- error("Invalid PPPoE type (%d)", PPPOE_TYPE(packet->vertype));
- return -1;
- }
-
- /* Do some sanity checks on packet */
- if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
- error("Invalid PPPoE packet length (%u)", len);
- return -1;
- }
-
- /* Step through the tags */
- curTag = packet->payload;
- while (curTag - packet->payload + TAG_HDR_SIZE <= len) {
- /* Alignment is not guaranteed, so do this by hand... */
- tagType = (curTag[0] << 8) + curTag[1];
- tagLen = (curTag[2] << 8) + curTag[3];
- if (tagType == TAG_END_OF_LIST) {
- return 0;
- }
- if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
- error("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: 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.vertype = PPPOE_VER_TYPE(1, 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->hostUniq.length) {
- int len = ntohs(conn->hostUniq.length);
- memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
- cursor += len + TAG_HDR_SIZE;
- plen += len + TAG_HDR_SIZE;
- }
-
- /* Copy error message */
- if (msg) {
- PPPoETag err;
- size_t elen = strlen(msg);
- err.type = htons(TAG_GENERIC_ERROR);
- err.length = htons(elen);
- strcpy(err.payload, msg);
- memcpy(cursor, &err, elen + TAG_HDR_SIZE);
- cursor += elen + TAG_HDR_SIZE;
- plen += elen + TAG_HDR_SIZE;
- }
-
- /* Copy cookie and relay-ID if needed */
- if (conn->cookie.type) {
- CHECK_ROOM(cursor, packet.payload,
- ntohs(conn->cookie.length) + TAG_HDR_SIZE);
- memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
- cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
- plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
- }
-
- if (conn->relayId.type) {
- CHECK_ROOM(cursor, packet.payload,
- ntohs(conn->relayId.length) + TAG_HDR_SIZE);
- memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
- cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
- plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
- }
-
- packet.length = htons(plen);
- sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
- info("Sent PADT");
-}
-
-#define EH(x) (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5]
-
-/* Print out a PPPOE packet for debugging */
-void pppoe_printpkt(PPPoEPacket *packet,
- void (*printer)(void *, char *, ...), void *arg)
-{
- int len = ntohs(packet->length);
- int i, tag, tlen, text;
-
- switch (ntohs(packet->ethHdr.h_proto)) {
- case ETH_PPPOE_DISCOVERY:
- printer(arg, "PPPOE Discovery V%dT%d ", PPPOE_VER(packet->vertype),
- PPPOE_TYPE(packet->vertype));
- switch (packet->code) {
- case CODE_PADI:
- printer(arg, "PADI");
- break;
- case CODE_PADO:
- printer(arg, "PADO");
- break;
- case CODE_PADR:
- printer(arg, "PADR");
- break;
- case CODE_PADS:
- printer(arg, "PADS");
- break;
- case CODE_PADT:
- printer(arg, "PADT");
- break;
- default:
- printer(arg, "unknown code %x", packet->code);
- }
- printer(arg, " session 0x%x length %d\n", ntohs(packet->session), len);
- break;
- case ETH_PPPOE_SESSION:
- printer(arg, "PPPOE Session V%dT%d", PPPOE_VER(packet->vertype),
- PPPOE_TYPE(packet->vertype));
- printer(arg, " code 0x%x session 0x%x length %d\n", packet->code,
- ntohs(packet->session), len);
- break;
- default:
- printer(arg, "Unknown ethernet frame with proto = 0x%x\n",
- ntohs(packet->ethHdr.h_proto));
- }
-
- printer(arg, " dst %02x:%02x:%02x:%02x:%02x:%02x ", EH(packet->ethHdr.h_dest));
- printer(arg, " src %02x:%02x:%02x:%02x:%02x:%02x\n", EH(packet->ethHdr.h_source));
- if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY)
- return;
-
- for (i = 0; i + TAG_HDR_SIZE <= len; i += tlen) {
- tag = (packet->payload[i] << 8) + packet->payload[i+1];
- tlen = (packet->payload[i+2] << 8) + packet->payload[i+3];
- if (i + tlen + TAG_HDR_SIZE > len)
- break;
- text = 0;
- i += TAG_HDR_SIZE;
- printer(arg, " [");
- switch (tag) {
- case TAG_END_OF_LIST:
- printer(arg, "end-of-list");
- break;
- case TAG_SERVICE_NAME:
- printer(arg, "service-name");
- text = 1;
- break;
- case TAG_AC_NAME:
- printer(arg, "AC-name");
- text = 1;
- break;
- case TAG_HOST_UNIQ:
- printer(arg, "host-uniq");
- break;
- case TAG_AC_COOKIE:
- printer(arg, "AC-cookie");
- break;
- case TAG_VENDOR_SPECIFIC:
- printer(arg, "vendor-specific");
- break;
- case TAG_RELAY_SESSION_ID:
- printer(arg, "relay-session-id");
- break;
- case TAG_PPP_MAX_PAYLOAD:
- printer(arg, "PPP-max-payload");
- break;
- case TAG_SERVICE_NAME_ERROR:
- printer(arg, "service-name-error");
- text = 1;
- break;
- case TAG_AC_SYSTEM_ERROR:
- printer(arg, "AC-system-error");
- text = 1;
- break;
- case TAG_GENERIC_ERROR:
- printer(arg, "generic-error");
- text = 1;
- break;
- default:
- printer(arg, "unknown tag 0x%x", tag);
- }
- if (tlen) {
- if (text)
- printer(arg, " %.*v", tlen, &packet->payload[i]);
- else if (tlen <= 32)
- printer(arg, " %.*B", tlen, &packet->payload[i]);
- else
- printer(arg, " %.32B... (length %d)",
- &packet->payload[i], tlen);
- }
- printer(arg, "]");
- }
- printer(arg, "\n");
-}
-
-void pppoe_log_packet(const char *prefix, PPPoEPacket *packet)
-{
- init_pr_log(prefix, LOG_DEBUG);
- pppoe_printpkt(packet, pr_log, NULL);
- end_pr_log();
-}
+++ /dev/null
-/* config.h. Generated automatically by configure. */
-/* config.h.in. Generated automatically from configure.in by autoheader. */
-
-/* Define to empty if the keyword does not work. */
-/* #undef const */
-
-/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
-#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. */
-#define HAVE_LINUX_KERNEL_PPPOE 1
-
-/* 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. */
-#define HAVE_NET_BPF_H 1
-
-/* 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/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. */
-#define HAVE_SYS_UIO_H 1
-
-/* 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 */
-#define HAVE_N_HDLC 1
+++ /dev/null
-/***********************************************************************
-*
-* debug.c
-*
-* Implementation of user-space PPPoE redirector for Linux.
-*
-* Functions for printing debugging information
-*
-* Copyright (C) 2000 by Roaring Penguin Software Inc.
-*
-* This program may be distributed according to the terms of the GNU
-* General Public License, version 2 or (at your option) any later version.
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: debug.c,v 1.2 2008/06/09 08:34:23 paulus Exp $";
-
-#include "pppoe.h"
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <ctype.h>
-
-/**********************************************************************
-*%FUNCTION: dumpHex
-*%ARGUMENTS:
-* fp -- file to dump to
-* buf -- buffer to dump
-* len -- length of data
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Dumps buffer to fp in an easy-to-read format
-***********************************************************************/
-void
-dumpHex(FILE *fp, unsigned char const *buf, int len)
-{
- int i;
- int base;
-
- if (!fp) return;
-
- /* do NOT dump PAP packets */
- if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
- fprintf(fp, "(PAP Authentication Frame -- Contents not dumped)\n");
- return;
- }
-
- for (base=0; base<len; base += 16) {
- for (i=base; i<base+16; i++) {
- if (i < len) {
- fprintf(fp, "%02x ", (unsigned) buf[i]);
- } else {
- fprintf(fp, " ");
- }
- }
- fprintf(fp, " ");
- for (i=base; i<base+16; i++) {
- if (i < len) {
- if (isprint(buf[i])) {
- fprintf(fp, "%c", buf[i]);
- } else {
- fprintf(fp, ".");
- }
- } else {
- break;
- }
- }
- fprintf(fp, "\n");
- }
-}
-
-/**********************************************************************
-*%FUNCTION: dumpPacket
-*%ARGUMENTS:
-* fp -- file to dump to
-* packet -- a PPPoE packet
-* dir -- either SENT or RCVD
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Dumps the PPPoE packet to fp in an easy-to-read format
-***********************************************************************/
-void
-dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir)
-{
- int len = ntohs(packet->length);
-
- /* Sheesh... printing times is a pain... */
- struct timeval tv;
- time_t now;
- int millisec;
- struct tm *lt;
- char timebuf[256];
-
- UINT16_t type = etherType(packet);
- if (!fp) return;
- gettimeofday(&tv, NULL);
- now = (time_t) tv.tv_sec;
- millisec = tv.tv_usec / 1000;
- lt = localtime(&now);
- strftime(timebuf, 256, "%H:%M:%S", lt);
- fprintf(fp, "%s.%03d %s PPPoE ", timebuf, millisec, dir);
- if (type == Eth_PPPOE_Discovery) {
- fprintf(fp, "Discovery (%x) ", (unsigned) type);
- } else if (type == Eth_PPPOE_Session) {
- fprintf(fp, "Session (%x) ", (unsigned) type);
- } else {
- fprintf(fp, "Unknown (%x) ", (unsigned) type);
- }
-
- switch(packet->code) {
- case CODE_PADI: fprintf(fp, "PADI "); break;
- case CODE_PADO: fprintf(fp, "PADO "); break;
- case CODE_PADR: fprintf(fp, "PADR "); break;
- case CODE_PADS: fprintf(fp, "PADS "); break;
- case CODE_PADT: fprintf(fp, "PADT "); break;
- case CODE_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));
-}
+++ /dev/null
-/***********************************************************************
-*
-* discovery.c
-*
-* Perform PPPoE discovery
-*
-* Copyright (C) 1999 by Roaring Penguin Software Inc.
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: discovery.c,v 1.6 2008/06/15 04:35:50 paulus Exp $";
-
-#define _GNU_SOURCE 1
-#include "pppoe.h"
-#include "pppd/pppd.h"
-#include "pppd/fsm.h"
-#include "pppd/lcp.h"
-
-#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>
-
-/* Calculate time remaining until *exp, return 0 if now >= *exp */
-static int time_left(struct timeval *diff, struct timeval *exp)
-{
- struct timeval now;
-
- if (get_time(&now) < 0) {
- error("get_time: %m");
- return 0;
- }
-
- if (now.tv_sec > exp->tv_sec
- || (now.tv_sec == exp->tv_sec && now.tv_usec >= exp->tv_usec))
- return 0;
-
- diff->tv_sec = exp->tv_sec - now.tv_sec;
- diff->tv_usec = exp->tv_usec - now.tv_usec;
- if (diff->tv_usec < 0) {
- diff->tv_usec += 1000000;
- --diff->tv_sec;
- }
-
- return 1;
-}
-
-/**********************************************************************
-*%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)
-{
- PPPoETag *tag = extra;
-
- if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
- tag->length = memcmp(data, tag->payload, len);
-}
-
-/**********************************************************************
-*%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)
-{
- PPPoETag hostUniq = conn->hostUniq;
-
- /* 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->hostUniq.length) return 1;
-
- parsePacket(packet, parseForHostUniq, &hostUniq);
- return !hostUniq.length;
-}
-
-/**********************************************************************
-*%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;
- UINT16_t mru;
- int i;
-
- switch(type) {
- case TAG_AC_NAME:
- pc->seenACName = 1;
- if (conn->printACNames) {
- info("Access-Concentrator: %.*s", (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->serviceName && len == strlen(conn->serviceName) &&
- !strncmp((char *) data, conn->serviceName, len)) {
- pc->serviceNameOK = 1;
- }
- break;
- case TAG_AC_COOKIE:
- conn->cookie.type = htons(type);
- conn->cookie.length = htons(len);
- memcpy(conn->cookie.payload, data, len);
- break;
- case TAG_RELAY_SESSION_ID:
- conn->relayId.type = htons(type);
- conn->relayId.length = htons(len);
- memcpy(conn->relayId.payload, data, len);
- break;
- case TAG_PPP_MAX_PAYLOAD:
- if (len == sizeof(mru)) {
- memcpy(&mru, data, sizeof(mru));
- mru = ntohs(mru);
- if (mru >= ETH_PPPOE_MTU) {
- if (lcp_allowoptions[0].mru > mru)
- lcp_allowoptions[0].mru = mru;
- if (lcp_wantoptions[0].mru > mru)
- lcp_wantoptions[0].mru = mru;
- conn->seenMaxPayload = 1;
- }
- }
- break;
- case TAG_SERVICE_NAME_ERROR:
- error("PADO: Service-Name-Error: %.*s", (int) len, data);
- conn->error = 1;
- break;
- case TAG_AC_SYSTEM_ERROR:
- error("PADO: System-Error: %.*s", (int) len, data);
- conn->error = 1;
- break;
- case TAG_GENERIC_ERROR:
- error("PADO: Generic-Error: %.*s", (int) len, data);
- conn->error = 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;
- UINT16_t mru;
- switch(type) {
- case TAG_SERVICE_NAME:
- dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
- break;
- case TAG_PPP_MAX_PAYLOAD:
- if (len == sizeof(mru)) {
- memcpy(&mru, data, sizeof(mru));
- mru = ntohs(mru);
- if (mru >= ETH_PPPOE_MTU) {
- if (lcp_allowoptions[0].mru > mru)
- lcp_allowoptions[0].mru = mru;
- if (lcp_wantoptions[0].mru > mru)
- lcp_wantoptions[0].mru = mru;
- conn->seenMaxPayload = 1;
- }
- }
- break;
- case TAG_SERVICE_NAME_ERROR:
- error("PADS: Service-Name-Error: %.*s", (int) len, data);
- conn->error = 1;
- break;
- case TAG_AC_SYSTEM_ERROR:
- error("PADS: System-Error: %.*s", (int) len, data);
- conn->error = 1;
- break;
- case TAG_GENERIC_ERROR:
- error("PADS: Generic-Error: %.*s", (int) len, data);
- conn->error = 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.vertype = PPPOE_VER_TYPE(1, 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->hostUniq.length) {
- int len = ntohs(conn->hostUniq.length);
- CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
- memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
- cursor += len + TAG_HDR_SIZE;
- plen += len + TAG_HDR_SIZE;
- }
-
- /* Add our maximum MTU/MRU */
- if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
- PPPoETag maxPayload;
- UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
- maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
- maxPayload.length = htons(sizeof(mru));
- memcpy(maxPayload.payload, &mru, sizeof(mru));
- CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
- memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
- cursor += sizeof(mru) + TAG_HDR_SIZE;
- plen += sizeof(mru) + TAG_HDR_SIZE;
- }
-
- packet.length = htons(plen);
-
- sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
-}
-
-/**********************************************************************
-*%FUNCTION: waitForPADO
-*%ARGUMENTS:
-* conn -- PPPoEConnection structure
-* timeout -- how long to wait (in seconds)
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Waits for a PADO packet and copies useful information
-***********************************************************************/
-void
-waitForPADO(PPPoEConnection *conn, int timeout)
-{
- fd_set readable;
- int r;
- struct timeval tv;
- struct timeval expire_at;
-
- 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;
- conn->seenMaxPayload = 0;
- conn->error = 0;
-
- if (get_time(&expire_at) < 0) {
- error("get_time (waitForPADO): %m");
- return;
- }
- expire_at.tv_sec += timeout;
-
- do {
- if (BPF_BUFFER_IS_EMPTY) {
- if (!time_left(&tv, &expire_at))
- return; /* Timed out */
-
- FD_ZERO(&readable);
- FD_SET(conn->discoverySocket, &readable);
-
- while(1) {
- r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
- if (r >= 0 || errno != EINTR || got_sigterm) break;
- }
- if (r < 0) {
- error("select (waitForPADO): %m");
- return;
- }
- if (r == 0)
- return; /* Timed out */
- }
-
- /* Get the packet */
- receivePacket(conn->discoverySocket, &packet, &len);
-
- /* Check length */
- if (ntohs(packet.length) + HDR_SIZE > len) {
- error("Bogus PPPoE length field (%u)",
- (unsigned int) ntohs(packet.length));
- continue;
- }
-
-#ifdef USE_BPF
- /* If it's not a Discovery packet, loop again */
- if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
-#endif
-
- /* If it's not for us, loop again */
- if (!packetIsForMe(conn, &packet)) continue;
-
- if (packet.code == CODE_PADO) {
- if (NOT_UNICAST(packet.ethHdr.h_source)) {
- error("Ignoring PADO packet from non-unicast MAC address");
- continue;
- }
- if (conn->req_peer
- && memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
- warn("Ignoring PADO packet from wrong MAC address");
- continue;
- }
- if (parsePacket(&packet, parsePADOTags, &pc) < 0)
- return;
- if (conn->error)
- return;
- if (!pc.seenACName) {
- error("Ignoring PADO packet with no AC-Name tag");
- continue;
- }
- if (!pc.seenServiceName) {
- error("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);
- 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.vertype = PPPOE_VER_TYPE(1, 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->hostUniq.length) {
- int len = ntohs(conn->hostUniq.length);
- CHECK_ROOM(cursor, packet.payload, len+TAG_HDR_SIZE);
- memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
- cursor += len + TAG_HDR_SIZE;
- plen += len + TAG_HDR_SIZE;
- }
-
- /* Add our maximum MTU/MRU */
- if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
- PPPoETag maxPayload;
- UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
- maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
- maxPayload.length = htons(sizeof(mru));
- memcpy(maxPayload.payload, &mru, sizeof(mru));
- CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
- memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
- cursor += sizeof(mru) + TAG_HDR_SIZE;
- plen += sizeof(mru) + 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));
-}
-
-/**********************************************************************
-*%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;
-
- PPPoEPacket packet;
- int len;
-
- if (get_time(&expire_at) < 0) {
- error("get_time (waitForPADS): %m");
- return;
- }
- expire_at.tv_sec += timeout;
-
- conn->error = 0;
- do {
- if (BPF_BUFFER_IS_EMPTY) {
- if (!time_left(&tv, &expire_at))
- return; /* Timed out */
-
- FD_ZERO(&readable);
- FD_SET(conn->discoverySocket, &readable);
-
- while(1) {
- r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
- if (r >= 0 || errno != EINTR || got_sigterm) break;
- }
- if (r < 0) {
- error("select (waitForPADS): %m");
- return;
- }
- if (r == 0)
- return; /* Timed out */
- }
-
- /* Get the packet */
- receivePacket(conn->discoverySocket, &packet, &len);
-
- /* Check length */
- if (ntohs(packet.length) + HDR_SIZE > len) {
- error("Bogus PPPoE length field (%u)",
- (unsigned int) ntohs(packet.length));
- continue;
- }
-
-#ifdef USE_BPF
- /* If it's not a Discovery packet, loop again */
- if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
-#endif
-
- /* If 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 */
- if (parsePacket(&packet, parsePADSTags, conn) < 0)
- return;
- if (conn->error)
- return;
- 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;
-
- info("PPP session is %d", (int) ntohs(conn->session));
-
- /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
- if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
- error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
- }
-}
-
-/**********************************************************************
-*%FUNCTION: discovery
-*%ARGUMENTS:
-* conn -- PPPoE connection info structure
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Performs the PPPoE discovery phase
-***********************************************************************/
-void
-discovery(PPPoEConnection *conn)
-{
- int padiAttempts = 0;
- int padrAttempts = 0;
- int timeout = conn->discoveryTimeout;
-
- do {
- padiAttempts++;
- if (got_sigterm || padiAttempts > conn->discoveryAttempts) {
- warn("Timeout waiting for PADO packets");
- close(conn->discoverySocket);
- conn->discoverySocket = -1;
- return;
- }
- sendPADI(conn);
- conn->discoveryState = STATE_SENT_PADI;
- waitForPADO(conn, timeout);
-
- timeout *= 2;
- } while (conn->discoveryState == STATE_SENT_PADI);
-
- timeout = conn->discoveryTimeout;
- do {
- padrAttempts++;
- if (got_sigterm || padrAttempts > conn->discoveryAttempts) {
- warn("Timeout waiting for PADS packets");
- close(conn->discoverySocket);
- conn->discoverySocket = -1;
- return;
- }
- sendPADR(conn);
- conn->discoveryState = STATE_SENT_PADR;
- waitForPADS(conn, timeout);
- timeout *= 2;
- } while (conn->discoveryState == STATE_SENT_PADR);
-
- if (!conn->seenMaxPayload) {
- /* RFC 4638: MUST limit MTU/MRU to 1492 */
- if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU)
- lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
- if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)
- lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
- }
-
- /* We're done. */
- close(conn->discoverySocket);
- conn->discoverySocket = -1;
- conn->discoveryState = STATE_SESSION;
- return;
-}
+++ /dev/null
-/***********************************************************************
-*
-* if.c
-*
-* Implementation of user-space PPPoE redirector for Linux.
-*
-* Functions for opening a raw socket and reading/writing raw Ethernet frames.
-*
-* Copyright (C) 2000 by Roaring Penguin Software Inc.
-*
-* This program may be distributed according to the terms of the GNU
-* General Public License, version 2 or (at your option) any later version.
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: if.c,v 1.2 2008/06/09 08:34:23 paulus Exp $";
-
-#define _GNU_SOURCE 1
-#include "pppoe.h"
-#include "pppd/pppd.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_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_NET_IF_ARP_H
-#include <net/if_arp.h>
-#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) {
- error("Invalid ether type 0x%x", type);
- }
- return type;
-}
-
-/**********************************************************************
-*%FUNCTION: openInterface
-*%ARGUMENTS:
-* ifname -- name of interface
-* type -- Ethernet frame type
-* hwaddr -- if non-NULL, set to the hardware address
-*%RETURNS:
-* A raw socket for talking to the Ethernet card. Exits on error.
-*%DESCRIPTION:
-* Opens a raw Ethernet socket
-***********************************************************************/
-int
-openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
-{
- int optval=1;
- int fd;
- struct ifreq ifr;
- int domain, stype;
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- struct sockaddr_ll sa;
-#else
- struct sockaddr sa;
-#endif
-
- memset(&sa, 0, sizeof(sa));
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- domain = PF_PACKET;
- stype = SOCK_RAW;
-#else
- domain = PF_INET;
- stype = SOCK_PACKET;
-#endif
-
- if ((fd = socket(domain, stype, htons(type))) < 0) {
- /* Give a more helpful message for the common error case */
- if (errno == EPERM) {
- fatal("Cannot create raw socket -- pppoe must be run as root.");
- }
- error("Can't open socket for pppoe: %m");
- return -1;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
- error("Can't set socket options for pppoe: %m");
- close(fd);
- return -1;
- }
-
- /* Fill in hardware address */
- if (hwaddr) {
- strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
- error("Can't get hardware address for %s: %m", ifname);
- close(fd);
- return -1;
- }
- memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-#ifdef ARPHRD_ETHER
- if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- warn("Interface %.16s is not Ethernet", ifname);
- }
-#endif
- if (NOT_UNICAST(hwaddr)) {
- fatal("Can't use interface %.16s: it has broadcast/multicast MAC address",
- ifname);
- }
- }
-
- /* Sanity check on MTU */
- strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
- error("Can't get MTU for %s: %m", ifname);
- } else if (ifr.ifr_mtu < ETH_DATA_LEN) {
- error("Interface %.16s has MTU of %d -- should be at least %d.",
- ifname, ifr.ifr_mtu, ETH_DATA_LEN);
- error("This may cause serious connection problems.");
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- /* Get interface index */
- sa.sll_family = AF_PACKET;
- sa.sll_protocol = htons(type);
-
- strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
- error("Could not get interface index for %s: %m", ifname);
- close(fd);
- return -1;
- }
- sa.sll_ifindex = ifr.ifr_ifindex;
-
-#else
- strcpy(sa.sa_data, ifname);
-#endif
-
- /* We're only interested in packets on specified interface */
- if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- error("Failed to bind to interface %s: %m", ifname);
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-
-/***********************************************************************
-*%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)
-{
- int err;
-
- if (debug)
- pppoe_log_packet("Send ", pkt);
-#if defined(HAVE_STRUCT_SOCKADDR_LL)
- err = send(sock, pkt, size, 0);
-#else
- struct sockaddr sa;
-
- strcpy(sa.sa_data, conn->ifName);
- err = sendto(sock, pkt, size, 0, &sa, sizeof(sa));
-#endif
- if (err < 0) {
- error("error sending pppoe packet: %m");
- return -1;
- }
- return 0;
-}
-
-/***********************************************************************
-*%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)
-{
- if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
- error("error receiving pppoe packet: %m");
- return -1;
- }
- if (debug)
- pppoe_log_packet("Recv ", pkt);
- return 0;
-}
+++ /dev/null
-/***********************************************************************
-*
-* plugin.c
-*
-* pppd plugin for kernel-mode PPPoE on Linux
-*
-* Copyright (C) 2001 by Roaring Penguin Software Inc., Michal Ostrowski
-* and Jamal Hadi Salim.
-*
-* Much code and many ideas derived from pppoe plugin by Michal
-* Ostrowski and Jamal Hadi Salim, which carries this copyright:
-*
-* Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
-* Jamal Hadi Salim <hadi@cyberus.ca>
-* Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
-* which is based in part on work from Jens Axboe and Paul Mackerras.
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version
-* 2 of the License, or (at your option) any later version.
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: plugin.c,v 1.17 2008/06/15 04:35:50 paulus Exp $";
-
-#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 <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/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 char *pppoe_reqd_mac = NULL;
-unsigned char pppoe_reqd_mac_addr[6];
-static char *host_uniq;
-static int pppoe_padi_timeout = PADI_TIMEOUT;
-static int pppoe_padi_attempts = MAX_PADI_ATTEMPTS;
-
-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"},
- { "pppoe-mac", o_string, &pppoe_reqd_mac,
- "Only connect to specified MAC address" },
- { "host-uniq", o_string, &host_uniq,
- "Set the Host-Uniq to the supplied hex string" },
- { "pppoe-padi-timeout", o_int, &pppoe_padi_timeout,
- "Initial timeout for discovery packets in seconds" },
- { "pppoe-padi-attempts", o_int, &pppoe_padi_attempts,
- "Number of discovery attempts" },
- { 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) {
- novm("PPPoE session data");
- }
- memset(conn, 0, sizeof(PPPoEConnection));
- conn->ifName = devnam;
- conn->discoverySocket = -1;
- conn->sessionSocket = -1;
- conn->printACNames = printACNames;
- conn->discoveryTimeout = pppoe_padi_timeout;
- conn->discoveryAttempts = pppoe_padi_attempts;
- 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;
- struct ifreq ifr;
- int s;
-
- /* 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;
- }
-
- /* Restore configuration */
- lcp_allowoptions[0].mru = conn->mtu;
- lcp_wantoptions[0].mru = conn->mru;
-
- /* Update maximum MRU */
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- error("Can't get MTU for %s: %m", conn->ifName);
- goto errout;
- }
- strlcpy(ifr.ifr_name, conn->ifName, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
- error("Can't get MTU for %s: %m", conn->ifName);
- close(s);
- goto errout;
- }
- close(s);
-
- if (lcp_allowoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
- lcp_allowoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
- if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
- lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
-
- if (host_uniq) {
- if (!parseHostUniq(host_uniq, &conn->hostUniq))
- fatal("Illegal value for host-uniq option");
- } else {
- /* if a custom host-uniq is not supplied, use our PID */
- pid_t pid = getpid();
- conn->hostUniq.type = htons(TAG_HOST_UNIQ);
- conn->hostUniq.length = htons(sizeof(pid));
- memcpy(conn->hostUniq.payload, &pid, sizeof(pid));
- }
-
- conn->acName = acName;
- conn->serviceName = pppd_pppoe_service;
- 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");
- goto errout;
- }
- }
-
- /* 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);
- goto errout;
- }
-
- return conn->sessionSocket;
-
- errout:
- if (conn->discoverySocket >= 0) {
- sendPADT(conn, NULL);
- close(conn->discoverySocket);
- conn->discoverySocket = -1;
- }
- close(conn->sessionSocket);
- return -1;
-}
-
-static void
-PPPOERecvConfig(int mru,
- u_int32_t asyncmap,
- int pcomp,
- int accomp)
-{
-#if 0 /* broken protocol, but no point harrassing the users I guess... */
- if (mru > MAX_PPPOE_MTU)
- warn("Couldn't increase MRU to %d", mru);
-#endif
-}
-
-/**********************************************************************
- * %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 && errno != EALREADY)
- error("Failed to disconnect PPPoE socket: %d %m", errno);
- close(conn->sessionSocket);
- if (conn->discoverySocket >= 0) {
- sendPADT(conn, NULL);
- close(conn->discoverySocket);
- }
-}
-
-static void
-PPPOEDeviceOptions(void)
-{
- char buf[MAXPATHLEN];
-
- strlcpy(buf, _PATH_ETHOPT, MAXPATHLEN);
- strlcat(buf, devnam, MAXPATHLEN);
- 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;
-
- /*
- * Take any otherwise-unrecognized option as a possible device name,
- * and test if it is the name of a network interface with a
- * hardware address whose sa_family is ARPHRD_ETHER.
- */
- if (strlen(cmd) > 4 && !strncmp(cmd, "nic-", 4)) {
- /* Strip off "nic-" */
- cmd += 4;
- }
-
- /* Open a socket */
- if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
- r = 0;
- }
-
- /* Try getting interface index */
- if (r) {
- strlcpy(ifr.ifr_name, cmd, sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
- r = 0;
- } else {
- if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
- r = 0;
- } else {
- if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- if (doit)
- error("Interface %s not Ethernet", cmd);
- r = 0;
- }
- }
- }
- }
-
- /* Close socket */
- close(fd);
- if (r && doit) {
- strlcpy(devnam, cmd, sizeof(devnam));
- if (the_channel != &pppoe_channel) {
-
- the_channel = &pppoe_channel;
- modem = 0;
-
- PPPOEInitDevice();
- }
- return 1;
- }
-
- 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);
-}
-
-void pppoe_check_options(void)
-{
- unsigned int mac[6];
- int i;
-
- if (pppoe_reqd_mac != NULL) {
- if (sscanf(pppoe_reqd_mac, "%x:%x:%x:%x:%x:%x",
- &mac[0], &mac[1], &mac[2], &mac[3],
- &mac[4], &mac[5]) != 6) {
- option_error("cannot parse pppoe-mac option value");
- exit(EXIT_OPTION_ERROR);
- }
- for (i = 0; i < 6; ++i)
- conn->req_peer_mac[i] = mac[i];
- conn->req_peer = 1;
- }
-
- 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;
-
- if (lcp_allowoptions[0].mru > MAX_PPPOE_MTU)
- lcp_allowoptions[0].mru = MAX_PPPOE_MTU;
- if (lcp_wantoptions[0].mru > MAX_PPPOE_MTU)
- lcp_wantoptions[0].mru = MAX_PPPOE_MTU;
-
- /* Save configuration */
- conn->mtu = lcp_allowoptions[0].mru;
- conn->mru = lcp_wantoptions[0].mru;
-
- ccp_allowoptions[0].deflate = 0;
- ccp_wantoptions[0].deflate = 0;
-
- ipcp_allowoptions[0].neg_vj = 0;
- ipcp_wantoptions[0].neg_vj = 0;
-
- ccp_allowoptions[0].bsd_compress = 0;
- ccp_wantoptions[0].bsd_compress = 0;
-}
-
-struct channel pppoe_channel = {
- .options = Options,
- .process_extra_options = &PPPOEDeviceOptions,
- .check_options = pppoe_check_options,
- .connect = &PPPOEConnectDevice,
- .disconnect = &PPPOEDisconnectDevice,
- .establish_ppp = &generic_establish_ppp,
- .disestablish_ppp = &generic_disestablish_ppp,
- .send_config = NULL,
- .recv_config = &PPPOERecvConfig,
- .close = NULL,
- .cleanup = NULL
-};
+++ /dev/null
-/*
- * Perform PPPoE discovery
- *
- * Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
- * Copyright (C) 2004 Marco d'Itri <md@linux.it>
- *
- * This program may be distributed according to the terms of the GNU
- * General Public License, version 2 or (at your option) any later version.
- *
- */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-
-#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_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_NET_IF_ARP_H
-#include <net/if_arp.h>
-#endif
-
-char *xstrdup(const char *s);
-void usage(void);
-
-void die(int status)
-{
- exit(status);
-}
-
-void error(char *fmt, ...)
-{
- va_list pvar;
- va_start(pvar, fmt);
- vfprintf(stderr, fmt, pvar);
- va_end(pvar);
-}
-
-/* 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) {
- fprintf(stderr, "Invalid ether type 0x%x\n", type);
- }
- return type;
-}
-
-/**********************************************************************
-*%FUNCTION: openInterface
-*%ARGUMENTS:
-* ifname -- name of interface
-* type -- Ethernet frame type
-* hwaddr -- if non-NULL, set to the hardware address
-*%RETURNS:
-* A raw socket for talking to the Ethernet card. Exits on error.
-*%DESCRIPTION:
-* Opens a raw Ethernet socket
-***********************************************************************/
-int
-openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
-{
- int optval=1;
- int fd;
- struct ifreq ifr;
- int domain, stype;
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- struct sockaddr_ll sa;
-#else
- struct sockaddr sa;
-#endif
-
- memset(&sa, 0, sizeof(sa));
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- domain = PF_PACKET;
- stype = SOCK_RAW;
-#else
- domain = PF_INET;
- stype = SOCK_PACKET;
-#endif
-
- if ((fd = socket(domain, stype, htons(type))) < 0) {
- /* Give a more helpful message for the common error case */
- if (errno == EPERM) {
- rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
- }
- fatalSys("socket");
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
- fatalSys("setsockopt");
- }
-
- /* Fill in hardware address */
- if (hwaddr) {
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
- fatalSys("ioctl(SIOCGIFHWADDR)");
- }
- memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-#ifdef ARPHRD_ETHER
- if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- char buffer[256];
- sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
- rp_fatal(buffer);
- }
-#endif
- if (NOT_UNICAST(hwaddr)) {
- char buffer[256];
- sprintf(buffer,
- "Interface %.16s has broadcast/multicast MAC address??",
- ifname);
- rp_fatal(buffer);
- }
- }
-
- /* Sanity check on MTU */
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
- fatalSys("ioctl(SIOCGIFMTU)");
- }
- if (ifr.ifr_mtu < ETH_DATA_LEN) {
- fprintf(stderr, "Interface %.16s has MTU of %d -- should be %d.\n",
- ifname, ifr.ifr_mtu, ETH_DATA_LEN);
- fprintf(stderr, "You may have serious connection problems.\n");
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- /* Get interface index */
- sa.sll_family = AF_PACKET;
- sa.sll_protocol = htons(type);
-
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_name[IFNAMSIZ - 1] = 0;
- if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
- fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
- }
- sa.sll_ifindex = ifr.ifr_ifindex;
-
-#else
- strcpy(sa.sa_data, ifname);
-#endif
-
- /* We're only interested in packets on specified interface */
- if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- fatalSys("bind");
- }
-
- return fd;
-}
-
-
-/***********************************************************************
-*%FUNCTION: sendPacket
-*%ARGUMENTS:
-* sock -- socket to send to
-* pkt -- the packet to transmit
-* size -- size of packet (in bytes)
-*%RETURNS:
-* 0 on success; -1 on failure
-*%DESCRIPTION:
-* Transmits a packet
-***********************************************************************/
-int
-sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
-{
-#if defined(HAVE_STRUCT_SOCKADDR_LL)
- if (send(sock, pkt, size, 0) < 0) {
- sysErr("send (sendPacket)");
- return -1;
- }
-#else
- struct sockaddr sa;
-
- if (!conn) {
- rp_fatal("relay and server not supported on Linux 2.0 kernels");
- }
- strcpy(sa.sa_data, conn->ifName);
- if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
- sysErr("sendto (sendPacket)");
- return -1;
- }
-#endif
- return 0;
-}
-
-/***********************************************************************
-*%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)
-{
- if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
- sysErr("recv (receivePacket)");
- return -1;
- }
- return 0;
-}
-
-/**********************************************************************
-*%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 (PPPOE_VER(packet->vertype) != 1) {
- fprintf(stderr, "Invalid PPPoE version (%d)\n",
- PPPOE_VER(packet->vertype));
- return -1;
- }
- if (PPPOE_TYPE(packet->vertype) != 1) {
- fprintf(stderr, "Invalid PPPoE type (%d)\n",
- PPPOE_TYPE(packet->vertype));
- return -1;
- }
-
- /* Do some sanity checks on packet */
- if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
- fprintf(stderr, "Invalid PPPoE packet length (%u)\n", 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 = (curTag[0] << 8) + curTag[1];
- tagLen = (curTag[2] << 8) + curTag[3];
- if (tagType == TAG_END_OF_LIST) {
- return 0;
- }
- if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
- fprintf(stderr, "Invalid PPPoE tag length (%u)\n", tagLen);
- return -1;
- }
- func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
- curTag = curTag + TAG_HDR_SIZE + tagLen;
- }
- return 0;
-}
-
-/**********************************************************************
-*%FUNCTION: parseForHostUniq
-*%ARGUMENTS:
-* type -- tag type
-* len -- tag length
-* data -- tag data.
-* extra -- user-supplied pointer. This is assumed to be a pointer to int.
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* If a HostUnique tag is found which matches our PID, sets *extra to 1.
-***********************************************************************/
-void
-parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
- void *extra)
-{
- PPPoETag *tag = extra;
-
- if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
- tag->length = memcmp(data, tag->payload, len);
-}
-
-/**********************************************************************
-*%FUNCTION: packetIsForMe
-*%ARGUMENTS:
-* conn -- PPPoE connection info
-* packet -- a received PPPoE packet
-*%RETURNS:
-* 1 if packet is for this PPPoE daemon; 0 otherwise.
-*%DESCRIPTION:
-* If we are using the Host-Unique tag, verifies that packet contains
-* our unique identifier.
-***********************************************************************/
-int
-packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
-{
- PPPoETag hostUniq = conn->hostUniq;
-
- /* 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->hostUniq.length) return 1;
-
- parsePacket(packet, parseForHostUniq, &hostUniq);
- return !hostUniq.length;
-}
-
-/**********************************************************************
-*%FUNCTION: parsePADOTags
-*%ARGUMENTS:
-* type -- tag type
-* len -- tag length
-* data -- tag data
-* extra -- extra user data. Should point to a PacketCriteria structure
-* which gets filled in according to selected AC name and service
-* name.
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Picks interesting tags out of a PADO packet
-***********************************************************************/
-void
-parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
- void *extra)
-{
- struct PacketCriteria *pc = (struct PacketCriteria *) extra;
- PPPoEConnection *conn = pc->conn;
- int i;
-
- switch(type) {
- case TAG_AC_NAME:
- 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);
- }
- break;
- case TAG_AC_SYSTEM_ERROR:
- if (conn->printACNames) {
- printf("Got a System-Error tag: %.*s\n", (int) len, data);
- }
- break;
- case TAG_GENERIC_ERROR:
- if (conn->printACNames) {
- printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
- }
- break;
- }
-}
-
-/***********************************************************************
-*%FUNCTION: sendPADI
-*%ARGUMENTS:
-* conn -- PPPoEConnection structure
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Sends a PADI packet
-***********************************************************************/
-void
-sendPADI(PPPoEConnection *conn)
-{
- PPPoEPacket packet;
- unsigned char *cursor = packet.payload;
- PPPoETag *svc = (PPPoETag *) (&packet.payload);
- UINT16_t namelen = 0;
- UINT16_t plen;
-
- if (conn->serviceName) {
- namelen = (UINT16_t) strlen(conn->serviceName);
- }
- plen = TAG_HDR_SIZE + namelen;
- CHECK_ROOM(cursor, packet.payload, plen);
-
- /* Set destination to Ethernet broadcast address */
- memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
- memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
-
- packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
- packet.vertype = PPPOE_VER_TYPE(1, 1);
- packet.code = CODE_PADI;
- packet.session = 0;
-
- svc->type = TAG_SERVICE_NAME;
- svc->length = htons(namelen);
- CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
-
- if (conn->serviceName) {
- memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
- }
- cursor += namelen + TAG_HDR_SIZE;
-
- /* If we're using Host-Uniq, copy it over */
- if (conn->hostUniq.length) {
- int len = ntohs(conn->hostUniq.length);
- CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
- memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
- cursor += len + TAG_HDR_SIZE;
- plen += len + TAG_HDR_SIZE;
- }
-
- packet.length = htons(plen);
-
- sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
- if (conn->debugFile) {
- dumpPacket(conn->debugFile, &packet, "SENT");
- fprintf(conn->debugFile, "\n");
- fflush(conn->debugFile);
- }
-}
-
-/**********************************************************************
-*%FUNCTION: waitForPADO
-*%ARGUMENTS:
-* conn -- PPPoEConnection structure
-* timeout -- how long to wait (in seconds)
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Waits for a PADO packet and copies useful information
-***********************************************************************/
-void
-waitForPADO(PPPoEConnection *conn, int timeout)
-{
- fd_set readable;
- int r;
- struct timeval tv;
- PPPoEPacket packet;
- int len;
-
- struct PacketCriteria pc;
- pc.conn = conn;
- pc.acNameOK = (conn->acName) ? 0 : 1;
- pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
- pc.seenACName = 0;
- pc.seenServiceName = 0;
- conn->error = 0;
-
- do {
- if (BPF_BUFFER_IS_EMPTY) {
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- FD_ZERO(&readable);
- FD_SET(conn->discoverySocket, &readable);
-
- while(1) {
- r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
- if (r >= 0 || errno != EINTR) break;
- }
- if (r < 0) {
- perror("select (waitForPADO)");
- return;
- }
- if (r == 0) return; /* Timed out */
- }
-
- /* Get the packet */
- receivePacket(conn->discoverySocket, &packet, &len);
-
- /* Check length */
- if (ntohs(packet.length) + HDR_SIZE > len) {
- fprintf(stderr, "Bogus PPPoE length field (%u)\n",
- (unsigned int) ntohs(packet.length));
- continue;
- }
-
-#ifdef USE_BPF
- /* If it's not a Discovery packet, loop again */
- if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
-#endif
-
- if (conn->debugFile) {
- dumpPacket(conn->debugFile, &packet, "RCVD");
- fprintf(conn->debugFile, "\n");
- fflush(conn->debugFile);
- }
- /* If it's not for us, loop again */
- if (!packetIsForMe(conn, &packet)) continue;
-
- if (packet.code == CODE_PADO) {
- if (BROADCAST(packet.ethHdr.h_source)) {
- fprintf(stderr, "Ignoring PADO packet from broadcast MAC address\n");
- continue;
- }
- parsePacket(&packet, parsePADOTags, &pc);
- if (conn->error)
- return;
- if (!pc.seenACName) {
- fprintf(stderr, "Ignoring PADO packet with no AC-Name tag\n");
- continue;
- }
- if (!pc.seenServiceName) {
- fprintf(stderr, "Ignoring PADO packet with no Service-Name tag\n");
- 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: discovery
-*%ARGUMENTS:
-* conn -- PPPoE connection info structure
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Performs the PPPoE discovery phase
-***********************************************************************/
-void
-discovery(PPPoEConnection *conn)
-{
- int padiAttempts = 0;
- int timeout = conn->discoveryTimeout;
-
- conn->discoverySocket =
- openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
-
- do {
- padiAttempts++;
- if (padiAttempts > conn->discoveryAttempts) {
- fprintf(stderr, "Timeout waiting for PADO packets\n");
- close(conn->discoverySocket);
- conn->discoverySocket = -1;
- return;
- }
- sendPADI(conn);
- conn->discoveryState = STATE_SENT_PADI;
- waitForPADO(conn, timeout);
- } while (!conn->numPADOs);
-}
-
-int main(int argc, char *argv[])
-{
- int opt;
- PPPoEConnection *conn;
-
- conn = malloc(sizeof(PPPoEConnection));
- if (!conn)
- fatalSys("malloc");
-
- memset(conn, 0, sizeof(PPPoEConnection));
-
- conn->printACNames = 1;
- conn->discoveryTimeout = PADI_TIMEOUT;
- conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
-
- while ((opt = getopt(argc, argv, "I:D:VUQS:C:W:t:a:h")) > 0) {
- switch(opt) {
- case 'S':
- conn->serviceName = xstrdup(optarg);
- break;
- case 'C':
- conn->acName = xstrdup(optarg);
- break;
- 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 'a':
- if (sscanf(optarg, "%d", &conn->discoveryAttempts) != 1) {
- fprintf(stderr, "Illegal argument to -a: Should be -a attempts\n");
- exit(EXIT_FAILURE);
- }
- if (conn->discoveryAttempts < 1) {
- conn->discoveryAttempts = 1;
- }
- break;
- case 'U':
- if(conn->hostUniq.length) {
- fprintf(stderr, "-U and -W are mutually exclusive\n");
- exit(EXIT_FAILURE);
- } else {
- pid_t pid = getpid();
- conn->hostUniq.type = htons(TAG_HOST_UNIQ);
- conn->hostUniq.length = htons(sizeof(pid));
- memcpy(conn->hostUniq.payload, &pid, sizeof(pid));
- }
- break;
- case 'W':
- if(conn->hostUniq.length) {
- fprintf(stderr, "-U and -W are mutually exclusive\n");
- exit(EXIT_FAILURE);
- }
- if (!parseHostUniq(optarg, &conn->hostUniq)) {
- fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'D':
- conn->debugFile = fopen(optarg, "w");
- if (!conn->debugFile) {
- fprintf(stderr, "Could not open %s: %s\n",
- optarg, strerror(errno));
- exit(1);
- }
- fprintf(conn->debugFile, "pppoe-discovery %s\n", RP_VERSION);
- break;
- case 'I':
- conn->ifName = xstrdup(optarg);
- break;
- case 'Q':
- conn->printACNames = 0;
- break;
- case 'V':
- case 'h':
- usage();
- exit(0);
- default:
- usage();
- exit(1);
- }
- }
-
- /* default interface name */
- if (!conn->ifName)
- conn->ifName = strdup("eth0");
-
- conn->discoverySocket = -1;
- conn->sessionSocket = -1;
-
- discovery(conn);
-
- if (!conn->numPADOs)
- exit(1);
- else
- exit(0);
-}
-
-void rp_fatal(char const *str)
-{
- fprintf(stderr, "%s\n", str);
- exit(1);
-}
-
-void fatalSys(char const *str)
-{
- perror(str);
- exit(1);
-}
-
-void sysErr(char const *str)
-{
- rp_fatal(str);
-}
-
-char *xstrdup(const char *s)
-{
- register char *ret = strdup(s);
- if (!ret)
- sysErr("strdup");
- return ret;
-}
-
-void usage(void)
-{
- fprintf(stderr, "Usage: pppoe-discovery [options]\n");
- fprintf(stderr, "Options:\n");
- fprintf(stderr, " -I if_name -- Specify interface (default eth0)\n");
- fprintf(stderr, " -D filename -- Log debugging information in filename.\n");
- fprintf(stderr,
- " -t timeout -- Initial timeout for discovery packets in seconds\n"
- " -a attempts -- Number of discovery attempts\n"
- " -V -- Print version and exit.\n"
- " -Q -- Quit Mode: Do not print access concentrator names\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 hexvalue -- Set the Host-Unique to the supplied hex string.\n"
- " -h -- Print usage information.\n");
- fprintf(stderr, "\nVersion " RP_VERSION "\n");
-}
+++ /dev/null
-/***********************************************************************
-*
-* pppoe.h
-*
-* Declaration of various PPPoE constants
-*
-* Copyright (C) 2000 Roaring Penguin Software Inc.
-*
-* This program may be distributed according to the terms of the GNU
-* General Public License, version 2 or (at your option) any later version.
-*
-* $Id: pppoe.h,v 1.4 2008/06/15 04:35:50 paulus Exp $
-*
-***********************************************************************/
-
-#include "config.h"
-
-#include <stdio.h> /* For FILE */
-#include <sys/types.h> /* For pid_t */
-#include <ctype.h>
-#include <string.h>
-
-#include "pppd/pppd.h" /* For error */
-
-/* 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_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-/* This has to be included before Linux 4.8's linux/in.h
- * gets dragged in. */
-#include <netinet/in.h>
-
-/* 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
-
-#define BPF_BUFFER_IS_EMPTY 1
-#define BPF_BUFFER_HAS_DATA 0
-
-/* 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>
-#else
-
-#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
-#endif
-
-/* Ethernet frame types according to RFC 2516 */
-#define ETH_PPPOE_DISCOVERY 0x8863
-#define ETH_PPPOE_SESSION 0x8864
-
-/* But some brain-dead peers disobey the RFC, so frame types are variables */
-extern UINT16_t Eth_PPPOE_Discovery;
-extern UINT16_t Eth_PPPOE_Session;
-
-/* PPPoE codes */
-#define CODE_PADI 0x09
-#define CODE_PADO 0x07
-#define CODE_PADR 0x19
-#define CODE_PADS 0x65
-#define CODE_PADT 0xA7
-
-/* 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_PPP_MAX_PAYLOAD 0x0120
-#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
-
-/* There are other fixed-size buffers preventing
- this from being increased to 16110. The buffer
- sizes would need to be properly de-coupled from
- the default MRU. For now, getting up to 1500 is
- enough. */
-#define ETH_JUMBO_LEN 1508
-
-/* A PPPoE Packet, including Ethernet headers */
-typedef struct PPPoEPacketStruct {
- struct ethhdr ethHdr; /* Ethernet header */
- unsigned int vertype:8; /* PPPoE Version and Type (must both be 1) */
- unsigned int code:8; /* PPPoE code */
- unsigned int session:16; /* PPPoE session */
- unsigned int length:16; /* Payload length */
- unsigned char payload[ETH_JUMBO_LEN]; /* A bit of room to spare */
-} PPPoEPacket;
-
-#define PPPOE_VER(vt) ((vt) >> 4)
-#define PPPOE_TYPE(vt) ((vt) & 0xf)
-#define PPPOE_VER_TYPE(v, t) (((v) << 4) | (t))
-
-/* 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_JUMBO_LEN - PPPOE_OVERHEAD)
-#define PPP_OVERHEAD 2 /* protocol */
-#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - PPP_OVERHEAD)
-#define TOTAL_OVERHEAD (PPPOE_OVERHEAD + PPP_OVERHEAD)
-#define ETH_PPPOE_MTU (ETH_DATA_LEN - TOTAL_OVERHEAD)
-
-/* PPPoE Tag */
-
-typedef struct PPPoETagStruct {
- unsigned int type:16; /* tag type */
- unsigned int length:16; /* Length of payload */
- unsigned char payload[ETH_JUMBO_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 */
- unsigned char req_peer_mac[ETH_ALEN]; /* required peer MAC address */
- unsigned char req_peer; /* require mac addr to match req_peer_mac */
- 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 */
- PPPoETag hostUniq; /* Use Host-Uniq tag */
- int printACNames; /* Just print AC names */
- 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 error; /* Error packet received */
- int debug; /* Set to log packets sent and received */
- int discoveryTimeout; /* Timeout for discovery packets */
- int discoveryAttempts; /* Number of discovery attempts */
- int seenMaxPayload;
- int mtu; /* Stored MTU */
- int mru; /* Stored MRU */
-} 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);
-void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir);
-void dumpHex(FILE *fp, unsigned char const *buf, int len);
-int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra);
-void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra);
-void syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
-void asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
-void asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
-void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
-char *strDup(char const *str);
-void sendPADT(PPPoEConnection *conn, char const *msg);
-void sendSessionPacket(PPPoEConnection *conn,
- PPPoEPacket *packet, int len);
-void initPPP(void);
-void clampMSS(PPPoEPacket *packet, char const *dir, int clampMss);
-UINT16_t computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr);
-UINT16_t pppFCS16(UINT16_t fcs, unsigned char *cp, int len);
-void discovery(PPPoEConnection *conn);
-unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
- PPPoETag *tag);
-
-void pppoe_printpkt(PPPoEPacket *packet,
- void (*printer)(void *, char *, ...), void *arg);
-void pppoe_log_packet(const char *prefix, PPPoEPacket *packet);
-
-static inline int parseHostUniq(const char *uniq, PPPoETag *tag)
-{
- unsigned i, len = strlen(uniq);
-
-#define hex(x) \
- (((x) <= '9') ? ((x) - '0') : \
- (((x) <= 'F') ? ((x) - 'A' + 10) : \
- ((x) - 'a' + 10)))
-
- if (!len || len % 2 || len / 2 > sizeof(tag->payload))
- return 0;
-
- for (i = 0; i < len; i += 2) {
- if (!isxdigit(uniq[i]) || !isxdigit(uniq[i+1]))
- return 0;
-
- tag->payload[i / 2] = (char)(hex(uniq[i]) << 4 | hex(uniq[i+1]));
- }
-
-#undef hex
-
- tag->type = htons(TAG_HOST_UNIQ);
- tag->length = htons(len / 2);
- return 1;
-}
-
-#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) { \
- error("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)
the serial port.
.SH PPPOE OPTIONS
To establish PPP link over Ethernet (PPPoE) it is needed to load pppd's
-\fBplugin rp-pppoe.so\fR and then specify option \fBnic-\fIinterface\fR
+\fBplugin pppoe.so\fR and then specify option \fBnic-\fIinterface\fR
instead of modem options \fIttyname\fR and \fIspeed\fR.
Recognized pppd's PPPoE options are:
.TP