diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 60 |
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 | ||
4991 | static int __dev_set_promiscuity(struct net_device *dev, int inc) | 4991 | static 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 | } |
5060 | EXPORT_SYMBOL(dev_set_promiscuity); | 5062 | EXPORT_SYMBOL(dev_set_promiscuity); |
5061 | 5063 | ||
5062 | /** | 5064 | static 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 | |||
5075 | int 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 | |||
5109 | int dev_set_allmulti(struct net_device *dev, int inc) | ||
5110 | { | ||
5111 | return __dev_set_allmulti(dev, inc, true); | ||
5112 | } | ||
5103 | EXPORT_SYMBOL(dev_set_allmulti); | 5113 | EXPORT_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, | |||
5271 | int dev_change_flags(struct net_device *dev, unsigned int flags) | 5285 | int 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 | } |