aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdevice.h11
-rw-r--r--net/core/dev.c69
2 files changed, 80 insertions, 0 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7a8f22fb4eee..aa389c77aa3e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -177,6 +177,14 @@ struct netif_rx_stats
177 177
178DECLARE_PER_CPU(struct netif_rx_stats, netdev_rx_stat); 178DECLARE_PER_CPU(struct netif_rx_stats, netdev_rx_stat);
179 179
180struct dev_addr_list
181{
182 struct dev_addr_list *next;
183 u8 da_addr[MAX_ADDR_LEN];
184 u8 da_addrlen;
185 int da_users;
186 int da_gusers;
187};
180 188
181/* 189/*
182 * We tag multicasts with these structures. 190 * We tag multicasts with these structures.
@@ -1008,6 +1016,9 @@ extern void dev_mc_upload(struct net_device *dev);
1008extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); 1016extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
1009extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); 1017extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
1010extern void dev_mc_discard(struct net_device *dev); 1018extern void dev_mc_discard(struct net_device *dev);
1019extern int __dev_addr_delete(struct dev_addr_list **list, void *addr, int alen, int all);
1020extern int __dev_addr_add(struct dev_addr_list **list, void *addr, int alen, int newonly);
1021extern void __dev_addr_discard(struct dev_addr_list **list);
1011extern void dev_set_promiscuity(struct net_device *dev, int inc); 1022extern void dev_set_promiscuity(struct net_device *dev, int inc);
1012extern void dev_set_allmulti(struct net_device *dev, int inc); 1023extern void dev_set_allmulti(struct net_device *dev, int inc);
1013extern void netdev_state_change(struct net_device *dev); 1024extern void netdev_state_change(struct net_device *dev);
diff --git a/net/core/dev.c b/net/core/dev.c
index a0a46e7ed137..18759ccdf219 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2553,6 +2553,75 @@ void dev_set_allmulti(struct net_device *dev, int inc)
2553 dev_mc_upload(dev); 2553 dev_mc_upload(dev);
2554} 2554}
2555 2555
2556int __dev_addr_delete(struct dev_addr_list **list, void *addr, int alen,
2557 int glbl)
2558{
2559 struct dev_addr_list *da;
2560
2561 for (; (da = *list) != NULL; list = &da->next) {
2562 if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
2563 alen == da->da_addrlen) {
2564 if (glbl) {
2565 int old_glbl = da->da_gusers;
2566 da->da_gusers = 0;
2567 if (old_glbl == 0)
2568 break;
2569 }
2570 if (--da->da_users)
2571 return 0;
2572
2573 *list = da->next;
2574 kfree(da);
2575 return 0;
2576 }
2577 }
2578 return -ENOENT;
2579}
2580
2581int __dev_addr_add(struct dev_addr_list **list, void *addr, int alen, int glbl)
2582{
2583 struct dev_addr_list *da;
2584
2585 for (da = *list; da != NULL; da = da->next) {
2586 if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
2587 da->da_addrlen == alen) {
2588 if (glbl) {
2589 int old_glbl = da->da_gusers;
2590 da->da_gusers = 1;
2591 if (old_glbl)
2592 return 0;
2593 }
2594 da->da_users++;
2595 return 0;
2596 }
2597 }
2598
2599 da = kmalloc(sizeof(*da), GFP_ATOMIC);
2600 if (da == NULL)
2601 return -ENOMEM;
2602 memcpy(da->da_addr, addr, alen);
2603 da->da_addrlen = alen;
2604 da->da_users = 1;
2605 da->da_gusers = glbl ? 1 : 0;
2606 da->next = *list;
2607 *list = da;
2608 return 0;
2609}
2610
2611void __dev_addr_discard(struct dev_addr_list **list)
2612{
2613 struct dev_addr_list *tmp;
2614
2615 while (*list != NULL) {
2616 tmp = *list;
2617 *list = tmp->next;
2618 if (tmp->da_users > tmp->da_gusers)
2619 printk("__dev_addr_discard: address leakage! "
2620 "da_users=%d\n", tmp->da_users);
2621 kfree(tmp);
2622 }
2623}
2624
2556unsigned dev_get_flags(const struct net_device *dev) 2625unsigned dev_get_flags(const struct net_device *dev)
2557{ 2626{
2558 unsigned flags; 2627 unsigned flags;