summaryrefslogtreecommitdiff
path: root/debian/patches/libdde_addr_list.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/libdde_addr_list.patch')
-rw-r--r--debian/patches/libdde_addr_list.patch423
1 files changed, 423 insertions, 0 deletions
diff --git a/debian/patches/libdde_addr_list.patch b/debian/patches/libdde_addr_list.patch
new file mode 100644
index 00000000..c1b4d96d
--- /dev/null
+++ b/debian/patches/libdde_addr_list.patch
@@ -0,0 +1,423 @@
+commit f001fde5eadd915f4858d22ed70d7040f48767cf
+Author: Jiri Pirko <jpirko@redhat.com>
+Date: Tue May 5 02:48:28 2009 +0000
+
+ net: introduce a list of device addresses dev_addr_list (v6)
+
+ v5 -> v6 (current):
+ -removed so far unused static functions
+ -corrected dev_addr_del_multiple to call del instead of add
+
+ v4 -> v5:
+ -added device address type (suggested by davem)
+ -removed refcounting (better to have simplier code then safe potentially few
+ bytes)
+
+ v3 -> v4:
+ -changed kzalloc to kmalloc in __hw_addr_add_ii()
+ -ASSERT_RTNL() avoided in dev_addr_flush() and dev_addr_init()
+
+ v2 -> v3:
+ -removed unnecessary rcu read locking
+ -moved dev_addr_flush() calling to ensure no null dereference of dev_addr
+
+ v1 -> v2:
+ -added forgotten ASSERT_RTNL to dev_addr_init and dev_addr_flush
+ -removed unnecessary rcu_read locking in dev_addr_init
+ -use compare_ether_addr_64bits instead of compare_ether_addr
+ -use L1_CACHE_BYTES as size for allocating struct netdev_hw_addr
+ -use call_rcu instead of rcu_synchronize
+ -moved is_etherdev_addr into __KERNEL__ ifdef
+
+ This patch introduces a new list in struct net_device and brings a set of
+ functions to handle the work with device address list. The list is a replacement
+ for the original dev_addr field and because in some situations there is need to
+ carry several device addresses with the net device. To be backward compatible,
+ dev_addr is made to point to the first member of the list so original drivers
+ sees no difference.
+
+ Signed-off-by: Jiri Pirko <jpirko@redhat.com>
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/etherdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/etherdevice.h 2012-04-16 00:26:43.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/etherdevice.h 2012-04-16 00:34:43.000000000 +0000
+@@ -182,6 +182,33 @@
+ return compare_ether_addr(addr1, addr2);
+ #endif
+ }
++
++/**
++ * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
++ * @dev: Pointer to a device structure
++ * @addr: Pointer to a six-byte array containing the Ethernet address
++ *
++ * Compare passed address with all addresses of the device. Return true if the
++ * address if one of the device addresses.
++ *
++ * Note that this function calls compare_ether_addr_64bits() so take care of
++ * the right padding.
++ */
++static inline bool is_etherdev_addr(const struct net_device *dev,
++ const u8 addr[6 + 2])
++{
++ struct netdev_hw_addr *ha;
++ int res = 1;
++
++ rcu_read_lock();
++ for_each_dev_addr(dev, ha) {
++ res = compare_ether_addr_64bits(addr, ha->addr);
++ if (!res)
++ break;
++ }
++ rcu_read_unlock();
++ return !res;
++}
+ #endif /* __KERNEL__ */
+
+ #endif /* _LINUX_ETHERDEVICE_H */
+Index: hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:33:34.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:43.000000000 +0000
+@@ -211,6 +211,16 @@
+ #define dmi_users da_users
+ #define dmi_gusers da_gusers
+
++struct netdev_hw_addr {
++ struct list_head list;
++ unsigned char addr[MAX_ADDR_LEN];
++ unsigned char type;
++#define NETDEV_HW_ADDR_T_LAN 1
++#define NETDEV_HW_ADDR_T_SAN 2
++#define NETDEV_HW_ADDR_T_SLAVE 3
++ struct rcu_head rcu_head;
++};
++
+ struct hh_cache
+ {
+ struct hh_cache *hh_next; /* Next entry */
+@@ -757,8 +767,11 @@
+ */
+ unsigned long last_rx; /* Time of last Rx */
+ /* Interface address info used in eth_type_trans() */
+- unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast
+- because most packets are unicast) */
++ unsigned char *dev_addr; /* hw address, (before bcast
++ because most packets are
++ unicast) */
++
++ struct list_head dev_addr_list; /* list of device hw addresses */
+
+ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+
+@@ -1768,6 +1781,13 @@
+ spin_unlock_bh(&dev->addr_list_lock);
+ }
+
++/*
++ * dev_addr_list walker. Should be used only for read access. Call with
++ * rcu_read_lock held.
++ */
++#define for_each_dev_addr(dev, ha) \
++ list_for_each_entry_rcu(ha, &dev->dev_addr_list, list)
++
+ /* These functions live elsewhere (drivers/net/net_init.c, but related) */
+
+ extern void ether_setup(struct net_device *dev);
+@@ -1780,6 +1800,19 @@
+ alloc_netdev_mq(sizeof_priv, name, setup, 1)
+ extern int register_netdev(struct net_device *dev);
+ extern void unregister_netdev(struct net_device *dev);
++
++/* Functions used for device addresses handling */
++extern int dev_addr_add(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type);
++extern int dev_addr_del(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type);
++extern int dev_addr_add_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type);
++extern int dev_addr_del_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type);
++
+ /* 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);
+Index: hurd-debian/libdde_linux26/lib/src/net/core/dev.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:26:43.000000000 +0000
++++ hurd-debian/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:43.000000000 +0000
+@@ -3397,6 +3397,252 @@
+ netif_addr_unlock_bh(dev);
+ }
+
++/* hw addresses list handling functions */
++
++static int __hw_addr_add(struct list_head *list, unsigned char *addr,
++ int addr_len, unsigned char addr_type)
++{
++ struct netdev_hw_addr *ha;
++ int alloc_size;
++
++ if (addr_len > MAX_ADDR_LEN)
++ return -EINVAL;
++
++ alloc_size = sizeof(*ha);
++ if (alloc_size < L1_CACHE_BYTES)
++ alloc_size = L1_CACHE_BYTES;
++ ha = kmalloc(alloc_size, GFP_ATOMIC);
++ if (!ha)
++ return -ENOMEM;
++ memcpy(ha->addr, addr, addr_len);
++ ha->type = addr_type;
++ list_add_tail_rcu(&ha->list, list);
++ return 0;
++}
++
++static void ha_rcu_free(struct rcu_head *head)
++{
++ struct netdev_hw_addr *ha;
++
++ ha = container_of(head, struct netdev_hw_addr, rcu_head);
++ kfree(ha);
++}
++
++static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
++ int addr_len, unsigned char addr_type,
++ int ignore_index)
++{
++ struct netdev_hw_addr *ha;
++ int i = 0;
++
++ list_for_each_entry(ha, list, list) {
++ if (i++ != ignore_index &&
++ !memcmp(ha->addr, addr, addr_len) &&
++ (ha->type == addr_type || !addr_type)) {
++ list_del_rcu(&ha->list);
++ call_rcu(&ha->rcu_head, ha_rcu_free);
++ return 0;
++ }
++ }
++ return -ENOENT;
++}
++
++static int __hw_addr_add_multiple_ii(struct list_head *to_list,
++ struct list_head *from_list,
++ int addr_len, unsigned char addr_type,
++ int ignore_index)
++{
++ int err;
++ struct netdev_hw_addr *ha, *ha2;
++ unsigned char type;
++
++ list_for_each_entry(ha, from_list, list) {
++ type = addr_type ? addr_type : ha->type;
++ err = __hw_addr_add(to_list, ha->addr, addr_len, type);
++ if (err)
++ goto unroll;
++ }
++ return 0;
++
++unroll:
++ list_for_each_entry(ha2, from_list, list) {
++ if (ha2 == ha)
++ break;
++ type = addr_type ? addr_type : ha2->type;
++ __hw_addr_del_ii(to_list, ha2->addr, addr_len, type,
++ ignore_index);
++ }
++ return err;
++}
++
++static void __hw_addr_del_multiple_ii(struct list_head *to_list,
++ struct list_head *from_list,
++ int addr_len, unsigned char addr_type,
++ int ignore_index)
++{
++ struct netdev_hw_addr *ha;
++ unsigned char type;
++
++ list_for_each_entry(ha, from_list, list) {
++ type = addr_type ? addr_type : ha->type;
++ __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type,
++ ignore_index);
++ }
++}
++
++static void __hw_addr_flush(struct list_head *list)
++{
++ struct netdev_hw_addr *ha, *tmp;
++
++ list_for_each_entry_safe(ha, tmp, list, list) {
++ list_del_rcu(&ha->list);
++ call_rcu(&ha->rcu_head, ha_rcu_free);
++ }
++}
++
++/* Device addresses handling functions */
++
++static void dev_addr_flush(struct net_device *dev)
++{
++ /* rtnl_mutex must be held here */
++
++ __hw_addr_flush(&dev->dev_addr_list);
++ dev->dev_addr = NULL;
++}
++
++static int dev_addr_init(struct net_device *dev)
++{
++ unsigned char addr[MAX_ADDR_LEN];
++ struct netdev_hw_addr *ha;
++ int err;
++
++ /* rtnl_mutex must be held here */
++
++ INIT_LIST_HEAD(&dev->dev_addr_list);
++ memset(addr, 0, sizeof(*addr));
++ err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr),
++ NETDEV_HW_ADDR_T_LAN);
++ if (!err) {
++ /*
++ * Get the first (previously created) address from the list
++ * and set dev_addr pointer to this location.
++ */
++ ha = list_first_entry(&dev->dev_addr_list,
++ struct netdev_hw_addr, list);
++ dev->dev_addr = ha->addr;
++ }
++ return err;
++}
++
++/**
++ * dev_addr_add - Add a device address
++ * @dev: device
++ * @addr: address to add
++ * @addr_type: address type
++ *
++ * Add a device address to the device or increase the reference count if
++ * it already exists.
++ *
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_add(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type)
++{
++ int err;
++
++ ASSERT_RTNL();
++
++ err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len,
++ addr_type);
++ if (!err)
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
++ return err;
++}
++EXPORT_SYMBOL(dev_addr_add);
++
++/**
++ * dev_addr_del - Release a device address.
++ * @dev: device
++ * @addr: address to delete
++ * @addr_type: address type
++ *
++ * Release reference to a device address and remove it from the device
++ * if the reference count drops to zero.
++ *
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_del(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type)
++{
++ int err;
++
++ ASSERT_RTNL();
++
++ err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len,
++ addr_type, 0);
++ if (!err)
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
++ return err;
++}
++EXPORT_SYMBOL(dev_addr_del);
++
++/**
++ * dev_addr_add_multiple - Add device addresses from another device
++ * @to_dev: device to which addresses will be added
++ * @from_dev: device from which addresses will be added
++ * @addr_type: address type - 0 means type will be used from from_dev
++ *
++ * Add device addresses of the one device to another.
++ **
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_add_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type)
++{
++ int err;
++
++ ASSERT_RTNL();
++
++ if (from_dev->addr_len != to_dev->addr_len)
++ return -EINVAL;
++ err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
++ &from_dev->dev_addr_list,
++ to_dev->addr_len, addr_type, 0);
++ if (!err)
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
++ return err;
++}
++EXPORT_SYMBOL(dev_addr_add_multiple);
++
++/**
++ * dev_addr_del_multiple - Delete device addresses by another device
++ * @to_dev: device where the addresses will be deleted
++ * @from_dev: device by which addresses the addresses will be deleted
++ * @addr_type: address type - 0 means type will used from from_dev
++ *
++ * Deletes addresses in to device by the list of addresses in from device.
++ *
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_del_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type)
++{
++ ASSERT_RTNL();
++
++ if (from_dev->addr_len != to_dev->addr_len)
++ return -EINVAL;
++ __hw_addr_del_multiple_ii(&to_dev->dev_addr_list,
++ &from_dev->dev_addr_list,
++ to_dev->addr_len, addr_type, 0);
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
++ return 0;
++}
++EXPORT_SYMBOL(dev_addr_del_multiple);
++
++/* unicast and multicast addresses handling functions */
++
+ int __dev_addr_delete(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+ {
+@@ -4737,6 +4983,7 @@
+
+ dev->gso_max_size = GSO_MAX_SIZE;
+
++ dev_addr_init(dev);
+ netdev_init_queues(dev);
+
+ INIT_LIST_HEAD(&dev->napi_list);
+@@ -4762,6 +5009,9 @@
+
+ kfree(dev->_tx);
+
++ /* Flush device addresses */
++ dev_addr_flush(dev);
++
+ list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
+ netif_napi_del(p);
+