diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 43265207d463..6b150c072a41 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -109,6 +109,9 @@ struct tun_struct { | |||
109 | 109 | ||
110 | struct tap_filter txflt; | 110 | struct tap_filter txflt; |
111 | struct socket socket; | 111 | struct socket socket; |
112 | struct socket_wq wq; | ||
113 | |||
114 | int vnet_hdr_sz; | ||
112 | 115 | ||
113 | #ifdef TUN_DEBUG | 116 | #ifdef TUN_DEBUG |
114 | int debug; | 117 | int debug; |
@@ -323,7 +326,7 @@ static void tun_net_uninit(struct net_device *dev) | |||
323 | /* Inform the methods they need to stop using the dev. | 326 | /* Inform the methods they need to stop using the dev. |
324 | */ | 327 | */ |
325 | if (tfile) { | 328 | if (tfile) { |
326 | wake_up_all(&tun->socket.wait); | 329 | wake_up_all(&tun->wq.wait); |
327 | if (atomic_dec_and_test(&tfile->count)) | 330 | if (atomic_dec_and_test(&tfile->count)) |
328 | __tun_detach(tun); | 331 | __tun_detach(tun); |
329 | } | 332 | } |
@@ -398,7 +401,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
398 | /* Notify and wake up reader process */ | 401 | /* Notify and wake up reader process */ |
399 | if (tun->flags & TUN_FASYNC) | 402 | if (tun->flags & TUN_FASYNC) |
400 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); | 403 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); |
401 | wake_up_interruptible_poll(&tun->socket.wait, POLLIN | | 404 | wake_up_interruptible_poll(&tun->wq.wait, POLLIN | |
402 | POLLRDNORM | POLLRDBAND); | 405 | POLLRDNORM | POLLRDBAND); |
403 | return NETDEV_TX_OK; | 406 | return NETDEV_TX_OK; |
404 | 407 | ||
@@ -498,7 +501,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | |||
498 | 501 | ||
499 | DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); | 502 | DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); |
500 | 503 | ||
501 | poll_wait(file, &tun->socket.wait, wait); | 504 | poll_wait(file, &tun->wq.wait, wait); |
502 | 505 | ||
503 | if (!skb_queue_empty(&sk->sk_receive_queue)) | 506 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
504 | mask |= POLLIN | POLLRDNORM; | 507 | mask |= POLLIN | POLLRDNORM; |
@@ -563,7 +566,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
563 | } | 566 | } |
564 | 567 | ||
565 | if (tun->flags & TUN_VNET_HDR) { | 568 | if (tun->flags & TUN_VNET_HDR) { |
566 | if ((len -= sizeof(gso)) > count) | 569 | if ((len -= tun->vnet_hdr_sz) > count) |
567 | return -EINVAL; | 570 | return -EINVAL; |
568 | 571 | ||
569 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) | 572 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) |
@@ -575,7 +578,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
575 | 578 | ||
576 | if (gso.hdr_len > len) | 579 | if (gso.hdr_len > len) |
577 | return -EINVAL; | 580 | return -EINVAL; |
578 | offset += sizeof(gso); | 581 | offset += tun->vnet_hdr_sz; |
579 | } | 582 | } |
580 | 583 | ||
581 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { | 584 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { |
@@ -718,7 +721,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
718 | 721 | ||
719 | if (tun->flags & TUN_VNET_HDR) { | 722 | if (tun->flags & TUN_VNET_HDR) { |
720 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ | 723 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ |
721 | if ((len -= sizeof(gso)) < 0) | 724 | if ((len -= tun->vnet_hdr_sz) < 0) |
722 | return -EINVAL; | 725 | return -EINVAL; |
723 | 726 | ||
724 | if (skb_is_gso(skb)) { | 727 | if (skb_is_gso(skb)) { |
@@ -749,7 +752,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
749 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, | 752 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, |
750 | sizeof(gso)))) | 753 | sizeof(gso)))) |
751 | return -EFAULT; | 754 | return -EFAULT; |
752 | total += sizeof(gso); | 755 | total += tun->vnet_hdr_sz; |
753 | } | 756 | } |
754 | 757 | ||
755 | len = min_t(int, skb->len, len); | 758 | len = min_t(int, skb->len, len); |
@@ -773,7 +776,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, | |||
773 | 776 | ||
774 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); | 777 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); |
775 | 778 | ||
776 | add_wait_queue(&tun->socket.wait, &wait); | 779 | add_wait_queue(&tun->wq.wait, &wait); |
777 | while (len) { | 780 | while (len) { |
778 | current->state = TASK_INTERRUPTIBLE; | 781 | current->state = TASK_INTERRUPTIBLE; |
779 | 782 | ||
@@ -804,7 +807,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, | |||
804 | } | 807 | } |
805 | 808 | ||
806 | current->state = TASK_RUNNING; | 809 | current->state = TASK_RUNNING; |
807 | remove_wait_queue(&tun->socket.wait, &wait); | 810 | remove_wait_queue(&tun->wq.wait, &wait); |
808 | 811 | ||
809 | return ret; | 812 | return ret; |
810 | } | 813 | } |
@@ -861,6 +864,7 @@ static struct rtnl_link_ops tun_link_ops __read_mostly = { | |||
861 | static void tun_sock_write_space(struct sock *sk) | 864 | static void tun_sock_write_space(struct sock *sk) |
862 | { | 865 | { |
863 | struct tun_struct *tun; | 866 | struct tun_struct *tun; |
867 | wait_queue_head_t *wqueue; | ||
864 | 868 | ||
865 | if (!sock_writeable(sk)) | 869 | if (!sock_writeable(sk)) |
866 | return; | 870 | return; |
@@ -868,8 +872,9 @@ static void tun_sock_write_space(struct sock *sk) | |||
868 | if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) | 872 | if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) |
869 | return; | 873 | return; |
870 | 874 | ||
871 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | 875 | wqueue = sk_sleep(sk); |
872 | wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT | | 876 | if (wqueue && waitqueue_active(wqueue)) |
877 | wake_up_interruptible_sync_poll(wqueue, POLLOUT | | ||
873 | POLLWRNORM | POLLWRBAND); | 878 | POLLWRNORM | POLLWRBAND); |
874 | 879 | ||
875 | tun = tun_sk(sk)->tun; | 880 | tun = tun_sk(sk)->tun; |
@@ -1033,13 +1038,15 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
1033 | tun->dev = dev; | 1038 | tun->dev = dev; |
1034 | tun->flags = flags; | 1039 | tun->flags = flags; |
1035 | tun->txflt.count = 0; | 1040 | tun->txflt.count = 0; |
1041 | tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr); | ||
1036 | 1042 | ||
1037 | err = -ENOMEM; | 1043 | err = -ENOMEM; |
1038 | sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); | 1044 | sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); |
1039 | if (!sk) | 1045 | if (!sk) |
1040 | goto err_free_dev; | 1046 | goto err_free_dev; |
1041 | 1047 | ||
1042 | init_waitqueue_head(&tun->socket.wait); | 1048 | tun->socket.wq = &tun->wq; |
1049 | init_waitqueue_head(&tun->wq.wait); | ||
1043 | tun->socket.ops = &tun_socket_ops; | 1050 | tun->socket.ops = &tun_socket_ops; |
1044 | sock_init_data(&tun->socket, sk); | 1051 | sock_init_data(&tun->socket, sk); |
1045 | sk->sk_write_space = tun_sock_write_space; | 1052 | sk->sk_write_space = tun_sock_write_space; |
@@ -1174,6 +1181,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1174 | struct sock_fprog fprog; | 1181 | struct sock_fprog fprog; |
1175 | struct ifreq ifr; | 1182 | struct ifreq ifr; |
1176 | int sndbuf; | 1183 | int sndbuf; |
1184 | int vnet_hdr_sz; | ||
1177 | int ret; | 1185 | int ret; |
1178 | 1186 | ||
1179 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) | 1187 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) |
@@ -1319,6 +1327,25 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1319 | tun->socket.sk->sk_sndbuf = sndbuf; | 1327 | tun->socket.sk->sk_sndbuf = sndbuf; |
1320 | break; | 1328 | break; |
1321 | 1329 | ||
1330 | case TUNGETVNETHDRSZ: | ||
1331 | vnet_hdr_sz = tun->vnet_hdr_sz; | ||
1332 | if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz))) | ||
1333 | ret = -EFAULT; | ||
1334 | break; | ||
1335 | |||
1336 | case TUNSETVNETHDRSZ: | ||
1337 | if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) { | ||
1338 | ret = -EFAULT; | ||
1339 | break; | ||
1340 | } | ||
1341 | if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) { | ||
1342 | ret = -EINVAL; | ||
1343 | break; | ||
1344 | } | ||
1345 | |||
1346 | tun->vnet_hdr_sz = vnet_hdr_sz; | ||
1347 | break; | ||
1348 | |||
1322 | case TUNATTACHFILTER: | 1349 | case TUNATTACHFILTER: |
1323 | /* Can be set only for TAPs */ | 1350 | /* Can be set only for TAPs */ |
1324 | ret = -EINVAL; | 1351 | ret = -EINVAL; |