--- ppp-2.4.6/pppd/plugins/rp-pppoe/discovery.c +++ ppp-2.4.6/pppd/plugins/rp-pppoe/discovery.c @@ -39,6 +39,7 @@ #endif #include +#include /* Calculate time remaining until *exp, return 0 if now >= *exp */ static int time_left(struct timeval *diff, struct timeval *exp) @@ -251,6 +252,80 @@ } /*********************************************************************** +*%FUNCTION: recvPacketForMe +*%ARGUMENTS: +* packet -- output parameter +* len -- output parameter length +* conn -- connection +* start -- operation startup timestamp +* timeout -- how long to wait (in seconds) +*%RETURNS: +* -1: error +* 0: timed out +* 1: packet received +*%DESCRIPTION: +* receive and filter junk packets +***********************************************************************/ + +static int +recvPacketForMe(PPPoEPacket *packet, int *len, PPPoEConnection *conn, time_t start, int timeout) +{ + fd_set readable; + int r; + struct timeval tv; + time_t now; + int time_remain; + + do { + time(&now); + time_remain = timeout - (int)difftime(now, start); + if (time_remain <= 0) return 0; /* Timed out */ + + if (BPF_BUFFER_IS_EMPTY) { + tv.tv_sec = time_remain; + tv.tv_usec = 0; + + FD_ZERO(&readable); + FD_SET(conn->discoverySocket, &readable); + + r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); + if (r < 0) + { + if (errno == EINTR) + { + continue; /* interrupted, so retry */ + }else + { + error("pppoe: recvPacketForMe: select: %m"); + return -1; + } + } + + if (r == 0) return 0; /* Timed out */ + } + + /* Get the packet */ + receivePacket(conn->discoverySocket, packet, len); + + /* Check length */ + if (ntohs(packet->length) + HDR_SIZE > *len) { + error("Bogus PPPoE length field (%u)", + (unsigned int) ntohs(packet->length)); + continue; + } + +#ifdef USE_BPF + /* If it's not a Discovery packet, loop again */ + if (etherType(&packet) != Eth_PPPOE_Discovery) continue; +#endif + /* If it's not for us, loop again */ + }while ( ! packetIsForMe(conn, packet)); + + return 1; +} + + +/*********************************************************************** *%FUNCTION: sendPADI *%ARGUMENTS: * conn -- PPPoEConnection structure @@ -344,13 +419,12 @@ void waitForPADO(PPPoEConnection *conn, int timeout) { - fd_set readable; int r; - struct timeval tv; struct timeval expire_at; PPPoEPacket packet; int len; + time_t start; struct PacketCriteria pc; pc.conn = conn; @@ -367,43 +441,10 @@ } expire_at.tv_sec += timeout; + time(&start); do { - if (BPF_BUFFER_IS_EMPTY) { - if (!time_left(&tv, &expire_at)) - return; /* Timed out */ - - FD_ZERO(&readable); - FD_SET(conn->discoverySocket, &readable); - - while(1) { - r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); - if (r >= 0 || errno != EINTR) break; - } - if (r < 0) { - error("select (waitForPADO): %m"); - return; - } - if (r == 0) - return; /* Timed out */ - } - - /* Get the packet */ - receivePacket(conn->discoverySocket, &packet, &len); - - /* Check length */ - if (ntohs(packet.length) + HDR_SIZE > len) { - error("Bogus PPPoE length field (%u)", - (unsigned int) ntohs(packet.length)); - continue; - } - -#ifdef USE_BPF - /* If it's not a Discovery packet, loop again */ - if (etherType(&packet) != Eth_PPPOE_Discovery) continue; -#endif - - /* If it's not for us, loop again */ - if (!packetIsForMe(conn, &packet)) continue; + r = recvPacketForMe(&packet, &len, conn, start, timeout); + if (r<=0) return; /* Timed out or error */ if (packet.code == CODE_PADO) { if (NOT_UNICAST(packet.ethHdr.h_source)) { @@ -537,13 +578,12 @@ static void waitForPADS(PPPoEConnection *conn, int timeout) { - fd_set readable; int r; - struct timeval tv; struct timeval expire_at; PPPoEPacket packet; int len; + time_t start; if (gettimeofday(&expire_at, NULL) < 0) { error("gettimeofday (waitForPADS): %m"); @@ -551,48 +591,15 @@ } expire_at.tv_sec += timeout; + time(&start); conn->error = 0; do { - if (BPF_BUFFER_IS_EMPTY) { - if (!time_left(&tv, &expire_at)) - return; /* Timed out */ - - FD_ZERO(&readable); - FD_SET(conn->discoverySocket, &readable); - - while(1) { - r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); - if (r >= 0 || errno != EINTR) break; - } - if (r < 0) { - error("select (waitForPADS): %m"); - return; - } - if (r == 0) - return; /* Timed out */ - } - - /* Get the packet */ - receivePacket(conn->discoverySocket, &packet, &len); - - /* Check length */ - if (ntohs(packet.length) + HDR_SIZE > len) { - error("Bogus PPPoE length field (%u)", - (unsigned int) ntohs(packet.length)); - continue; - } - -#ifdef USE_BPF - /* If it's not a Discovery packet, loop again */ - if (etherType(&packet) != Eth_PPPOE_Discovery) continue; -#endif + r = recvPacketForMe(&packet, &len, conn, start, timeout); + if (r<=0) return; /* Timed out or error */ /* If it's not from the AC, it's not for me */ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue; - /* If it's not for us, loop again */ - if (!packetIsForMe(conn, &packet)) continue; - /* Is it PADS? */ if (packet.code == CODE_PADS) { /* Parse for goodies */