diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 61 |
1 files changed, 40 insertions, 21 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a225d5ee3c2f..c02280a4d126 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -502,29 +502,31 @@ static void addrconf_forward_change(struct net *net, __s32 newf) | |||
502 | rcu_read_unlock(); | 502 | rcu_read_unlock(); |
503 | } | 503 | } |
504 | 504 | ||
505 | static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | 505 | static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) |
506 | { | 506 | { |
507 | struct net *net; | 507 | struct net *net; |
508 | int old; | ||
509 | |||
510 | if (!rtnl_trylock()) | ||
511 | return restart_syscall(); | ||
508 | 512 | ||
509 | net = (struct net *)table->extra2; | 513 | net = (struct net *)table->extra2; |
510 | if (p == &net->ipv6.devconf_dflt->forwarding) | 514 | old = *p; |
511 | return 0; | 515 | *p = newf; |
512 | 516 | ||
513 | if (!rtnl_trylock()) { | 517 | if (p == &net->ipv6.devconf_dflt->forwarding) { |
514 | /* Restore the original values before restarting */ | 518 | rtnl_unlock(); |
515 | *p = old; | 519 | return 0; |
516 | return restart_syscall(); | ||
517 | } | 520 | } |
518 | 521 | ||
519 | if (p == &net->ipv6.devconf_all->forwarding) { | 522 | if (p == &net->ipv6.devconf_all->forwarding) { |
520 | __s32 newf = net->ipv6.devconf_all->forwarding; | ||
521 | net->ipv6.devconf_dflt->forwarding = newf; | 523 | net->ipv6.devconf_dflt->forwarding = newf; |
522 | addrconf_forward_change(net, newf); | 524 | addrconf_forward_change(net, newf); |
523 | } else if ((!*p) ^ (!old)) | 525 | } else if ((!newf) ^ (!old)) |
524 | dev_forward_change((struct inet6_dev *)table->extra1); | 526 | dev_forward_change((struct inet6_dev *)table->extra1); |
525 | rtnl_unlock(); | 527 | rtnl_unlock(); |
526 | 528 | ||
527 | if (*p) | 529 | if (newf) |
528 | rt6_purge_dflt_routers(net); | 530 | rt6_purge_dflt_routers(net); |
529 | return 1; | 531 | return 1; |
530 | } | 532 | } |
@@ -4260,9 +4262,17 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, | |||
4260 | int *valp = ctl->data; | 4262 | int *valp = ctl->data; |
4261 | int val = *valp; | 4263 | int val = *valp; |
4262 | loff_t pos = *ppos; | 4264 | loff_t pos = *ppos; |
4265 | ctl_table lctl; | ||
4263 | int ret; | 4266 | int ret; |
4264 | 4267 | ||
4265 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4268 | /* |
4269 | * ctl->data points to idev->cnf.forwarding, we should | ||
4270 | * not modify it until we get the rtnl lock. | ||
4271 | */ | ||
4272 | lctl = *ctl; | ||
4273 | lctl.data = &val; | ||
4274 | |||
4275 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); | ||
4266 | 4276 | ||
4267 | if (write) | 4277 | if (write) |
4268 | ret = addrconf_fixup_forwarding(ctl, valp, val); | 4278 | ret = addrconf_fixup_forwarding(ctl, valp, val); |
@@ -4300,26 +4310,27 @@ static void addrconf_disable_change(struct net *net, __s32 newf) | |||
4300 | rcu_read_unlock(); | 4310 | rcu_read_unlock(); |
4301 | } | 4311 | } |
4302 | 4312 | ||
4303 | static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) | 4313 | static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) |
4304 | { | 4314 | { |
4305 | struct net *net; | 4315 | struct net *net; |
4316 | int old; | ||
4317 | |||
4318 | if (!rtnl_trylock()) | ||
4319 | return restart_syscall(); | ||
4306 | 4320 | ||
4307 | net = (struct net *)table->extra2; | 4321 | net = (struct net *)table->extra2; |
4322 | old = *p; | ||
4323 | *p = newf; | ||
4308 | 4324 | ||
4309 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) | 4325 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) { |
4326 | rtnl_unlock(); | ||
4310 | return 0; | 4327 | return 0; |
4311 | |||
4312 | if (!rtnl_trylock()) { | ||
4313 | /* Restore the original values before restarting */ | ||
4314 | *p = old; | ||
4315 | return restart_syscall(); | ||
4316 | } | 4328 | } |
4317 | 4329 | ||
4318 | if (p == &net->ipv6.devconf_all->disable_ipv6) { | 4330 | if (p == &net->ipv6.devconf_all->disable_ipv6) { |
4319 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; | ||
4320 | net->ipv6.devconf_dflt->disable_ipv6 = newf; | 4331 | net->ipv6.devconf_dflt->disable_ipv6 = newf; |
4321 | addrconf_disable_change(net, newf); | 4332 | addrconf_disable_change(net, newf); |
4322 | } else if ((!*p) ^ (!old)) | 4333 | } else if ((!newf) ^ (!old)) |
4323 | dev_disable_change((struct inet6_dev *)table->extra1); | 4334 | dev_disable_change((struct inet6_dev *)table->extra1); |
4324 | 4335 | ||
4325 | rtnl_unlock(); | 4336 | rtnl_unlock(); |
@@ -4333,9 +4344,17 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write, | |||
4333 | int *valp = ctl->data; | 4344 | int *valp = ctl->data; |
4334 | int val = *valp; | 4345 | int val = *valp; |
4335 | loff_t pos = *ppos; | 4346 | loff_t pos = *ppos; |
4347 | ctl_table lctl; | ||
4336 | int ret; | 4348 | int ret; |
4337 | 4349 | ||
4338 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4350 | /* |
4351 | * ctl->data points to idev->cnf.disable_ipv6, we should | ||
4352 | * not modify it until we get the rtnl lock. | ||
4353 | */ | ||
4354 | lctl = *ctl; | ||
4355 | lctl.data = &val; | ||
4356 | |||
4357 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); | ||
4339 | 4358 | ||
4340 | if (write) | 4359 | if (write) |
4341 | ret = addrconf_disable_ipv6(ctl, valp, val); | 4360 | ret = addrconf_disable_ipv6(ctl, valp, val); |