net: convert multicast list to list_head
Converts the list and the core manipulating with it to be the same as uc_list. +uses two functions for adding/removing mc address (normal and "global" variant) instead of a function parameter. +removes dev_mcast.c completely. +exposes netdev_hw_addr_list_* macros along with __hw_addr_* functions for manipulation with lists on a sandbox (used in bonding and 80211 drivers) Signed-off-by: Jiri Pirko <jpirko@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
a748ee2426
commit
22bedad3ce
145
net/core/dev.c
145
net/core/dev.c
@ -3968,140 +3968,6 @@ void dev_set_rx_mode(struct net_device *dev)
|
||||
netif_addr_unlock_bh(dev);
|
||||
}
|
||||
|
||||
/* multicast addresses handling functions */
|
||||
|
||||
int __dev_addr_delete(struct dev_addr_list **list, int *count,
|
||||
void *addr, int alen, int glbl)
|
||||
{
|
||||
struct dev_addr_list *da;
|
||||
|
||||
for (; (da = *list) != NULL; list = &da->next) {
|
||||
if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
|
||||
alen == da->da_addrlen) {
|
||||
if (glbl) {
|
||||
int old_glbl = da->da_gusers;
|
||||
da->da_gusers = 0;
|
||||
if (old_glbl == 0)
|
||||
break;
|
||||
}
|
||||
if (--da->da_users)
|
||||
return 0;
|
||||
|
||||
*list = da->next;
|
||||
kfree(da);
|
||||
(*count)--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __dev_addr_add(struct dev_addr_list **list, int *count,
|
||||
void *addr, int alen, int glbl)
|
||||
{
|
||||
struct dev_addr_list *da;
|
||||
|
||||
for (da = *list; da != NULL; da = da->next) {
|
||||
if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
|
||||
da->da_addrlen == alen) {
|
||||
if (glbl) {
|
||||
int old_glbl = da->da_gusers;
|
||||
da->da_gusers = 1;
|
||||
if (old_glbl)
|
||||
return 0;
|
||||
}
|
||||
da->da_users++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
da = kzalloc(sizeof(*da), GFP_ATOMIC);
|
||||
if (da == NULL)
|
||||
return -ENOMEM;
|
||||
memcpy(da->da_addr, addr, alen);
|
||||
da->da_addrlen = alen;
|
||||
da->da_users = 1;
|
||||
da->da_gusers = glbl ? 1 : 0;
|
||||
da->next = *list;
|
||||
*list = da;
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
|
||||
struct dev_addr_list **from, int *from_count)
|
||||
{
|
||||
struct dev_addr_list *da, *next;
|
||||
int err = 0;
|
||||
|
||||
da = *from;
|
||||
while (da != NULL) {
|
||||
next = da->next;
|
||||
if (!da->da_synced) {
|
||||
err = __dev_addr_add(to, to_count,
|
||||
da->da_addr, da->da_addrlen, 0);
|
||||
if (err < 0)
|
||||
break;
|
||||
da->da_synced = 1;
|
||||
da->da_users++;
|
||||
} else if (da->da_users == 1) {
|
||||
__dev_addr_delete(to, to_count,
|
||||
da->da_addr, da->da_addrlen, 0);
|
||||
__dev_addr_delete(from, from_count,
|
||||
da->da_addr, da->da_addrlen, 0);
|
||||
}
|
||||
da = next;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dev_addr_sync);
|
||||
|
||||
void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
|
||||
struct dev_addr_list **from, int *from_count)
|
||||
{
|
||||
struct dev_addr_list *da, *next;
|
||||
|
||||
da = *from;
|
||||
while (da != NULL) {
|
||||
next = da->next;
|
||||
if (da->da_synced) {
|
||||
__dev_addr_delete(to, to_count,
|
||||
da->da_addr, da->da_addrlen, 0);
|
||||
da->da_synced = 0;
|
||||
__dev_addr_delete(from, from_count,
|
||||
da->da_addr, da->da_addrlen, 0);
|
||||
}
|
||||
da = next;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dev_addr_unsync);
|
||||
|
||||
static void __dev_addr_discard(struct dev_addr_list **list)
|
||||
{
|
||||
struct dev_addr_list *tmp;
|
||||
|
||||
while (*list != NULL) {
|
||||
tmp = *list;
|
||||
*list = tmp->next;
|
||||
if (tmp->da_users > tmp->da_gusers)
|
||||
printk("__dev_addr_discard: address leakage! "
|
||||
"da_users=%d\n", tmp->da_users);
|
||||
kfree(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void dev_addr_discard(struct net_device *dev)
|
||||
{
|
||||
netif_addr_lock_bh(dev);
|
||||
|
||||
__dev_addr_discard(&dev->mc_list);
|
||||
netdev_mc_count(dev) = 0;
|
||||
|
||||
netif_addr_unlock_bh(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(dev_addr_discard);
|
||||
|
||||
/**
|
||||
* dev_get_flags - get flags reported to userspace
|
||||
* @dev: device
|
||||
@ -4412,8 +4278,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
|
||||
return -EINVAL;
|
||||
if (!netif_device_present(dev))
|
||||
return -ENODEV;
|
||||
return dev_mc_add(dev, ifr->ifr_hwaddr.sa_data,
|
||||
dev->addr_len, 1);
|
||||
return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
|
||||
|
||||
case SIOCDELMULTI:
|
||||
if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
|
||||
@ -4421,8 +4286,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
|
||||
return -EINVAL;
|
||||
if (!netif_device_present(dev))
|
||||
return -ENODEV;
|
||||
return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data,
|
||||
dev->addr_len, 1);
|
||||
return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
|
||||
|
||||
case SIOCSIFTXQLEN:
|
||||
if (ifr->ifr_qlen < 0)
|
||||
@ -4730,7 +4594,7 @@ static void rollback_registered_many(struct list_head *head)
|
||||
* Flush the unicast and multicast chains
|
||||
*/
|
||||
dev_uc_flush(dev);
|
||||
dev_addr_discard(dev);
|
||||
dev_mc_flush(dev);
|
||||
|
||||
if (dev->netdev_ops->ndo_uninit)
|
||||
dev->netdev_ops->ndo_uninit(dev);
|
||||
@ -5310,6 +5174,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
|
||||
if (dev_addr_init(dev))
|
||||
goto free_rx;
|
||||
|
||||
dev_mc_init(dev);
|
||||
dev_uc_init(dev);
|
||||
|
||||
dev_net_set(dev, &init_net);
|
||||
@ -5545,7 +5410,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
|
||||
* Flush the unicast and multicast chains
|
||||
*/
|
||||
dev_uc_flush(dev);
|
||||
dev_addr_discard(dev);
|
||||
dev_mc_flush(dev);
|
||||
|
||||
netdev_unregister_kobject(dev);
|
||||
|
||||
|
Reference in New Issue
Block a user