diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 52 |
1 files changed, 28 insertions, 24 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a1b0697340ba..735bf41c654a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -93,7 +93,6 @@ struct tun_file { | |||
93 | atomic_t count; | 93 | atomic_t count; |
94 | struct tun_struct *tun; | 94 | struct tun_struct *tun; |
95 | struct net *net; | 95 | struct net *net; |
96 | wait_queue_head_t read_wait; | ||
97 | }; | 96 | }; |
98 | 97 | ||
99 | struct tun_sock; | 98 | struct tun_sock; |
@@ -156,6 +155,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
156 | tfile->tun = tun; | 155 | tfile->tun = tun; |
157 | tun->tfile = tfile; | 156 | tun->tfile = tfile; |
158 | dev_hold(tun->dev); | 157 | dev_hold(tun->dev); |
158 | sock_hold(tun->sk); | ||
159 | atomic_inc(&tfile->count); | 159 | atomic_inc(&tfile->count); |
160 | 160 | ||
161 | out: | 161 | out: |
@@ -165,11 +165,8 @@ out: | |||
165 | 165 | ||
166 | static void __tun_detach(struct tun_struct *tun) | 166 | static void __tun_detach(struct tun_struct *tun) |
167 | { | 167 | { |
168 | struct tun_file *tfile = tun->tfile; | ||
169 | |||
170 | /* Detach from net device */ | 168 | /* Detach from net device */ |
171 | netif_tx_lock_bh(tun->dev); | 169 | netif_tx_lock_bh(tun->dev); |
172 | tfile->tun = NULL; | ||
173 | tun->tfile = NULL; | 170 | tun->tfile = NULL; |
174 | netif_tx_unlock_bh(tun->dev); | 171 | netif_tx_unlock_bh(tun->dev); |
175 | 172 | ||
@@ -333,12 +330,19 @@ static void tun_net_uninit(struct net_device *dev) | |||
333 | /* Inform the methods they need to stop using the dev. | 330 | /* Inform the methods they need to stop using the dev. |
334 | */ | 331 | */ |
335 | if (tfile) { | 332 | if (tfile) { |
336 | wake_up_all(&tfile->read_wait); | 333 | wake_up_all(&tun->socket.wait); |
337 | if (atomic_dec_and_test(&tfile->count)) | 334 | if (atomic_dec_and_test(&tfile->count)) |
338 | __tun_detach(tun); | 335 | __tun_detach(tun); |
339 | } | 336 | } |
340 | } | 337 | } |
341 | 338 | ||
339 | static void tun_free_netdev(struct net_device *dev) | ||
340 | { | ||
341 | struct tun_struct *tun = netdev_priv(dev); | ||
342 | |||
343 | sock_put(tun->sk); | ||
344 | } | ||
345 | |||
342 | /* Net device open. */ | 346 | /* Net device open. */ |
343 | static int tun_net_open(struct net_device *dev) | 347 | static int tun_net_open(struct net_device *dev) |
344 | { | 348 | { |
@@ -393,7 +397,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
393 | /* Notify and wake up reader process */ | 397 | /* Notify and wake up reader process */ |
394 | if (tun->flags & TUN_FASYNC) | 398 | if (tun->flags & TUN_FASYNC) |
395 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); | 399 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); |
396 | wake_up_interruptible(&tun->tfile->read_wait); | 400 | wake_up_interruptible(&tun->socket.wait); |
397 | return 0; | 401 | return 0; |
398 | 402 | ||
399 | drop: | 403 | drop: |
@@ -490,7 +494,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | |||
490 | 494 | ||
491 | DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); | 495 | DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); |
492 | 496 | ||
493 | poll_wait(file, &tfile->read_wait, wait); | 497 | poll_wait(file, &tun->socket.wait, wait); |
494 | 498 | ||
495 | if (!skb_queue_empty(&tun->readq)) | 499 | if (!skb_queue_empty(&tun->readq)) |
496 | mask |= POLLIN | POLLRDNORM; | 500 | mask |= POLLIN | POLLRDNORM; |
@@ -518,7 +522,7 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, | |||
518 | int err; | 522 | int err; |
519 | 523 | ||
520 | /* Under a page? Don't bother with paged skb. */ | 524 | /* Under a page? Don't bother with paged skb. */ |
521 | if (prepad + len < PAGE_SIZE) | 525 | if (prepad + len < PAGE_SIZE || !linear) |
522 | linear = len; | 526 | linear = len; |
523 | 527 | ||
524 | skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, | 528 | skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, |
@@ -565,7 +569,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
565 | 569 | ||
566 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { | 570 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { |
567 | align = NET_IP_ALIGN; | 571 | align = NET_IP_ALIGN; |
568 | if (unlikely(len < ETH_HLEN)) | 572 | if (unlikely(len < ETH_HLEN || |
573 | (gso.hdr_len && gso.hdr_len < ETH_HLEN))) | ||
569 | return -EINVAL; | 574 | return -EINVAL; |
570 | } | 575 | } |
571 | 576 | ||
@@ -762,7 +767,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
762 | goto out; | 767 | goto out; |
763 | } | 768 | } |
764 | 769 | ||
765 | add_wait_queue(&tfile->read_wait, &wait); | 770 | add_wait_queue(&tun->socket.wait, &wait); |
766 | while (len) { | 771 | while (len) { |
767 | current->state = TASK_INTERRUPTIBLE; | 772 | current->state = TASK_INTERRUPTIBLE; |
768 | 773 | ||
@@ -793,7 +798,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
793 | } | 798 | } |
794 | 799 | ||
795 | current->state = TASK_RUNNING; | 800 | current->state = TASK_RUNNING; |
796 | remove_wait_queue(&tfile->read_wait, &wait); | 801 | remove_wait_queue(&tun->socket.wait, &wait); |
797 | 802 | ||
798 | out: | 803 | out: |
799 | tun_put(tun); | 804 | tun_put(tun); |
@@ -810,7 +815,7 @@ static void tun_setup(struct net_device *dev) | |||
810 | tun->group = -1; | 815 | tun->group = -1; |
811 | 816 | ||
812 | dev->ethtool_ops = &tun_ethtool_ops; | 817 | dev->ethtool_ops = &tun_ethtool_ops; |
813 | dev->destructor = free_netdev; | 818 | dev->destructor = tun_free_netdev; |
814 | } | 819 | } |
815 | 820 | ||
816 | /* Trivial set of netlink ops to allow deleting tun or tap | 821 | /* Trivial set of netlink ops to allow deleting tun or tap |
@@ -847,7 +852,7 @@ static void tun_sock_write_space(struct sock *sk) | |||
847 | 852 | ||
848 | static void tun_sock_destruct(struct sock *sk) | 853 | static void tun_sock_destruct(struct sock *sk) |
849 | { | 854 | { |
850 | dev_put(container_of(sk, struct tun_sock, sk)->tun->dev); | 855 | free_netdev(container_of(sk, struct tun_sock, sk)->tun->dev); |
851 | } | 856 | } |
852 | 857 | ||
853 | static struct proto tun_proto = { | 858 | static struct proto tun_proto = { |
@@ -861,7 +866,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
861 | struct sock *sk; | 866 | struct sock *sk; |
862 | struct tun_struct *tun; | 867 | struct tun_struct *tun; |
863 | struct net_device *dev; | 868 | struct net_device *dev; |
864 | struct tun_file *tfile = file->private_data; | ||
865 | int err; | 869 | int err; |
866 | 870 | ||
867 | dev = __dev_get_by_name(net, ifr->ifr_name); | 871 | dev = __dev_get_by_name(net, ifr->ifr_name); |
@@ -919,13 +923,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
919 | if (!sk) | 923 | if (!sk) |
920 | goto err_free_dev; | 924 | goto err_free_dev; |
921 | 925 | ||
922 | /* This ref count is for tun->sk. */ | 926 | init_waitqueue_head(&tun->socket.wait); |
923 | dev_hold(dev); | ||
924 | sock_init_data(&tun->socket, sk); | 927 | sock_init_data(&tun->socket, sk); |
925 | sk->sk_write_space = tun_sock_write_space; | 928 | sk->sk_write_space = tun_sock_write_space; |
926 | sk->sk_destruct = tun_sock_destruct; | ||
927 | sk->sk_sndbuf = INT_MAX; | 929 | sk->sk_sndbuf = INT_MAX; |
928 | sk->sk_sleep = &tfile->read_wait; | ||
929 | 930 | ||
930 | tun->sk = sk; | 931 | tun->sk = sk; |
931 | container_of(sk, struct tun_sock, sk)->tun = tun; | 932 | container_of(sk, struct tun_sock, sk)->tun = tun; |
@@ -941,11 +942,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
941 | err = -EINVAL; | 942 | err = -EINVAL; |
942 | err = register_netdevice(tun->dev); | 943 | err = register_netdevice(tun->dev); |
943 | if (err < 0) | 944 | if (err < 0) |
944 | goto err_free_dev; | 945 | goto err_free_sk; |
946 | |||
947 | sk->sk_destruct = tun_sock_destruct; | ||
945 | 948 | ||
946 | err = tun_attach(tun, file); | 949 | err = tun_attach(tun, file); |
947 | if (err < 0) | 950 | if (err < 0) |
948 | goto err_free_dev; | 951 | goto failed; |
949 | } | 952 | } |
950 | 953 | ||
951 | DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name); | 954 | DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name); |
@@ -1265,7 +1268,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) | |||
1265 | atomic_set(&tfile->count, 0); | 1268 | atomic_set(&tfile->count, 0); |
1266 | tfile->tun = NULL; | 1269 | tfile->tun = NULL; |
1267 | tfile->net = get_net(current->nsproxy->net_ns); | 1270 | tfile->net = get_net(current->nsproxy->net_ns); |
1268 | init_waitqueue_head(&tfile->read_wait); | ||
1269 | file->private_data = tfile; | 1271 | file->private_data = tfile; |
1270 | return 0; | 1272 | return 0; |
1271 | } | 1273 | } |
@@ -1283,14 +1285,16 @@ static int tun_chr_close(struct inode *inode, struct file *file) | |||
1283 | __tun_detach(tun); | 1285 | __tun_detach(tun); |
1284 | 1286 | ||
1285 | /* If desireable, unregister the netdevice. */ | 1287 | /* If desireable, unregister the netdevice. */ |
1286 | if (!(tun->flags & TUN_PERSIST)) { | 1288 | if (!(tun->flags & TUN_PERSIST)) |
1287 | sock_put(tun->sk); | ||
1288 | unregister_netdevice(tun->dev); | 1289 | unregister_netdevice(tun->dev); |
1289 | } | ||
1290 | 1290 | ||
1291 | rtnl_unlock(); | 1291 | rtnl_unlock(); |
1292 | } | 1292 | } |
1293 | 1293 | ||
1294 | tun = tfile->tun; | ||
1295 | if (tun) | ||
1296 | sock_put(tun->sk); | ||
1297 | |||
1294 | put_net(tfile->net); | 1298 | put_net(tfile->net); |
1295 | kfree(tfile); | 1299 | kfree(tfile); |
1296 | 1300 | ||