--- /dev/null
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/common.c ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/common.c
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/common.c Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/common.c Mon Jul 8 16:38:24 2002
+@@ -11,13 +11,18 @@
+ * This program may be distributed according to the terms of the GNU
+ * General Public License, version 2 or (at your option) any later version.
+ *
++* LIC: GPL
++*
+ ***********************************************************************/
+
+ static char const RCSID[] =
+-"$Id$";
++"$Id$";
++/* For vsnprintf prototype */
++#define _ISOC99_SOURCE 1
+
+ #include "pppoe.h"
+
++
+ #ifdef HAVE_SYSLOG_H
+ #include <syslog.h>
+ #endif
+@@ -25,6 +30,7 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <stdlib.h>
++#include <stdarg.h>
+
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+@@ -93,7 +99,7 @@
+ * tag -- will be filled in with tag contents
+ *%RETURNS:
+ * A pointer to the tag if one of the specified type is found; NULL
+-* otherwise.
++* otherwise.
+ *%DESCRIPTION:
+ * Looks for a specific tag type.
+ ***********************************************************************/
+@@ -248,21 +254,38 @@
+ unsigned char *mssopt = NULL;
+ UINT16_t csum;
+
+- int len;
++ int len, minlen;
+
+- /* Is it IPv4? */
+- if (packet->payload[0] != 0x00 ||
+- packet->payload[1] != 0x21) {
+- /* Nope, ignore it */
+- return;
+- }
++ /* check PPP protocol type */
++ if (packet->payload[0] & 0x01) {
++ /* 8 bit protocol type */
++
++ /* Is it IPv4? */
++ if (packet->payload[0] != 0x21) {
++ /* Nope, ignore it */
++ return;
++ }
++
++ ipHdr = packet->payload + 1;
++ minlen = 41;
++ } else {
++ /* 16 bit protocol type */
+
+- ipHdr = packet->payload + 2;
++ /* Is it IPv4? */
++ if (packet->payload[0] != 0x00 ||
++ packet->payload[1] != 0x21) {
++ /* Nope, ignore it */
++ return;
++ }
++
++ ipHdr = packet->payload + 2;
++ minlen = 42;
++ }
+
+ /* Is it too short? */
+ len = (int) ntohs(packet->length);
+- if (len < 42) {
+- /* 20 byte IP header; 20 byte TCP header; 2 byte PPP protocol */
++ if (len < minlen) {
++ /* 20 byte IP header; 20 byte TCP header; at least 1 or 2 byte PPP protocol */
+ return;
+ }
+
+@@ -423,7 +446,7 @@
+ 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,
+@@ -451,6 +474,31 @@
+ syslog(LOG_INFO,"Sent PADT");
+ }
+
++/***********************************************************************
++*%FUNCTION: sendPADTf
++*%ARGUMENTS:
++* conn -- PPPoE connection
++* msg -- printf-style format string
++* args -- arguments for msg
++*%RETURNS:
++* Nothing
++*%DESCRIPTION:
++* Sends a PADT packet with a formatted message
++***********************************************************************/
++void
++sendPADTf(PPPoEConnection *conn, char const *fmt, ...)
++{
++ char msg[512];
++ va_list ap;
++
++ va_start(ap, fmt);
++ vsnprintf(msg, sizeof(msg), fmt, ap);
++ va_end(ap);
++ msg[511] = 0;
++
++ sendPADT(conn, msg);
++}
++
+ /**********************************************************************
+ *%FUNCTION: parseLogErrs
+ *%ARGUMENTS:
+@@ -482,4 +530,3 @@
+ break;
+ }
+ }
+-
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/config.h ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/config.h
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/config.h Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/config.h Sat Aug 10 19:06:59 2002
+@@ -1,5 +1,6 @@
+-/* config.h. Generated automatically by configure. */
++/* config.h. Generated by configure. */
+ /* config.h.in. Generated automatically from configure.in by autoheader. */
++/* LIC: GPL */
+
+ /* Define to empty if the keyword does not work. */
+ /* #undef const */
+@@ -133,3 +134,8 @@
+
+ /* Define if bitfields are packed in reverse order */
+ #define PACK_BITFIELDS_REVERSED 1
++
++/* Solaris moans if we don't do this... */
++#ifdef __sun
++#define __EXTENSIONS__ 1
++#endif
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/debug.c ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/debug.c
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/debug.c Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/debug.c Mon Jul 8 16:38:24 2002
+@@ -11,10 +11,12 @@
+ * This program may be distributed according to the terms of the GNU
+ * General Public License, version 2 or (at your option) any later version.
+ *
++* LIC: GPL
++*
+ ***********************************************************************/
+
+ static char const RCSID[] =
+-"$Id$";
++"$Id$";
+
+ #include "pppoe.h"
+ #include <sys/time.h>
+@@ -116,6 +118,8 @@
+ 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;
+ }
+
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/discovery.c ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/discovery.c
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/discovery.c Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/discovery.c Mon Jul 8 16:38:24 2002
+@@ -6,10 +6,12 @@
+ *
+ * Copyright (C) 1999 by Roaring Penguin Software Inc.
+ *
++* LIC: GPL
++*
+ ***********************************************************************/
+
+ static char const RCSID[] =
+-"$Id$";
++"$Id$";
+
+ #include "pppoe.h"
+
+@@ -322,12 +324,12 @@
+ pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
+ pc.seenACName = 0;
+ pc.seenServiceName = 0;
+-
++
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+-
++
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+@@ -340,7 +342,7 @@
+ }
+ if (r == 0) return; /* Timed out */
+ }
+-
++
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+@@ -379,19 +381,17 @@
+ continue;
+ }
+ conn->numPADOs++;
+- if (conn->printACNames) {
+- printf("--------------------------------------------------\n");
+- }
+ 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[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;
+@@ -504,10 +504,10 @@
+ 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;
+@@ -621,7 +621,6 @@
+
+ /* If we're only printing access concentrator names, we're done */
+ if (conn->printACNames) {
+- printf("--------------------------------------------------\n");
+ exit(0);
+ }
+
+@@ -641,4 +640,3 @@
+ conn->discoveryState = STATE_SESSION;
+ return;
+ }
+-
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/if.c ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/if.c
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/if.c Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/if.c Mon Jul 8 16:38:24 2002
+@@ -11,10 +11,12 @@
+ * This program may be distributed according to the terms of the GNU
+ * General Public License, version 2 or (at your option) any later version.
+ *
++* LIC: GPL
++*
+ ***********************************************************************/
+
+ static char const RCSID[] =
+-"$Id$";
++"$Id$";
+
+ #include "pppoe.h"
+
+@@ -87,7 +89,7 @@
+
+ static int dl_abssaplen;
+ static int dl_saplen;
+-static int dl_addrlen;
++static int dl_addrlen;
+
+ #endif
+
+@@ -169,7 +171,7 @@
+ if (ifr->ifr_addr.sa_family == AF_LINK) {
+ sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
+ if ((sdl->sdl_type == IFT_ETHER) &&
+- (sdl->sdl_alen == ETH_ALEN) &&
++ (sdl->sdl_alen == ETH_ALEN) &&
+ !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
+ if (found) {
+ char buffer[256];
+@@ -177,14 +179,14 @@
+ rp_fatal(buffer);
+ } else {
+ found = 1;
+- memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
++ memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
+ }
+ }
+ }
+ }
+ if (!found) {
+ char buffer[256];
+- sprintf(buffer, "interface %.16s has no ethernet address", ifname);
++ sprintf(buffer, "interface %.16s has no ethernet address", ifname);
+ rp_fatal(buffer);
+ }
+ }
+@@ -207,23 +209,23 @@
+ * Note that the ethernet type names come from "pppoe.h" and are
+ * used here to maintain consistency with the rest of this file. */
+ static struct bpf_insn bpfRun[] = { /* run PPPoE */
+- BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
+- BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
++ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
++ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
+ #define PPPOE_BCAST_CMPW 4 /* offset of word compare */
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
+- BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
++ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
+ #define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
+- BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
++ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
+ #define PPPOE_FILTER_CMPW 8 /* offset of word compare */
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
+- BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
++ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
+ #define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
+- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
+- BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
+- BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
++ BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
++ BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
+ };
+
+ /* Fix the potentially varying parts */
+@@ -242,14 +244,14 @@
+ struct bpf_program bpfProgram;
+ memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
+ bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
+- (0xff << 8) | 0xff);
++ (0xff << 8) | 0xff);
+ bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
+ bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | hwaddr[3]);
+ bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
+ bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
+ bpfProgram.bf_insns = &bpfInsn[0];
+-
++
+ /* Apply the filter */
+ if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
+ fatalSys("ioctl(BIOCSETF)");
+@@ -362,9 +364,9 @@
+ fatalSys("ioctl(BIOCVERSION)");
+ }
+ if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
+- (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
++ (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
+ char buffer[256];
+- sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
++ sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+ bpf_ver.bv_major, bpf_ver.bv_minor);
+ rp_fatal(buffer);
+@@ -394,7 +396,7 @@
+ }
+
+ syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
+- ifname,
++ ifname,
+ hwaddr[0], hwaddr[1], hwaddr[2],
+ hwaddr[3], hwaddr[4], hwaddr[5],
+ bpfName, bpfLength);
+@@ -548,12 +550,12 @@
+
+ short tmp_sap;
+
+- tmp_sap = htons(pkt->ethHdr.h_proto);
+- data_size = size - sizeof(struct ethhdr);
++ tmp_sap = htons(pkt->ethHdr.h_proto);
++ data_size = size - sizeof(struct ethhdr);
+
+ memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
+ memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
+- memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
++ memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
+
+ if (dl_saplen > 0) { /* order is sap+phys */
+ (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
+@@ -564,7 +566,7 @@
+ }
+
+ #ifdef DL_DEBUG
+- printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
++ printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
+ addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
+ addr[6],addr[7]);
+ #endif
+@@ -667,20 +669,20 @@
+ }
+ #else
+ #ifdef USE_DLPI
+- struct strbuf data;
+- int flags = 0;
+- int retval;
+-
+- data.buf = (char *) pkt;
+- data.maxlen = MAXDLBUF;
+- data.len = 0;
+-
++ struct strbuf data;
++ int flags = 0;
++ int retval;
++
++ data.buf = (char *) pkt;
++ data.maxlen = MAXDLBUF;
++ data.len = 0;
++
+ if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
+ sysErr("read (receivePacket)");
+ return -1;
+ }
+
+- *size = data.len;
++ *size = data.len;
+
+ #else
+ if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+@@ -708,34 +710,50 @@
+ openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+ {
+ int fd;
+- long buf[MAXDLBUF];
++ long buf[MAXDLBUF];
+
+ union DL_primitives *dlp;
+
+- char base_dev[PATH_MAX];
+- int ppa;
++ char base_dev[PATH_MAX];
++ int ppa;
+
+ if(strlen(ifname) > PATH_MAX) {
+- rp_fatal("socket: string to long");
++ rp_fatal("socket: Interface name too long");
++ }
++
++ if (strlen(ifname) < 2) {
++ rp_fatal("socket: Interface name too short");
+ }
+
+ ppa = atoi(&ifname[strlen(ifname)-1]);
+- strncpy(base_dev, ifname, PATH_MAX);
+- base_dev[strlen(base_dev)-1] = '\0';
++ strncpy(base_dev, ifname, PATH_MAX);
++ base_dev[strlen(base_dev)-1] = '\0';
+
+ /* rearranged order of DLPI code - delphys 20010803 */
+ dlp = (union DL_primitives*) buf;
+
+- if (( fd = open(base_dev, O_RDWR)) < 0) {
++ if ( (fd = open(base_dev, O_RDWR)) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
++ /* Common error is to omit /dev/ */
++ if (errno == ENOENT) {
++ char ifname[512];
++ snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev);
++ if ((fd = open(ifname, O_RDWR)) < 0) {
++ if (errno == EPERM) {
++ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
++ }
++ }
++ }
++ }
++ if (fd < 0) {
+ fatalSys("socket");
+ }
+
+ /* rearranged order of DLPI code - delphys 20010803 */
+- dlattachreq(fd, ppa);
++ dlattachreq(fd, ppa);
+ dlokack(fd, (char *)buf);
+
+ dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
+@@ -753,8 +771,8 @@
+ /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */
+ memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL);
+
+- if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
+- fatalSys("DLIOCRAW");
++ if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
++ fatalSys("DLIOCRAW");
+ }
+
+ if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
+@@ -766,332 +784,332 @@
+
+ void dlpromisconreq(int fd, u_long level)
+ {
+- dl_promiscon_req_t promiscon_req;
+- struct strbuf ctl;
+- int flags;
++ dl_promiscon_req_t promiscon_req;
++ struct strbuf ctl;
++ int flags;
+
+- promiscon_req.dl_primitive = DL_PROMISCON_REQ;
+- promiscon_req.dl_level = level;
++ promiscon_req.dl_primitive = DL_PROMISCON_REQ;
++ promiscon_req.dl_level = level;
+
+- ctl.maxlen = 0;
+- ctl.len = sizeof (promiscon_req);
+- ctl.buf = (char *) &promiscon_req;
++ ctl.maxlen = 0;
++ ctl.len = sizeof (promiscon_req);
++ ctl.buf = (char *) &promiscon_req;
+
+- flags = 0;
++ flags = 0;
+
+- if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+- fatalSys("dlpromiscon: putmsg");
++ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
++ fatalSys("dlpromiscon: putmsg");
+
+ }
+
+ void dlinforeq(int fd)
+ {
+- dl_info_req_t info_req;
+- struct strbuf ctl;
+- int flags;
++ dl_info_req_t info_req;
++ struct strbuf ctl;
++ int flags;
+
+- info_req.dl_primitive = DL_INFO_REQ;
++ info_req.dl_primitive = DL_INFO_REQ;
+
+- ctl.maxlen = 0;
+- ctl.len = sizeof (info_req);
+- ctl.buf = (char *) &info_req;
++ ctl.maxlen = 0;
++ ctl.len = sizeof (info_req);
++ ctl.buf = (char *) &info_req;
+
+- flags = RS_HIPRI;
++ flags = RS_HIPRI;
+
+- if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+- fatalSys("dlinforeq: putmsg");
++ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
++ fatalSys("dlinforeq: putmsg");
+ }
+
+ void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
+ {
+- long buf[MAXDLBUF];
+- union DL_primitives *dlp;
+- struct strbuf data, ctl;
+-
+- dlp = (union DL_primitives*) buf;
+-
+- dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
+- dlp->unitdata_req.dl_dest_addr_length = addrlen;
+- dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
+- dlp->unitdata_req.dl_priority.dl_min = minpri;
+- dlp->unitdata_req.dl_priority.dl_max = maxpri;
+-
+- (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
+-
+- ctl.maxlen = 0;
+- ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
+- ctl.buf = (char *) buf;
+-
+- data.maxlen = 0;
+- data.len = datalen;
+- data.buf = (char *) datap;
++ long buf[MAXDLBUF];
++ union DL_primitives *dlp;
++ struct strbuf data, ctl;
++
++ dlp = (union DL_primitives*) buf;
++
++ dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
++ dlp->unitdata_req.dl_dest_addr_length = addrlen;
++ dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
++ dlp->unitdata_req.dl_priority.dl_min = minpri;
++ dlp->unitdata_req.dl_priority.dl_max = maxpri;
++
++ (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
+
+- if (putmsg(fd, &ctl, &data, 0) < 0)
+- fatalSys("dlunitdatareq: putmsg");
++ ctl.maxlen = 0;
++ ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
++ ctl.buf = (char *) buf;
++
++ data.maxlen = 0;
++ data.len = datalen;
++ data.buf = (char *) datap;
++
++ if (putmsg(fd, &ctl, &data, 0) < 0)
++ fatalSys("dlunitdatareq: putmsg");
+ }
+
+ void dlinfoack(int fd, char *bufp)
+ {
+- union DL_primitives *dlp;
+- struct strbuf ctl;
+- int flags;
++ union DL_primitives *dlp;
++ struct strbuf ctl;
++ int flags;
+
+- ctl.maxlen = MAXDLBUF;
+- ctl.len = 0;
+- ctl.buf = bufp;
++ ctl.maxlen = MAXDLBUF;
++ ctl.len = 0;
++ ctl.buf = bufp;
+
+- strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
++ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
+
+- dlp = (union DL_primitives *) ctl.buf;
++ dlp = (union DL_primitives *) ctl.buf;
+
+- expecting(DL_INFO_ACK, dlp);
++ expecting(DL_INFO_ACK, dlp);
+
+- if (ctl.len < sizeof (dl_info_ack_t)) {
++ if (ctl.len < sizeof (dl_info_ack_t)) {
+ char buffer[256];
+- sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
+- rp_fatal(buffer);
++ sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
++ rp_fatal(buffer);
+ }
+
+- if (flags != RS_HIPRI)
+- rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
++ if (flags != RS_HIPRI)
++ rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
+
+- if (ctl.len < sizeof (dl_info_ack_t)) {
++ if (ctl.len < sizeof (dl_info_ack_t)) {
+ char buffer[256];
+- sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
+- rp_fatal(buffer);
++ sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
++ rp_fatal(buffer);
+ }
+ }
+
+ void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
+ {
+- dl_bind_req_t bind_req;
+- struct strbuf ctl;
+- int flags;
+-
+- bind_req.dl_primitive = DL_BIND_REQ;
+- bind_req.dl_sap = sap;
+- bind_req.dl_max_conind = max_conind;
+- bind_req.dl_service_mode = service_mode;
+- bind_req.dl_conn_mgmt = conn_mgmt;
+- bind_req.dl_xidtest_flg = xidtest;
+-
+- ctl.maxlen = 0;
+- ctl.len = sizeof (bind_req);
+- ctl.buf = (char *) &bind_req;
++ dl_bind_req_t bind_req;
++ struct strbuf ctl;
++ int flags;
++
++ bind_req.dl_primitive = DL_BIND_REQ;
++ bind_req.dl_sap = sap;
++ bind_req.dl_max_conind = max_conind;
++ bind_req.dl_service_mode = service_mode;
++ bind_req.dl_conn_mgmt = conn_mgmt;
++ bind_req.dl_xidtest_flg = xidtest;
++
++ ctl.maxlen = 0;
++ ctl.len = sizeof (bind_req);
++ ctl.buf = (char *) &bind_req;
+
+- flags = 0;
++ flags = 0;
+
+- if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+- fatalSys("dlbindreq: putmsg");
++ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
++ fatalSys("dlbindreq: putmsg");
+ }
+
+ void dlattachreq(int fd, u_long ppa)
+ {
+- dl_attach_req_t attach_req;
+- struct strbuf ctl;
+- int flags;
++ dl_attach_req_t attach_req;
++ struct strbuf ctl;
++ int flags;
+
+- attach_req.dl_primitive = DL_ATTACH_REQ;
+- attach_req.dl_ppa = ppa;
++ attach_req.dl_primitive = DL_ATTACH_REQ;
++ attach_req.dl_ppa = ppa;
+
+- ctl.maxlen = 0;
+- ctl.len = sizeof (attach_req);
+- ctl.buf = (char *) &attach_req;
++ ctl.maxlen = 0;
++ ctl.len = sizeof (attach_req);
++ ctl.buf = (char *) &attach_req;
+
+- flags = 0;
++ flags = 0;
+
+- if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+- fatalSys("dlattachreq: putmsg");
++ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
++ fatalSys("dlattachreq: putmsg");
+ }
+
+ void dlokack(int fd, char *bufp)
+ {
+- union DL_primitives *dlp;
+- struct strbuf ctl;
+- int flags;
++ union DL_primitives *dlp;
++ struct strbuf ctl;
++ int flags;
+
+- ctl.maxlen = MAXDLBUF;
+- ctl.len = 0;
+- ctl.buf = bufp;
++ ctl.maxlen = MAXDLBUF;
++ ctl.len = 0;
++ ctl.buf = bufp;
+
+- strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
++ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
+
+- dlp = (union DL_primitives *) ctl.buf;
++ dlp = (union DL_primitives *) ctl.buf;
+
+- expecting(DL_OK_ACK, dlp);
++ expecting(DL_OK_ACK, dlp);
+
+- if (ctl.len < sizeof (dl_ok_ack_t)) {
++ if (ctl.len < sizeof (dl_ok_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlokack: response ctl.len too short: %d", ctl.len);
+- rp_fatal(buffer);
++ rp_fatal(buffer);
+ }
+
+- if (flags != RS_HIPRI)
+- rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
++ if (flags != RS_HIPRI)
++ rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
+
+- if (ctl.len < sizeof (dl_ok_ack_t)) {
+- char buffer[256];
++ if (ctl.len < sizeof (dl_ok_ack_t)) {
++ char buffer[256];
+ sprintf(buffer, "dlokack: short response ctl.len: %d", ctl.len);
+- rp_fatal(buffer);
++ rp_fatal(buffer);
+ }
+ }
+
+ void dlbindack(int fd, char *bufp)
+ {
+- union DL_primitives *dlp;
+- struct strbuf ctl;
+- int flags;
++ union DL_primitives *dlp;
++ struct strbuf ctl;
++ int flags;
+
+- ctl.maxlen = MAXDLBUF;
+- ctl.len = 0;
+- ctl.buf = bufp;
++ ctl.maxlen = MAXDLBUF;
++ ctl.len = 0;
++ ctl.buf = bufp;
+
+- strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
++ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
+
+- dlp = (union DL_primitives *) ctl.buf;
++ dlp = (union DL_primitives *) ctl.buf;
+
+- expecting(DL_BIND_ACK, dlp);
++ expecting(DL_BIND_ACK, dlp);
+
+- if (flags != RS_HIPRI)
+- rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
++ if (flags != RS_HIPRI)
++ rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
+
+- if (ctl.len < sizeof (dl_bind_ack_t)) {
++ if (ctl.len < sizeof (dl_bind_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len);
+- rp_fatal(buffer);
++ rp_fatal(buffer);
+ }
+ }
+
+ int strioctl(int fd, int cmd, int timout, int len, char *dp)
+ {
+- struct strioctl sioc;
+- int rc;
++ struct strioctl sioc;
++ int rc;
+
+- sioc.ic_cmd = cmd;
+- sioc.ic_timout = timout;
+- sioc.ic_len = len;
+- sioc.ic_dp = dp;
+- rc = ioctl(fd, I_STR, &sioc);
+-
+- if (rc < 0)
+- return (rc);
+- else
+- return (sioc.ic_len);
++ sioc.ic_cmd = cmd;
++ sioc.ic_timout = timout;
++ sioc.ic_len = len;
++ sioc.ic_dp = dp;
++ rc = ioctl(fd, I_STR, &sioc);
++
++ if (rc < 0)
++ return (rc);
++ else
++ return (sioc.ic_len);
+ }
+
+ void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
+ {
+- int rc;
+- static char errmsg[80];
++ int rc;
++ static char errmsg[80];
+
+- /*
+- * Start timer.
+- */
+- (void) signal(SIGALRM, sigalrm);
+- if (alarm(MAXWAIT) < 0) {
+- (void) sprintf(errmsg, "%s: alarm", caller);
+- fatalSys(errmsg);
+- }
+-
+- /*
+- * Set flags argument and issue getmsg().
+- */
+- *flagsp = 0;
+- if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
+- (void) sprintf(errmsg, "%s: getmsg", caller);
+- fatalSys(errmsg);
+- }
+-
+- /*
+- * Stop timer.
+- */
+- if (alarm(0) < 0) {
+- (void) sprintf(errmsg, "%s: alarm", caller);
+- fatalSys(errmsg);
+- }
+-
+- /*
+- * Check for MOREDATA and/or MORECTL.
+- */
+- if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
+- char buffer[256];
++ /*
++ * Start timer.
++ */
++ (void) signal(SIGALRM, sigalrm);
++ if (alarm(MAXWAIT) < 0) {
++ (void) sprintf(errmsg, "%s: alarm", caller);
++ fatalSys(errmsg);
++ }
++
++ /*
++ * Set flags argument and issue getmsg().
++ */
++ *flagsp = 0;
++ if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
++ (void) sprintf(errmsg, "%s: getmsg", caller);
++ fatalSys(errmsg);
++ }
++
++ /*
++ * Stop timer.
++ */
++ if (alarm(0) < 0) {
++ (void) sprintf(errmsg, "%s: alarm", caller);
++ fatalSys(errmsg);
++ }
++
++ /*
++ * Check for MOREDATA and/or MORECTL.
++ */
++ if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
++ char buffer[256];
+ sprintf(buffer, "%s: MORECTL|MOREDATA", caller);
+ rp_fatal(buffer);
+ }
+-
+- if (rc & MORECTL) {
++
++ if (rc & MORECTL) {
+ char buffer[256];
+ sprintf(buffer, "%s: MORECTL", caller);
+- rp_fatal(buffer);
++ rp_fatal(buffer);
+ }
+-
+- if (rc & MOREDATA) {
+- char buffer[256];
++
++ if (rc & MOREDATA) {
++ char buffer[256];
+ sprintf(buffer, "%s: MOREDATA", caller);
+ rp_fatal(buffer);
+ }
+
+- /*
+- * Check for at least sizeof (long) control data portion.
+- */
+- if (ctlp->len < sizeof (long)) {
+- char buffer[256];
++ /*
++ * Check for at least sizeof (long) control data portion.
++ */
++ if (ctlp->len < sizeof (long)) {
++ char buffer[256];
+ sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len);
+- rp_fatal(buffer);
++ rp_fatal(buffer);
+ }
+ }
+
+ void sigalrm(int sig)
+ {
+- (void) rp_fatal("sigalrm: TIMEOUT");
++ (void) rp_fatal("sigalrm: TIMEOUT");
+ }
+
+ void expecting(int prim, union DL_primitives *dlp)
+ {
+- if (dlp->dl_primitive != (u_long)prim) {
+- char buffer[256];
++ if (dlp->dl_primitive != (u_long)prim) {
++ char buffer[256];
+ sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
+- rp_fatal(buffer);
+- exit(1);
++ rp_fatal(buffer);
++ exit(1);
+ }
+ }
+
+ char *dlprim(u_long prim)
+ {
+- static char primbuf[80];
++ static char primbuf[80];
+
+- switch ((int)prim) {
+- CASERET(DL_INFO_REQ);
+- CASERET(DL_INFO_ACK);
+- CASERET(DL_ATTACH_REQ);
+- CASERET(DL_DETACH_REQ);
+- CASERET(DL_BIND_REQ);
+- CASERET(DL_BIND_ACK);
+- CASERET(DL_UNBIND_REQ);
+- CASERET(DL_OK_ACK);
+- CASERET(DL_ERROR_ACK);
+- CASERET(DL_SUBS_BIND_REQ);
+- CASERET(DL_SUBS_BIND_ACK);
+- CASERET(DL_UNITDATA_REQ);
+- CASERET(DL_UNITDATA_IND);
+- CASERET(DL_UDERROR_IND);
+- CASERET(DL_UDQOS_REQ);
+- CASERET(DL_CONNECT_REQ);
+- CASERET(DL_CONNECT_IND);
+- CASERET(DL_CONNECT_RES);
+- CASERET(DL_CONNECT_CON);
+- CASERET(DL_TOKEN_REQ);
+- CASERET(DL_TOKEN_ACK);
+- CASERET(DL_DISCONNECT_REQ);
+- CASERET(DL_DISCONNECT_IND);
+- CASERET(DL_RESET_REQ);
+- CASERET(DL_RESET_IND);
+- CASERET(DL_RESET_RES);
+- CASERET(DL_RESET_CON);
+- default:
+- (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
+- return (primbuf);
+- }
++ switch ((int)prim) {
++ CASERET(DL_INFO_REQ);
++ CASERET(DL_INFO_ACK);
++ CASERET(DL_ATTACH_REQ);
++ CASERET(DL_DETACH_REQ);
++ CASERET(DL_BIND_REQ);
++ CASERET(DL_BIND_ACK);
++ CASERET(DL_UNBIND_REQ);
++ CASERET(DL_OK_ACK);
++ CASERET(DL_ERROR_ACK);
++ CASERET(DL_SUBS_BIND_REQ);
++ CASERET(DL_SUBS_BIND_ACK);
++ CASERET(DL_UNITDATA_REQ);
++ CASERET(DL_UNITDATA_IND);
++ CASERET(DL_UDERROR_IND);
++ CASERET(DL_UDQOS_REQ);
++ CASERET(DL_CONNECT_REQ);
++ CASERET(DL_CONNECT_IND);
++ CASERET(DL_CONNECT_RES);
++ CASERET(DL_CONNECT_CON);
++ CASERET(DL_TOKEN_REQ);
++ CASERET(DL_TOKEN_ACK);
++ CASERET(DL_DISCONNECT_REQ);
++ CASERET(DL_DISCONNECT_IND);
++ CASERET(DL_RESET_REQ);
++ CASERET(DL_RESET_IND);
++ CASERET(DL_RESET_RES);
++ CASERET(DL_RESET_CON);
++ default:
++ (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
++ return (primbuf);
++ }
+ }
+
+ #endif /* USE_DLPI */
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/plugin.c ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/plugin.c
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/plugin.c Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/plugin.c Mon Jul 8 16:38:24 2002
+@@ -19,10 +19,13 @@
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
++*
++* LIC: GPL
++*
+ ***********************************************************************/
+
+ static char const RCSID[] =
+-"$Id$";
++"$Id$";
+
+ #define _GNU_SOURCE 1
+ #include "pppoe.h"
+@@ -48,9 +51,9 @@
+ #include <signal.h>
+ #include <net/ethernet.h>
+ #include <net/if_arp.h>
+-#include "ppp_defs.h"
+-#include "if_ppp.h"
+-#include "if_pppox.h"
++#include <linux/ppp_defs.h>
++#include <linux/if_ppp.h>
++#include <linux/if_pppox.h>
+
+ #define _PATH_ETHOPT _ROOT_PATH "/etc/ppp/options."
+
+@@ -275,13 +278,9 @@
+ int fd;
+ struct ifreq ifr;
+
+- /* Only do it if name is "ethXXX" or "nic-XXXX. In latter case,
+- strip off the "nic-" */
++ /* Only do it if name is "ethXXX" */
+ /* Thanks to Russ Couturier for this fix */
+- if (strlen(cmd) > 4 && !strncmp(cmd, "nic-", 4)) {
+- /* Strip off "nic-" */
+- cmd += 4;
+- } else if (strlen(cmd) < 4 || strncmp(cmd, "eth", 3)) {
++ if (strlen(cmd) < 4 || strncmp(cmd, "eth", 3)) {
+ if (OldDevnameHook) return OldDevnameHook(cmd, argv, doit);
+ return 0;
+ }
+@@ -399,12 +398,11 @@
+ void
+ rp_fatal(char const *str)
+ {
+- char buf[1024];
+ printErr(str);
+- sprintf(buf, "RP-PPPoE: %.256s", str);
+- sendPADT(conn, buf);
++ sendPADTf(conn, "RP-PPPoE: %.256s", str);
+ exit(1);
+ }
++
+ /**********************************************************************
+ *%FUNCTION: sysErr
+ *%ARGUMENTS:
+diff -urN ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/pppoe.h ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/pppoe.h
+--- ppp-2.4.2-20020809.org/pppd/plugins/rp-pppoe/pppoe.h Fri Aug 9 22:14:40 2002
++++ ppp-2.4.2-20020809/pppd/plugins/rp-pppoe/pppoe.h Mon Jul 8 16:38:24 2002
+@@ -9,14 +9,12 @@
+ * This program may be distributed according to the terms of the GNU
+ * General Public License, version 2 or (at your option) any later version.
+ *
+-* $Id$
++* LIC: GPL
++*
++* $Id$
+ *
+ ***********************************************************************/
+
+-#ifdef __sun__
+-#define __EXTENSIONS__
+-#endif
+-
+ #include "config.h"
+
+ #if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+@@ -160,6 +158,12 @@
+ #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 */
+@@ -174,6 +178,12 @@
+ #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
+@@ -298,6 +308,8 @@
+ void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+ char *strDup(char const *str);
+ void sendPADT(PPPoEConnection *conn, char const *msg);
++void sendPADTf(PPPoEConnection *conn, char const *fmt, ...);
++
+ void sendSessionPacket(PPPoEConnection *conn,
+ PPPoEPacket *packet, int len);
+ void initPPP(void);