Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf742482 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NET]: dev: introduce generic net_device address lists



Introduce struct dev_addr_list and list maintenance functions
based on dev_mc_list and the related functions. This will be
used by follow-up patches for both multicast and secondary
unicast addresses.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 75ebe8f7
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -177,6 +177,14 @@ struct netif_rx_stats

DECLARE_PER_CPU(struct netif_rx_stats, netdev_rx_stat);

struct dev_addr_list
{
	struct dev_addr_list	*next;
	u8			da_addr[MAX_ADDR_LEN];
	u8			da_addrlen;
	int			da_users;
	int			da_gusers;
};

/*
 *	We tag multicasts with these structures.
@@ -1008,6 +1016,9 @@ extern void dev_mc_upload(struct net_device *dev);
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);
extern int 		__dev_addr_delete(struct dev_addr_list **list, void *addr, int alen, int all);
extern int		__dev_addr_add(struct dev_addr_list **list, void *addr, int alen, int newonly);
extern void		__dev_addr_discard(struct dev_addr_list **list);
extern void		dev_set_promiscuity(struct net_device *dev, int inc);
extern void		dev_set_allmulti(struct net_device *dev, int inc);
extern void		netdev_state_change(struct net_device *dev);
+69 −0
Original line number Diff line number Diff line
@@ -2553,6 +2553,75 @@ void dev_set_allmulti(struct net_device *dev, int inc)
		dev_mc_upload(dev);
}

int __dev_addr_delete(struct dev_addr_list **list, 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);
			return 0;
		}
	}
	return -ENOENT;
}

int __dev_addr_add(struct dev_addr_list **list, 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 = kmalloc(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;
	return 0;
}

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);
	}
}

unsigned dev_get_flags(const struct net_device *dev)
{
	unsigned flags;