|
|
@@ -942,7 +942,7 @@ int dev_open(struct net_device *dev)
|
|
|
/*
|
|
|
* Initialize multicasting status
|
|
|
*/
|
|
|
- dev_mc_upload(dev);
|
|
|
+ dev_set_rx_mode(dev);
|
|
|
|
|
|
/*
|
|
|
* Wakeup transmit queue engine
|
|
|
@@ -2498,17 +2498,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * dev_set_promiscuity - update promiscuity count on a device
|
|
|
- * @dev: device
|
|
|
- * @inc: modifier
|
|
|
- *
|
|
|
- * Add or remove promiscuity from a device. While the count in the device
|
|
|
- * remains above zero the interface remains promiscuous. Once it hits zero
|
|
|
- * the device reverts back to normal filtering operation. A negative inc
|
|
|
- * value is used to drop promiscuity on the device.
|
|
|
- */
|
|
|
-void dev_set_promiscuity(struct net_device *dev, int inc)
|
|
|
+static void __dev_set_promiscuity(struct net_device *dev, int inc)
|
|
|
{
|
|
|
unsigned short old_flags = dev->flags;
|
|
|
|
|
|
@@ -2517,7 +2507,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
|
|
|
else
|
|
|
dev->flags |= IFF_PROMISC;
|
|
|
if (dev->flags != old_flags) {
|
|
|
- dev_mc_upload(dev);
|
|
|
printk(KERN_INFO "device %s %s promiscuous mode\n",
|
|
|
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
|
|
|
"left");
|
|
|
@@ -2530,6 +2519,25 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * dev_set_promiscuity - update promiscuity count on a device
|
|
|
+ * @dev: device
|
|
|
+ * @inc: modifier
|
|
|
+ *
|
|
|
+ * Add or remove promiscuity from a device. While the count in the device
|
|
|
+ * remains above zero the interface remains promiscuous. Once it hits zero
|
|
|
+ * the device reverts back to normal filtering operation. A negative inc
|
|
|
+ * value is used to drop promiscuity on the device.
|
|
|
+ */
|
|
|
+void dev_set_promiscuity(struct net_device *dev, int inc)
|
|
|
+{
|
|
|
+ unsigned short old_flags = dev->flags;
|
|
|
+
|
|
|
+ __dev_set_promiscuity(dev, inc);
|
|
|
+ if (dev->flags != old_flags)
|
|
|
+ dev_set_rx_mode(dev);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* dev_set_allmulti - update allmulti count on a device
|
|
|
* @dev: device
|
|
|
@@ -2550,7 +2558,48 @@ void dev_set_allmulti(struct net_device *dev, int inc)
|
|
|
if ((dev->allmulti += inc) == 0)
|
|
|
dev->flags &= ~IFF_ALLMULTI;
|
|
|
if (dev->flags ^ old_flags)
|
|
|
- dev_mc_upload(dev);
|
|
|
+ dev_set_rx_mode(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Upload unicast and multicast address lists to device and
|
|
|
+ * configure RX filtering. When the device doesn't support unicast
|
|
|
+ * filtering it is put in promiscous mode while unicast addresses
|
|
|
+ * are present.
|
|
|
+ */
|
|
|
+void __dev_set_rx_mode(struct net_device *dev)
|
|
|
+{
|
|
|
+ /* dev_open will call this function so the list will stay sane. */
|
|
|
+ if (!(dev->flags&IFF_UP))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!netif_device_present(dev))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (dev->set_rx_mode)
|
|
|
+ dev->set_rx_mode(dev);
|
|
|
+ else {
|
|
|
+ /* Unicast addresses changes may only happen under the rtnl,
|
|
|
+ * therefore calling __dev_set_promiscuity here is safe.
|
|
|
+ */
|
|
|
+ if (dev->uc_count > 0 && !dev->uc_promisc) {
|
|
|
+ __dev_set_promiscuity(dev, 1);
|
|
|
+ dev->uc_promisc = 1;
|
|
|
+ } else if (dev->uc_count == 0 && dev->uc_promisc) {
|
|
|
+ __dev_set_promiscuity(dev, -1);
|
|
|
+ dev->uc_promisc = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dev->set_multicast_list)
|
|
|
+ dev->set_multicast_list(dev);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void dev_set_rx_mode(struct net_device *dev)
|
|
|
+{
|
|
|
+ netif_tx_lock_bh(dev);
|
|
|
+ __dev_set_rx_mode(dev);
|
|
|
+ netif_tx_unlock_bh(dev);
|
|
|
}
|
|
|
|
|
|
int __dev_addr_delete(struct dev_addr_list **list, void *addr, int alen,
|
|
|
@@ -2622,6 +2671,66 @@ void __dev_addr_discard(struct dev_addr_list **list)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * dev_unicast_delete - Release secondary unicast address.
|
|
|
+ * @dev: device
|
|
|
+ *
|
|
|
+ * Release reference to a secondary unicast address and remove it
|
|
|
+ * from the device if the reference count drop to zero.
|
|
|
+ *
|
|
|
+ * The caller must hold the rtnl_mutex.
|
|
|
+ */
|
|
|
+int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ ASSERT_RTNL();
|
|
|
+
|
|
|
+ netif_tx_lock_bh(dev);
|
|
|
+ err = __dev_addr_delete(&dev->uc_list, addr, alen, 0);
|
|
|
+ if (!err) {
|
|
|
+ dev->uc_count--;
|
|
|
+ __dev_set_rx_mode(dev);
|
|
|
+ }
|
|
|
+ netif_tx_unlock_bh(dev);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dev_unicast_delete);
|
|
|
+
|
|
|
+/**
|
|
|
+ * dev_unicast_add - add a secondary unicast address
|
|
|
+ * @dev: device
|
|
|
+ *
|
|
|
+ * Add a secondary unicast address to the device or increase
|
|
|
+ * the reference count if it already exists.
|
|
|
+ *
|
|
|
+ * The caller must hold the rtnl_mutex.
|
|
|
+ */
|
|
|
+int dev_unicast_add(struct net_device *dev, void *addr, int alen)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ ASSERT_RTNL();
|
|
|
+
|
|
|
+ netif_tx_lock_bh(dev);
|
|
|
+ err = __dev_addr_add(&dev->uc_list, addr, alen, 0);
|
|
|
+ if (!err) {
|
|
|
+ dev->uc_count++;
|
|
|
+ __dev_set_rx_mode(dev);
|
|
|
+ }
|
|
|
+ netif_tx_unlock_bh(dev);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dev_unicast_add);
|
|
|
+
|
|
|
+static void dev_unicast_discard(struct net_device *dev)
|
|
|
+{
|
|
|
+ netif_tx_lock_bh(dev);
|
|
|
+ __dev_addr_discard(&dev->uc_list);
|
|
|
+ dev->uc_count = 0;
|
|
|
+ netif_tx_unlock_bh(dev);
|
|
|
+}
|
|
|
+
|
|
|
unsigned dev_get_flags(const struct net_device *dev)
|
|
|
{
|
|
|
unsigned flags;
|
|
|
@@ -2665,7 +2774,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
|
|
|
* Load in the correct multicast list now the flags have changed.
|
|
|
*/
|
|
|
|
|
|
- dev_mc_upload(dev);
|
|
|
+ dev_set_rx_mode(dev);
|
|
|
|
|
|
/*
|
|
|
* Have we downed the interface. We handle IFF_UP ourselves
|
|
|
@@ -2678,7 +2787,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
|
|
|
ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
|
|
|
|
|
|
if (!ret)
|
|
|
- dev_mc_upload(dev);
|
|
|
+ dev_set_rx_mode(dev);
|
|
|
}
|
|
|
|
|
|
if (dev->flags & IFF_UP &&
|
|
|
@@ -3558,8 +3667,9 @@ void unregister_netdevice(struct net_device *dev)
|
|
|
raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
|
|
|
|
|
|
/*
|
|
|
- * Flush the multicast chain
|
|
|
+ * Flush the unicast and multicast chains
|
|
|
*/
|
|
|
+ dev_unicast_discard(dev);
|
|
|
dev_mc_discard(dev);
|
|
|
|
|
|
if (dev->uninit)
|