diff options
Diffstat (limited to 'drivers/net/tun.c')
| -rw-r--r-- | drivers/net/tun.c | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 43265207d463..97b25533e5fb 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 | } |
| @@ -393,12 +396,11 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 393 | 396 | ||
| 394 | /* Enqueue packet */ | 397 | /* Enqueue packet */ |
| 395 | skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); | 398 | skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); |
| 396 | dev->trans_start = jiffies; | ||
| 397 | 399 | ||
| 398 | /* Notify and wake up reader process */ | 400 | /* Notify and wake up reader process */ |
| 399 | if (tun->flags & TUN_FASYNC) | 401 | if (tun->flags & TUN_FASYNC) |
| 400 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); | 402 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); |
| 401 | wake_up_interruptible_poll(&tun->socket.wait, POLLIN | | 403 | wake_up_interruptible_poll(&tun->wq.wait, POLLIN | |
| 402 | POLLRDNORM | POLLRDBAND); | 404 | POLLRDNORM | POLLRDBAND); |
| 403 | return NETDEV_TX_OK; | 405 | return NETDEV_TX_OK; |
| 404 | 406 | ||
| @@ -415,7 +417,6 @@ static void tun_net_mclist(struct net_device *dev) | |||
| 415 | * _rx_ path and has nothing to do with the _tx_ path. | 417 | * _rx_ path and has nothing to do with the _tx_ path. |
| 416 | * In rx path we always accept everything userspace gives us. | 418 | * In rx path we always accept everything userspace gives us. |
| 417 | */ | 419 | */ |
| 418 | return; | ||
| 419 | } | 420 | } |
| 420 | 421 | ||
| 421 | #define MIN_MTU 68 | 422 | #define MIN_MTU 68 |
| @@ -498,7 +499,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | |||
| 498 | 499 | ||
| 499 | DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); | 500 | DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); |
| 500 | 501 | ||
| 501 | poll_wait(file, &tun->socket.wait, wait); | 502 | poll_wait(file, &tun->wq.wait, wait); |
| 502 | 503 | ||
| 503 | if (!skb_queue_empty(&sk->sk_receive_queue)) | 504 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
| 504 | mask |= POLLIN | POLLRDNORM; | 505 | mask |= POLLIN | POLLRDNORM; |
| @@ -563,7 +564,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
| 563 | } | 564 | } |
| 564 | 565 | ||
| 565 | if (tun->flags & TUN_VNET_HDR) { | 566 | if (tun->flags & TUN_VNET_HDR) { |
| 566 | if ((len -= sizeof(gso)) > count) | 567 | if ((len -= tun->vnet_hdr_sz) > count) |
| 567 | return -EINVAL; | 568 | return -EINVAL; |
| 568 | 569 | ||
| 569 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) | 570 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) |
| @@ -575,7 +576,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
| 575 | 576 | ||
| 576 | if (gso.hdr_len > len) | 577 | if (gso.hdr_len > len) |
| 577 | return -EINVAL; | 578 | return -EINVAL; |
| 578 | offset += sizeof(gso); | 579 | offset += tun->vnet_hdr_sz; |
| 579 | } | 580 | } |
| 580 | 581 | ||
| 581 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { | 582 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { |
| @@ -718,7 +719,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
| 718 | 719 | ||
| 719 | if (tun->flags & TUN_VNET_HDR) { | 720 | if (tun->flags & TUN_VNET_HDR) { |
| 720 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ | 721 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ |
| 721 | if ((len -= sizeof(gso)) < 0) | 722 | if ((len -= tun->vnet_hdr_sz) < 0) |
| 722 | return -EINVAL; | 723 | return -EINVAL; |
| 723 | 724 | ||
| 724 | if (skb_is_gso(skb)) { | 725 | if (skb_is_gso(skb)) { |
| @@ -749,7 +750,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
| 749 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, | 750 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, |
| 750 | sizeof(gso)))) | 751 | sizeof(gso)))) |
| 751 | return -EFAULT; | 752 | return -EFAULT; |
| 752 | total += sizeof(gso); | 753 | total += tun->vnet_hdr_sz; |
| 753 | } | 754 | } |
| 754 | 755 | ||
| 755 | len = min_t(int, skb->len, len); | 756 | len = min_t(int, skb->len, len); |
| @@ -773,7 +774,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, | |||
| 773 | 774 | ||
| 774 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); | 775 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); |
| 775 | 776 | ||
| 776 | add_wait_queue(&tun->socket.wait, &wait); | 777 | add_wait_queue(&tun->wq.wait, &wait); |
| 777 | while (len) { | 778 | while (len) { |
| 778 | current->state = TASK_INTERRUPTIBLE; | 779 | current->state = TASK_INTERRUPTIBLE; |
| 779 | 780 | ||
| @@ -804,7 +805,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, | |||
| 804 | } | 805 | } |
| 805 | 806 | ||
| 806 | current->state = TASK_RUNNING; | 807 | current->state = TASK_RUNNING; |
| 807 | remove_wait_queue(&tun->socket.wait, &wait); | 808 | remove_wait_queue(&tun->wq.wait, &wait); |
| 808 | 809 | ||
| 809 | return ret; | 810 | return ret; |
| 810 | } | 811 | } |
| @@ -861,6 +862,7 @@ static struct rtnl_link_ops tun_link_ops __read_mostly = { | |||
| 861 | static void tun_sock_write_space(struct sock *sk) | 862 | static void tun_sock_write_space(struct sock *sk) |
| 862 | { | 863 | { |
| 863 | struct tun_struct *tun; | 864 | struct tun_struct *tun; |
| 865 | wait_queue_head_t *wqueue; | ||
| 864 | 866 | ||
| 865 | if (!sock_writeable(sk)) | 867 | if (!sock_writeable(sk)) |
| 866 | return; | 868 | return; |
| @@ -868,8 +870,9 @@ static void tun_sock_write_space(struct sock *sk) | |||
| 868 | if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) | 870 | if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) |
| 869 | return; | 871 | return; |
| 870 | 872 | ||
| 871 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | 873 | wqueue = sk_sleep(sk); |
| 872 | wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT | | 874 | if (wqueue && waitqueue_active(wqueue)) |
| 875 | wake_up_interruptible_sync_poll(wqueue, POLLOUT | | ||
| 873 | POLLWRNORM | POLLWRBAND); | 876 | POLLWRNORM | POLLWRBAND); |
| 874 | 877 | ||
| 875 | tun = tun_sk(sk)->tun; | 878 | tun = tun_sk(sk)->tun; |
| @@ -1033,13 +1036,15 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1033 | tun->dev = dev; | 1036 | tun->dev = dev; |
| 1034 | tun->flags = flags; | 1037 | tun->flags = flags; |
| 1035 | tun->txflt.count = 0; | 1038 | tun->txflt.count = 0; |
| 1039 | tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr); | ||
| 1036 | 1040 | ||
| 1037 | err = -ENOMEM; | 1041 | err = -ENOMEM; |
| 1038 | sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); | 1042 | sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); |
| 1039 | if (!sk) | 1043 | if (!sk) |
| 1040 | goto err_free_dev; | 1044 | goto err_free_dev; |
| 1041 | 1045 | ||
| 1042 | init_waitqueue_head(&tun->socket.wait); | 1046 | tun->socket.wq = &tun->wq; |
| 1047 | init_waitqueue_head(&tun->wq.wait); | ||
| 1043 | tun->socket.ops = &tun_socket_ops; | 1048 | tun->socket.ops = &tun_socket_ops; |
| 1044 | sock_init_data(&tun->socket, sk); | 1049 | sock_init_data(&tun->socket, sk); |
| 1045 | sk->sk_write_space = tun_sock_write_space; | 1050 | sk->sk_write_space = tun_sock_write_space; |
| @@ -1174,6 +1179,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
| 1174 | struct sock_fprog fprog; | 1179 | struct sock_fprog fprog; |
| 1175 | struct ifreq ifr; | 1180 | struct ifreq ifr; |
| 1176 | int sndbuf; | 1181 | int sndbuf; |
| 1182 | int vnet_hdr_sz; | ||
| 1177 | int ret; | 1183 | int ret; |
| 1178 | 1184 | ||
| 1179 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) | 1185 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) |
| @@ -1319,6 +1325,25 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
| 1319 | tun->socket.sk->sk_sndbuf = sndbuf; | 1325 | tun->socket.sk->sk_sndbuf = sndbuf; |
| 1320 | break; | 1326 | break; |
| 1321 | 1327 | ||
| 1328 | case TUNGETVNETHDRSZ: | ||
| 1329 | vnet_hdr_sz = tun->vnet_hdr_sz; | ||
| 1330 | if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz))) | ||
| 1331 | ret = -EFAULT; | ||
| 1332 | break; | ||
| 1333 | |||
| 1334 | case TUNSETVNETHDRSZ: | ||
| 1335 | if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) { | ||
| 1336 | ret = -EFAULT; | ||
| 1337 | break; | ||
| 1338 | } | ||
| 1339 | if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) { | ||
| 1340 | ret = -EINVAL; | ||
| 1341 | break; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | tun->vnet_hdr_sz = vnet_hdr_sz; | ||
| 1345 | break; | ||
| 1346 | |||
| 1322 | case TUNATTACHFILTER: | 1347 | case TUNATTACHFILTER: |
| 1323 | /* Can be set only for TAPs */ | 1348 | /* Can be set only for TAPs */ |
| 1324 | ret = -EINVAL; | 1349 | ret = -EINVAL; |
| @@ -1342,7 +1367,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
| 1342 | default: | 1367 | default: |
| 1343 | ret = -EINVAL; | 1368 | ret = -EINVAL; |
| 1344 | break; | 1369 | break; |
| 1345 | }; | 1370 | } |
| 1346 | 1371 | ||
| 1347 | unlock: | 1372 | unlock: |
| 1348 | rtnl_unlock(); | 1373 | rtnl_unlock(); |
