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 <benjamin.cama@telecom-bretagne.eu>
Signed-off-by: Paul Mackerras <paulus@samba.org>
ipv6cp_options *wo = &ipv6cp_wantoptions[u];
#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
ipv6cp_options *wo = &ipv6cp_wantoptions[u];
#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+#if defined(SOL2) || defined(__linux__)
if (!sif6up(u))
return 0;
#else
if (!sifup(u))
return 0;
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;
#endif
if (!sif6addr(u, wo->ourid, wo->hisid))
return 0;
#endif
/* bring the interface up for IPv6 */
#endif
/* bring the interface up for IPv6 */
+#if defined(SOL2) || defined(__linux__)
if (!sif6up(f->unit)) {
if (debug)
if (!sif6up(f->unit)) {
if (debug)
- warn("sifup failed (IPV6)");
+ warn("sif6up failed (IPV6)");
ipv6cp_close(f->unit, "Interface configuration failed");
return;
}
ipv6cp_close(f->unit, "Interface configuration failed");
return;
}
ipv6cp_close(f->unit, "Interface configuration failed");
return;
}
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)) {
#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
ipv6cp_clear_addrs(f->unit,
ipv6cp_gotoptions[f->unit].ourid,
ipv6cp_hisoptions[f->unit].hisid);
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
}
sifdown(f->unit);
#endif
}
static unsigned char inbuf[512]; /* buffer for chars read from loopback */
static int if_is_up; /* Interface has been marked up */
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 */
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 */
if_is_up = 0;
sifdown(0);
}
if_is_up = 0;
sifdown(0);
}
+ if (if6_is_up)
+ sif6down(0);
+
/*
* Delete any routes through the device.
*/
/*
* Delete any routes through the device.
*/
- 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;
- }
- 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++;
}
/********************************************************************
}
/********************************************************************
if (if_is_up && --if_is_up > 0)
return 1;
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) {
memset (&ifr, '\0', sizeof (ifr));
strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 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))
ifr.ifr_flags |= IFF_POINTOPOINT;
if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
if (! ok_error (errno))