summaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-01-14 08:27:10 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-01-14 08:27:10 -0800
commit6843cc0e0f59643d75a624999012b4dd72bfe1cf (patch)
tree6924ab19725e67b3f35f90277b2b670d0f0e0958 /drivers/net/tun.c
parent7c8284c3aa127ffe72a90a1bad52183ec9ad870a (diff)
parentd0b9cec3e27d0e9fda2fbf6aaacece68c99b1104 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller: 1) Fix regression allowing IP_TTL setting of zero, fix from Cong Wang. 2) Fix leak regressions in tunap, from Jason Wang. 3) be2net driver always returns IRQ_HANDLED in INTx handler, fix from Sathya Perla. 4) qlge doesn't really support NETIF_F_TSO6, don't set that flag. Fix from Amerigo Wang. 5) Add 802.11ad Atheros wil6210 driver, from Vladimir Kondratiev. 6) Fix MTU calculations in mac80211 layer, from T Krishna Chaitanya. 7) Station info layer of mac80211 needs to use del_timer_sync(), from Johannes Berg. 8) tcp_read_sock() can loop forever, because we don't immediately stop when recv_actor() returns zero. Fix from Eric Dumazet. 9) Fix WARN_ON() in tcp_cleanup_rbuf(). We have to use sk_eat_skb() in tcp_recv_skb() to handle the case where a large GRO packet is split up while it is use by a splice() operation. Fix also from Eric Dumazet. 10) addrconf_get_prefix_route() in ipv6 tests flags incorrectly, it does: if (X && (p->flags & Y) != 0) when it really meant to go: if (X && (p->flags & X) != 0) fix from Romain Kuntz. 11) Fix lost Kconfig dependency for bfin_mac driver hardware timestamping. From Lars-Peter Clausen. 12) Fix regression in handling of RST without ACK in TCP, from Eric Dumazet. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (37 commits) be2net: fix unconditionally returning IRQ_HANDLED in INTx tuntap: fix leaking reference count tuntap: forbid calling TUNSETIFF when detached tuntap: switch to use rtnl_dereference() net, wireless: overwrite default_ethtool_ops qlge: remove NETIF_F_TSO6 flag tcp: accept RST without ACK flag net: ethernet: xilinx: Do not use NO_IRQ in axienet net: ethernet: xilinx: Do not use axienet on PPC bnx2x: Allow management traffic after boot from SAN bnx2x: Fix fastpath structures when memory allocation fails bfin_mac: Restore hardware time-stamping dependency on BF518 tun: avoid owner checks on IFF_ATTACH_QUEUE bnx2x: move debugging code before the return tuntap: refuse to re-attach to different tun_struct ipv6: use addrconf_get_prefix_route for prefix route lookup [v2] ipv6: fix the noflags test in addrconf_get_prefix_route tcp: fix splice() and tcp collapsing interaction tcp: splice: fix an infinite loop in tcp_read_sock() net: prevent setting ttl=0 via IP_TTL ...
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 fbd106edbe5..af372d0957f 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)
struct tun_struct *tun;
struct net_device *dev;
- tun = rcu_dereference_protected(tfile->tun,
- lockdep_rtnl_is_held());
+ tun = rtnl_dereference(tfile->tun);
+
if (tun) {
u16 index = tfile->queue_index;
BUG_ON(index >= tun->numqueues);
@@ -414,8 +414,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
rcu_assign_pointer(tun->tfiles[index],
tun->tfiles[tun->numqueues - 1]);
rcu_assign_pointer(tfile->tun, NULL);
- ntfile = rcu_dereference_protected(tun->tfiles[index],
- lockdep_rtnl_is_held());
+ ntfile = rtnl_dereference(tun->tfiles[index]);
ntfile->queue_index = index;
--tun->numqueues;
@@ -429,8 +428,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
/* Drop read queue */
skb_queue_purge(&tfile->sk.sk_receive_queue);
tun_set_real_num_queues(tun);
- } else if (tfile->detached && clean)
+ } else if (tfile->detached && clean) {
tun = tun_enable_queue(tfile);
+ sock_put(&tfile->sk);
+ }
if (clean) {
if (tun && tun->numqueues == 0 && tun->numdisabled == 0 &&
@@ -458,8 +459,7 @@ static void tun_detach_all(struct net_device *dev)
int i, n = tun->numqueues;
for (i = 0; i < n; i++) {
- tfile = rcu_dereference_protected(tun->tfiles[i],
- lockdep_rtnl_is_held());
+ tfile = rtnl_dereference(tun->tfiles[i]);
BUG_ON(!tfile);
wake_up_all(&tfile->wq.wait);
rcu_assign_pointer(tfile->tun, NULL);
@@ -469,8 +469,7 @@ static void tun_detach_all(struct net_device *dev)
synchronize_net();
for (i = 0; i < n; i++) {
- tfile = rcu_dereference_protected(tun->tfiles[i],
- lockdep_rtnl_is_held());
+ tfile = rtnl_dereference(tun->tfiles[i]);
/* Drop read queue */
skb_queue_purge(&tfile->sk.sk_receive_queue);
sock_put(&tfile->sk);
@@ -481,6 +480,9 @@ static void tun_detach_all(struct net_device *dev)
sock_put(&tfile->sk);
}
BUG_ON(tun->numdisabled != 0);
+
+ if (tun->flags & TUN_PERSIST)
+ module_put(THIS_MODULE);
}
static 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)
int err;
err = -EINVAL;
- if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held()))
+ if (rtnl_dereference(tfile->tun))
goto out;
err = -EBUSY;
@@ -1544,6 +1546,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
struct net_device *dev;
int err;
+ if (tfile->detached)
+ return -EINVAL;
+
dev = __dev_get_by_name(net, ifr->ifr_name);
if (dev) {
if (ifr->ifr_flags & IFF_TUN_EXCL)
@@ -1738,8 +1743,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
struct tun_file *tfile;
for (i = 0; i < n; i++) {
- tfile = rcu_dereference_protected(tun->tfiles[i],
- lockdep_rtnl_is_held());
+ tfile = rtnl_dereference(tun->tfiles[i]);
sk_detach_filter(tfile->socket.sk);
}
@@ -1752,8 +1756,7 @@ static int tun_attach_filter(struct tun_struct *tun)
struct tun_file *tfile;
for (i = 0; i < tun->numqueues; i++) {
- tfile = rcu_dereference_protected(tun->tfiles[i],
- lockdep_rtnl_is_held());
+ tfile = rtnl_dereference(tun->tfiles[i]);
ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
if (ret) {
tun_detach_filter(tun, i);
@@ -1771,8 +1774,7 @@ static void tun_set_sndbuf(struct tun_struct *tun)
int i;
for (i = 0; i < tun->numqueues; i++) {
- tfile = rcu_dereference_protected(tun->tfiles[i],
- lockdep_rtnl_is_held());
+ tfile = rtnl_dereference(tun->tfiles[i]);
tfile->socket.sk->sk_sndbuf = tun->sndbuf;
}
}
@@ -1789,13 +1791,10 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
tun = tfile->detached;
if (!tun)
ret = -EINVAL;
- else if (tun_not_capable(tun))
- ret = -EPERM;
else
ret = tun_attach(tun, file);
} else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
- tun = rcu_dereference_protected(tfile->tun,
- lockdep_rtnl_is_held());
+ tun = rtnl_dereference(tfile->tun);
if (!tun || !(tun->flags & TUN_TAP_MQ))
ret = -EINVAL;
else
@@ -1880,10 +1879,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
/* Disable/Enable persist mode. Keep an extra reference to the
* module to prevent the module being unprobed.
*/
- if (arg) {
+ if (arg && !(tun->flags & TUN_PERSIST)) {
tun->flags |= TUN_PERSIST;
__module_get(THIS_MODULE);
- } else {
+ }
+ if (!arg && (tun->flags & TUN_PERSIST)) {
tun->flags &= ~TUN_PERSIST;
module_put(THIS_MODULE);
}