diff -Naur ppp-2.4.5.org/pppd/plugins/rp-pppoe/discovery.c ppp-2.4.5.me/pppd/plugins/rp-pppoe/discovery.c --- ppp-2.4.5.org/pppd/plugins/rp-pppoe/discovery.c 2009-11-17 01:26:07.000000000 +0300 +++ ppp-2.4.5.me/pppd/plugins/rp-pppoe/discovery.c 2010-10-11 21:51:16.000000000 +0400 @@ -37,6 +37,7 @@ #endif #include +#include /********************************************************************** *%FUNCTION: parseForHostUniq @@ -196,6 +197,86 @@ } } + +/********************************************************************** +*%FUNCTION: recvPacketForMe +*%ARGUMENTS: +* packet -- output parameter +* len -- output parameter length +* conn -- connection +* timeout -- don't wait more than timeout +*%RETURNS: +* -1: error +* 0: timed out +* 1: packet recived +*%DESCRIPTION: +* recive and filter junk packets +***********************************************************************/ + +static int +recvPacketForMe(PPPoEPacket *packet, int *len, PPPoEConnection *conn, int timeout) +{ + + fd_set readable; + int r; + struct timeval tv; + time_t start, now; + int time_remain; + + start = time(&now); + do { + time(&now); + time_remain = timeout - (int)difftime(now, start); + if (time_remain > timeout) time_remain = timeout; + + if (time_remain <= 0) /* Timed out */ + return 0; + + 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 +358,11 @@ void waitForPADO(PPPoEConnection *conn, int timeout) { - fd_set readable; int r; - struct timeval tv; PPPoEPacket packet; int len; + time_t start, now; + int time_remain; struct PacketCriteria pc; pc.conn = conn; @@ -291,42 +372,16 @@ pc.seenServiceName = 0; conn->error = 0; + start = time(&now); 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; - } + time(&now); + time_remain = timeout - (int)difftime(now, start); + if (time_remain > timeout) time_remain = timeout; -#ifdef USE_BPF - /* If it's not a Discovery packet, loop again */ - if (etherType(&packet) != Eth_PPPOE_Discovery) continue; -#endif + if (time_remain <= 0) return; /* Timed out */ - /* If it's not for us, loop again */ - if (!packetIsForMe(conn, &packet)) continue; + r = recvPacketForMe(&packet, &len, conn, time_remain); + if (r<=0) return; /* Timed out or error */ if (packet.code == CODE_PADO) { if (NOT_UNICAST(packet.ethHdr.h_source)) { @@ -447,52 +502,23 @@ static void waitForPADS(PPPoEConnection *conn, int timeout) { - fd_set readable; int r; - struct timeval tv; PPPoEPacket packet; int len; + time_t start, now; + int time_remain; + start = time(&now); 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 + time(&now); + time_remain = timeout - (int)difftime(now, start); + if (time_remain > timeout) time_remain = timeout; - /* If it's not from the AC, it's not for me */ - if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue; + if (time_remain <= 0) return; /* Timed out */ - /* If it's not for us, loop again */ - if (!packetIsForMe(conn, &packet)) continue; + r = recvPacketForMe(&packet, &len, conn, time_remain); + if (r<=0) return; /* Timed out or error */ /* Is it PADS? */ if (packet.code == CODE_PADS) {