* 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>
+/* 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:
/**********************************************************************
*%FUNCTION: parseForHostUniq
*%ARGUMENTS:
fd_set readable;
int r;
struct timeval tv;
fd_set readable;
int r;
struct timeval tv;
+ struct timeval expire_at;
+
PPPoEPacket packet;
int len;
PPPoEPacket packet;
int len;
conn->seenMaxPayload = 0;
conn->error = 0;
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) {
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);
FD_ZERO(&readable);
FD_SET(conn->discoverySocket, &readable);
error("select (waitForPADO): %m");
return;
}
error("select (waitForPADO): %m");
return;
}
- if (r == 0) return; /* Timed out */
+ if (r == 0)
+ return; /* Timed out */
fd_set readable;
int r;
struct timeval tv;
fd_set readable;
int r;
struct timeval tv;
+ struct timeval expire_at;
+
PPPoEPacket packet;
int len;
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) {
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);
FD_ZERO(&readable);
FD_SET(conn->discoverySocket, &readable);
error("select (waitForPADS): %m");
return;
}
error("select (waitForPADS): %m");
return;
}
+ if (r == 0)
+ return; /* Timed out */
int padrAttempts = 0;
int timeout = conn->discoveryTimeout;
int padrAttempts = 0;
int timeout = conn->discoveryTimeout;
- conn->discoverySocket =
- openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
-
do {
padiAttempts++;
if (padiAttempts > MAX_PADI_ATTEMPTS) {
do {
padiAttempts++;
if (padiAttempts > MAX_PADI_ATTEMPTS) {
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <linux/ppp_defs.h>
#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
#include <linux/if_pppox.h>
#ifndef _ROOT_PATH
+ /* 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;
/* Restore configuration */
lcp_allowoptions[0].mru = conn->mtu;
lcp_wantoptions[0].mru = conn->mru;
conn->peerEth[i] = (unsigned char) mac[i];
}
} else {
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");
discovery(conn);
if (conn->discoveryState != STATE_SESSION) {
error("Unable to complete PPPoE Discovery");
}
}
/* Set PPPoE session-number for further consumption */
ppp_session_number = ntohs(conn->session);
}
}
/* 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;
sp.sa_family = AF_PPPOX;
sp.sa_protocol = PX_PROTO_OE;
sp.sa_addr.pppoe.sid = conn->session;
if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
sizeof(struct sockaddr_pppox)) < 0) {
error("Failed to connect PPPoE socket: %d %m", errno);
if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
sizeof(struct sockaddr_pppox)) < 0) {
error("Failed to connect PPPoE socket: %d %m", errno);
- close(conn->sessionSocket);
close(conn->discoverySocket);
conn->discoverySocket = -1;
}
close(conn->discoverySocket);
conn->discoverySocket = -1;
}
+ close(conn->sessionSocket);