aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c61
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
505static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) 505static 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
4303static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) 4313static 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);