net: Fix continued iteration in rtnl_bridge_getlink()
authorBen Hutchings <bhutchings@solarflare.com>
Fri, 2 Nov 2012 12:56:52 +0000 (12:56 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 3 Nov 2012 01:53:35 +0000 (21:53 -0400)
Commit e5a55a898720096f43bc24938f8875c0a1b34cd7 ('net: create generic
bridge ops') broke the handling of a non-zero starting index in
rtnl_bridge_getlink() (based on the old br_dump_ifinfo()).

When the starting index is non-zero, we need to increment the current
index for each entry that we are skipping.  Also, we need to check the
index before both cases, since we may previously have stopped
iteration between getting information about a device from its master
and from itself.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Tested-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/rtnetlink.c

index 51dc58ff009100f766c640a43dae7f03deb10f7d..a0e350763fbef3a08dfee9f3734e23ad8d5dbb64 100644 (file)
@@ -2315,28 +2315,19 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
                const struct net_device_ops *ops = dev->netdev_ops;
                struct net_device *master = dev->master;
 
-               if (idx < cb->args[0])
-                       continue;
-
                if (master && master->netdev_ops->ndo_bridge_getlink) {
-                       const struct net_device_ops *bops = master->netdev_ops;
-                       int err = bops->ndo_bridge_getlink(skb, portid,
-                                                          seq, dev);
-
-                       if (err < 0)
+                       if (idx >= cb->args[0] &&
+                           master->netdev_ops->ndo_bridge_getlink(
+                                   skb, portid, seq, dev) < 0)
                                break;
-                       else
-                               idx++;
+                       idx++;
                }
 
                if (ops->ndo_bridge_getlink) {
-                       int err = ops->ndo_bridge_getlink(skb, portid,
-                                                         seq, dev);
-
-                       if (err < 0)
+                       if (idx >= cb->args[0] &&
+                           ops->ndo_bridge_getlink(skb, portid, seq, dev) < 0)
                                break;
-                       else
-                               idx++;
+                       idx++;
                }
        }
        rcu_read_unlock();