Commit 991fb3f7 authored by Nicolas Dichtel's avatar Nicolas Dichtel Committed by David S. Miller

dev: always advertise rx_flags changes via netlink

When flags IFF_PROMISC and IFF_ALLMULTI are changed, netlink messages are not
consistent. For example, if a multicast daemon is running (flag IFF_ALLMULTI
set in dev->flags but not dev->gflags, ie not exported to userspace) and then a
user sets it via netlink (flag IFF_ALLMULTI set in dev->flags and dev->gflags, ie
exported to userspace), no netlink message is sent.
Same for IFF_PROMISC and because dev->promiscuity is exported via
IFLA_PROMISCUITY, we may send a netlink message after each change of this
counter.
Signed-off-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a528c219
...@@ -4988,7 +4988,7 @@ static void dev_change_rx_flags(struct net_device *dev, int flags) ...@@ -4988,7 +4988,7 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
ops->ndo_change_rx_flags(dev, flags); ops->ndo_change_rx_flags(dev, flags);
} }
static int __dev_set_promiscuity(struct net_device *dev, int inc) static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
{ {
unsigned int old_flags = dev->flags; unsigned int old_flags = dev->flags;
kuid_t uid; kuid_t uid;
...@@ -5031,6 +5031,8 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc) ...@@ -5031,6 +5031,8 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
dev_change_rx_flags(dev, IFF_PROMISC); dev_change_rx_flags(dev, IFF_PROMISC);
} }
if (notify)
__dev_notify_flags(dev, old_flags, IFF_PROMISC);
return 0; return 0;
} }
...@@ -5050,7 +5052,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc) ...@@ -5050,7 +5052,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc)
unsigned int old_flags = dev->flags; unsigned int old_flags = dev->flags;
int err; int err;
err = __dev_set_promiscuity(dev, inc); err = __dev_set_promiscuity(dev, inc, true);
if (err < 0) if (err < 0)
return err; return err;
if (dev->flags != old_flags) if (dev->flags != old_flags)
...@@ -5059,22 +5061,9 @@ int dev_set_promiscuity(struct net_device *dev, int inc) ...@@ -5059,22 +5061,9 @@ int dev_set_promiscuity(struct net_device *dev, int inc)
} }
EXPORT_SYMBOL(dev_set_promiscuity); EXPORT_SYMBOL(dev_set_promiscuity);
/** static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify)
* dev_set_allmulti - update allmulti count on a device
* @dev: device
* @inc: modifier
*
* Add or remove reception of all multicast frames to a device. While the
* count in the device remains above zero the interface remains listening
* to all interfaces. Once it hits zero the device reverts back to normal
* filtering operation. A negative @inc value is used to drop the counter
* when releasing a resource needing all multicasts.
* Return 0 if successful or a negative errno code on error.
*/
int dev_set_allmulti(struct net_device *dev, int inc)
{ {
unsigned int old_flags = dev->flags; unsigned int old_flags = dev->flags, old_gflags = dev->gflags;
ASSERT_RTNL(); ASSERT_RTNL();
...@@ -5097,9 +5086,30 @@ int dev_set_allmulti(struct net_device *dev, int inc) ...@@ -5097,9 +5086,30 @@ int dev_set_allmulti(struct net_device *dev, int inc)
if (dev->flags ^ old_flags) { if (dev->flags ^ old_flags) {
dev_change_rx_flags(dev, IFF_ALLMULTI); dev_change_rx_flags(dev, IFF_ALLMULTI);
dev_set_rx_mode(dev); dev_set_rx_mode(dev);
if (notify)
__dev_notify_flags(dev, old_flags,
dev->gflags ^ old_gflags);
} }
return 0; return 0;
} }
/**
* dev_set_allmulti - update allmulti count on a device
* @dev: device
* @inc: modifier
*
* Add or remove reception of all multicast frames to a device. While the
* count in the device remains above zero the interface remains listening
* to all interfaces. Once it hits zero the device reverts back to normal
* filtering operation. A negative @inc value is used to drop the counter
* when releasing a resource needing all multicasts.
* Return 0 if successful or a negative errno code on error.
*/
int dev_set_allmulti(struct net_device *dev, int inc)
{
return __dev_set_allmulti(dev, inc, true);
}
EXPORT_SYMBOL(dev_set_allmulti); EXPORT_SYMBOL(dev_set_allmulti);
/* /*
...@@ -5124,10 +5134,10 @@ void __dev_set_rx_mode(struct net_device *dev) ...@@ -5124,10 +5134,10 @@ void __dev_set_rx_mode(struct net_device *dev)
* therefore calling __dev_set_promiscuity here is safe. * therefore calling __dev_set_promiscuity here is safe.
*/ */
if (!netdev_uc_empty(dev) && !dev->uc_promisc) { if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
__dev_set_promiscuity(dev, 1); __dev_set_promiscuity(dev, 1, false);
dev->uc_promisc = true; dev->uc_promisc = true;
} else if (netdev_uc_empty(dev) && dev->uc_promisc) { } else if (netdev_uc_empty(dev) && dev->uc_promisc) {
__dev_set_promiscuity(dev, -1); __dev_set_promiscuity(dev, -1, false);
dev->uc_promisc = false; dev->uc_promisc = false;
} }
} }
...@@ -5216,9 +5226,13 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags) ...@@ -5216,9 +5226,13 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags)
if ((flags ^ dev->gflags) & IFF_PROMISC) { if ((flags ^ dev->gflags) & IFF_PROMISC) {
int inc = (flags & IFF_PROMISC) ? 1 : -1; int inc = (flags & IFF_PROMISC) ? 1 : -1;
unsigned int old_flags = dev->flags;
dev->gflags ^= IFF_PROMISC; dev->gflags ^= IFF_PROMISC;
dev_set_promiscuity(dev, inc);
if (__dev_set_promiscuity(dev, inc, false) >= 0)
if (dev->flags != old_flags)
dev_set_rx_mode(dev);
} }
/* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI
...@@ -5229,7 +5243,7 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags) ...@@ -5229,7 +5243,7 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags)
int inc = (flags & IFF_ALLMULTI) ? 1 : -1; int inc = (flags & IFF_ALLMULTI) ? 1 : -1;
dev->gflags ^= IFF_ALLMULTI; dev->gflags ^= IFF_ALLMULTI;
dev_set_allmulti(dev, inc); __dev_set_allmulti(dev, inc, false);
} }
return ret; return ret;
...@@ -5271,13 +5285,13 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, ...@@ -5271,13 +5285,13 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
int dev_change_flags(struct net_device *dev, unsigned int flags) int dev_change_flags(struct net_device *dev, unsigned int flags)
{ {
int ret; int ret;
unsigned int changes, old_flags = dev->flags; unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags;
ret = __dev_change_flags(dev, flags); ret = __dev_change_flags(dev, flags);
if (ret < 0) if (ret < 0)
return ret; return ret;
changes = old_flags ^ dev->flags; changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags);
__dev_notify_flags(dev, old_flags, changes); __dev_notify_flags(dev, old_flags, changes);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment