aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c44
1 files changed, 22 insertions, 22 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index fbd106edbe59..af372d0957fe 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -404,8 +404,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
404 struct tun_struct *tun; 404 struct tun_struct *tun;
405 struct net_device *dev; 405 struct net_device *dev;
406 406
407 tun = rcu_dereference_protected(tfile->tun, 407 tun = rtnl_dereference(tfile->tun);
408 lockdep_rtnl_is_held()); 408
409 if (tun) { 409 if (tun) {
410 u16 index = tfile->queue_index; 410 u16 index = tfile->queue_index;
411 BUG_ON(index >= tun->numqueues); 411 BUG_ON(index >= tun->numqueues);
@@ -414,8 +414,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
414 rcu_assign_pointer(tun->tfiles[index], 414 rcu_assign_pointer(tun->tfiles[index],
415 tun->tfiles[tun->numqueues - 1]); 415 tun->tfiles[tun->numqueues - 1]);
416 rcu_assign_pointer(tfile->tun, NULL); 416 rcu_assign_pointer(tfile->tun, NULL);
417 ntfile = rcu_dereference_protected(tun->tfiles[index], 417 ntfile = rtnl_dereference(tun->tfiles[index]);
418 lockdep_rtnl_is_held());
419 ntfile->queue_index = index; 418 ntfile->queue_index = index;
420 419
421 --tun->numqueues; 420 --tun->numqueues;
@@ -429,8 +428,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
429 /* Drop read queue */ 428 /* Drop read queue */
430 skb_queue_purge(&tfile->sk.sk_receive_queue); 429 skb_queue_purge(&tfile->sk.sk_receive_queue);
431 tun_set_real_num_queues(tun); 430 tun_set_real_num_queues(tun);
432 } else if (tfile->detached && clean) 431 } else if (tfile->detached && clean) {
433 tun = tun_enable_queue(tfile); 432 tun = tun_enable_queue(tfile);
433 sock_put(&tfile->sk);
434 }
434 435
435 if (clean) { 436 if (clean) {
436 if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && 437 if (tun && tun->numqueues == 0 && tun->numdisabled == 0 &&
@@ -458,8 +459,7 @@ static void tun_detach_all(struct net_device *dev)
458 int i, n = tun->numqueues; 459 int i, n = tun->numqueues;
459 460
460 for (i = 0; i < n; i++) { 461 for (i = 0; i < n; i++) {
461 tfile = rcu_dereference_protected(tun->tfiles[i], 462 tfile = rtnl_dereference(tun->tfiles[i]);
462 lockdep_rtnl_is_held());
463 BUG_ON(!tfile); 463 BUG_ON(!tfile);
464 wake_up_all(&tfile->wq.wait); 464 wake_up_all(&tfile->wq.wait);
465 rcu_assign_pointer(tfile->tun, NULL); 465 rcu_assign_pointer(tfile->tun, NULL);
@@ -469,8 +469,7 @@ static void tun_detach_all(struct net_device *dev)
469 469
470 synchronize_net(); 470 synchronize_net();
471 for (i = 0; i < n; i++) { 471 for (i = 0; i < n; i++) {
472 tfile = rcu_dereference_protected(tun->tfiles[i], 472 tfile = rtnl_dereference(tun->tfiles[i]);
473 lockdep_rtnl_is_held());
474 /* Drop read queue */ 473 /* Drop read queue */
475 skb_queue_purge(&tfile->sk.sk_receive_queue); 474 skb_queue_purge(&tfile->sk.sk_receive_queue);
476 sock_put(&tfile->sk); 475 sock_put(&tfile->sk);
@@ -481,6 +480,9 @@ static void tun_detach_all(struct net_device *dev)
481 sock_put(&tfile->sk); 480 sock_put(&tfile->sk);
482 } 481 }
483 BUG_ON(tun->numdisabled != 0); 482 BUG_ON(tun->numdisabled != 0);
483
484 if (tun->flags & TUN_PERSIST)
485 module_put(THIS_MODULE);
484} 486}
485 487
486static int tun_attach(struct tun_struct *tun, struct file *file) 488static int tun_attach(struct tun_struct *tun, struct file *file)
@@ -489,7 +491,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
489 int err; 491 int err;
490 492
491 err = -EINVAL; 493 err = -EINVAL;
492 if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held())) 494 if (rtnl_dereference(tfile->tun))
493 goto out; 495 goto out;
494 496
495 err = -EBUSY; 497 err = -EBUSY;
@@ -1544,6 +1546,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
1544 struct net_device *dev; 1546 struct net_device *dev;
1545 int err; 1547 int err;
1546 1548
1549 if (tfile->detached)
1550 return -EINVAL;
1551
1547 dev = __dev_get_by_name(net, ifr->ifr_name); 1552 dev = __dev_get_by_name(net, ifr->ifr_name);
1548 if (dev) { 1553 if (dev) {
1549 if (ifr->ifr_flags & IFF_TUN_EXCL) 1554 if (ifr->ifr_flags & IFF_TUN_EXCL)
@@ -1738,8 +1743,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
1738 struct tun_file *tfile; 1743 struct tun_file *tfile;
1739 1744
1740 for (i = 0; i < n; i++) { 1745 for (i = 0; i < n; i++) {
1741 tfile = rcu_dereference_protected(tun->tfiles[i], 1746 tfile = rtnl_dereference(tun->tfiles[i]);
1742 lockdep_rtnl_is_held());
1743 sk_detach_filter(tfile->socket.sk); 1747 sk_detach_filter(tfile->socket.sk);
1744 } 1748 }
1745 1749
@@ -1752,8 +1756,7 @@ static int tun_attach_filter(struct tun_struct *tun)
1752 struct tun_file *tfile; 1756 struct tun_file *tfile;
1753 1757
1754 for (i = 0; i < tun->numqueues; i++) { 1758 for (i = 0; i < tun->numqueues; i++) {
1755 tfile = rcu_dereference_protected(tun->tfiles[i], 1759 tfile = rtnl_dereference(tun->tfiles[i]);
1756 lockdep_rtnl_is_held());
1757 ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); 1760 ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
1758 if (ret) { 1761 if (ret) {
1759 tun_detach_filter(tun, i); 1762 tun_detach_filter(tun, i);
@@ -1771,8 +1774,7 @@ static void tun_set_sndbuf(struct tun_struct *tun)
1771 int i; 1774 int i;
1772 1775
1773 for (i = 0; i < tun->numqueues; i++) { 1776 for (i = 0; i < tun->numqueues; i++) {
1774 tfile = rcu_dereference_protected(tun->tfiles[i], 1777 tfile = rtnl_dereference(tun->tfiles[i]);
1775 lockdep_rtnl_is_held());
1776 tfile->socket.sk->sk_sndbuf = tun->sndbuf; 1778 tfile->socket.sk->sk_sndbuf = tun->sndbuf;
1777 } 1779 }
1778} 1780}
@@ -1789,13 +1791,10 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
1789 tun = tfile->detached; 1791 tun = tfile->detached;
1790 if (!tun) 1792 if (!tun)
1791 ret = -EINVAL; 1793 ret = -EINVAL;
1792 else if (tun_not_capable(tun))
1793 ret = -EPERM;
1794 else 1794 else
1795 ret = tun_attach(tun, file); 1795 ret = tun_attach(tun, file);
1796 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { 1796 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
1797 tun = rcu_dereference_protected(tfile->tun, 1797 tun = rtnl_dereference(tfile->tun);
1798 lockdep_rtnl_is_held());
1799 if (!tun || !(tun->flags & TUN_TAP_MQ)) 1798 if (!tun || !(tun->flags & TUN_TAP_MQ))
1800 ret = -EINVAL; 1799 ret = -EINVAL;
1801 else 1800 else
@@ -1880,10 +1879,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
1880 /* Disable/Enable persist mode. Keep an extra reference to the 1879 /* Disable/Enable persist mode. Keep an extra reference to the
1881 * module to prevent the module being unprobed. 1880 * module to prevent the module being unprobed.
1882 */ 1881 */
1883 if (arg) { 1882 if (arg && !(tun->flags & TUN_PERSIST)) {
1884 tun->flags |= TUN_PERSIST; 1883 tun->flags |= TUN_PERSIST;
1885 __module_get(THIS_MODULE); 1884 __module_get(THIS_MODULE);
1886 } else { 1885 }
1886 if (!arg && (tun->flags & TUN_PERSIST)) {
1887 tun->flags &= ~TUN_PERSIST; 1887 tun->flags &= ~TUN_PERSIST;
1888 module_put(THIS_MODULE); 1888 module_put(THIS_MODULE);
1889 } 1889 }