Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4417da668c0021903464f92db278ddae348e0299
Commit:     4417da668c0021903464f92db278ddae348e0299
Parent:     3fba5a8b1e3df2384b90493538161e83cf15dd5f
Author:     Patrick McHardy <[EMAIL PROTECTED]>
AuthorDate: Wed Jun 27 01:28:10 2007 -0700
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Tue Jul 10 22:15:56 2007 -0700

    [NET]: dev: secondary unicast address support
    
    Add support for configuring secondary unicast addresses on network
    devices. To support this devices capable of filtering multiple
    unicast addresses need to change their set_multicast_list function
    to configure unicast filters as well and assign it to dev->set_rx_mode
    instead of dev->set_multicast_list. Other devices are put into promiscous
    mode when secondary unicast addresses are present.
    
    Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 include/linux/netdevice.h |   12 +++-
 net/core/dev.c            |  144 +++++++++++++++++++++++++++++++++++++++-----
 net/core/dev_mcast.c      |   37 +-----------
 3 files changed, 139 insertions(+), 54 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9e114e7..2c0cc19 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -397,6 +397,9 @@ struct net_device
        unsigned char           addr_len;       /* hardware address length      
*/
        unsigned short          dev_id;         /* for shared network cards */
 
+       struct dev_addr_list    *uc_list;       /* Secondary unicast mac 
addresses */
+       int                     uc_count;       /* Number of installed ucasts   
*/
+       int                     uc_promisc;
        struct dev_addr_list    *mc_list;       /* Multicast mac addresses      
*/
        int                     mc_count;       /* Number of installed mcasts   
*/
        int                     promiscuity;
@@ -502,6 +505,8 @@ struct net_device
                                                void *saddr,
                                                unsigned len);
        int                     (*rebuild_header)(struct sk_buff *skb);
+#define HAVE_SET_RX_MODE
+       void                    (*set_rx_mode)(struct net_device *dev);
 #define HAVE_MULTICAST                  
        void                    (*set_multicast_list)(struct net_device *dev);
 #define HAVE_SET_MAC_ADDR               
@@ -1008,8 +1013,11 @@ extern struct net_device *alloc_netdev(int sizeof_priv, 
const char *name,
                                       void (*setup)(struct net_device *));
 extern int             register_netdev(struct net_device *dev);
 extern void            unregister_netdev(struct net_device *dev);
-/* Functions used for multicast support */
-extern void            dev_mc_upload(struct net_device *dev);
+/* Functions used for secondary unicast and multicast support */
+extern void            dev_set_rx_mode(struct net_device *dev);
+extern void            __dev_set_rx_mode(struct net_device *dev);
+extern int             dev_unicast_delete(struct net_device *dev, void *addr, 
int alen);
+extern int             dev_unicast_add(struct net_device *dev, void *addr, int 
alen);
 extern int             dev_mc_delete(struct net_device *dev, void *addr, int 
alen, int all);
 extern int             dev_mc_add(struct net_device *dev, void *addr, int 
alen, int newonly);
 extern void            dev_mc_discard(struct net_device *dev);
diff --git a/net/core/dev.c b/net/core/dev.c
index 18759cc..36e9bf8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -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");
@@ -2531,6 +2520,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
  *     @inc: modifier
@@ -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)
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 7029074..5cc9b44 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -64,39 +64,6 @@
  */
 
 /*
- *     Update the multicast list into the physical NIC controller.
- */
-
-static void __dev_mc_upload(struct net_device *dev)
-{
-       /* Don't do anything till we up the interface
-        * [dev_open will call this function so the list will
-        * stay sane]
-        */
-
-       if (!(dev->flags&IFF_UP))
-               return;
-
-       /*
-        *      Devices with no set multicast or which have been
-        *      detached don't get set.
-        */
-
-       if (dev->set_multicast_list == NULL ||
-           !netif_device_present(dev))
-               return;
-
-       dev->set_multicast_list(dev);
-}
-
-void dev_mc_upload(struct net_device *dev)
-{
-       netif_tx_lock_bh(dev);
-       __dev_mc_upload(dev);
-       netif_tx_unlock_bh(dev);
-}
-
-/*
  *     Delete a device level multicast
  */
 
@@ -114,7 +81,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int 
alen, int glbl)
                 *      loaded filter is now wrong. Fix it
                 */
 
-               __dev_mc_upload(dev);
+               __dev_set_rx_mode(dev);
        }
        netif_tx_unlock_bh(dev);
        return err;
@@ -132,7 +99,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, 
int glbl)
        err = __dev_addr_add(&dev->mc_list, addr, alen, glbl);
        if (!err) {
                dev->mc_count++;
-               __dev_mc_upload(dev);
+               __dev_set_rx_mode(dev);
        }
        netif_tx_unlock_bh(dev);
        return err;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to