From 1817d83e51a411044e730ba89ebdb0480e1c8cd4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 20 May 2012 19:36:23 +1000 Subject: [PATCH] rp-pppoe plugin: Import some fixes from rp-pppoe-3.10 * Make timeout for PADO/PADS be the total time we wait for, not the time that each individual select call waits for. * Open the discovery socket in PPPOEConnectDevice() rather than discovery(). * Open the session socket earlier in PPPOEConnectDevice() to avoid missing session packets sent by the server just after the PADS packet. Signed-off-by: Paul Mackerras --- pppd/plugins/rp-pppoe/discovery.c | 57 ++++++++++++++++++++++++++----- pppd/plugins/rp-pppoe/plugin.c | 25 ++++++++------ 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/pppd/plugins/rp-pppoe/discovery.c b/pppd/plugins/rp-pppoe/discovery.c index a856490..04877cb 100644 --- a/pppd/plugins/rp-pppoe/discovery.c +++ b/pppd/plugins/rp-pppoe/discovery.c @@ -40,6 +40,30 @@ static char const RCSID[] = #include +/* Calculate time remaining until *exp, return 0 if now >= *exp */ +static int time_left(struct timeval *diff, struct timeval *exp) +{ + struct timeval now; + + if (gettimeofday(&now, NULL) < 0) { + error("gettimeofday: %m"); + return 0; + } + + if (now.tv_sec > exp->tv_sec + || (now.tv_sec == exp->tv_sec && now.tv_usec >= exp->tv_usec)) + return 0; + + diff->tv_sec = exp->tv_sec - now.tv_sec; + diff->tv_usec = exp->tv_usec - now.tv_usec; + if (diff->tv_usec < 0) { + diff->tv_usec += 1000000; + --diff->tv_sec; + } + + return 1; +} + /********************************************************************** *%FUNCTION: parseForHostUniq *%ARGUMENTS: @@ -323,6 +347,8 @@ waitForPADO(PPPoEConnection *conn, int timeout) fd_set readable; int r; struct timeval tv; + struct timeval expire_at; + PPPoEPacket packet; int len; @@ -335,10 +361,16 @@ waitForPADO(PPPoEConnection *conn, int timeout) conn->seenMaxPayload = 0; conn->error = 0; + if (gettimeofday(&expire_at, NULL) < 0) { + error("gettimeofday (waitForPADO): %m"); + return; + } + expire_at.tv_sec += timeout; + do { if (BPF_BUFFER_IS_EMPTY) { - tv.tv_sec = timeout; - tv.tv_usec = 0; + if (!time_left(&tv, &expire_at)) + return; /* Timed out */ FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); @@ -351,7 +383,8 @@ waitForPADO(PPPoEConnection *conn, int timeout) error("select (waitForPADO): %m"); return; } - if (r == 0) return; /* Timed out */ + if (r == 0) + return; /* Timed out */ } /* Get the packet */ @@ -507,14 +540,22 @@ waitForPADS(PPPoEConnection *conn, int timeout) fd_set readable; int r; struct timeval tv; + struct timeval expire_at; + PPPoEPacket packet; int len; + if (gettimeofday(&expire_at, NULL) < 0) { + error("gettimeofday (waitForPADS): %m"); + return; + } + expire_at.tv_sec += timeout; + conn->error = 0; do { if (BPF_BUFFER_IS_EMPTY) { - tv.tv_sec = timeout; - tv.tv_usec = 0; + if (!time_left(&tv, &expire_at)) + return; /* Timed out */ FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); @@ -527,7 +568,8 @@ waitForPADS(PPPoEConnection *conn, int timeout) error("select (waitForPADS): %m"); return; } - if (r == 0) return; + if (r == 0) + return; /* Timed out */ } /* Get the packet */ @@ -590,9 +632,6 @@ discovery(PPPoEConnection *conn) int padrAttempts = 0; int timeout = conn->discoveryTimeout; - conn->discoverySocket = - openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth); - do { padiAttempts++; if (padiAttempts > MAX_PADI_ATTEMPTS) { diff --git a/pppd/plugins/rp-pppoe/plugin.c b/pppd/plugins/rp-pppoe/plugin.c index 97011aa..a8c2bb4 100644 --- a/pppd/plugins/rp-pppoe/plugin.c +++ b/pppd/plugins/rp-pppoe/plugin.c @@ -49,7 +49,6 @@ static char const RCSID[] = #include #include #include -#include #include #ifndef _ROOT_PATH @@ -133,6 +132,17 @@ PPPOEConnectDevice(void) struct ifreq ifr; int s; + /* Open session socket before discovery phase, to avoid losing session */ + /* packets sent by peer just after PADS packet (noted on some Cisco */ + /* server equipment). */ + /* Opening this socket just before waitForPADS in the discovery() */ + /* function would be more appropriate, but it would mess-up the code */ + conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE); + if (conn->sessionSocket < 0) { + error("Failed to create PPPoE socket: %m"); + return -1; + } + /* Restore configuration */ lcp_allowoptions[0].mru = conn->mtu; lcp_wantoptions[0].mru = conn->mru; @@ -172,23 +182,18 @@ PPPOEConnectDevice(void) conn->peerEth[i] = (unsigned char) mac[i]; } } else { + conn->discoverySocket = + openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth); discovery(conn); if (conn->discoveryState != STATE_SESSION) { error("Unable to complete PPPoE Discovery"); - return -1; + goto errout; } } /* Set PPPoE session-number for further consumption */ ppp_session_number = ntohs(conn->session); - /* Make the session socket */ - conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE); - if (conn->sessionSocket < 0) { - error("Failed to create PPPoE socket: %m"); - goto errout; - } - sp.sa_family = AF_PPPOX; sp.sa_protocol = PX_PROTO_OE; sp.sa_addr.pppoe.sid = conn->session; @@ -218,7 +223,6 @@ PPPOEConnectDevice(void) if (connect(conn->sessionSocket, (struct sockaddr *) &sp, sizeof(struct sockaddr_pppox)) < 0) { error("Failed to connect PPPoE socket: %d %m", errno); - close(conn->sessionSocket); goto errout; } @@ -230,6 +234,7 @@ PPPOEConnectDevice(void) close(conn->discoverySocket); conn->discoverySocket = -1; } + close(conn->sessionSocket); return -1; } -- 2.39.2