From: Benjamin Cama Date: Wed, 26 Feb 2014 18:13:39 +0000 (+0100) Subject: pppd: Separate IPv6 handling for sifup/sifdown X-Git-Tag: ppp-2.4.7~10 X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=b04d2dc6df5c6b5650fea44250d58757ee3dac4a pppd: Separate IPv6 handling for sifup/sifdown The current code is buggy regarding handling of link state when using both IPCP and IPv6CP: if IPv6CP has been set up and if during IPCP negociation, ipcp_up() fails, it will incorrectly take the interface down. The simple solution here is to change the platform code to do the same as on Solaris: separate IPv6CP up/down state handling with sif6up() and sif6down(), so that we really know when the interface is allowed to go down. Signed-off-by: Benjamin Cama Signed-off-by: Paul Mackerras --- diff --git a/pppd/ipv6cp.c b/pppd/ipv6cp.c index caa2b26..7e76073 100644 --- a/pppd/ipv6cp.c +++ b/pppd/ipv6cp.c @@ -1147,13 +1147,13 @@ ipv6_demand_conf(u) ipv6cp_options *wo = &ipv6cp_wantoptions[u]; #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__))) -#if defined(SOL2) +#if defined(SOL2) || defined(__linux__) if (!sif6up(u)) return 0; #else if (!sifup(u)) return 0; -#endif /* defined(SOL2) */ +#endif /* defined(SOL2) || defined(__linux__) */ #endif if (!sif6addr(u, wo->ourid, wo->hisid)) return 0; @@ -1260,10 +1260,10 @@ ipv6cp_up(f) #endif /* bring the interface up for IPv6 */ -#if defined(SOL2) +#if defined(SOL2) || defined(__linux__) if (!sif6up(f->unit)) { if (debug) - warn("sifup failed (IPV6)"); + warn("sif6up failed (IPV6)"); ipv6cp_close(f->unit, "Interface configuration failed"); return; } @@ -1274,7 +1274,7 @@ ipv6cp_up(f) ipv6cp_close(f->unit, "Interface configuration failed"); return; } -#endif /* defined(SOL2) */ +#endif /* defined(SOL2) || defined(__linux__) */ #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sif6addr(f->unit, go->ourid, ho->hisid)) { @@ -1349,7 +1349,9 @@ ipv6cp_down(f) ipv6cp_clear_addrs(f->unit, ipv6cp_gotoptions[f->unit].ourid, ipv6cp_hisoptions[f->unit].hisid); -#if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC))) +#if defined(__linux__) + sif6down(f->unit); +#elif defined(SVR4) && (defined(SNI) || defined(__USLC)) sifdown(f->unit); #endif } diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 72a7727..a0af43b 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -205,6 +205,7 @@ static char loop_name[20]; static unsigned char inbuf[512]; /* buffer for chars read from loopback */ static int if_is_up; /* Interface has been marked up */ +static int if6_is_up; /* Interface has been marked up for IPv6, to help differentiate */ static int have_default_route; /* Gateway for default route added */ static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */ static char proxy_arp_dev[16]; /* Device for proxy arp entry */ @@ -338,6 +339,9 @@ void sys_cleanup(void) if_is_up = 0; sifdown(0); } + if (if6_is_up) + sif6down(0); + /* * Delete any routes through the device. */ @@ -2252,25 +2256,12 @@ int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid) int sifup(int u) { - struct ifreq ifr; - - memset (&ifr, '\0', sizeof (ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { - if (! ok_error (errno)) - error("ioctl (SIOCGIFFLAGS): %m (line %d)", __LINE__); - return 0; - } + int ret; - ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT); - if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { - if (! ok_error (errno)) - error("ioctl(SIOCSIFFLAGS): %m (line %d)", __LINE__); - return 0; - } - if_is_up++; + if ((ret = setifstate(u, 1))) + if_is_up++; - return 1; + return ret; } /******************************************************************** @@ -2281,11 +2272,59 @@ int sifup(int u) int sifdown (int u) { - struct ifreq ifr; - if (if_is_up && --if_is_up > 0) return 1; +#ifdef INET6 + if (if6_is_up) + return 1; +#endif /* INET6 */ + + return setifstate(u, 0); +} + +#ifdef INET6 +/******************************************************************** + * + * sif6up - Config the interface up for IPv6 + */ + +int sif6up(int u) +{ + int ret; + + if ((ret = setifstate(u, 1))) + if6_is_up = 1; + + return ret; +} + +/******************************************************************** + * + * sif6down - Disable the IPv6CP protocol and config the interface + * down if there are no remaining protocols. + */ + +int sif6down (int u) +{ + if6_is_up = 0; + + if (if_is_up) + return 1; + + return setifstate(u, 0); +} +#endif /* INET6 */ + +/******************************************************************** + * + * setifstate - Config the interface up or down + */ + +int setifstate (int u, int state) +{ + struct ifreq ifr; + memset (&ifr, '\0', sizeof (ifr)); strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { @@ -2294,7 +2333,10 @@ int sifdown (int u) return 0; } - ifr.ifr_flags &= ~IFF_UP; + if (state) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; ifr.ifr_flags |= IFF_POINTOPOINT; if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { if (! ok_error (errno))