]> git.ozlabs.org Git - ppp.git/commitdiff
Merge branch 'pppoe-discovery' of https://github.com/pali/ppp
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 26 Nov 2021 00:05:06 +0000 (11:05 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 26 Nov 2021 00:05:06 +0000 (11:05 +1100)
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
1  2 
pppd/plugins/pppoe/Makefile.am
pppd/plugins/pppoe/common.c
pppd/plugins/pppoe/discovery.c
pppd/plugins/pppoe/plugin.c
pppd/plugins/pppoe/pppoe-discovery.c
pppd/plugins/pppoe/pppoe.h
pppd/pppd.8

index e3c01cd054e9e03282ba2a9893b0bc9c9e4b3471,0000000000000000000000000000000000000000..0d70380a13893385dafcacc9aa8cd4b70505f62e
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,14 @@@
- pppoe_discovery_SOURCES = pppoe-discovery.c debug.c
 +pppd_plugin_LTLIBRARIES = pppoe.la 
 +pppd_plugindir = $(PPPD_PLUGIN_DIR)
 +sbin_PROGRAMS = pppoe-discovery
 +dist_man8_MANS = pppoe-discovery.8
 +
 +noinst_HEADERS = \
 +    pppoe.h
 +
 +pppoe_la_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/include
 +pppoe_la_LDFLAGS = -module -avoid-version
 +pppoe_la_SOURCES = plugin.c discovery.c if.c common.c
 +
 +pppoe_discovery_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/include
++pppoe_discovery_SOURCES = pppoe-discovery.c discovery.c if.c common.c
index 64bed1af6ca63df5de7344bbdc85c8ea262f22e8,f57d9de3d0e31d95bd38ca25d835ad7388e3f559..8b0e636acb800ab923a6b6c6d2cb3053448189f2
  static char const RCSID[] =
  "$Id: common.c,v 1.3 2008/06/09 08:34:23 paulus Exp $";
  
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
  #define _GNU_SOURCE 1
  #include "pppoe.h"
  #include "pppd/pppd.h"
@@@ -136,7 -132,7 +136,7 @@@ sendPADT(PPPoEConnection *conn, char co
        size_t elen = strlen(msg);
        err.type = htons(TAG_GENERIC_ERROR);
        err.length = htons(elen);
 -      strcpy(err.payload, msg);
 +      strcpy((char*) err.payload, msg);
        memcpy(cursor, &err, elen + TAG_HDR_SIZE);
        cursor += elen + TAG_HDR_SIZE;
        plen += elen + TAG_HDR_SIZE;
      info("Sent PADT");
  }
  
+ static void
+ pppoe_printpkt_hex(void (*printer)(void *, char *, ...), void *arg, unsigned char const *buf, int len)
+ {
+     int i;
+     int base;
+     /* do NOT dump PAP packets */
+     if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
+       printer(arg, "(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) {
+               printer(arg, "%02x ", (unsigned) buf[i]);
+           } else {
+               printer(arg, "   ");
+           }
+       }
+       printer(arg, "  ");
+       for (i=base; i<base+16; i++) {
+           if (i < len) {
+               if (isprint(buf[i])) {
+                   printer(arg, "%c", buf[i]);
+               } else {
+                   printer(arg, ".");
+               }
+           } else {
+               break;
+           }
+       }
+       printer(arg, "\n");
+     }
+ }
  #define EH(x) (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5]
  
  /* Print out a PPPOE packet for debugging */
@@@ -171,7 -203,7 +207,7 @@@ void pppoe_printpkt(PPPoEPacket *packet
                    void (*printer)(void *, char *, ...), void *arg)
  {
      int len = ntohs(packet->length);
-     int i, tag, tlen, text;
+     int i, j, tag, tlen, text;
  
      switch (ntohs(packet->ethHdr.h_proto)) {
      case ETH_PPPOE_DISCOVERY:
  
      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 (pppoe_verbose >= 2)
+       pppoe_printpkt_hex(printer, arg, packet->payload, ntohs(packet->length));
      if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY)
        return;
  
        }
        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, " %.*s", tlen, &packet->payload[i]);
+           else {
+               for (j = 0; j < tlen && j < 32; j++)
+                   printer(arg, " %02x", (unsigned) *(&packet->payload[i]+j));
+               if (j < tlen)
+                   printer(arg, "... (length %d)", tlen);
+           }
        }
        printer(arg, "]");
      }
