|
@@ -1724,6 +1724,7 @@ static int __bond_release_one(struct net_device *bond_dev,
|
|
|
struct bonding *bond = netdev_priv(bond_dev);
|
|
|
struct slave *slave, *oldcurrent;
|
|
|
struct sockaddr addr;
|
|
|
+ int old_flags = bond_dev->flags;
|
|
|
netdev_features_t old_features = bond_dev->features;
|
|
|
|
|
|
/* slave is not a slave or master is not master of this slave */
|
|
@@ -1855,12 +1856,18 @@ static int __bond_release_one(struct net_device *bond_dev,
|
|
|
* bond_change_active_slave(..., NULL)
|
|
|
*/
|
|
|
if (!USES_PRIMARY(bond->params.mode)) {
|
|
|
- /* unset promiscuity level from slave */
|
|
|
- if (bond_dev->flags & IFF_PROMISC)
|
|
|
+ /* unset promiscuity level from slave
|
|
|
+ * NOTE: The NETDEV_CHANGEADDR call above may change the value
|
|
|
+ * of the IFF_PROMISC flag in the bond_dev, but we need the
|
|
|
+ * value of that flag before that change, as that was the value
|
|
|
+ * when this slave was attached, so we cache at the start of the
|
|
|
+ * function and use it here. Same goes for ALLMULTI below
|
|
|
+ */
|
|
|
+ if (old_flags & IFF_PROMISC)
|
|
|
dev_set_promiscuity(slave_dev, -1);
|
|
|
|
|
|
/* unset allmulti level from slave */
|
|
|
- if (bond_dev->flags & IFF_ALLMULTI)
|
|
|
+ if (old_flags & IFF_ALLMULTI)
|
|
|
dev_set_allmulti(slave_dev, -1);
|
|
|
|
|
|
bond_hw_addr_flush(bond_dev, slave_dev);
|