***********************************************************************/
static char const RCSID[] =
-"$Id: plugin.c,v 1.16 2008/06/09 08:34:23 paulus Exp $";
+"$Id: plugin.c,v 1.17 2008/06/15 04:35:50 paulus Exp $";
#define _GNU_SOURCE 1
#include "pppoe.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
static char *acName = NULL;
static char *existingSession = NULL;
static int printACNames = 0;
+static char *pppoe_reqd_mac = NULL;
+unsigned char pppoe_reqd_mac_addr[6];
static int PPPoEDevnameHook(char *cmd, char **argv, int doit);
static option_t Options[] = {
"Attach to existing session (sessid:macaddr)" },
{ "rp_pppoe_verbose", o_int, &printACNames,
"Be verbose about discovered access concentrators"},
+ { "pppoe-mac", o_string, &pppoe_reqd_mac,
+ "Only connect to specified MAC address" },
{ NULL }
};
int (*OldDevnameHook)(char *cmd, char **argv, int doit) = NULL;
novm("PPPoE session data");
}
memset(conn, 0, sizeof(PPPoEConnection));
- conn->acName = acName;
- conn->serviceName = pppd_pppoe_service;
conn->ifName = devnam;
conn->discoverySocket = -1;
conn->sessionSocket = -1;
PPPOEConnectDevice(void)
{
struct sockaddr_pppox sp;
+ 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;
+
+ /* Update maximum MRU */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ error("Can't get MTU for %s: %m", conn->ifName);
+ goto errout;
+ }
+ strncpy(ifr.ifr_name, conn->ifName, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
+ error("Can't get MTU for %s: %m", conn->ifName);
+ close(s);
+ goto errout;
+ }
+ close(s);
+
+ if (lcp_allowoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
+ lcp_allowoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+ if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
+ lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+ conn->acName = acName;
+ conn->serviceName = pppd_pppoe_service;
strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
if (existingSession) {
unsigned int mac[ETH_ALEN];
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;
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;
}
close(conn->discoverySocket);
conn->discoverySocket = -1;
}
+ close(conn->sessionSocket);
return -1;
}
memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
- sizeof(struct sockaddr_pppox)) < 0)
+ sizeof(struct sockaddr_pppox)) < 0 && errno != EALREADY)
error("Failed to disconnect PPPoE socket: %d %m", errno);
close(conn->sessionSocket);
- /* don't send PADT?? */
- if (conn->discoverySocket >= 0)
+ if (conn->discoverySocket >= 0) {
+ sendPADT(conn, NULL);
close(conn->discoverySocket);
+ }
}
static void
void pppoe_check_options(void)
{
+ unsigned int mac[6];
+ int i;
+
+ if (pppoe_reqd_mac != NULL) {
+ if (sscanf(pppoe_reqd_mac, "%x:%x:%x:%x:%x:%x",
+ &mac[0], &mac[1], &mac[2], &mac[3],
+ &mac[4], &mac[5]) != 6) {
+ option_error("cannot parse pppoe-mac option value");
+ exit(EXIT_OPTION_ERROR);
+ }
+ for (i = 0; i < 6; ++i)
+ conn->req_peer_mac[i] = mac[i];
+ conn->req_peer = 1;
+ }
+
lcp_allowoptions[0].neg_accompression = 0;
lcp_wantoptions[0].neg_accompression = 0;
if (lcp_wantoptions[0].mru > MAX_PPPOE_MTU)
lcp_wantoptions[0].mru = MAX_PPPOE_MTU;
+ /* Save configuration */
+ conn->mtu = lcp_allowoptions[0].mru;
+ conn->mru = lcp_wantoptions[0].mru;
+
ccp_allowoptions[0].deflate = 0;
ccp_wantoptions[0].deflate = 0;