diff options
-rw-r--r-- | include/linux/etherdevice.h | 27 | ||||
-rw-r--r-- | include/linux/netdevice.h | 37 | ||||
-rw-r--r-- | net/core/dev.c | 250 |
3 files changed, 312 insertions, 2 deletions
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index a1f17abba7dc..3d7a6687d247 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h | |||
@@ -182,6 +182,33 @@ static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2], | |||
182 | return compare_ether_addr(addr1, addr2); | 182 | return compare_ether_addr(addr1, addr2); |
183 | #endif | 183 | #endif |
184 | } | 184 | } |
185 | |||
186 | /** | ||
187 | * is_etherdev_addr - Tell if given Ethernet address belongs to the device. | ||
188 | * @dev: Pointer to a device structure | ||
189 | * @addr: Pointer to a six-byte array containing the Ethernet address | ||
190 | * | ||
191 | * Compare passed address with all addresses of the device. Return true if the | ||
192 | * address if one of the device addresses. | ||
193 | * | ||
194 | * Note that this function calls compare_ether_addr_64bits() so take care of | ||
195 | * the right padding. | ||
196 | */ | ||
197 | static inline bool is_etherdev_addr(const struct net_device *dev, | ||
198 | const u8 addr[6 + 2]) | ||
199 | { | ||
200 | struct netdev_hw_addr *ha; | ||
201 | int res = 1; | ||
202 | |||
203 | rcu_read_lock(); | ||
204 | for_each_dev_addr(dev, ha) { | ||
205 | res = compare_ether_addr_64bits(addr, ha->addr); | ||
206 | if (!res) | ||
207 | break; | ||
208 | } | ||
209 | rcu_read_unlock(); | ||
210 | return !res; | ||
211 | } | ||
185 | #endif /* __KERNEL__ */ | 212 | #endif /* __KERNEL__ */ |
186 | 213 | ||
187 | /** | 214 | /** |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ff42aba403c5..02882e2ebd49 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -210,6 +210,16 @@ struct dev_addr_list | |||
210 | #define dmi_users da_users | 210 | #define dmi_users da_users |
211 | #define dmi_gusers da_gusers | 211 | #define dmi_gusers da_gusers |
212 | 212 | ||
213 | struct netdev_hw_addr { | ||
214 | struct list_head list; | ||
215 | unsigned char addr[MAX_ADDR_LEN]; | ||
216 | unsigned char type; | ||
217 | #define NETDEV_HW_ADDR_T_LAN 1 | ||
218 | #define NETDEV_HW_ADDR_T_SAN 2 | ||
219 | #define NETDEV_HW_ADDR_T_SLAVE 3 | ||
220 | struct rcu_head rcu_head; | ||
221 | }; | ||
222 | |||
213 | struct hh_cache | 223 | struct hh_cache |
214 | { | 224 | { |
215 | struct hh_cache *hh_next; /* Next entry */ | 225 | struct hh_cache *hh_next; /* Next entry */ |
@@ -784,8 +794,11 @@ struct net_device | |||
784 | */ | 794 | */ |
785 | unsigned long last_rx; /* Time of last Rx */ | 795 | unsigned long last_rx; /* Time of last Rx */ |
786 | /* Interface address info used in eth_type_trans() */ | 796 | /* Interface address info used in eth_type_trans() */ |
787 | unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast | 797 | unsigned char *dev_addr; /* hw address, (before bcast |
788 | because most packets are unicast) */ | 798 | because most packets are |
799 | unicast) */ | ||
800 | |||
801 | struct list_head dev_addr_list; /* list of device hw addresses */ | ||
789 | 802 | ||
790 | unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ | 803 | unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ |
791 | 804 | ||
@@ -1791,6 +1804,13 @@ static inline void netif_addr_unlock_bh(struct net_device *dev) | |||
1791 | spin_unlock_bh(&dev->addr_list_lock); | 1804 | spin_unlock_bh(&dev->addr_list_lock); |
1792 | } | 1805 | } |
1793 | 1806 | ||
1807 | /* | ||
1808 | * dev_addr_list walker. Should be used only for read access. Call with | ||
1809 | * rcu_read_lock held. | ||
1810 | */ | ||
1811 | #define for_each_dev_addr(dev, ha) \ | ||
1812 | list_for_each_entry_rcu(ha, &dev->dev_addr_list, list) | ||
1813 | |||
1794 | /* These functions live elsewhere (drivers/net/net_init.c, but related) */ | 1814 | /* These functions live elsewhere (drivers/net/net_init.c, but related) */ |
1795 | 1815 | ||
1796 | extern void ether_setup(struct net_device *dev); | 1816 | extern void ether_setup(struct net_device *dev); |
@@ -1803,6 +1823,19 @@ extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, | |||
1803 | alloc_netdev_mq(sizeof_priv, name, setup, 1) | 1823 | alloc_netdev_mq(sizeof_priv, name, setup, 1) |
1804 | extern int register_netdev(struct net_device *dev); | 1824 | extern int register_netdev(struct net_device *dev); |
1805 | extern void unregister_netdev(struct net_device *dev); | 1825 | extern void unregister_netdev(struct net_device *dev); |
1826 | |||
1827 | /* Functions used for device addresses handling */ | ||
1828 | extern int dev_addr_add(struct net_device *dev, unsigned char *addr, | ||
1829 | unsigned char addr_type); | ||
1830 | extern int dev_addr_del(struct net_device *dev, unsigned char *addr, | ||
1831 | unsigned char addr_type); | ||
1832 | extern int dev_addr_add_multiple(struct net_device *to_dev, | ||
1833 | struct net_device *from_dev, | ||
1834 | unsigned char addr_type); | ||
1835 | extern int dev_addr_del_multiple(struct net_device *to_dev, | ||
1836 | struct net_device *from_dev, | ||
1837 | unsigned char addr_type); | ||
1838 | |||
1806 | /* Functions used for secondary unicast and multicast support */ | 1839 | /* Functions used for secondary unicast and multicast support */ |
1807 | extern void dev_set_rx_mode(struct net_device *dev); | 1840 | extern void dev_set_rx_mode(struct net_device *dev); |
1808 | extern void __dev_set_rx_mode(struct net_device *dev); | 1841 | extern void __dev_set_rx_mode(struct net_device *dev); |
diff --git a/net/core/dev.c b/net/core/dev.c index 3c8073fe970a..637ea71b0a0d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3434,6 +3434,252 @@ void dev_set_rx_mode(struct net_device *dev) | |||
3434 | netif_addr_unlock_bh(dev); | 3434 | netif_addr_unlock_bh(dev); |
3435 | } | 3435 | } |
3436 | 3436 | ||
3437 | /* hw addresses list handling functions */ | ||
3438 | |||
3439 | static int __hw_addr_add(struct list_head *list, unsigned char *addr, | ||
3440 | int addr_len, unsigned char addr_type) | ||
3441 | { | ||
3442 | struct netdev_hw_addr *ha; | ||
3443 | int alloc_size; | ||
3444 | |||
3445 | if (addr_len > MAX_ADDR_LEN) | ||
3446 | return -EINVAL; | ||
3447 | |||
3448 | alloc_size = sizeof(*ha); | ||
3449 | if (alloc_size < L1_CACHE_BYTES) | ||
3450 | alloc_size = L1_CACHE_BYTES; | ||
3451 | ha = kmalloc(alloc_size, GFP_ATOMIC); | ||
3452 | if (!ha) | ||
3453 | return -ENOMEM; | ||
3454 | memcpy(ha->addr, addr, addr_len); | ||
3455 | ha->type = addr_type; | ||
3456 | list_add_tail_rcu(&ha->list, list); | ||
3457 | return 0; | ||
3458 | } | ||
3459 | |||
3460 | static void ha_rcu_free(struct rcu_head *head) | ||
3461 | { | ||
3462 | struct netdev_hw_addr *ha; | ||
3463 | |||
3464 | ha = container_of(head, struct netdev_hw_addr, rcu_head); | ||
3465 | kfree(ha); | ||
3466 | } | ||
3467 | |||
3468 | static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr, | ||
3469 | int addr_len, unsigned char addr_type, | ||
3470 | int ignore_index) | ||
3471 | { | ||
3472 | struct netdev_hw_addr *ha; | ||
3473 | int i = 0; | ||
3474 | |||
3475 | list_for_each_entry(ha, list, list) { | ||
3476 | if (i++ != ignore_index && | ||
3477 | !memcmp(ha->addr, addr, addr_len) && | ||
3478 | (ha->type == addr_type || !addr_type)) { | ||
3479 | list_del_rcu(&ha->list); | ||
3480 | call_rcu(&ha->rcu_head, ha_rcu_free); | ||
3481 | return 0; | ||
3482 | } | ||
3483 | } | ||
3484 | return -ENOENT; | ||
3485 | } | ||
3486 | |||
3487 | static int __hw_addr_add_multiple_ii(struct list_head *to_list, | ||
3488 | struct list_head *from_list, | ||
3489 | int addr_len, unsigned char addr_type, | ||
3490 | int ignore_index) | ||
3491 | { | ||
3492 | int err; | ||
3493 | struct netdev_hw_addr *ha, *ha2; | ||
3494 | unsigned char type; | ||
3495 | |||
3496 | list_for_each_entry(ha, from_list, list) { | ||
3497 | type = addr_type ? addr_type : ha->type; | ||
3498 | err = __hw_addr_add(to_list, ha->addr, addr_len, type); | ||
3499 | if (err) | ||
3500 | goto unroll; | ||
3501 | } | ||
3502 | return 0; | ||
3503 | |||
3504 | unroll: | ||
3505 | list_for_each_entry(ha2, from_list, list) { | ||
3506 | if (ha2 == ha) | ||
3507 | break; | ||
3508 | type = addr_type ? addr_type : ha2->type; | ||
3509 | __hw_addr_del_ii(to_list, ha2->addr, addr_len, type, | ||
3510 | ignore_index); | ||
3511 | } | ||
3512 | return err; | ||
3513 | } | ||
3514 | |||
3515 | static void __hw_addr_del_multiple_ii(struct list_head *to_list, | ||
3516 | struct list_head *from_list, | ||
3517 | int addr_len, unsigned char addr_type, | ||
3518 | int ignore_index) | ||
3519 | { | ||
3520 | struct netdev_hw_addr *ha; | ||
3521 | unsigned char type; | ||
3522 | |||
3523 | list_for_each_entry(ha, from_list, list) { | ||
3524 | type = addr_type ? addr_type : ha->type; | ||
3525 | __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type, | ||
3526 | ignore_index); | ||
3527 | } | ||
3528 | } | ||
3529 | |||
3530 | static void __hw_addr_flush(struct list_head *list) | ||
3531 | { | ||
3532 | struct netdev_hw_addr *ha, *tmp; | ||
3533 | |||
3534 | list_for_each_entry_safe(ha, tmp, list, list) { | ||
3535 | list_del_rcu(&ha->list); | ||
3536 | call_rcu(&ha->rcu_head, ha_rcu_free); | ||
3537 | } | ||
3538 | } | ||
3539 | |||
3540 | /* Device addresses handling functions */ | ||
3541 | |||
3542 | static void dev_addr_flush(struct net_device *dev) | ||
3543 | { | ||
3544 | /* rtnl_mutex must be held here */ | ||
3545 | |||
3546 | __hw_addr_flush(&dev->dev_addr_list); | ||
3547 | dev->dev_addr = NULL; | ||
3548 | } | ||
3549 | |||
3550 | static int dev_addr_init(struct net_device *dev) | ||
3551 | { | ||
3552 | unsigned char addr[MAX_ADDR_LEN]; | ||
3553 | struct netdev_hw_addr *ha; | ||
3554 | int err; | ||
3555 | |||
3556 | /* rtnl_mutex must be held here */ | ||
3557 | |||
3558 | INIT_LIST_HEAD(&dev->dev_addr_list); | ||
3559 | memset(addr, 0, sizeof(*addr)); | ||
3560 | err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr), | ||
3561 | NETDEV_HW_ADDR_T_LAN); | ||
3562 | if (!err) { | ||
3563 | /* | ||
3564 | * Get the first (previously created) address from the list | ||
3565 | * and set dev_addr pointer to this location. | ||
3566 | */ | ||
3567 | ha = list_first_entry(&dev->dev_addr_list, | ||
3568 | struct netdev_hw_addr, list); | ||
3569 | dev->dev_addr = ha->addr; | ||
3570 | } | ||
3571 | return err; | ||
3572 | } | ||
3573 | |||
3574 | /** | ||
3575 | * dev_addr_add - Add a device address | ||
3576 | * @dev: device | ||
3577 | * @addr: address to add | ||
3578 | * @addr_type: address type | ||
3579 | * | ||
3580 | * Add a device address to the device or increase the reference count if | ||
3581 | * it already exists. | ||
3582 | * | ||
3583 | * The caller must hold the rtnl_mutex. | ||
3584 | */ | ||
3585 | int dev_addr_add(struct net_device *dev, unsigned char *addr, | ||
3586 | unsigned char addr_type) | ||
3587 | { | ||
3588 | int err; | ||
3589 | |||
3590 | ASSERT_RTNL(); | ||
3591 | |||
3592 | err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len, | ||
3593 | addr_type); | ||
3594 | if (!err) | ||
3595 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
3596 | return err; | ||
3597 | } | ||
3598 | EXPORT_SYMBOL(dev_addr_add); | ||
3599 | |||
3600 | /** | ||
3601 | * dev_addr_del - Release a device address. | ||
3602 | * @dev: device | ||
3603 | * @addr: address to delete | ||
3604 | * @addr_type: address type | ||
3605 | * | ||
3606 | * Release reference to a device address and remove it from the device | ||
3607 | * if the reference count drops to zero. | ||
3608 | * | ||
3609 | * The caller must hold the rtnl_mutex. | ||
3610 | */ | ||
3611 | int dev_addr_del(struct net_device *dev, unsigned char *addr, | ||
3612 | unsigned char addr_type) | ||
3613 | { | ||
3614 | int err; | ||
3615 | |||
3616 | ASSERT_RTNL(); | ||
3617 | |||
3618 | err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, | ||
3619 | addr_type, 0); | ||
3620 | if (!err) | ||
3621 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
3622 | return err; | ||
3623 | } | ||
3624 | EXPORT_SYMBOL(dev_addr_del); | ||
3625 | |||
3626 | /** | ||
3627 | * dev_addr_add_multiple - Add device addresses from another device | ||
3628 | * @to_dev: device to which addresses will be added | ||
3629 | * @from_dev: device from which addresses will be added | ||
3630 | * @addr_type: address type - 0 means type will be used from from_dev | ||
3631 | * | ||
3632 | * Add device addresses of the one device to another. | ||
3633 | ** | ||
3634 | * The caller must hold the rtnl_mutex. | ||
3635 | */ | ||
3636 | int dev_addr_add_multiple(struct net_device *to_dev, | ||
3637 | struct net_device *from_dev, | ||
3638 | unsigned char addr_type) | ||
3639 | { | ||
3640 | int err; | ||
3641 | |||
3642 | ASSERT_RTNL(); | ||
3643 | |||
3644 | if (from_dev->addr_len != to_dev->addr_len) | ||
3645 | return -EINVAL; | ||
3646 | err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list, | ||
3647 | &from_dev->dev_addr_list, | ||
3648 | to_dev->addr_len, addr_type, 0); | ||
3649 | if (!err) | ||
3650 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
3651 | return err; | ||
3652 | } | ||
3653 | EXPORT_SYMBOL(dev_addr_add_multiple); | ||
3654 | |||
3655 | /** | ||
3656 | * dev_addr_del_multiple - Delete device addresses by another device | ||
3657 | * @to_dev: device where the addresses will be deleted | ||
3658 | * @from_dev: device by which addresses the addresses will be deleted | ||
3659 | * @addr_type: address type - 0 means type will used from from_dev | ||
3660 | * | ||
3661 | * Deletes addresses in to device by the list of addresses in from device. | ||
3662 | * | ||
3663 | * The caller must hold the rtnl_mutex. | ||
3664 | */ | ||
3665 | int dev_addr_del_multiple(struct net_device *to_dev, | ||
3666 | struct net_device *from_dev, | ||
3667 | unsigned char addr_type) | ||
3668 | { | ||
3669 | ASSERT_RTNL(); | ||
3670 | |||
3671 | if (from_dev->addr_len != to_dev->addr_len) | ||
3672 | return -EINVAL; | ||
3673 | __hw_addr_del_multiple_ii(&to_dev->dev_addr_list, | ||
3674 | &from_dev->dev_addr_list, | ||
3675 | to_dev->addr_len, addr_type, 0); | ||
3676 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
3677 | return 0; | ||
3678 | } | ||
3679 | EXPORT_SYMBOL(dev_addr_del_multiple); | ||
3680 | |||
3681 | /* unicast and multicast addresses handling functions */ | ||
3682 | |||
3437 | int __dev_addr_delete(struct dev_addr_list **list, int *count, | 3683 | int __dev_addr_delete(struct dev_addr_list **list, int *count, |
3438 | void *addr, int alen, int glbl) | 3684 | void *addr, int alen, int glbl) |
3439 | { | 3685 | { |
@@ -4776,6 +5022,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, | |||
4776 | 5022 | ||
4777 | dev->gso_max_size = GSO_MAX_SIZE; | 5023 | dev->gso_max_size = GSO_MAX_SIZE; |
4778 | 5024 | ||
5025 | dev_addr_init(dev); | ||
4779 | netdev_init_queues(dev); | 5026 | netdev_init_queues(dev); |
4780 | 5027 | ||
4781 | INIT_LIST_HEAD(&dev->napi_list); | 5028 | INIT_LIST_HEAD(&dev->napi_list); |
@@ -4801,6 +5048,9 @@ void free_netdev(struct net_device *dev) | |||
4801 | 5048 | ||
4802 | kfree(dev->_tx); | 5049 | kfree(dev->_tx); |
4803 | 5050 | ||
5051 | /* Flush device addresses */ | ||
5052 | dev_addr_flush(dev); | ||
5053 | |||
4804 | list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) | 5054 | list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) |
4805 | netif_napi_del(p); | 5055 | netif_napi_del(p); |
4806 | 5056 | ||