X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fplugins%2Frp-pppoe%2Fplugin.c;h=c89be94250bc660203beb0a163776fddbb5d074b;hb=733c00a6ce0244ba5003f4f71a014db8200a30fe;hp=2968e72e93c2fb8936520888f0697b49f74852ae;hpb=427e3d851c86e35655e14f1dfa9c831a8fab94d9;p=ppp.git diff --git a/pppd/plugins/rp-pppoe/plugin.c b/pppd/plugins/rp-pppoe/plugin.c index 2968e72..c89be94 100644 --- a/pppd/plugins/rp-pppoe/plugin.c +++ b/pppd/plugins/rp-pppoe/plugin.c @@ -23,7 +23,7 @@ ***********************************************************************/ 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" @@ -49,7 +49,6 @@ static char const RCSID[] = #include #include #include -#include #include #ifndef _ROOT_PATH @@ -67,6 +66,8 @@ char *pppd_pppoe_service = NULL; 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[] = { @@ -82,6 +83,8 @@ 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; @@ -104,8 +107,6 @@ PPPOEInitDevice(void) 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; @@ -128,7 +129,45 @@ static int 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]; @@ -143,22 +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; @@ -188,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; } @@ -200,6 +234,7 @@ PPPOEConnectDevice(void) close(conn->discoverySocket); conn->discoverySocket = -1; } + close(conn->sessionSocket); return -1; } @@ -235,12 +270,13 @@ PPPOEDisconnectDevice(void) 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 @@ -348,6 +384,21 @@ plugin_init(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; @@ -362,6 +413,10 @@ void pppoe_check_options(void) 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;