lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <78EAC2D97114034EB62AAA10FCC2510608047D83@USA7061MS01.na.xerox.net>
Date:	Fri, 14 Nov 2008 14:59:27 -0800
From:	"Tarr, Stephen F" <Stephen.Tarr@...ox.com>
To:	<netdev@...r.kernel.org>
Subject: IPv6 and link state transitions

I'm using 2.6.27.4 on a powerpc with the gianfar Ethernet driver
and an MII PHY.  If I boot the system with the Ethernet cable
disconnected, wait 30 seconds or so, then plug in the cable, the
interface comes up but I don't see the expected IPv6 DAD probe
for the link-local address.

Adding some printfs in addrconf.c shows a NETDEV_UP when the
interface is initialized but no NETDEV_CHANGE when the link comes
up.  The transition is detected by the phy driver but filtered out
by the test-and-clear in netif_carrier_on because
(dev->state & NOCARRIER) is already clear.

With Brian Haley's patch to force a link state transition at
startup, the behavior gets even more interesting.  In that case,
I see the initial NETDEV_UP and an immediate NETDEV_CHANGE/link
down.  When the cable's connected, I see a NETDEV_CHANGE/link up
followed by an immediate MLDv2 announcement and a DAD probe.
(These were apparently queued up by the NETDEV_UP event, but
held off by the Ethernet driver.)  After the initialization
timeout, I see the expected DAD probe, router solicitation and
so on.

This patch to the gianfar driver fixes the problem, but only for
that driver.  A better approach might be to set the initial link
state in the phy driver, but I'd appreciate some suggestions for
how and where to do that.

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 3bc19b7..46566ba 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -533,6 +533,9 @@ static int init_phy(struct net_device *dev)
        char phy_id[BUS_ID_SIZE];
        phy_interface_t interface;

+       // assume link down until phy reports otherwise
+       set_bit(__LINK_STATE_NOCARRIER, &dev->state);
+
        priv->oldlink = 0;
        priv->oldspeed = 0;
        priv->oldduplex = -1;


There's a related problem if the cable is disconnected and
reconnected (perhaps to a different network).  In that case,
addrconf assumes that the previously autoconfigured addresses
are still valid, at least until it receives a router advertisement
on the new network.  The following patch against 2.6.27.4 is an
attempt to fix that problem, pick up the logic of Brian's patch,
and streamline the handling of NETDEV_UP and NETDEV_CHANGE.  The
significant logic change is the call to addrconf_ifdown when the
link goes away.  Again, I'd appreciate suggestions for a better
way to do this:

--- a/net/ipv6/addrconf.c       2008-11-13 23:38:16.178646603 -0800
+++ b/net/ipv6/addrconf.c       2008-11-13 23:38:40.986501970 -0800
@@ -2468,46 +2468,36 @@
        case NETDEV_UP:
        case NETDEV_CHANGE:
                if (dev->flags & IFF_SLAVE)
                        break;

-               if (event == NETDEV_UP) {
-                       if (!addrconf_qdisc_ok(dev)) {
-                               /* device is not ready yet. */
-                               printk(KERN_INFO
-                                       "ADDRCONF(NETDEV_UP): %s: "
-                                       "link is not ready\n",
-                                       dev->name);
-                               break;
-                       }
-
-                       if (!idev && dev->mtu >= IPV6_MIN_MTU)
-                               idev = ipv6_add_dev(dev);
-
-                       if (idev)
-                               idev->if_flags |= IF_READY;
-               } else {
-                       if (!addrconf_qdisc_ok(dev)) {
-                               /* device is still not ready. */
-                               break;
-                       }
-
-                       if (idev) {
-                               if (idev->if_flags & IF_READY) {
-                                       /* device is already configured.
*/
-                                       break;
-                               }
-                               idev->if_flags |= IF_READY;
-                       }
-
-                       printk(KERN_INFO
-                                       "ADDRCONF(NETDEV_CHANGE): %s: "
-                                       "link becomes ready\n",
-                                       dev->name);
-
-                       run_pending = 1;
-               }
+               if (!addrconf_qdisc_ok(dev)) {
+                       /* device is not ready. */
+                       printk(KERN_INFO
+                               "ADDRCONF(%s): %s: link is down\n",
+                               (event == NETDEV_UP)
+                                       ? "NETDEV_UP" : "NETDEV_CHANGE",
+                               dev->name);
+                       if (event == NETDEV_CHANGE) {
+                           addrconf_ifdown(dev, 1);
+                       }
+                       break;
+               }
+
+               printk(KERN_INFO
+                       "ADDRCONF(%s): %s: link is up\n",
+                       (event == NETDEV_UP)
+                               ? "NETDEV_UP" : "NETDEV_CHANGE",
+                       dev->name);
+
+               if (!idev && dev->mtu >= IPV6_MIN_MTU)
+                       idev = ipv6_add_dev(dev);
+
+               if (idev && !(idev->if_flags & IF_READY)) {
+                       idev->if_flags |= IF_READY;
+                       run_pending = 1;
+               }

                switch(dev->type) {
 #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
                case ARPHRD_SIT:
                        addrconf_sit_config(dev);



-Steve Tarr
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