diff -Nru ppp-2.4.5.orig/pppd/plugins/rp-pppoe/discovery.c ppp-2.4.5/pppd/plugins/rp-pppoe/discovery.c --- ppp-2.4.5.orig/pppd/plugins/rp-pppoe/discovery.c 2009-11-16 23:26:07.000000000 +0100 +++ ppp-2.4.5/pppd/plugins/rp-pppoe/discovery.c 2010-11-27 10:06:46.000000000 +0100 @@ -37,6 +37,7 @@ #endif #include +#include /********************************************************************** *%FUNCTION: parseForHostUniq @@ -196,6 +197,83 @@ } } + +/********************************************************************** +*%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 /* select error */ + { + 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: @@ -277,11 +355,10 @@ void waitForPADO(PPPoEConnection *conn, int timeout) { - fd_set readable; int r; - struct timeval tv; PPPoEPacket packet; int len; + time_t start; struct PacketCriteria pc; pc.conn = conn; @@ -291,42 +368,10 @@ pc.seenServiceName = 0; conn->error = 0; + time(&start); 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) { - 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)) { @@ -447,53 +492,20 @@ static void waitForPADS(PPPoEConnection *conn, int timeout) { - fd_set readable; int r; - struct timeval tv; PPPoEPacket packet; int len; + time_t start; + time(&start); 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) { - error("select (waitForPADS): %m"); - return; - } - if (r == 0) return; - } - - /* 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 */ diff -Nru ppp-2.4.5.orig/pppd/plugins/rp-pppoe/pppoe-discovery.c ppp-2.4.5/pppd/plugins/rp-pppoe/pppoe-discovery.c --- ppp-2.4.5.orig/pppd/plugins/rp-pppoe/pppoe-discovery.c 2009-11-16 23:26:07.000000000 +0100 +++ ppp-2.4.5/pppd/plugins/rp-pppoe/pppoe-discovery.c 2010-11-27 10:14:54.000000000 +0100 @@ -513,6 +513,8 @@ struct timeval tv; PPPoEPacket packet; int len; + time_t start, now; + int time_remain; struct PacketCriteria pc; pc.conn = conn; @@ -522,9 +524,14 @@ pc.seenServiceName = 0; conn->error = 0; + time(&start); do { + time(&now); + time_remain = timeout - ((int)start - (int)now); + if (time_remain <= 0) return; /* Timed out */ + if (BPF_BUFFER_IS_EMPTY) { - tv.tv_sec = timeout; + tv.tv_sec = time_remain; tv.tv_usec = 0; FD_ZERO(&readable);