rp-pppoe plugin: Import some fixes from rp-pppoe-3.10
authorPaul Mackerras <paulus@samba.org>
Sun, 20 May 2012 09:36:23 +0000 (19:36 +1000)
committerPaul Mackerras <paulus@samba.org>
Sun, 20 May 2012 09:36:23 +0000 (19:36 +1000)
* 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 <paulus@samba.org>
pppd/plugins/rp-pppoe/discovery.c
pppd/plugins/rp-pppoe/plugin.c

index a856490f96fb7ba887ae2e8dda16a91eae358769..04877cb8295f767d90c989142da799a14c3fc4ec 100644 (file)
@@ -40,6 +40,30 @@ static char const RCSID[] =
 
 #include <signal.h>
 
+/* 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) {
index 97011aaab938cc5066281846113ebf1bac32921a..a8c2bb4f4a6aec1cb76f30ebfa5403f852cc092f 100644 (file)
@@ -49,7 +49,6 @@ static char const RCSID[] =
 #include <net/ethernet.h>
 #include <net/if_arp.h>
 #include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
 #include <linux/if_pppox.h>
 
 #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;
 }