@@ -1698,6 +1698,7 @@ enum netdev_priv_flags {
* @perm_addr: Permanent hw address
* @addr_assign_type: Hw address assignment type
* @addr_len: Hardware address length
+ * @vid_len: Virtual ID length, set in case of IVDF
* @upper_level: Maximum depth level of upper devices.
* @lower_level: Maximum depth level of lower devices.
* @neigh_priv_len: Used in neigh_alloc()
@@ -1950,6 +1951,7 @@ struct net_device {
unsigned char perm_addr[MAX_ADDR_LEN];
unsigned char addr_assign_type;
unsigned char addr_len;
+ unsigned char vid_len;
unsigned char upper_level;
unsigned char lower_level;
unsigned short neigh_priv_len;
@@ -4316,8 +4318,10 @@ int dev_addr_init(struct net_device *dev);
/* Functions used for unicast addresses handling */
int dev_uc_add(struct net_device *dev, const unsigned char *addr);
+int dev_vid_uc_add(struct net_device *dev, const unsigned char *addr);
int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr);
int dev_uc_del(struct net_device *dev, const unsigned char *addr);
+int dev_vid_uc_del(struct net_device *dev, const unsigned char *addr);
int dev_uc_sync(struct net_device *to, struct net_device *from);
int dev_uc_sync_multiple(struct net_device *to, struct net_device *from);
void dev_uc_unsync(struct net_device *to, struct net_device *from);
@@ -541,6 +541,35 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr,
}
EXPORT_SYMBOL(dev_addr_del);
+static int get_addr_len(struct net_device *dev)
+{
+ return dev->addr_len + dev->vid_len;
+}
+
+/**
+ * set_vid_addr - Copy a device address into a new address with IVDF.
+ * @dev: device
+ * @addr: address to copy
+ * @naddr: location of new address
+ *
+ * Transform a regular device address into one with IVDF (Individual
+ * Virtual Device Filtering). If the device does not support IVDF, the
+ * original device address length is returned and no copying is done.
+ * Otherwise, the length of the IVDF address is returned.
+ * The VID is set to zero which denotes the address of a real device.
+ */
+static int set_vid_addr(struct net_device *dev, const unsigned char *addr,
+ unsigned char *naddr)
+{
+ if (!dev->vid_len)
+ return dev->addr_len;
+
+ memcpy(naddr, addr, dev->addr_len);
+ memset(naddr + dev->addr_len, 0, dev->vid_len);
+
+ return get_addr_len(dev);
+}
+
/*
* Unicast list handling functions
*/
@@ -552,18 +581,22 @@ EXPORT_SYMBOL(dev_addr_del);
*/
int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)
{
+ unsigned char naddr[MAX_ADDR_LEN];
struct netdev_hw_addr *ha;
- int err;
+ int addr_len, err;
+
+ addr_len = set_vid_addr(dev, addr, naddr);
+ addr = dev->vid_len ? naddr : addr;
netif_addr_lock_bh(dev);
list_for_each_entry(ha, &dev->uc.list, list) {
- if (!memcmp(ha->addr, addr, dev->addr_len) &&
+ if (!memcmp(ha->addr, addr, addr_len) &&
ha->type == NETDEV_HW_ADDR_T_UNICAST) {
err = -EEXIST;
goto out;
}
}
- err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len,
+ err = __hw_addr_create_ex(&dev->uc, addr, addr_len,
NETDEV_HW_ADDR_T_UNICAST, true, false);
if (!err)
__dev_set_rx_mode(dev);
@@ -574,47 +607,89 @@ int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)
EXPORT_SYMBOL(dev_uc_add_excl);
/**
- * dev_uc_add - Add a secondary unicast address
+ * dev_vid_uc_add - Add a secondary unicast address with tag
* @dev: device
- * @addr: address to add
+ * @addr: address to add, includes vid tag already
*
* Add a secondary unicast address to the device or increase
* the reference count if it already exists.
*/
-int dev_uc_add(struct net_device *dev, const unsigned char *addr)
+int dev_vid_uc_add(struct net_device *dev, const unsigned char *addr)
{
int err;
netif_addr_lock_bh(dev);
- err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
+ err = __hw_addr_add(&dev->uc, addr, get_addr_len(dev),
NETDEV_HW_ADDR_T_UNICAST);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
return err;
}
+EXPORT_SYMBOL(dev_vid_uc_add);
+
+/**
+ * dev_uc_add - Add a secondary unicast address
+ * @dev: device
+ * @addr: address to add
+ *
+ * Add a secondary unicast address to the device or increase
+ * the reference count if it already exists.
+ */
+int dev_uc_add(struct net_device *dev, const unsigned char *addr)
+{
+ unsigned char naddr[MAX_ADDR_LEN];
+ int err;
+
+ set_vid_addr(dev, addr, naddr);
+ addr = dev->vid_len ? naddr : addr;
+
+ err = dev_vid_uc_add(dev, addr);
+ return err;
+}
EXPORT_SYMBOL(dev_uc_add);
/**
* dev_uc_del - Release secondary unicast address.
* @dev: device
- * @addr: address to delete
+ * @addr: address to delete, includes vid tag already
*
* Release reference to a secondary unicast address and remove it
* from the device if the reference count drops to zero.
*/
-int dev_uc_del(struct net_device *dev, const unsigned char *addr)
+int dev_vid_uc_del(struct net_device *dev, const unsigned char *addr)
{
int err;
netif_addr_lock_bh(dev);
- err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
+ err = __hw_addr_del(&dev->uc, addr, get_addr_len(dev),
NETDEV_HW_ADDR_T_UNICAST);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
return err;
}
+EXPORT_SYMBOL(dev_vid_uc_del);
+
+/**
+ * dev_uc_del - Release secondary unicast address.
+ * @dev: device
+ * @addr: address to delete
+ *
+ * Release reference to a secondary unicast address and remove it
+ * from the device if the reference count drops to zero.
+ */
+int dev_uc_del(struct net_device *dev, const unsigned char *addr)
+{
+ unsigned char naddr[MAX_ADDR_LEN];
+ int err;
+
+ set_vid_addr(dev, addr, naddr);
+ addr = dev->vid_len ? naddr : addr;
+
+ err = dev_vid_uc_del(dev, addr);
+ return err;
+}
EXPORT_SYMBOL(dev_uc_del);
/**
@@ -638,7 +713,7 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)
return -EINVAL;
netif_addr_lock(to);
- err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
+ err = __hw_addr_sync(&to->uc, &from->uc, get_addr_len(to));
if (!err)
__dev_set_rx_mode(to);
netif_addr_unlock(to);
@@ -668,7 +743,7 @@ int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
return -EINVAL;
netif_addr_lock(to);
- err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
+ err = __hw_addr_sync_multiple(&to->uc, &from->uc, get_addr_len(to));
if (!err)
__dev_set_rx_mode(to);
netif_addr_unlock(to);
@@ -692,7 +767,7 @@ void dev_uc_unsync(struct net_device *to, struct net_device *from)
netif_addr_lock_bh(from);
netif_addr_lock(to);
- __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
+ __hw_addr_unsync(&to->mc, &from->mc, get_addr_len(to));
__dev_set_rx_mode(to);
netif_addr_unlock(to);
netif_addr_unlock_bh(from);
@@ -736,18 +811,22 @@ EXPORT_SYMBOL(dev_uc_init);
*/
int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr)
{
+ unsigned char naddr[MAX_ADDR_LEN];
struct netdev_hw_addr *ha;
- int err;
+ int addr_len, err;
+
+ addr_len = set_vid_addr(dev, addr, naddr);
+ addr = dev->vid_len ? naddr : addr;
netif_addr_lock_bh(dev);
list_for_each_entry(ha, &dev->mc.list, list) {
- if (!memcmp(ha->addr, addr, dev->addr_len) &&
+ if (!memcmp(ha->addr, addr, addr_len) &&
ha->type == NETDEV_HW_ADDR_T_MULTICAST) {
err = -EEXIST;
goto out;
}
}
- err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len,
+ err = __hw_addr_create_ex(&dev->mc, addr, addr_len,
NETDEV_HW_ADDR_T_MULTICAST, true, false);
if (!err)
__dev_set_rx_mode(dev);
@@ -760,10 +839,14 @@ EXPORT_SYMBOL(dev_mc_add_excl);
static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
bool global)
{
- int err;
+ unsigned char naddr[MAX_ADDR_LEN];
+ int addr_len, err;
+
+ addr_len = set_vid_addr(dev, addr, naddr);
+ addr = dev->vid_len ? naddr : addr;
netif_addr_lock_bh(dev);
- err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
+ err = __hw_addr_add_ex(&dev->mc, addr, addr_len,
NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
if (!err)
__dev_set_rx_mode(dev);
@@ -800,10 +883,14 @@ EXPORT_SYMBOL(dev_mc_add_global);
static int __dev_mc_del(struct net_device *dev, const unsigned char *addr,
bool global)
{
- int err;
+ unsigned char naddr[MAX_ADDR_LEN];
+ int addr_len, err;
+
+ addr_len = set_vid_addr(dev, addr, naddr);
+ addr = dev->vid_len ? naddr : addr;
netif_addr_lock_bh(dev);
- err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len,
+ err = __hw_addr_del_ex(&dev->mc, addr, addr_len,
NETDEV_HW_ADDR_T_MULTICAST, global, false);
if (!err)
__dev_set_rx_mode(dev);