index bd281bdb863b1a6be44e6c9530f99e7b6f05997e,86ea20715eac0def559f80decbfb79998a4428df..b32b0c891dcd89c5fb46ebe402adc698f9a0611f
  static char const RCSID[] =
  "$Id: discovery.c,v 1.6 2008/06/15 04:35:50 paulus Exp $";
  
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
  #define _GNU_SOURCE 1
  #include "pppoe.h"
  #include "pppd/pppd.h"
@@@ -142,7 -138,7 +142,7 @@@ parsePADOTags(UINT16_t type, UINT16_t l
      switch(type) {
      case TAG_AC_NAME:
        pc->seenACName = 1;
-       if (conn->printACNames) {
+       if (pppoe_verbose >= 1) {
            info("Access-Concentrator: %.*s", (int) len, data);
        }
        if (conn->acName && len == strlen(conn->acName) &&
        break;
      case TAG_SERVICE_NAME:
        pc->seenServiceName = 1;
+       if (pppoe_verbose >= 1 && len > 0) {
+           info("Service-Name: %.*s", (int) len, data);
+       }
        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);
+       if (pppoe_verbose >= 1) {
+           char buffer[100];
+           char *ptr = buffer;
+           ptr += sprintf(ptr, "Cookie:");
+           /* Print first 20 bytes of cookie */
+           for (i=0; i<len && i < 20; i++) {
+               ptr += sprintf(ptr, " %02x", (unsigned) data[i]);
+           }
+           if (i < len) ptr += sprintf(ptr, "...");
+           info(buffer);
+       }
+       if (conn->discoveryState != STATE_RECEIVED_PADO) {
+           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);
+       if (pppoe_verbose >= 1) {
+           char buffer[100];
+           char *ptr = buffer;
+           ptr += sprintf(ptr, "Relay-ID:");
+           /* Print first 20 bytes of relay ID */
+           for (i=0; i<len && i < 20; i++) {
+               ptr += printf(ptr, " %02x", (unsigned) data[i]);
+           }
+           if (i < len) ptr += printf(ptr, "...");
+           info(buffer);
+       }
+       if (conn->discoveryState != STATE_RECEIVED_PADO) {
+           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;
+           info("Max-Payload: %u", (unsigned) mru);
+           if (mru >= ETH_PPPOE_MTU && conn->discoveryState != STATE_RECEIVED_PADO) {
+               if (conn->mtu > mru)
+                   conn->mtu = mru;
+               if (conn->mru > mru)
+                   conn->mru = mru;
                conn->seenMaxPayload = 1;
            }
        }
@@@ -215,17 -241,19 +245,19 @@@ parsePADSTags(UINT16_t type, UINT16_t l
      UINT16_t mru;
      switch(type) {
      case TAG_SERVICE_NAME:
-       dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
+       if (pppoe_verbose >= 1 && len > 0) {
+           info("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;
+               if (conn->mtu > mru)
+                   conn->mtu = mru;
+               if (conn->mru > mru)
+                   conn->mru = mru;
                conn->seenMaxPayload = 1;
            }
        }
@@@ -310,9 -338,9 +342,9 @@@ sendPADI(PPPoEConnection *conn
      }
  
      /* Add our maximum MTU/MRU */
-     if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+     if (MIN(conn->mtu, conn->mru) > ETH_PPPOE_MTU) {
        PPPoETag maxPayload;
-       UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+       UINT16_t mru = htons(MIN(conn->mtu, conn->mru));
        maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
        maxPayload.length = htons(sizeof(mru));
        memcpy(maxPayload.payload, &mru, sizeof(mru));
@@@ -355,7 -383,6 +387,6 @@@ waitForPADO(PPPoEConnection *conn, int 
      pc.seenACName    = 0;
      pc.seenServiceName = 0;
      conn->seenMaxPayload = 0;
-     conn->error = 0;
  
      if (get_time(&expire_at) < 0) {
        error("get_time (waitForPADO): %m");
                return;         /* Timed out */
        }
  
+       conn->error = 0;
        /* Get the packet */
        receivePacket(conn->discoverySocket, &packet, &len);
  
                continue;
            }
            if (parsePacket(&packet, parsePADOTags, &pc) < 0)
-               return;
+               continue;
            if (conn->error)
-               return;
+               continue;
            if (!pc.seenACName) {
                error("Ignoring PADO packet with no AC-Name tag");
                continue;
                error("Ignoring PADO packet with no Service-Name tag");
                continue;
            }
+           if (pppoe_verbose >= 1) {
+               info("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x",
+                      (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]);
+               info("--------------------------------------------------");
+           }
            conn->numPADOs++;
-           if (pc.acNameOK && pc.serviceNameOK) {
+           if (pc.acNameOK && pc.serviceNameOK && conn->discoveryState != STATE_RECEIVED_PADO) {
                memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
                conn->discoveryState = STATE_RECEIVED_PADO;
-               break;
            }
        }
-     } while (conn->discoveryState != STATE_RECEIVED_PADO);
+     } while (pppoe_verbose >= 1 || conn->discoveryState != STATE_RECEIVED_PADO);
  }
  
  /***********************************************************************
@@@ -483,9 -520,9 +524,9 @@@ sendPADR(PPPoEConnection *conn
      }
  
      /* Add our maximum MTU/MRU */
-     if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+     if (MIN(conn->mtu, conn->mru) > ETH_PPPOE_MTU) {
        PPPoETag maxPayload;
-       UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+       UINT16_t mru = htons(MIN(conn->mtu, conn->mru));
        maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
        maxPayload.length = htons(sizeof(mru));
        memcpy(maxPayload.payload, &mru, sizeof(mru));
@@@ -609,19 -646,18 +650,18 @@@ waitForPADS(PPPoEConnection *conn, int 
  }
  
  /**********************************************************************
- *%FUNCTION: discovery
+ *%FUNCTION: discovery1
  *%ARGUMENTS:
  * conn -- PPPoE connection info structure
  *%RETURNS:
  * Nothing
  *%DESCRIPTION:
- * Performs the PPPoE discovery phase
+ * Performs the PPPoE discovery phase 1
  ***********************************************************************/
  void
- discovery(PPPoEConnection *conn)
+ discovery1(PPPoEConnection *conn)
  {
      int padiAttempts = 0;
-     int padrAttempts = 0;
      int timeout = conn->discoveryTimeout;
  
      do {
  
        timeout *= 2;
      } while (conn->discoveryState == STATE_SENT_PADI);
+ }
+ /**********************************************************************
+ *%FUNCTION: discovery2
+ *%ARGUMENTS:
+ * conn -- PPPoE connection info structure
+ *%RETURNS:
+ * Nothing
+ *%DESCRIPTION:
+ * Performs the PPPoE discovery phase 2
+ ***********************************************************************/
+ void
+ discovery2(PPPoEConnection *conn)
+ {
+     int padrAttempts = 0;
+     int timeout = conn->discoveryTimeout;
  
-     timeout = conn->discoveryTimeout;
      do {
        padrAttempts++;
        if (got_sigterm || padrAttempts > conn->discoveryAttempts) {
  
      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;
+       if (conn->mtu > ETH_PPPOE_MTU)
+           conn->mtu = ETH_PPPOE_MTU;
+       if (conn->mru > ETH_PPPOE_MTU)
+           conn->mru = ETH_PPPOE_MTU;
      }
  
      /* We're done. */
index 8bcd1f8d0306d372997647d0e5c9221836057919,e9353eb009b4a63dabdb22a2845d5c6960090f7c..c53450752b7c481fda436891622ebdac2cdc9c6b
  static char const RCSID[] =
  "$Id: plugin.c,v 1.17 2008/06/15 04:35:50 paulus Exp $";
  
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
  #define _GNU_SOURCE 1
  #include "pppoe.h"
  
@@@ -68,7 -64,7 +68,7 @@@ extern int new_style_driver
  char *pppd_pppoe_service = NULL;
  static char *acName = NULL;
  static char *existingSession = NULL;
static int printACNames = 0;
int pppoe_verbose = 0;
  static char *pppoe_reqd_mac = NULL;
  unsigned char pppoe_reqd_mac_addr[6];
  static char *pppoe_host_uniq;
@@@ -93,9 -89,9 +93,9 @@@ static option_t Options[] = 
        "Attach to existing session (sessid:macaddr)" },
      { "rp_pppoe_sess",    o_string, &existingSession,
        "Legacy alias for pppoe-sess", OPT_ALIAS },
-     { "pppoe-verbose", o_int, &printACNames,
+     { "pppoe-verbose", o_int, &pppoe_verbose,
        "Be verbose about discovered access concentrators" },
-     { "rp_pppoe_verbose", o_int, &printACNames,
+     { "rp_pppoe_verbose", o_int, &pppoe_verbose,
        "Legacy alias for pppoe-verbose", OPT_ALIAS },
      { "pppoe-mac", o_string, &pppoe_reqd_mac,
        "Only connect to specified MAC address" },
@@@ -132,7 -128,6 +132,6 @@@ PPPOEInitDevice(void
      conn->ifName = devnam;
      conn->discoverySocket = -1;
      conn->sessionSocket = -1;
-     conn->printACNames = printACNames;
      conn->discoveryTimeout = pppoe_padi_timeout;
      conn->discoveryAttempts = pppoe_padi_attempts;
      return 1;
@@@ -166,8 -161,8 +165,8 @@@ PPPOEConnectDevice(void
      }
  
      /* Restore configuration */
-     lcp_allowoptions[0].mru = conn->mtu;
-     lcp_wantoptions[0].mru = conn->mru;
+     lcp_allowoptions[0].mru = conn->mtu = conn->storedmtu;
+     lcp_wantoptions[0].mru = conn->mru = conn->storedmru;
  
      /* Update maximum MRU */
      s = socket(AF_INET, SOCK_DGRAM, 0);
      close(s);
  
      if (lcp_allowoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
-       lcp_allowoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+       lcp_allowoptions[0].mru = conn->mtu = ifr.ifr_mtu - TOTAL_OVERHEAD;
      if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
-       lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+       lcp_wantoptions[0].mru = conn->mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
  
      if (pppoe_host_uniq) {
        if (!parseHostUniq(pppoe_host_uniq, &conn->hostUniq))
            error("Failed to create PPPoE discovery socket: %m");
            goto errout;
        }
-       discovery(conn);
+       discovery1(conn);
+       /* discovery1() may update conn->mtu and conn->mru */
+       lcp_allowoptions[0].mru = conn->mtu;
+       lcp_wantoptions[0].mru = conn->mru;
+       if (conn->discoveryState != STATE_RECEIVED_PADO) {
+           error("Unable to complete PPPoE Discovery phase 1");
+           goto errout;
+       }
+       discovery2(conn);
+       /* discovery2() may update conn->mtu and conn->mru */
+       lcp_allowoptions[0].mru = conn->mtu;
+       lcp_wantoptions[0].mru = conn->mru;
        if (conn->discoveryState != STATE_SESSION) {
-           error("Unable to complete PPPoE Discovery");
+           error("Unable to complete PPPoE Discovery phase 2");
            goto errout;
        }
      }
@@@ -452,8 -458,8 +462,8 @@@ void pppoe_check_options(void
        lcp_wantoptions[0].mru = MAX_PPPOE_MTU;
  
      /* Save configuration */
-     conn->mtu = lcp_allowoptions[0].mru;
-     conn->mru = lcp_wantoptions[0].mru;
+     conn->storedmtu = lcp_allowoptions[0].mru;
+     conn->storedmru = lcp_wantoptions[0].mru;
  
      ccp_allowoptions[0].deflate = 0;
      ccp_wantoptions[0].deflate = 0;
index 96d6333edddfd451d710dcbf78d42ecc2ee5a7e8,2557b38d08a58be6112baa1ea93b923885c28c88..1fe999dbdf55b16fa7bbefe5ce6557b1f848fa26
@@@ -9,10 -9,6 +9,10 @@@
   *
   */
  
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
  #include <stdarg.h>
  #include <stdio.h>
  #include <stdlib.h>
@@@ -20,6 -16,7 +20,7 @@@
  #include <errno.h>
  #include <string.h>
  #include <time.h>
+ #include <signal.h>
  
  #include "pppoe.h"
  
  #include <net/if_arp.h>
  #endif
  
- char *xstrdup(const char *s);
- void usage(void);
+ int debug;
+ int got_sigterm;
+ int pppoe_verbose;
+ static FILE *debugFile;
  
- void die(int status)
- {
-       exit(status);
- }
- void error(char *fmt, ...)
+ void
+ fatal(char *fmt, ...)
  {
      va_list pvar;
      va_start(pvar, fmt);
      vfprintf(stderr, fmt, pvar);
      va_end(pvar);
+     fputc('\n', stderr);
+     exit(1);
  }
  
- /* 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)
+ void
+ error(char *fmt, ...)
  {
-     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.");
-       }
-       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) {
-           fatal("Interface %.16s is not Ethernet", ifname);
-       }
- #endif
-       if (NOT_UNICAST(hwaddr)) {
-           fatal("Interface %.16s has broadcast/multicast MAC address??", ifname);
-       }
-     }
-     /* 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;
+     va_list pvar;
+     va_start(pvar, fmt);
+     vfprintf(stderr, fmt, pvar);
+     fputc('\n', stderr);
+     va_end(pvar);
  }
  
- /***********************************************************************
- *%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)
+ void
+ warn(char *fmt, ...)
  {
- #if defined(HAVE_STRUCT_SOCKADDR_LL)
-     if (send(sock, pkt, size, 0) < 0) {
-       fatalSys("send (sendPacket)");
-       return -1;
-     }
- #else
-     struct sockaddr sa;
-     if (!conn) {
-       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) {
-       fatalSys("sendto (sendPacket)");
-       return -1;
-     }
- #endif
-     return 0;
+     va_list pvar;
+     va_start(pvar, fmt);
+     vfprintf(stderr, fmt, pvar);
+     fputc('\n', stderr);
+     va_end(pvar);
  }
  
- /***********************************************************************
- *%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)
+ void
+ info(char *fmt, ...)
  {
-     if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
-       fatalSys("recv (receivePacket)");
-       return -1;
-     }
-     return 0;
+     va_list pvar;
+     va_start(pvar, fmt);
+     vprintf(fmt, pvar);
+     putchar('\n');
+     va_end(pvar);
  }
  
- /**********************************************************************
- *%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)
+ void
+ init_pr_log(const char *prefix, int level)
  {
-     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)
+ end_pr_log(void)
  {
-     PPPoETag *tag = extra;
-     if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
-       tag->length = memcmp(data, tag->payload, len);
+     fflush(debugFile);
  }
  
- /**********************************************************************
- *%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)
+ void
+ pr_log(void *arg, char *fmt, ...)
  {
-     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;
+     va_list ap;
+     va_start(ap, fmt);
+     vfprintf(debugFile, fmt, ap);
+     va_end(ap);
  }
  
- /**********************************************************************
- *%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)
+ size_t
+ strlcpy(char *dest, const char *src, size_t len)
  {
-     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);
+     size_t ret = strlen(src);
+     if (len != 0) {
+       if (ret < len)
+           strcpy(dest, src);
+       else {
+           strncpy(dest, src, len - 1);
+           dest[len-1] = 0;
        }
-       break;
-     case TAG_GENERIC_ERROR:
-       if (conn->printACNames) {
-           printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
-       }
-       break;
      }
+     return ret;
  }
  
- /***********************************************************************
- *%FUNCTION: sendPADI
- *%ARGUMENTS:
- * conn -- PPPoEConnection structure
- *%RETURNS:
- * Nothing
- *%DESCRIPTION:
- * Sends a PADI packet
- ***********************************************************************/
- void
- sendPADI(PPPoEConnection *conn)
+ static char *
+ xstrdup(const char *s)
  {
-     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);
+     char *ret = strdup(s);
+     if (!ret) {
+         perror("strdup");
+         exit(1);
      }
+     return ret;
  }
  
- /**********************************************************************
- *%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)
+ int
+ get_time(struct timeval *tv)
  {
-     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);
+     return gettimeofday(tv, NULL);
  }
  
- /**********************************************************************
- *%FUNCTION: discovery
- *%ARGUMENTS:
- * conn -- PPPoE connection info structure
- *%RETURNS:
- * Nothing
- *%DESCRIPTION:
- * Performs the PPPoE discovery phase
- ***********************************************************************/
- void
- discovery(PPPoEConnection *conn)
+ static void
+ term_handler(int signum)
  {
-     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);
+     got_sigterm = 1;
  }
  
+ static void usage(void);
  int main(int argc, char *argv[])
  {
      int opt;
      PPPoEConnection *conn;
  
+     signal(SIGINT, term_handler);
+     signal(SIGTERM, term_handler);
      conn = malloc(sizeof(PPPoEConnection));
-     if (!conn)
-       fatalSys("malloc");
+     if (!conn) {
+         perror("malloc");
+         exit(1);
+     }
  
      memset(conn, 0, sizeof(PPPoEConnection));
  
-     conn->printACNames = 1;
+     pppoe_verbose = 1;
      conn->discoveryTimeout = PADI_TIMEOUT;
      conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
  
              }
            break;
        case 'D':
-           conn->debugFile = fopen(optarg, "w");
-           if (!conn->debugFile) {
+           pppoe_verbose = 2;
+           debug = 1;
+           debugFile = fopen(optarg, "w");
+           if (!debugFile) {
                fprintf(stderr, "Could not open %s: %s\n",
                        optarg, strerror(errno));
                exit(1);
            }
-           fprintf(conn->debugFile, "pppoe-discovery from pppd %s\n", VERSION);
+           fprintf(debugFile, "pppoe-discovery from pppd %s\n", VERSION);
            break;
        case 'I':
            conn->ifName = xstrdup(optarg);
            break;
        case 'Q':
-           conn->printACNames = 0;
+           pppoe_verbose = 0;
            break;
        case 'V':
        case 'h':
  
      /* default interface name */
      if (!conn->ifName)
-       conn->ifName = strdup("eth0");
+       conn->ifName = xstrdup("eth0");
  
-     conn->discoverySocket = -1;
      conn->sessionSocket = -1;
  
-     discovery(conn);
+     conn->discoverySocket = openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+     if (conn->discoverySocket < 0) {
+       perror("Cannot create PPPoE discovery socket");
+       exit(1);
+     }
+     discovery1(conn);
  
      if (!conn->numPADOs)
        exit(1);
        exit(0);
  }
  
- void fatal(char * fmt, ...)
- {
-     va_list ap;
-     va_start(ap, fmt);
-     vfprintf(stderr, fmt, ap);
-     va_end(ap);
-     fputc('\n', stderr);
-     exit(1);
- }
- void fatalSys(char const *str)
- {
-     perror(str);
-     exit(1);
- }
- char *xstrdup(const char *s)
- {
-     register char *ret = strdup(s);
-     if (!ret)
-       fatalSys("strdup");
-     return ret;
- }
- void usage(void)
+ static void
+ usage(void)
  {
      fprintf(stderr, "Usage: pppoe-discovery [options]\n");
      fprintf(stderr, "Options:\n");
index 5d96f0cf0c88ee197cc8732d90dce4186cf87b52,9c5073b08f7f0adcb5c17a205f0e522b9b9da5d7..26e14f5d9f4fade2857887b4ee600e39abce00fa
@@@ -13,6 -13,8 +13,6 @@@
  *
  ***********************************************************************/
  
 -#include "config.h"
 -
  #include <stdio.h>            /* For FILE */
  #include <sys/types.h>                /* For pid_t */
  #include <ctype.h>
@@@ -231,18 -233,17 +231,17 @@@ typedef struct PPPoEConnectionStruct 
      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 */
+     int storedmtu;            /* Stored MTU */
+     int storedmru;            /* Stored MRU */
+     int mtu;
+     int mru;
  } PPPoEConnection;
  
  /* Structure used to determine acceptable PADO or PADS packet */
@@@ -259,9 -260,6 +258,6 @@@ 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 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);
@@@ -276,10 -274,12 +272,12 @@@ 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);
+ void discovery1(PPPoEConnection *conn);
+ void discovery2(PPPoEConnection *conn);
  unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
                       PPPoETag *tag);
  
+ extern int pppoe_verbose;
  void pppoe_printpkt(PPPoEPacket *packet,
                    void (*printer)(void *, char *, ...), void *arg);
  void pppoe_log_packet(const char *prefix, PPPoEPacket *packet);
diff --combined pppd/pppd.8
index 7417a36ed2632ae4172a2776b1c4d574c62f8d2e,cbbcb45d812145186c9ed1f5c618471b96e348f6..b31594ac3be8b97b5b67cacd02ae55328a37ccbf
@@@ -55,8 -55,8 +55,8 @@@ non-privileged user
  .I speed
  An option that is a decimal number is taken as the desired baud rate
  for the serial device.  On systems such as
 -4.4BSD and NetBSD, any speed can be specified.  Other systems
 -(e.g. Linux, SunOS) only support the commonly-used baud rates.
 +Linux, 4.4BSD and NetBSD, any speed can be specified.  Other systems
 +(e.g. SunOS) only support the commonly-used baud rates.
  .TP
  .B asyncmap \fImap
  This option sets the Async-Control-Character-Map (ACCM) for this end
@@@ -127,6 -127,12 +127,6 @@@ is no other default route with the sam
  value of -1, the route is only added if there is no default route at
  all.
  .TP
 -.B defaultroute6
 -Add a default IPv6 route to the system routing tables, using the peer as
 -the gateway, when IPv6CP negotiation is successfully completed.
 -This entry is removed when the PPP connection is broken.  This option
 -is privileged if the \fInodefaultroute6\fR option has been specified.
 -.TP
  .B replacedefaultroute
  This option is a flag to the defaultroute option. If defaultroute is
  set and this flag is also set, pppd replaces an existing default route
@@@ -260,16 -266,10 +260,16 @@@ compression in the corresponding direct
  \fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
  .TP
  .B ca \fIca-file
 -(EAP-TLS) Use the file \fIca-file\fR as the X.509 Certificate Authority
 +(EAP-TLS, or PEAP) Use the file \fIca-file\fR as the X.509 Certificate Authority
  (CA) file (in PEM format), needed for setting up an EAP-TLS connection.
  This option is used on the client-side in conjunction with the \fBcert\fR
 -and \fBkey\fR options.
 +and \fBkey\fR options.  Either \fIca\fR, or \fIcapath\fR options are required
 +for PEAP. EAP-TLS may also use the entry in eaptls-client or eaptls-server
 +for a CA certificate associated with a particular peer.
 +.TP
 +.B capath \fIpath
 +(EAP-TLS, or PEAP) Specify a location that contains public CA certificates.
 +Either \fIca\fR, or \fIcapath\fR options are required for PEAP.
  .TP
  .B cdtrcts
  Use a non-standard hardware flow control (i.e. DTR/CTS) to control
@@@ -326,15 -326,15 +326,15 @@@ negotiation by sending its first LCP pa
  or \fBpty\fR option is used.
  .TP
  .B crl \fIfilename
 -(EAP-TLS) Use the file \fIfilename\fR as the Certificate Revocation List
 +(EAP-TLS, or PEAP) Use the file \fIfilename\fR as the Certificate Revocation List
  to check for the validity of the peer's certificate. This option is not
 -mandatory for setting up an EAP-TLS connection. Also see the \fBcrl-dir\fR
 +mandatory for setting up a TLS connection. Also see the \fBcrl-dir\fR
  option.
  .TP
  .B crl-dir \fIdirectory
 -(EAP-TLS) Use the directory \fIdirectory\fR to scan for CRL files in
 +(EAP-TLS, or PEAP) Use the directory \fIdirectory\fR to scan for CRL files in
  has format ($hash.r0) to check for the validity of the peer's certificate.
 -This option is not mandatory for setting up an EAP-TLS connection.
 +This option is not mandatory for setting up a TLS connection.
  Also see the \fBcrl\fR option.
  .TP
  .B debug
@@@ -354,17 -354,6 +354,17 @@@ Disable MRU [Maximum Receive Unit] nego
  pppd will use the default MRU value of 1500 bytes for both the
  transmit and receive direction.
  .TP
 +.B defaultroute6
 +Add a default IPv6 route to the system routing tables, using the peer as
 +the gateway, when IPv6CP negotiation is successfully completed.
 +This entry is removed when the PPP connection is broken.  This option
 +is privileged if the \fInodefaultroute6\fR option has been specified.
 +\fBWARNING: Do not enable this option by default\fR.  IPv6 routing tables
 +are managed by kernel (as apposite to IPv4) and IPv6 default route is
 +configured by kernel automatically too based on ICMPv6 Router Advertisement
 +packets.  This option may conflict with kernel IPv6 route setup and should
 +be used only for broken IPv6 networks.
 +.TP
  .B deflate \fInr,nt
  Request that the peer compress packets that it sends, using the
  Deflate scheme, with a maximum window size of \fI2**nr\fR bytes, and
@@@ -504,18 -493,6 +504,18 @@@ to send configure-Rejects instead to \f
  Set the maximum number of IPCP terminate-request transmissions to
  \fIn\fR (default 3).
  .TP
 +.B ipcp\-no\-address
 +Disable negotiation of addresses via IP-Address IPCP option.
 +.TP
 +.B ipcp\-no\-addresses
 +Disable negotiation of addresses via old-style deprecated IP-Addresses
 +IPCP option. pppd by default try to use new-style IP-Address IPCP option.
 +If new-style is not supported by peer or is disabled by \fBipcp\-no\-address\fR
 +option then pppd fallbacks to old-style deprecated IP-Addresses IPCP option.
 +When both new-style and old-style are disabled by both \fBipcp\-no\-address\fR
 +and \fBipcp\-no\-addresses\fR options then negotiation of IP addresses
 +is completely disabled.
 +.TP
  .B ipcp\-restart \fIn
  Set the IPCP restart interval (retransmission timeout) to \fIn\fR
  seconds (default 3).
@@@ -730,11 -707,6 +730,11 @@@ network control protocol comes up)
  Terminate after \fIn\fR consecutive failed connection attempts.  A
  value of 0 means no limit.  The default value is 10.
  .TP
 +.B max-tls-version \fIstring
 +(EAP-TLS, or PEAP) Configures the max allowed TLS version used during
 +negotiation with a peer.  The default value for this is \fI1.2\fR.  Values
 +allowed for this option is \fI1.0.\fR, \fI1.1\fR, \fI1.2\fR, \fI1.3\fR.
 +.TP
  .B modem
  Use the modem control lines.  This option is the default.  With this
  option, pppd will wait for the CD (Carrier Detect) signal from the
@@@ -952,9 -924,6 +952,9 @@@ situation, the ppp interface can be use
  device routes, but the peer itself cannot be addressed directly for IP
  traffic.
  .TP
 +.B nosendip
 +Don't send our local IP address to peer during IP address negotiation.
 +.TP
  .B notty
  Normally, pppd requires a terminal device.  With this option, pppd
  will allocate itself a pseudo-tty master/slave pair and use the slave
@@@ -1184,16 -1153,6 +1184,16 @@@ The device used by pppd with this optio
  Currently supports Microgate SyncLink adapters
  under Linux and FreeBSD 2.2.8 and later.
  .TP
 +.B tls-verify-method \fIstring
 +(EAP-TLS, or PEAP) Match the value specified for \fIremotename\fR to that that
 +of the X509 certificates subject name, common name, or suffix of the common
 +name.  Respective values allowed for this option is: \fInone\fR, \fIsubject\fR,
 +\fIname\fR, or \fIsuffix\fR.  The default value for this option is \fIname\fR.
 +.TP
 +.B tls-verify-key-usage
 +(EAP-TLS, or PEAP) Enables examination of peer certificate's purpose, and
 +extended key usage attributes.
 +.TP
  .B unit \fInum
  Sets the ppp unit number (for a ppp0 or ppp1 etc interface name) for outbound
  connections.  If the unit is already in use a dynamically allocated number will
@@@ -1240,16 -1199,6 +1240,16 @@@ USEPEERDNS will be set to 1.  In additi
  /etc/ppp/resolv.conf file containing one or two nameserver lines with
  the address(es) supplied by the peer.
  .TP
 +.B usepeerwins
 +Ask the peer for up to 2 WINS server addresses.  The addresses supplied
 +by the peer (if any) are passed to the /etc/ppp/ip\-up script in the
 +environment variables WINS1 and WINS2, and the environment variable
 +USEPEERWINS will be set to 1.
 +.LP
 +Please note that some modems (like the Huawei E220) requires this option in
 +order to avoid a race condition that results in the incorrect DNS servers
 +being assigned.
 +.TP
  .B user \fIname
  Sets the name used for authenticating the local system to the peer to
  \fIname\fR.
@@@ -1294,8 -1243,9 +1294,9 @@@ Attach to existing PPPoE session. For b
  \fBrp_pppoe_sess\fP option name is supported.
  .TP
  .B pppoe-verbose \fIn
- Be verbose about discovered access concentrators. For backward
- compatibility also \fBrp_pppoe_verbose\fP option name is supported.
+ Be verbose about discovered access concentrators. When set to 2 or bigger
+ value then dump also discovery packets. For backward compatibility also
+ \fBrp_pppoe_verbose\fP option name is supported.
  .TP
  .B pppoe-mac \fImacaddr
  Connect to specified MAC address.
@@@ -1801,14 -1751,6 +1802,14 @@@ IPCP has come up
  The IP address for the remote end of the link.  This is only set when
  IPCP has come up.
  .TP
 +.B LLLOCAL
 +The Link-Local IPv6 address for the local end of the link.  This is only
 +set when IPV6CP has come up.
 +.TP
 +.B LLREMOTE
 +The Link-Local IPv6 address for the remote end of the link.  This is only
 +set when IPV6CP has come up.
 +.TP
  .B PEERNAME
  The authenticated name of the peer.  This is only set if the peer
  authenticates itself.
@@@ -1852,15 -1794,6 +1853,15 @@@ option was given)
  If the peer supplies DNS server addresses, this variable is set to the
  second DNS server address supplied (whether or not the usepeerdns
  option was given).
 +.TP
 +.B WINS1
 +If the peer supplies WINS server addresses, this variable is set to the
 +first WINS server address supplied.
 +.TP
 +.B WINS2
 +If the peer supplies WINS server addresses, this variable is set to the
 +second WINS server address supplied.
 +.P
  .P
  Pppd invokes the following scripts, if they exist.  It is not an error
  if they don't exist.