aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2013-09-25 06:02:45 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-30 15:08:13 -0400
commit991fb3f74c142e1a1891ff4f7e9a6285a79a8ea1 (patch)
tree30a883054bf34f8f4d8b52506bc8b844ddd30b83 /net/core/dev.c
parenta528c219df2e865e178c538c7178961dfed5a13c (diff)
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: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c60
1 files changed, 37 insertions, 23 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 594a6b0ab3da..81340ed7f0f4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4988,7 +4988,7 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
4988 ops->ndo_change_rx_flags(dev, flags); 4988 ops->ndo_change_rx_flags(dev, flags);
4989} 4989}
4990 4990
4991static int __dev_set_promiscuity(struct net_device *dev, int inc) 4991static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
4992{ 4992{
4993 unsigned int old_flags = dev->flags; 4993 unsigned int old_flags = dev->flags;
4994 kuid_t uid; 4994 kuid_t uid;
@@ -5031,6 +5031,8 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
5031 5031
5032 dev_change_rx_flags(dev, IFF_PROMISC); 5032 dev_change_rx_flags(dev, IFF_PROMISC);
5033 } 5033 }
5034 if (notify)
5035 __dev_notify_flags(dev, old_flags, IFF_PROMISC);
5034 return 0; 5036 return 0;
5035} 5037}
5036 5038
@@ -5050,7 +5052,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc)
5050 unsigned int old_flags = dev->flags; 5052 unsigned int old_flags = dev->flags;
5051 int err; 5053 int err;
5052 5054
5053 err = __dev_set_promiscuity(dev, inc); 5055 err = __dev_set_promiscuity(dev, inc, true);
5054 if (err < 0) 5056 if (err < 0)
5055 return err; 5057 return err;
5056 if (dev->flags != old_flags) 5058 if (dev->flags != old_flags)
@@ -5059,22 +5061,9 @@ int dev_set_promiscuity(struct net_device *dev, int inc)
5059} 5061}
5060EXPORT_SYMBOL(dev_set_promiscuity); 5062EXPORT_SYMBOL(dev_set_promiscuity);
5061 5063
5062/** 5064static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify)
5063 * dev_set_allmulti - update allmulti count on a device
5064 * @dev: device
5065 * @inc: modifier
5066 *
5067 * Add or remove reception of all multicast frames to a device. While the
5068 * count in the device remains above zero the interface remains listening
5069 * to all interfaces. Once it hits zero the device reverts back to normal
5070 * filtering operation. A negative @inc value is used to drop the counter
5071 * when releasing a resource needing all multicasts.
5072 * Return 0 if successful or a negative errno code on error.
5073 */
5074
5075int dev_set_allmulti(struct net_device *dev, int inc)
5076{ 5065{
5077 unsigned int old_flags = dev->flags; 5066 unsigned int old_flags = dev->flags, old_gflags = dev->gflags;
5078 5067
5079 ASSERT_RTNL(); 5068 ASSERT_RTNL();
5080 5069
@@ -5097,9 +5086,30 @@ int dev_set_allmulti(struct net_device *dev, int inc)
5097 if (dev->flags ^ old_flags) { 5086 if (dev->flags ^ old_flags) {
5098 dev_change_rx_flags(dev, IFF_ALLMULTI); 5087 dev_change_rx_flags(dev, IFF_ALLMULTI);
5099 dev_set_rx_mode(dev); 5088 dev_set_rx_mode(dev);
5089 if (notify)
5090 __dev_notify_flags(dev, old_flags,
5091 dev->gflags ^ old_gflags);
5100 } 5092 }
5101 return 0; 5093 return 0;
5102} 5094}
5095
5096/**
5097 * dev_set_allmulti - update allmulti count on a device
5098 * @dev: device
5099 * @inc: modifier
5100 *
5101 * Add or remove reception of all multicast frames to a device. While the
5102 * count in the device remains above zero the interface remains listening
5103 * to all interfaces. Once it hits zero the device reverts back to normal
5104 * filtering operation. A negative @inc value is used to drop the counter
5105 * when releasing a resource needing all multicasts.
5106 * Return 0 if successful or a negative errno code on error.
5107 */
5108
5109int dev_set_allmulti(struct net_device *dev, int inc)
5110{
5111 return __dev_set_allmulti(dev, inc, true);
5112}
5103EXPORT_SYMBOL(dev_set_allmulti); 5113EXPORT_SYMBOL(dev_set_allmulti);
5104 5114
5105/* 5115/*
@@ -5124,10 +5134,10 @@ void __dev_set_rx_mode(struct net_device *dev)
5124 * therefore calling __dev_set_promiscuity here is safe. 5134 * therefore calling __dev_set_promiscuity here is safe.
5125 */ 5135 */
5126 if (!netdev_uc_empty(dev) && !dev->uc_promisc) { 5136 if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
5127 __dev_set_promiscuity(dev, 1); 5137 __dev_set_promiscuity(dev, 1, false);
5128 dev->uc_promisc = true; 5138 dev->uc_promisc = true;
5129 } else if (netdev_uc_empty(dev) && dev->uc_promisc) { 5139 } else if (netdev_uc_empty(dev) && dev->uc_promisc) {
5130 __dev_set_promiscuity(dev, -1); 5140 __dev_set_promiscuity(dev, -1, false);
5131 dev->uc_promisc = false; 5141 dev->uc_promisc = false;
5132 } 5142 }
5133 } 5143 }
@@ -5216,9 +5226,13 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags)
5216 5226
5217 if ((flags ^ dev->gflags) & IFF_PROMISC) { 5227 if ((flags ^ dev->gflags) & IFF_PROMISC) {
5218 int inc = (flags & IFF_PROMISC) ? 1 : -1; 5228 int inc = (flags & IFF_PROMISC) ? 1 : -1;
5229 unsigned int old_flags = dev->flags;
5219 5230
5220 dev->gflags ^= IFF_PROMISC; 5231 dev->gflags ^= IFF_PROMISC;
5221 dev_set_promiscuity(dev, inc); 5232
5233 if (__dev_set_promiscuity(dev, inc, false) >= 0)
5234 if (dev->flags != old_flags)
5235 dev_set_rx_mode(dev);
5222 } 5236 }
5223 5237
5224 /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI 5238 /* 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 int inc = (flags & IFF_ALLMULTI) ? 1 : -1; 5243 int inc = (flags & IFF_ALLMULTI) ? 1 : -1;
5230 5244
5231 dev->gflags ^= IFF_ALLMULTI; 5245 dev->gflags ^= IFF_ALLMULTI;
5232 dev_set_allmulti(dev, inc); 5246 __dev_set_allmulti(dev, inc, false);
5233 } 5247 }
5234 5248
5235 return ret; 5249 return ret;
@@ -5271,13 +5285,13 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
5271int dev_change_flags(struct net_device *dev, unsigned int flags) 5285int dev_change_flags(struct net_device *dev, unsigned int flags)
5272{ 5286{
5273 int ret; 5287 int ret;
5274 unsigned int changes, old_flags = dev->flags; 5288 unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags;
5275 5289
5276 ret = __dev_change_flags(dev, flags); 5290 ret = __dev_change_flags(dev, flags);
5277 if (ret < 0) 5291 if (ret < 0)
5278 return ret; 5292 return ret;
5279 5293
5280 changes = old_flags ^ dev->flags; 5294 changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags);
5281 __dev_notify_flags(dev, old_flags, changes); 5295 __dev_notify_flags(dev, old_flags, changes);
5282 return ret; 5296 return ret;
5283} 5297}