X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fplugins%2Fpppoe%2Fpppoe-discovery.c;h=10f51dc975dbd9df1a851ca056f586770e09aa8d;hb=HEAD;hp=e41d2863cb9bafe0e85eb321f8bd7421ad91c758;hpb=5b50b420fcd4708b6d5bdc55087c4c9fe06d215d;p=ppp.git diff --git a/pppd/plugins/pppoe/pppoe-discovery.c b/pppd/plugins/pppoe/pppoe-discovery.c index e41d286..5b1b2dc 100644 --- a/pppd/plugins/pppoe/pppoe-discovery.c +++ b/pppd/plugins/pppoe/pppoe-discovery.c @@ -9,6 +9,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -16,640 +20,148 @@ #include #include #include +#include +#include +#include +#include #include "pppoe.h" -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_NETPACKET_PACKET_H -#include -#elif defined(HAVE_LINUX_IF_PACKET_H) -#include -#endif - -#ifdef HAVE_ASM_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#include -#include -#include - -#ifdef HAVE_NET_IF_ARP_H -#include -#endif - -char *xstrdup(const char *s); -void usage(void); +int debug; +int got_sigterm; +int pppoe_verbose; +static FILE *debugFile; -void die(int status) +void +fatal(const char *fmt, ...) { - exit(status); + va_list pvar; + va_start(pvar, fmt); + vfprintf(stderr, fmt, pvar); + va_end(pvar); + fputc('\n', stderr); + exit(1); } -void error(char *fmt, ...) +void +error(const char *fmt, ...) { va_list pvar; va_start(pvar, fmt); vfprintf(stderr, fmt, pvar); + fputc('\n', stderr); 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) +void +warn(const char *fmt, ...) { - 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; + va_list pvar; + va_start(pvar, fmt); + vfprintf(stderr, fmt, pvar); + fputc('\n', stderr); + va_end(pvar); } -/********************************************************************** -*%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 +info(const 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); + vprintf(fmt, pvar); + putchar('\n'); + 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 +init_pr_log(const char *prefix, int level) { -#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; } -/*********************************************************************** -*%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 +end_pr_log(void) { - if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) { - fatalSys("recv (receivePacket)"); - return -1; - } - return 0; + fflush(debugFile); } -/********************************************************************** -*%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 +pr_log(void *arg, char *fmt, ...) { - 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; - } + va_list ap; + va_start(ap, fmt); + vfprintf(debugFile, fmt, ap); + va_end(ap); +} - /* 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; +size_t +strlcpy(char *dest, const char *src, size_t len) +{ + size_t ret = strlen(src); + + if (len != 0) { + if (ret < len) + strcpy(dest, src); + else { + strncpy(dest, src, len - 1); + dest[len-1] = 0; } - func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra); - curTag = curTag + TAG_HDR_SIZE + tagLen; } - return 0; + return ret; } -/********************************************************************** -*%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) +static char * +xstrdup(const char *s) { - PPPoETag *tag = extra; - - if (type == TAG_HOST_UNIQ && len == ntohs(tag->length)) - tag->length = memcmp(data, tag->payload, len); + char *ret = strdup(s); + if (!ret) { + perror("strdup"); + exit(1); + } + return ret; } -/********************************************************************** -*%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) +get_time(struct timeval *tv) { - 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; + return gettimeofday(tv, NULL); } -/********************************************************************** -*%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; icookie.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; irelayId.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; - } +int signaled(int signal) { + if (signal == SIGTERM) + return got_sigterm; + return 0; } -/*********************************************************************** -*%FUNCTION: sendPADI -*%ARGUMENTS: -* conn -- PPPoEConnection structure -*%RETURNS: -* Nothing -*%DESCRIPTION: -* Sends a PADI packet -***********************************************************************/ -void -sendPADI(PPPoEConnection *conn) +bool debug_on() { - 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); - } + return !!debug; } -/********************************************************************** -*%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) +static void +term_handler(int signum) { - 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); + got_sigterm = 1; } -/********************************************************************** -*%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); -} +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; @@ -701,19 +213,21 @@ int main(int argc, char *argv[]) } 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", PPPD_VERSION); break; case 'I': conn->ifName = xstrdup(optarg); break; case 'Q': - conn->printACNames = 0; + pppoe_verbose = 0; break; case 'V': case 'h': @@ -725,14 +239,26 @@ int main(int argc, char *argv[]) } } - /* default interface name */ - if (!conn->ifName) - conn->ifName = strdup("eth0"); + if (optind != argc) { + fprintf(stderr, "%s: extra argument '%s'\n", argv[0], argv[optind]); + usage(); + exit(EXIT_FAILURE); + } + + if (!conn->ifName) { + fprintf(stderr, "Interface was not specified\n"); + exit(EXIT_FAILURE); + } - 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); @@ -740,35 +266,12 @@ int main(int argc, char *argv[]) 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"); - fprintf(stderr, " -I if_name -- Specify interface (default eth0)\n"); + fprintf(stderr, " -I if_name -- Specify interface (mandatory option)\n"); fprintf(stderr, " -D filename -- Log debugging information in filename.\n"); fprintf(stderr, " -t timeout -- Initial timeout for discovery packets in seconds\n" @@ -780,5 +283,5 @@ void usage(void) " -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"); + fprintf(stderr, "\npppoe-discovery from pppd " PPPD_VERSION "\n"); }