ipv6: fail early when creating netdev named all or default
We create a proc dir for each network device, this will cause conflicts when the devices have name "all" or "default". Rather than emitting an ugly kernel warning, we could just fail earlier by checking the device name. Reported-by: Stephane Chazelas <stephane.chazelas@gmail.com> Cc: "David S. Miller" <davem@davemloft.net> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
20e61da7ff
Коммит
a317a2f19d
|
@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SYSCTL
|
#ifdef CONFIG_SYSCTL
|
||||||
static void addrconf_sysctl_register(struct inet6_dev *idev);
|
static int addrconf_sysctl_register(struct inet6_dev *idev);
|
||||||
static void addrconf_sysctl_unregister(struct inet6_dev *idev);
|
static void addrconf_sysctl_unregister(struct inet6_dev *idev);
|
||||||
#else
|
#else
|
||||||
static inline void addrconf_sysctl_register(struct inet6_dev *idev)
|
static inline int addrconf_sysctl_register(struct inet6_dev *idev)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
|
static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
|
||||||
|
@ -310,16 +311,16 @@ err_ip:
|
||||||
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct inet6_dev *ndev;
|
struct inet6_dev *ndev;
|
||||||
|
int err = -ENOMEM;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
if (dev->mtu < IPV6_MIN_MTU)
|
if (dev->mtu < IPV6_MIN_MTU)
|
||||||
return NULL;
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
|
ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
|
||||||
|
|
||||||
if (ndev == NULL)
|
if (ndev == NULL)
|
||||||
return NULL;
|
return ERR_PTR(err);
|
||||||
|
|
||||||
rwlock_init(&ndev->lock);
|
rwlock_init(&ndev->lock);
|
||||||
ndev->dev = dev;
|
ndev->dev = dev;
|
||||||
|
@ -332,7 +333,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
||||||
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
|
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
|
||||||
if (ndev->nd_parms == NULL) {
|
if (ndev->nd_parms == NULL) {
|
||||||
kfree(ndev);
|
kfree(ndev);
|
||||||
return NULL;
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
if (ndev->cnf.forwarding)
|
if (ndev->cnf.forwarding)
|
||||||
dev_disable_lro(dev);
|
dev_disable_lro(dev);
|
||||||
|
@ -346,17 +347,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
||||||
neigh_parms_release(&nd_tbl, ndev->nd_parms);
|
neigh_parms_release(&nd_tbl, ndev->nd_parms);
|
||||||
dev_put(dev);
|
dev_put(dev);
|
||||||
kfree(ndev);
|
kfree(ndev);
|
||||||
return NULL;
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snmp6_register_dev(ndev) < 0) {
|
if (snmp6_register_dev(ndev) < 0) {
|
||||||
ADBG(KERN_WARNING
|
ADBG(KERN_WARNING
|
||||||
"%s: cannot create /proc/net/dev_snmp6/%s\n",
|
"%s: cannot create /proc/net/dev_snmp6/%s\n",
|
||||||
__func__, dev->name);
|
__func__, dev->name);
|
||||||
neigh_parms_release(&nd_tbl, ndev->nd_parms);
|
goto err_release;
|
||||||
ndev->dead = 1;
|
|
||||||
in6_dev_finish_destroy(ndev);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One reference from device. We must do this before
|
/* One reference from device. We must do this before
|
||||||
|
@ -394,7 +392,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
||||||
|
|
||||||
ipv6_mc_init_dev(ndev);
|
ipv6_mc_init_dev(ndev);
|
||||||
ndev->tstamp = jiffies;
|
ndev->tstamp = jiffies;
|
||||||
addrconf_sysctl_register(ndev);
|
err = addrconf_sysctl_register(ndev);
|
||||||
|
if (err) {
|
||||||
|
ipv6_mc_destroy_dev(ndev);
|
||||||
|
del_timer(&ndev->regen_timer);
|
||||||
|
goto err_release;
|
||||||
|
}
|
||||||
/* protected by rtnl_lock */
|
/* protected by rtnl_lock */
|
||||||
rcu_assign_pointer(dev->ip6_ptr, ndev);
|
rcu_assign_pointer(dev->ip6_ptr, ndev);
|
||||||
|
|
||||||
|
@ -409,6 +412,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
||||||
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
|
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
|
||||||
|
|
||||||
return ndev;
|
return ndev;
|
||||||
|
|
||||||
|
err_release:
|
||||||
|
neigh_parms_release(&nd_tbl, ndev->nd_parms);
|
||||||
|
ndev->dead = 1;
|
||||||
|
in6_dev_finish_destroy(ndev);
|
||||||
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
|
static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
|
||||||
|
@ -420,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
|
||||||
idev = __in6_dev_get(dev);
|
idev = __in6_dev_get(dev);
|
||||||
if (!idev) {
|
if (!idev) {
|
||||||
idev = ipv6_add_dev(dev);
|
idev = ipv6_add_dev(dev);
|
||||||
if (!idev)
|
if (IS_ERR(idev))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2830,8 +2839,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||||
case NETDEV_REGISTER:
|
case NETDEV_REGISTER:
|
||||||
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
|
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
|
||||||
idev = ipv6_add_dev(dev);
|
idev = ipv6_add_dev(dev);
|
||||||
if (!idev)
|
if (IS_ERR(idev))
|
||||||
return notifier_from_errno(-ENOMEM);
|
return notifier_from_errno(PTR_ERR(idev));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2851,7 +2860,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||||
if (!idev && dev->mtu >= IPV6_MIN_MTU)
|
if (!idev && dev->mtu >= IPV6_MIN_MTU)
|
||||||
idev = ipv6_add_dev(dev);
|
idev = ipv6_add_dev(dev);
|
||||||
|
|
||||||
if (idev) {
|
if (!IS_ERR_OR_NULL(idev)) {
|
||||||
idev->if_flags |= IF_READY;
|
idev->if_flags |= IF_READY;
|
||||||
run_pending = 1;
|
run_pending = 1;
|
||||||
}
|
}
|
||||||
|
@ -2894,7 +2903,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idev) {
|
if (!IS_ERR_OR_NULL(idev)) {
|
||||||
if (run_pending)
|
if (run_pending)
|
||||||
addrconf_dad_run(idev);
|
addrconf_dad_run(idev);
|
||||||
|
|
||||||
|
@ -2929,7 +2938,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||||
|
|
||||||
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
|
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
|
||||||
idev = ipv6_add_dev(dev);
|
idev = ipv6_add_dev(dev);
|
||||||
if (idev)
|
if (!IS_ERR(idev))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2950,10 +2959,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||||
if (idev) {
|
if (idev) {
|
||||||
snmp6_unregister_dev(idev);
|
snmp6_unregister_dev(idev);
|
||||||
addrconf_sysctl_unregister(idev);
|
addrconf_sysctl_unregister(idev);
|
||||||
addrconf_sysctl_register(idev);
|
err = addrconf_sysctl_register(idev);
|
||||||
err = snmp6_register_dev(idev);
|
|
||||||
if (err)
|
if (err)
|
||||||
return notifier_from_errno(err);
|
return notifier_from_errno(err);
|
||||||
|
err = snmp6_register_dev(idev);
|
||||||
|
if (err) {
|
||||||
|
addrconf_sysctl_unregister(idev);
|
||||||
|
return notifier_from_errno(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -5248,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
|
||||||
kfree(t);
|
kfree(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addrconf_sysctl_register(struct inet6_dev *idev)
|
static int addrconf_sysctl_register(struct inet6_dev *idev)
|
||||||
{
|
{
|
||||||
neigh_sysctl_register(idev->dev, idev->nd_parms,
|
int err;
|
||||||
&ndisc_ifinfo_sysctl_change);
|
|
||||||
__addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
|
if (!sysctl_dev_name_is_allowed(idev->dev->name))
|
||||||
idev, &idev->cnf);
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = neigh_sysctl_register(idev->dev, idev->nd_parms,
|
||||||
|
&ndisc_ifinfo_sysctl_change);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
|
||||||
|
idev, &idev->cnf);
|
||||||
|
if (err)
|
||||||
|
neigh_sysctl_unregister(idev->nd_parms);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addrconf_sysctl_unregister(struct inet6_dev *idev)
|
static void addrconf_sysctl_unregister(struct inet6_dev *idev)
|
||||||
|
@ -5338,6 +5362,7 @@ static struct rtnl_af_ops inet6_ops = {
|
||||||
|
|
||||||
int __init addrconf_init(void)
|
int __init addrconf_init(void)
|
||||||
{
|
{
|
||||||
|
struct inet6_dev *idev;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
err = ipv6_addr_label_init();
|
err = ipv6_addr_label_init();
|
||||||
|
@ -5376,11 +5401,12 @@ int __init addrconf_init(void)
|
||||||
* device and it being up should be removed.
|
* device and it being up should be removed.
|
||||||
*/
|
*/
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
if (!ipv6_add_dev(init_net.loopback_dev))
|
idev = ipv6_add_dev(init_net.loopback_dev);
|
||||||
err = -ENOMEM;
|
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
if (err)
|
if (IS_ERR(idev)) {
|
||||||
|
err = PTR_ERR(idev);
|
||||||
goto errlo;
|
goto errlo;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < IN6_ADDR_HSIZE; i++)
|
for (i = 0; i < IN6_ADDR_HSIZE; i++)
|
||||||
INIT_HLIST_HEAD(&inet6_addr_lst[i]);
|
INIT_HLIST_HEAD(&inet6_addr_lst[i]);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче