diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/Makefile | 3 | ||||
| -rw-r--r-- | net/core/dev.c | 430 | ||||
| -rw-r--r-- | net/core/dev_addr_lists.c | 478 |
3 files changed, 483 insertions, 428 deletions
diff --git a/net/core/Makefile b/net/core/Makefile index 08791ac3e05a..0a899f1aadb9 100644 --- a/net/core/Makefile +++ b/net/core/Makefile | |||
| @@ -8,7 +8,8 @@ obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ | |||
| 8 | obj-$(CONFIG_SYSCTL) += sysctl_net_core.o | 8 | obj-$(CONFIG_SYSCTL) += sysctl_net_core.o |
| 9 | 9 | ||
| 10 | obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ | 10 | obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ |
| 11 | neighbour.o rtnetlink.o utils.o link_watch.o filter.o | 11 | neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ |
| 12 | dev_addr_lists.o | ||
| 12 | 13 | ||
| 13 | obj-$(CONFIG_XFRM) += flow.o | 14 | obj-$(CONFIG_XFRM) += flow.o |
| 14 | obj-y += net-sysfs.o | 15 | obj-y += net-sysfs.o |
diff --git a/net/core/dev.c b/net/core/dev.c index c6b52068d5ec..949c62dba719 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -3968,314 +3968,6 @@ void dev_set_rx_mode(struct net_device *dev) | |||
| 3968 | netif_addr_unlock_bh(dev); | 3968 | netif_addr_unlock_bh(dev); |
| 3969 | } | 3969 | } |
| 3970 | 3970 | ||
| 3971 | /* hw addresses list handling functions */ | ||
| 3972 | |||
| 3973 | static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr, | ||
| 3974 | int addr_len, unsigned char addr_type) | ||
| 3975 | { | ||
| 3976 | struct netdev_hw_addr *ha; | ||
| 3977 | int alloc_size; | ||
| 3978 | |||
| 3979 | if (addr_len > MAX_ADDR_LEN) | ||
| 3980 | return -EINVAL; | ||
| 3981 | |||
| 3982 | list_for_each_entry(ha, &list->list, list) { | ||
| 3983 | if (!memcmp(ha->addr, addr, addr_len) && | ||
| 3984 | ha->type == addr_type) { | ||
| 3985 | ha->refcount++; | ||
| 3986 | return 0; | ||
| 3987 | } | ||
| 3988 | } | ||
| 3989 | |||
| 3990 | |||
| 3991 | alloc_size = sizeof(*ha); | ||
| 3992 | if (alloc_size < L1_CACHE_BYTES) | ||
| 3993 | alloc_size = L1_CACHE_BYTES; | ||
| 3994 | ha = kmalloc(alloc_size, GFP_ATOMIC); | ||
| 3995 | if (!ha) | ||
| 3996 | return -ENOMEM; | ||
| 3997 | memcpy(ha->addr, addr, addr_len); | ||
| 3998 | ha->type = addr_type; | ||
| 3999 | ha->refcount = 1; | ||
| 4000 | ha->synced = false; | ||
| 4001 | list_add_tail_rcu(&ha->list, &list->list); | ||
| 4002 | list->count++; | ||
| 4003 | return 0; | ||
| 4004 | } | ||
| 4005 | |||
| 4006 | static void ha_rcu_free(struct rcu_head *head) | ||
| 4007 | { | ||
| 4008 | struct netdev_hw_addr *ha; | ||
| 4009 | |||
| 4010 | ha = container_of(head, struct netdev_hw_addr, rcu_head); | ||
| 4011 | kfree(ha); | ||
| 4012 | } | ||
| 4013 | |||
| 4014 | static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr, | ||
| 4015 | int addr_len, unsigned char addr_type) | ||
| 4016 | { | ||
| 4017 | struct netdev_hw_addr *ha; | ||
| 4018 | |||
| 4019 | list_for_each_entry(ha, &list->list, list) { | ||
| 4020 | if (!memcmp(ha->addr, addr, addr_len) && | ||
| 4021 | (ha->type == addr_type || !addr_type)) { | ||
| 4022 | if (--ha->refcount) | ||
| 4023 | return 0; | ||
| 4024 | list_del_rcu(&ha->list); | ||
| 4025 | call_rcu(&ha->rcu_head, ha_rcu_free); | ||
| 4026 | list->count--; | ||
| 4027 | return 0; | ||
| 4028 | } | ||
| 4029 | } | ||
| 4030 | return -ENOENT; | ||
| 4031 | } | ||
| 4032 | |||
| 4033 | static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, | ||
| 4034 | struct netdev_hw_addr_list *from_list, | ||
| 4035 | int addr_len, | ||
| 4036 | unsigned char addr_type) | ||
| 4037 | { | ||
| 4038 | int err; | ||
| 4039 | struct netdev_hw_addr *ha, *ha2; | ||
| 4040 | unsigned char type; | ||
| 4041 | |||
| 4042 | list_for_each_entry(ha, &from_list->list, list) { | ||
| 4043 | type = addr_type ? addr_type : ha->type; | ||
| 4044 | err = __hw_addr_add(to_list, ha->addr, addr_len, type); | ||
| 4045 | if (err) | ||
| 4046 | goto unroll; | ||
| 4047 | } | ||
| 4048 | return 0; | ||
| 4049 | |||
| 4050 | unroll: | ||
| 4051 | list_for_each_entry(ha2, &from_list->list, list) { | ||
| 4052 | if (ha2 == ha) | ||
| 4053 | break; | ||
| 4054 | type = addr_type ? addr_type : ha2->type; | ||
| 4055 | __hw_addr_del(to_list, ha2->addr, addr_len, type); | ||
| 4056 | } | ||
| 4057 | return err; | ||
| 4058 | } | ||
| 4059 | |||
| 4060 | static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list, | ||
| 4061 | struct netdev_hw_addr_list *from_list, | ||
| 4062 | int addr_len, | ||
| 4063 | unsigned char addr_type) | ||
| 4064 | { | ||
| 4065 | struct netdev_hw_addr *ha; | ||
| 4066 | unsigned char type; | ||
| 4067 | |||
| 4068 | list_for_each_entry(ha, &from_list->list, list) { | ||
| 4069 | type = addr_type ? addr_type : ha->type; | ||
| 4070 | __hw_addr_del(to_list, ha->addr, addr_len, addr_type); | ||
| 4071 | } | ||
| 4072 | } | ||
| 4073 | |||
| 4074 | static int __hw_addr_sync(struct netdev_hw_addr_list *to_list, | ||
| 4075 | struct netdev_hw_addr_list *from_list, | ||
| 4076 | int addr_len) | ||
| 4077 | { | ||
| 4078 | int err = 0; | ||
| 4079 | struct netdev_hw_addr *ha, *tmp; | ||
| 4080 | |||
| 4081 | list_for_each_entry_safe(ha, tmp, &from_list->list, list) { | ||
| 4082 | if (!ha->synced) { | ||
| 4083 | err = __hw_addr_add(to_list, ha->addr, | ||
| 4084 | addr_len, ha->type); | ||
| 4085 | if (err) | ||
| 4086 | break; | ||
| 4087 | ha->synced = true; | ||
| 4088 | ha->refcount++; | ||
| 4089 | } else if (ha->refcount == 1) { | ||
| 4090 | __hw_addr_del(to_list, ha->addr, addr_len, ha->type); | ||
| 4091 | __hw_addr_del(from_list, ha->addr, addr_len, ha->type); | ||
| 4092 | } | ||
| 4093 | } | ||
| 4094 | return err; | ||
| 4095 | } | ||
| 4096 | |||
| 4097 | static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, | ||
| 4098 | struct netdev_hw_addr_list *from_list, | ||
| 4099 | int addr_len) | ||
| 4100 | { | ||
| 4101 | struct netdev_hw_addr *ha, *tmp; | ||
| 4102 | |||
| 4103 | list_for_each_entry_safe(ha, tmp, &from_list->list, list) { | ||
| 4104 | if (ha->synced) { | ||
| 4105 | __hw_addr_del(to_list, ha->addr, | ||
| 4106 | addr_len, ha->type); | ||
| 4107 | ha->synced = false; | ||
| 4108 | __hw_addr_del(from_list, ha->addr, | ||
| 4109 | addr_len, ha->type); | ||
| 4110 | } | ||
| 4111 | } | ||
| 4112 | } | ||
| 4113 | |||
| 4114 | static void __hw_addr_flush(struct netdev_hw_addr_list *list) | ||
| 4115 | { | ||
| 4116 | struct netdev_hw_addr *ha, *tmp; | ||
| 4117 | |||
| 4118 | list_for_each_entry_safe(ha, tmp, &list->list, list) { | ||
| 4119 | list_del_rcu(&ha->list); | ||
| 4120 | call_rcu(&ha->rcu_head, ha_rcu_free); | ||
| 4121 | } | ||
| 4122 | list->count = 0; | ||
| 4123 | } | ||
| 4124 | |||
| 4125 | static void __hw_addr_init(struct netdev_hw_addr_list *list) | ||
| 4126 | { | ||
| 4127 | INIT_LIST_HEAD(&list->list); | ||
| 4128 | list->count = 0; | ||
| 4129 | } | ||
| 4130 | |||
| 4131 | /* Device addresses handling functions */ | ||
| 4132 | |||
| 4133 | static void dev_addr_flush(struct net_device *dev) | ||
| 4134 | { | ||
| 4135 | /* rtnl_mutex must be held here */ | ||
| 4136 | |||
| 4137 | __hw_addr_flush(&dev->dev_addrs); | ||
| 4138 | dev->dev_addr = NULL; | ||
| 4139 | } | ||
| 4140 | |||
| 4141 | static int dev_addr_init(struct net_device *dev) | ||
| 4142 | { | ||
| 4143 | unsigned char addr[MAX_ADDR_LEN]; | ||
| 4144 | struct netdev_hw_addr *ha; | ||
| 4145 | int err; | ||
| 4146 | |||
| 4147 | /* rtnl_mutex must be held here */ | ||
| 4148 | |||
| 4149 | __hw_addr_init(&dev->dev_addrs); | ||
| 4150 | memset(addr, 0, sizeof(addr)); | ||
| 4151 | err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr), | ||
| 4152 | NETDEV_HW_ADDR_T_LAN); | ||
| 4153 | if (!err) { | ||
| 4154 | /* | ||
| 4155 | * Get the first (previously created) address from the list | ||
| 4156 | * and set dev_addr pointer to this location. | ||
| 4157 | */ | ||
| 4158 | ha = list_first_entry(&dev->dev_addrs.list, | ||
| 4159 | struct netdev_hw_addr, list); | ||
| 4160 | dev->dev_addr = ha->addr; | ||
| 4161 | } | ||
| 4162 | return err; | ||
| 4163 | } | ||
| 4164 | |||
| 4165 | /** | ||
| 4166 | * dev_addr_add - Add a device address | ||
| 4167 | * @dev: device | ||
| 4168 | * @addr: address to add | ||
| 4169 | * @addr_type: address type | ||
| 4170 | * | ||
| 4171 | * Add a device address to the device or increase the reference count if | ||
| 4172 | * it already exists. | ||
| 4173 | * | ||
| 4174 | * The caller must hold the rtnl_mutex. | ||
| 4175 | */ | ||
| 4176 | int dev_addr_add(struct net_device *dev, unsigned char *addr, | ||
| 4177 | unsigned char addr_type) | ||
| 4178 | { | ||
| 4179 | int err; | ||
| 4180 | |||
| 4181 | ASSERT_RTNL(); | ||
| 4182 | |||
| 4183 | err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type); | ||
| 4184 | if (!err) | ||
| 4185 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
| 4186 | return err; | ||
| 4187 | } | ||
| 4188 | EXPORT_SYMBOL(dev_addr_add); | ||
| 4189 | |||
| 4190 | /** | ||
| 4191 | * dev_addr_del - Release a device address. | ||
| 4192 | * @dev: device | ||
| 4193 | * @addr: address to delete | ||
| 4194 | * @addr_type: address type | ||
| 4195 | * | ||
| 4196 | * Release reference to a device address and remove it from the device | ||
| 4197 | * if the reference count drops to zero. | ||
| 4198 | * | ||
| 4199 | * The caller must hold the rtnl_mutex. | ||
| 4200 | */ | ||
| 4201 | int dev_addr_del(struct net_device *dev, unsigned char *addr, | ||
| 4202 | unsigned char addr_type) | ||
| 4203 | { | ||
| 4204 | int err; | ||
| 4205 | struct netdev_hw_addr *ha; | ||
| 4206 | |||
| 4207 | ASSERT_RTNL(); | ||
| 4208 | |||
| 4209 | /* | ||
| 4210 | * We can not remove the first address from the list because | ||
| 4211 | * dev->dev_addr points to that. | ||
| 4212 | */ | ||
| 4213 | ha = list_first_entry(&dev->dev_addrs.list, | ||
| 4214 | struct netdev_hw_addr, list); | ||
| 4215 | if (ha->addr == dev->dev_addr && ha->refcount == 1) | ||
| 4216 | return -ENOENT; | ||
| 4217 | |||
| 4218 | err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len, | ||
| 4219 | addr_type); | ||
| 4220 | if (!err) | ||
| 4221 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
| 4222 | return err; | ||
| 4223 | } | ||
| 4224 | EXPORT_SYMBOL(dev_addr_del); | ||
| 4225 | |||
| 4226 | /** | ||
| 4227 | * dev_addr_add_multiple - Add device addresses from another device | ||
| 4228 | * @to_dev: device to which addresses will be added | ||
| 4229 | * @from_dev: device from which addresses will be added | ||
| 4230 | * @addr_type: address type - 0 means type will be used from from_dev | ||
| 4231 | * | ||
| 4232 | * Add device addresses of the one device to another. | ||
| 4233 | ** | ||
| 4234 | * The caller must hold the rtnl_mutex. | ||
| 4235 | */ | ||
| 4236 | int dev_addr_add_multiple(struct net_device *to_dev, | ||
| 4237 | struct net_device *from_dev, | ||
| 4238 | unsigned char addr_type) | ||
| 4239 | { | ||
| 4240 | int err; | ||
| 4241 | |||
| 4242 | ASSERT_RTNL(); | ||
| 4243 | |||
| 4244 | if (from_dev->addr_len != to_dev->addr_len) | ||
| 4245 | return -EINVAL; | ||
| 4246 | err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, | ||
| 4247 | to_dev->addr_len, addr_type); | ||
| 4248 | if (!err) | ||
| 4249 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
| 4250 | return err; | ||
| 4251 | } | ||
| 4252 | EXPORT_SYMBOL(dev_addr_add_multiple); | ||
| 4253 | |||
| 4254 | /** | ||
| 4255 | * dev_addr_del_multiple - Delete device addresses by another device | ||
| 4256 | * @to_dev: device where the addresses will be deleted | ||
| 4257 | * @from_dev: device by which addresses the addresses will be deleted | ||
| 4258 | * @addr_type: address type - 0 means type will used from from_dev | ||
| 4259 | * | ||
| 4260 | * Deletes addresses in to device by the list of addresses in from device. | ||
| 4261 | * | ||
| 4262 | * The caller must hold the rtnl_mutex. | ||
| 4263 | */ | ||
| 4264 | int dev_addr_del_multiple(struct net_device *to_dev, | ||
| 4265 | struct net_device *from_dev, | ||
| 4266 | unsigned char addr_type) | ||
| 4267 | { | ||
| 4268 | ASSERT_RTNL(); | ||
| 4269 | |||
| 4270 | if (from_dev->addr_len != to_dev->addr_len) | ||
| 4271 | return -EINVAL; | ||
| 4272 | __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, | ||
| 4273 | to_dev->addr_len, addr_type); | ||
| 4274 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
| 4275 | return 0; | ||
| 4276 | } | ||
| 4277 | EXPORT_SYMBOL(dev_addr_del_multiple); | ||
| 4278 | |||
| 4279 | /* multicast addresses handling functions */ | 3971 | /* multicast addresses handling functions */ |
| 4280 | 3972 | ||
| 4281 | int __dev_addr_delete(struct dev_addr_list **list, int *count, | 3973 | int __dev_addr_delete(struct dev_addr_list **list, int *count, |
| @@ -4336,57 +4028,6 @@ int __dev_addr_add(struct dev_addr_list **list, int *count, | |||
| 4336 | return 0; | 4028 | return 0; |
| 4337 | } | 4029 | } |
| 4338 | 4030 | ||
| 4339 | /** | ||
| 4340 | * dev_unicast_delete - Release secondary unicast address. | ||
| 4341 | * @dev: device | ||
| 4342 | * @addr: address to delete | ||
| 4343 | * | ||
| 4344 | * Release reference to a secondary unicast address and remove it | ||
| 4345 | * from the device if the reference count drops to zero. | ||
| 4346 | * | ||
| 4347 | * The caller must hold the rtnl_mutex. | ||
| 4348 | */ | ||
| 4349 | int dev_unicast_delete(struct net_device *dev, void *addr) | ||
| 4350 | { | ||
| 4351 | int err; | ||
| 4352 | |||
| 4353 | ASSERT_RTNL(); | ||
| 4354 | |||
| 4355 | netif_addr_lock_bh(dev); | ||
| 4356 | err = __hw_addr_del(&dev->uc, addr, dev->addr_len, | ||
| 4357 | NETDEV_HW_ADDR_T_UNICAST); | ||
| 4358 | if (!err) | ||
| 4359 | __dev_set_rx_mode(dev); | ||
| 4360 | netif_addr_unlock_bh(dev); | ||
| 4361 | return err; | ||
| 4362 | } | ||
| 4363 | EXPORT_SYMBOL(dev_unicast_delete); | ||
| 4364 | |||
| 4365 | /** | ||
| 4366 | * dev_unicast_add - add a secondary unicast address | ||
| 4367 | * @dev: device | ||
| 4368 | * @addr: address to add | ||
| 4369 | * | ||
| 4370 | * Add a secondary unicast address to the device or increase | ||
| 4371 | * the reference count if it already exists. | ||
| 4372 | * | ||
| 4373 | * The caller must hold the rtnl_mutex. | ||
| 4374 | */ | ||
| 4375 | int dev_unicast_add(struct net_device *dev, void *addr) | ||
| 4376 | { | ||
| 4377 | int err; | ||
| 4378 | |||
| 4379 | ASSERT_RTNL(); | ||
| 4380 | |||
| 4381 | netif_addr_lock_bh(dev); | ||
| 4382 | err = __hw_addr_add(&dev->uc, addr, dev->addr_len, | ||
| 4383 | NETDEV_HW_ADDR_T_UNICAST); | ||
| 4384 | if (!err) | ||
| 4385 | __dev_set_rx_mode(dev); | ||
| 4386 | netif_addr_unlock_bh(dev); | ||
| 4387 | return err; | ||
| 4388 | } | ||
| 4389 | EXPORT_SYMBOL(dev_unicast_add); | ||
| 4390 | 4031 | ||
| 4391 | int __dev_addr_sync(struct dev_addr_list **to, int *to_count, | 4032 | int __dev_addr_sync(struct dev_addr_list **to, int *to_count, |
| 4392 | struct dev_addr_list **from, int *from_count) | 4033 | struct dev_addr_list **from, int *from_count) |
| @@ -4436,71 +4077,6 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, | |||
| 4436 | } | 4077 | } |
| 4437 | EXPORT_SYMBOL_GPL(__dev_addr_unsync); | 4078 | EXPORT_SYMBOL_GPL(__dev_addr_unsync); |
| 4438 | 4079 | ||
| 4439 | /** | ||
| 4440 | * dev_unicast_sync - Synchronize device's unicast list to another device | ||
| 4441 | * @to: destination device | ||
| 4442 | * @from: source device | ||
| 4443 | * | ||
| 4444 | * Add newly added addresses to the destination device and release | ||
| 4445 | * addresses that have no users left. The source device must be | ||
| 4446 | * locked by netif_tx_lock_bh. | ||
| 4447 | * | ||
| 4448 | * This function is intended to be called from the dev->set_rx_mode | ||
| 4449 | * function of layered software devices. | ||
| 4450 | */ | ||
| 4451 | int dev_unicast_sync(struct net_device *to, struct net_device *from) | ||
| 4452 | { | ||
| 4453 | int err = 0; | ||
| 4454 | |||
| 4455 | if (to->addr_len != from->addr_len) | ||
| 4456 | return -EINVAL; | ||
| 4457 | |||
| 4458 | netif_addr_lock_bh(to); | ||
| 4459 | err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len); | ||
| 4460 | if (!err) | ||
| 4461 | __dev_set_rx_mode(to); | ||
| 4462 | netif_addr_unlock_bh(to); | ||
| 4463 | return err; | ||
| 4464 | } | ||
| 4465 | EXPORT_SYMBOL(dev_unicast_sync); | ||
| 4466 | |||
| 4467 | /** | ||
| 4468 | * dev_unicast_unsync - Remove synchronized addresses from the destination device | ||
| 4469 | * @to: destination device | ||
| 4470 | * @from: source device | ||
| 4471 | * | ||
| 4472 | * Remove all addresses that were added to the destination device by | ||
| 4473 | * dev_unicast_sync(). This function is intended to be called from the | ||
| 4474 | * dev->stop function of layered software devices. | ||
| 4475 | */ | ||
| 4476 | void dev_unicast_unsync(struct net_device *to, struct net_device *from) | ||
| 4477 | { | ||
| 4478 | if (to->addr_len != from->addr_len) | ||
| 4479 | return; | ||
| 4480 | |||
| 4481 | netif_addr_lock_bh(from); | ||
| 4482 | netif_addr_lock(to); | ||
| 4483 | __hw_addr_unsync(&to->uc, &from->uc, to->addr_len); | ||
| 4484 | __dev_set_rx_mode(to); | ||
| 4485 | netif_addr_unlock(to); | ||
| 4486 | netif_addr_unlock_bh(from); | ||
| 4487 | } | ||
| 4488 | EXPORT_SYMBOL(dev_unicast_unsync); | ||
| 4489 | |||
| 4490 | void dev_unicast_flush(struct net_device *dev) | ||
| 4491 | { | ||
| 4492 | netif_addr_lock_bh(dev); | ||
| 4493 | __hw_addr_flush(&dev->uc); | ||
| 4494 | netif_addr_unlock_bh(dev); | ||
| 4495 | } | ||
| 4496 | EXPORT_SYMBOL(dev_unicast_flush); | ||
| 4497 | |||
| 4498 | static void dev_unicast_init(struct net_device *dev) | ||
| 4499 | { | ||
| 4500 | __hw_addr_init(&dev->uc); | ||
| 4501 | } | ||
| 4502 | |||
| 4503 | |||
| 4504 | static void __dev_addr_discard(struct dev_addr_list **list) | 4080 | static void __dev_addr_discard(struct dev_addr_list **list) |
| 4505 | { | 4081 | { |
| 4506 | struct dev_addr_list *tmp; | 4082 | struct dev_addr_list *tmp; |
| @@ -5153,7 +4729,7 @@ static void rollback_registered_many(struct list_head *head) | |||
| 5153 | /* | 4729 | /* |
| 5154 | * Flush the unicast and multicast chains | 4730 | * Flush the unicast and multicast chains |
| 5155 | */ | 4731 | */ |
| 5156 | dev_unicast_flush(dev); | 4732 | dev_uc_flush(dev); |
| 5157 | dev_addr_discard(dev); | 4733 | dev_addr_discard(dev); |
| 5158 | 4734 | ||
| 5159 | if (dev->netdev_ops->ndo_uninit) | 4735 | if (dev->netdev_ops->ndo_uninit) |
| @@ -5734,7 +5310,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, | |||
| 5734 | if (dev_addr_init(dev)) | 5310 | if (dev_addr_init(dev)) |
| 5735 | goto free_rx; | 5311 | goto free_rx; |
| 5736 | 5312 | ||
| 5737 | dev_unicast_init(dev); | 5313 | dev_uc_init(dev); |
| 5738 | 5314 | ||
| 5739 | dev_net_set(dev, &init_net); | 5315 | dev_net_set(dev, &init_net); |
| 5740 | 5316 | ||
| @@ -5968,7 +5544,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char | |||
| 5968 | /* | 5544 | /* |
| 5969 | * Flush the unicast and multicast chains | 5545 | * Flush the unicast and multicast chains |
| 5970 | */ | 5546 | */ |
| 5971 | dev_unicast_flush(dev); | 5547 | dev_uc_flush(dev); |
| 5972 | dev_addr_discard(dev); | 5548 | dev_addr_discard(dev); |
| 5973 | 5549 | ||
| 5974 | netdev_unregister_kobject(dev); | 5550 | netdev_unregister_kobject(dev); |
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c new file mode 100644 index 000000000000..7e52b6d18add --- /dev/null +++ b/net/core/dev_addr_lists.c | |||
| @@ -0,0 +1,478 @@ | |||
| 1 | /* | ||
| 2 | * net/core/dev_addr_lists.c - Functions for handling net device lists | ||
| 3 | * Copyright (c) 2010 Jiri Pirko <jpirko@redhat.com> | ||
| 4 | * | ||
| 5 | * This file contains functions for working with unicast, multicast and device | ||
| 6 | * addresses lists. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/netdevice.h> | ||
| 15 | #include <linux/rtnetlink.h> | ||
| 16 | #include <linux/list.h> | ||
| 17 | |||
| 18 | /* | ||
| 19 | * General list handling functions | ||
| 20 | */ | ||
| 21 | |||
| 22 | static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr, | ||
| 23 | int addr_len, unsigned char addr_type) | ||
| 24 | { | ||
| 25 | struct netdev_hw_addr *ha; | ||
| 26 | int alloc_size; | ||
| 27 | |||
| 28 | if (addr_len > MAX_ADDR_LEN) | ||
| 29 | return -EINVAL; | ||
| 30 | |||
| 31 | list_for_each_entry(ha, &list->list, list) { | ||
| 32 | if (!memcmp(ha->addr, addr, addr_len) && | ||
| 33 | ha->type == addr_type) { | ||
| 34 | ha->refcount++; | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | |||
| 40 | alloc_size = sizeof(*ha); | ||
| 41 | if (alloc_size < L1_CACHE_BYTES) | ||
| 42 | alloc_size = L1_CACHE_BYTES; | ||
| 43 | ha = kmalloc(alloc_size, GFP_ATOMIC); | ||
| 44 | if (!ha) | ||
| 45 | return -ENOMEM; | ||
| 46 | memcpy(ha->addr, addr, addr_len); | ||
| 47 | ha->type = addr_type; | ||
| 48 | ha->refcount = 1; | ||
| 49 | ha->synced = false; | ||
| 50 | list_add_tail_rcu(&ha->list, &list->list); | ||
| 51 | list->count++; | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | static void ha_rcu_free(struct rcu_head *head) | ||
| 56 | { | ||
| 57 | struct netdev_hw_addr *ha; | ||
| 58 | |||
| 59 | ha = container_of(head, struct netdev_hw_addr, rcu_head); | ||
| 60 | kfree(ha); | ||
| 61 | } | ||
| 62 | |||
| 63 | static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr, | ||
| 64 | int addr_len, unsigned char addr_type) | ||
| 65 | { | ||
| 66 | struct netdev_hw_addr *ha; | ||
| 67 | |||
| 68 | list_for_each_entry(ha, &list->list, list) { | ||
| 69 | if (!memcmp(ha->addr, addr, addr_len) && | ||
| 70 | (ha->type == addr_type || !addr_type)) { | ||
| 71 | if (--ha->refcount) | ||
| 72 | return 0; | ||
| 73 | list_del_rcu(&ha->list); | ||
| 74 | call_rcu(&ha->rcu_head, ha_rcu_free); | ||
| 75 | list->count--; | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | return -ENOENT; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, | ||
| 83 | struct netdev_hw_addr_list *from_list, | ||
| 84 | int addr_len, | ||
| 85 | unsigned char addr_type) | ||
| 86 | { | ||
| 87 | int err; | ||
| 88 | struct netdev_hw_addr *ha, *ha2; | ||
| 89 | unsigned char type; | ||
| 90 | |||
| 91 | list_for_each_entry(ha, &from_list->list, list) { | ||
| 92 | type = addr_type ? addr_type : ha->type; | ||
| 93 | err = __hw_addr_add(to_list, ha->addr, addr_len, type); | ||
| 94 | if (err) | ||
| 95 | goto unroll; | ||
| 96 | } | ||
| 97 | return 0; | ||
| 98 | |||
| 99 | unroll: | ||
| 100 | list_for_each_entry(ha2, &from_list->list, list) { | ||
| 101 | if (ha2 == ha) | ||
| 102 | break; | ||
| 103 | type = addr_type ? addr_type : ha2->type; | ||
| 104 | __hw_addr_del(to_list, ha2->addr, addr_len, type); | ||
| 105 | } | ||
| 106 | return err; | ||
| 107 | } | ||
| 108 | |||
| 109 | static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list, | ||
| 110 | struct netdev_hw_addr_list *from_list, | ||
| 111 | int addr_len, | ||
| 112 | unsigned char addr_type) | ||
| 113 | { | ||
| 114 | struct netdev_hw_addr *ha; | ||
| 115 | unsigned char type; | ||
| 116 | |||
| 117 | list_for_each_entry(ha, &from_list->list, list) { | ||
| 118 | type = addr_type ? addr_type : ha->type; | ||
| 119 | __hw_addr_del(to_list, ha->addr, addr_len, addr_type); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | static int __hw_addr_sync(struct netdev_hw_addr_list *to_list, | ||
| 124 | struct netdev_hw_addr_list *from_list, | ||
| 125 | int addr_len) | ||
| 126 | { | ||
| 127 | int err = 0; | ||
| 128 | struct netdev_hw_addr *ha, *tmp; | ||
| 129 | |||
| 130 | list_for_each_entry_safe(ha, tmp, &from_list->list, list) { | ||
| 131 | if (!ha->synced) { | ||
| 132 | err = __hw_addr_add(to_list, ha->addr, | ||
| 133 | addr_len, ha->type); | ||
| 134 | if (err) | ||
| 135 | break; | ||
| 136 | ha->synced = true; | ||
| 137 | ha->refcount++; | ||
| 138 | } else if (ha->refcount == 1) { | ||
| 139 | __hw_addr_del(to_list, ha->addr, addr_len, ha->type); | ||
| 140 | __hw_addr_del(from_list, ha->addr, addr_len, ha->type); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | return err; | ||
| 144 | } | ||
| 145 | |||
| 146 | static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, | ||
| 147 | struct netdev_hw_addr_list *from_list, | ||
| 148 | int addr_len) | ||
| 149 | { | ||
| 150 | struct netdev_hw_addr *ha, *tmp; | ||
| 151 | |||
| 152 | list_for_each_entry_safe(ha, tmp, &from_list->list, list) { | ||
| 153 | if (ha->synced) { | ||
| 154 | __hw_addr_del(to_list, ha->addr, | ||
| 155 | addr_len, ha->type); | ||
| 156 | ha->synced = false; | ||
| 157 | __hw_addr_del(from_list, ha->addr, | ||
| 158 | addr_len, ha->type); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | static void __hw_addr_flush(struct netdev_hw_addr_list *list) | ||
| 164 | { | ||
| 165 | struct netdev_hw_addr *ha, *tmp; | ||
| 166 | |||
| 167 | list_for_each_entry_safe(ha, tmp, &list->list, list) { | ||
| 168 | list_del_rcu(&ha->list); | ||
| 169 | call_rcu(&ha->rcu_head, ha_rcu_free); | ||
| 170 | } | ||
| 171 | list->count = 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static void __hw_addr_init(struct netdev_hw_addr_list *list) | ||
| 175 | { | ||
| 176 | INIT_LIST_HEAD(&list->list); | ||
| 177 | list->count = 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Device addresses handling functions | ||
| 182 | */ | ||
| 183 | |||
| 184 | /** | ||
| 185 | * dev_addr_flush - Flush device address list | ||
| 186 | * @dev: device | ||
| 187 | * | ||
| 188 | * Flush device address list and reset ->dev_addr. | ||
| 189 | * | ||
| 190 | * The caller must hold the rtnl_mutex. | ||
| 191 | */ | ||
| 192 | void dev_addr_flush(struct net_device *dev) | ||
| 193 | { | ||
| 194 | /* rtnl_mutex must be held here */ | ||
| 195 | |||
| 196 | __hw_addr_flush(&dev->dev_addrs); | ||
| 197 | dev->dev_addr = NULL; | ||
| 198 | } | ||
| 199 | EXPORT_SYMBOL(dev_addr_flush); | ||
| 200 | |||
| 201 | /** | ||
| 202 | * dev_addr_init - Init device address list | ||
| 203 | * @dev: device | ||
| 204 | * | ||
| 205 | * Init device address list and create the first element, | ||
| 206 | * used by ->dev_addr. | ||
| 207 | * | ||
| 208 | * The caller must hold the rtnl_mutex. | ||
| 209 | */ | ||
| 210 | int dev_addr_init(struct net_device *dev) | ||
| 211 | { | ||
| 212 | unsigned char addr[MAX_ADDR_LEN]; | ||
| 213 | struct netdev_hw_addr *ha; | ||
| 214 | int err; | ||
| 215 | |||
| 216 | /* rtnl_mutex must be held here */ | ||
| 217 | |||
| 218 | __hw_addr_init(&dev->dev_addrs); | ||
| 219 | memset(addr, 0, sizeof(addr)); | ||
| 220 | err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr), | ||
| 221 | NETDEV_HW_ADDR_T_LAN); | ||
| 222 | if (!err) { | ||
| 223 | /* | ||
| 224 | * Get the first (previously created) address from the list | ||
| 225 | * and set dev_addr pointer to this location. | ||
| 226 | */ | ||
| 227 | ha = list_first_entry(&dev->dev_addrs.list, | ||
| 228 | struct netdev_hw_addr, list); | ||
| 229 | dev->dev_addr = ha->addr; | ||
| 230 | } | ||
| 231 | return err; | ||
| 232 | } | ||
| 233 | EXPORT_SYMBOL(dev_addr_init); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * dev_addr_add - Add a device address | ||
| 237 | * @dev: device | ||
| 238 | * @addr: address to add | ||
| 239 | * @addr_type: address type | ||
| 240 | * | ||
| 241 | * Add a device address to the device or increase the reference count if | ||
| 242 | * it already exists. | ||
| 243 | * | ||
| 244 | * The caller must hold the rtnl_mutex. | ||
| 245 | */ | ||
| 246 | int dev_addr_add(struct net_device *dev, unsigned char *addr, | ||
| 247 | unsigned char addr_type) | ||
| 248 | { | ||
| 249 | int err; | ||
| 250 | |||
| 251 | ASSERT_RTNL(); | ||
| 252 | |||
| 253 | err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type); | ||
| 254 | if (!err) | ||
| 255 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
| 256 | return err; | ||
| 257 | } | ||
| 258 | EXPORT_SYMBOL(dev_addr_add); | ||
| 259 | |||
| 260 | /** | ||
| 261 | * dev_addr_del - Release a device address. | ||
| 262 | * @dev: device | ||
| 263 | * @addr: address to delete | ||
| 264 | * @addr_type: address type | ||
| 265 | * | ||
| 266 | * Release reference to a device address and remove it from the device | ||
| 267 | * if the reference count drops to zero. | ||
| 268 | * | ||
| 269 | * The caller must hold the rtnl_mutex. | ||
| 270 | */ | ||
| 271 | int dev_addr_del(struct net_device *dev, unsigned char *addr, | ||
| 272 | unsigned char addr_type) | ||
| 273 | { | ||
| 274 | int err; | ||
| 275 | struct netdev_hw_addr *ha; | ||
| 276 | |||
| 277 | ASSERT_RTNL(); | ||
| 278 | |||
| 279 | /* | ||
| 280 | * We can not remove the first address from the list because | ||
| 281 | * dev->dev_addr points to that. | ||
| 282 | */ | ||
| 283 | ha = list_first_entry(&dev->dev_addrs.list, | ||
| 284 | struct netdev_hw_addr, list); | ||
| 285 | if (ha->addr == dev->dev_addr && ha->refcount == 1) | ||
| 286 | return -ENOENT; | ||
| 287 | |||
| 288 | err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len, | ||
| 289 | addr_type); | ||
| 290 | if (!err) | ||
| 291 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
| 292 | return err; | ||
| 293 | } | ||
| 294 | EXPORT_SYMBOL(dev_addr_del); | ||
| 295 | |||
| 296 | /** | ||
| 297 | * dev_addr_add_multiple - Add device addresses from another device | ||
| 298 | * @to_dev: device to which addresses will be added | ||
| 299 | * @from_dev: device from which addresses will be added | ||
| 300 | * @addr_type: address type - 0 means type will be used from from_dev | ||
| 301 | * | ||
| 302 | * Add device addresses of the one device to another. | ||
| 303 | ** | ||
| 304 | * The caller must hold the rtnl_mutex. | ||
| 305 | */ | ||
| 306 | int dev_addr_add_multiple(struct net_device *to_dev, | ||
| 307 | struct net_device *from_dev, | ||
| 308 | unsigned char addr_type) | ||
| 309 | { | ||
| 310 | int err; | ||
| 311 | |||
| 312 | ASSERT_RTNL(); | ||
| 313 | |||
| 314 | if (from_dev->addr_len != to_dev->addr_len) | ||
| 315 | return -EINVAL; | ||
| 316 | err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, | ||
| 317 | to_dev->addr_len, addr_type); | ||
| 318 | if (!err) | ||
| 319 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
| 320 | return err; | ||
| 321 | } | ||
| 322 | EXPORT_SYMBOL(dev_addr_add_multiple); | ||
| 323 | |||
| 324 | /** | ||
| 325 | * dev_addr_del_multiple - Delete device addresses by another device | ||
| 326 | * @to_dev: device where the addresses will be deleted | ||
| 327 | * @from_dev: device by which addresses the addresses will be deleted | ||
| 328 | * @addr_type: address type - 0 means type will used from from_dev | ||
| 329 | * | ||
| 330 | * Deletes addresses in to device by the list of addresses in from device. | ||
| 331 | * | ||
| 332 | * The caller must hold the rtnl_mutex. | ||
| 333 | */ | ||
| 334 | int dev_addr_del_multiple(struct net_device *to_dev, | ||
| 335 | struct net_device *from_dev, | ||
| 336 | unsigned char addr_type) | ||
| 337 | { | ||
| 338 | ASSERT_RTNL(); | ||
| 339 | |||
| 340 | if (from_dev->addr_len != to_dev->addr_len) | ||
| 341 | return -EINVAL; | ||
| 342 | __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, | ||
| 343 | to_dev->addr_len, addr_type); | ||
| 344 | call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); | ||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | EXPORT_SYMBOL(dev_addr_del_multiple); | ||
| 348 | |||
| 349 | /* | ||
| 350 | * Unicast list handling functions | ||
| 351 | */ | ||
| 352 | |||
| 353 | /** | ||
| 354 | * dev_uc_add - Add a secondary unicast address | ||
| 355 | * @dev: device | ||
| 356 | * @addr: address to add | ||
| 357 | * | ||
| 358 | * Add a secondary unicast address to the device or increase | ||
| 359 | * the reference count if it already exists. | ||
| 360 | */ | ||
| 361 | int dev_uc_add(struct net_device *dev, unsigned char *addr) | ||
| 362 | { | ||
| 363 | int err; | ||
| 364 | |||
| 365 | netif_addr_lock_bh(dev); | ||
| 366 | err = __hw_addr_add(&dev->uc, addr, dev->addr_len, | ||
| 367 | NETDEV_HW_ADDR_T_UNICAST); | ||
| 368 | if (!err) | ||
| 369 | __dev_set_rx_mode(dev); | ||
| 370 | netif_addr_unlock_bh(dev); | ||
| 371 | return err; | ||
| 372 | } | ||
| 373 | EXPORT_SYMBOL(dev_uc_add); | ||
| 374 | |||
| 375 | /** | ||
| 376 | * dev_uc_del - Release secondary unicast address. | ||
| 377 | * @dev: device | ||
| 378 | * @addr: address to delete | ||
| 379 | * | ||
| 380 | * Release reference to a secondary unicast address and remove it | ||
| 381 | * from the device if the reference count drops to zero. | ||
| 382 | */ | ||
| 383 | int dev_uc_del(struct net_device *dev, unsigned char *addr) | ||
| 384 | { | ||
| 385 | int err; | ||
| 386 | |||
| 387 | netif_addr_lock_bh(dev); | ||
| 388 | err = __hw_addr_del(&dev->uc, addr, dev->addr_len, | ||
| 389 | NETDEV_HW_ADDR_T_UNICAST); | ||
| 390 | if (!err) | ||
| 391 | __dev_set_rx_mode(dev); | ||
| 392 | netif_addr_unlock_bh(dev); | ||
| 393 | return err; | ||
| 394 | } | ||
| 395 | EXPORT_SYMBOL(dev_uc_del); | ||
| 396 | |||
| 397 | /** | ||
| 398 | * dev_uc_sync - Synchronize device's unicast list to another device | ||
| 399 | * @to: destination device | ||
| 400 | * @from: source device | ||
| 401 | * | ||
| 402 | * Add newly added addresses to the destination device and release | ||
| 403 | * addresses that have no users left. The source device must be | ||
| 404 | * locked by netif_tx_lock_bh. | ||
| 405 | * | ||
| 406 | * This function is intended to be called from the dev->set_rx_mode | ||
| 407 | * function of layered software devices. | ||
| 408 | */ | ||
| 409 | int dev_uc_sync(struct net_device *to, struct net_device *from) | ||
| 410 | { | ||
| 411 | int err = 0; | ||
| 412 | |||
| 413 | if (to->addr_len != from->addr_len) | ||
| 414 | return -EINVAL; | ||
| 415 | |||
| 416 | netif_addr_lock_bh(to); | ||
| 417 | err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len); | ||
| 418 | if (!err) | ||
| 419 | __dev_set_rx_mode(to); | ||
| 420 | netif_addr_unlock_bh(to); | ||
| 421 | return err; | ||
| 422 | } | ||
| 423 | EXPORT_SYMBOL(dev_uc_sync); | ||
| 424 | |||
| 425 | /** | ||
| 426 | * dev_uc_unsync - Remove synchronized addresses from the destination device | ||
| 427 | * @to: destination device | ||
| 428 | * @from: source device | ||
| 429 | * | ||
| 430 | * Remove all addresses that were added to the destination device by | ||
| 431 | * dev_uc_sync(). This function is intended to be called from the | ||
| 432 | * dev->stop function of layered software devices. | ||
| 433 | */ | ||
| 434 | void dev_uc_unsync(struct net_device *to, struct net_device *from) | ||
| 435 | { | ||
| 436 | if (to->addr_len != from->addr_len) | ||
| 437 | return; | ||
| 438 | |||
| 439 | netif_addr_lock_bh(from); | ||
| 440 | netif_addr_lock(to); | ||
| 441 | __hw_addr_unsync(&to->uc, &from->uc, to->addr_len); | ||
| 442 | __dev_set_rx_mode(to); | ||
| 443 | netif_addr_unlock(to); | ||
| 444 | netif_addr_unlock_bh(from); | ||
| 445 | } | ||
| 446 | EXPORT_SYMBOL(dev_uc_unsync); | ||
| 447 | |||
| 448 | /** | ||
| 449 | * dev_uc_flush - Flush unicast addresses | ||
| 450 | * @dev: device | ||
| 451 | * | ||
| 452 | * Flush unicast addresses. | ||
| 453 | */ | ||
| 454 | void dev_uc_flush(struct net_device *dev) | ||
| 455 | { | ||
| 456 | netif_addr_lock_bh(dev); | ||
| 457 | __hw_addr_flush(&dev->uc); | ||
| 458 | netif_addr_unlock_bh(dev); | ||
| 459 | } | ||
| 460 | EXPORT_SYMBOL(dev_uc_flush); | ||
| 461 | |||
| 462 | /** | ||
| 463 | * dev_uc_flush - Init unicast address list | ||
| 464 | * @dev: device | ||
| 465 | * | ||
| 466 | * Init unicast address list. | ||
| 467 | */ | ||
| 468 | void dev_uc_init(struct net_device *dev) | ||
| 469 | { | ||
| 470 | __hw_addr_init(&dev->uc); | ||
| 471 | } | ||
| 472 | EXPORT_SYMBOL(dev_uc_init); | ||
| 473 | |||
| 474 | /* | ||
| 475 | * Multicast list handling functions | ||
| 476 | */ | ||
| 477 | |||
| 478 | /* To be filled here */ | ||
