--- 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 <signal.h>
+#include <time.h>
/* 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 */