diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 110 |
1 files changed, 79 insertions, 31 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 735bf41c654a..811d3517fce0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -540,31 +540,38 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, | |||
540 | 540 | ||
541 | /* Get packet from user space buffer */ | 541 | /* Get packet from user space buffer */ |
542 | static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | 542 | static __inline__ ssize_t tun_get_user(struct tun_struct *tun, |
543 | struct iovec *iv, size_t count, | 543 | const struct iovec *iv, size_t count, |
544 | int noblock) | 544 | int noblock) |
545 | { | 545 | { |
546 | struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) }; | 546 | struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) }; |
547 | struct sk_buff *skb; | 547 | struct sk_buff *skb; |
548 | size_t len = count, align = 0; | 548 | size_t len = count, align = 0; |
549 | struct virtio_net_hdr gso = { 0 }; | 549 | struct virtio_net_hdr gso = { 0 }; |
550 | int offset = 0; | ||
550 | 551 | ||
551 | if (!(tun->flags & TUN_NO_PI)) { | 552 | if (!(tun->flags & TUN_NO_PI)) { |
552 | if ((len -= sizeof(pi)) > count) | 553 | if ((len -= sizeof(pi)) > count) |
553 | return -EINVAL; | 554 | return -EINVAL; |
554 | 555 | ||
555 | if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi))) | 556 | if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi))) |
556 | return -EFAULT; | 557 | return -EFAULT; |
558 | offset += sizeof(pi); | ||
557 | } | 559 | } |
558 | 560 | ||
559 | if (tun->flags & TUN_VNET_HDR) { | 561 | if (tun->flags & TUN_VNET_HDR) { |
560 | if ((len -= sizeof(gso)) > count) | 562 | if ((len -= sizeof(gso)) > count) |
561 | return -EINVAL; | 563 | return -EINVAL; |
562 | 564 | ||
563 | if (memcpy_fromiovec((void *)&gso, iv, sizeof(gso))) | 565 | if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) |
564 | return -EFAULT; | 566 | return -EFAULT; |
565 | 567 | ||
568 | if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && | ||
569 | gso.csum_start + gso.csum_offset + 2 > gso.hdr_len) | ||
570 | gso.hdr_len = gso.csum_start + gso.csum_offset + 2; | ||
571 | |||
566 | if (gso.hdr_len > len) | 572 | if (gso.hdr_len > len) |
567 | return -EINVAL; | 573 | return -EINVAL; |
574 | offset += sizeof(gso); | ||
568 | } | 575 | } |
569 | 576 | ||
570 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { | 577 | if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { |
@@ -581,7 +588,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, | |||
581 | return PTR_ERR(skb); | 588 | return PTR_ERR(skb); |
582 | } | 589 | } |
583 | 590 | ||
584 | if (skb_copy_datagram_from_iovec(skb, 0, iv, len)) { | 591 | if (skb_copy_datagram_from_iovec(skb, 0, iv, offset, len)) { |
585 | tun->dev->stats.rx_dropped++; | 592 | tun->dev->stats.rx_dropped++; |
586 | kfree_skb(skb); | 593 | kfree_skb(skb); |
587 | return -EFAULT; | 594 | return -EFAULT; |
@@ -673,7 +680,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, | |||
673 | 680 | ||
674 | DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); | 681 | DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); |
675 | 682 | ||
676 | result = tun_get_user(tun, (struct iovec *)iv, iov_length(iv, count), | 683 | result = tun_get_user(tun, iv, iov_length(iv, count), |
677 | file->f_flags & O_NONBLOCK); | 684 | file->f_flags & O_NONBLOCK); |
678 | 685 | ||
679 | tun_put(tun); | 686 | tun_put(tun); |
@@ -683,7 +690,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, | |||
683 | /* Put packet to the user space buffer */ | 690 | /* Put packet to the user space buffer */ |
684 | static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | 691 | static __inline__ ssize_t tun_put_user(struct tun_struct *tun, |
685 | struct sk_buff *skb, | 692 | struct sk_buff *skb, |
686 | struct iovec *iv, int len) | 693 | const struct iovec *iv, int len) |
687 | { | 694 | { |
688 | struct tun_pi pi = { 0, skb->protocol }; | 695 | struct tun_pi pi = { 0, skb->protocol }; |
689 | ssize_t total = 0; | 696 | ssize_t total = 0; |
@@ -697,7 +704,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
697 | pi.flags |= TUN_PKT_STRIP; | 704 | pi.flags |= TUN_PKT_STRIP; |
698 | } | 705 | } |
699 | 706 | ||
700 | if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi))) | 707 | if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi))) |
701 | return -EFAULT; | 708 | return -EFAULT; |
702 | total += sizeof(pi); | 709 | total += sizeof(pi); |
703 | } | 710 | } |
@@ -730,14 +737,15 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
730 | gso.csum_offset = skb->csum_offset; | 737 | gso.csum_offset = skb->csum_offset; |
731 | } /* else everything is zero */ | 738 | } /* else everything is zero */ |
732 | 739 | ||
733 | if (unlikely(memcpy_toiovec(iv, (void *)&gso, sizeof(gso)))) | 740 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, |
741 | sizeof(gso)))) | ||
734 | return -EFAULT; | 742 | return -EFAULT; |
735 | total += sizeof(gso); | 743 | total += sizeof(gso); |
736 | } | 744 | } |
737 | 745 | ||
738 | len = min_t(int, skb->len, len); | 746 | len = min_t(int, skb->len, len); |
739 | 747 | ||
740 | skb_copy_datagram_iovec(skb, 0, iv, len); | 748 | skb_copy_datagram_const_iovec(skb, 0, iv, total, len); |
741 | total += len; | 749 | total += len; |
742 | 750 | ||
743 | tun->dev->stats.tx_packets++; | 751 | tun->dev->stats.tx_packets++; |
@@ -792,7 +800,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
792 | } | 800 | } |
793 | netif_wake_queue(tun->dev); | 801 | netif_wake_queue(tun->dev); |
794 | 802 | ||
795 | ret = tun_put_user(tun, skb, (struct iovec *) iv, len); | 803 | ret = tun_put_user(tun, skb, iv, len); |
796 | kfree_skb(skb); | 804 | kfree_skb(skb); |
797 | break; | 805 | break; |
798 | } | 806 | } |
@@ -840,12 +848,12 @@ static void tun_sock_write_space(struct sock *sk) | |||
840 | if (!sock_writeable(sk)) | 848 | if (!sock_writeable(sk)) |
841 | return; | 849 | return; |
842 | 850 | ||
843 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | ||
844 | wake_up_interruptible_sync(sk->sk_sleep); | ||
845 | |||
846 | if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) | 851 | if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) |
847 | return; | 852 | return; |
848 | 853 | ||
854 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | ||
855 | wake_up_interruptible_sync(sk->sk_sleep); | ||
856 | |||
849 | tun = container_of(sk, struct tun_sock, sk)->tun; | 857 | tun = container_of(sk, struct tun_sock, sk)->tun; |
850 | kill_fasync(&tun->fasync, SIGIO, POLL_OUT); | 858 | kill_fasync(&tun->fasync, SIGIO, POLL_OUT); |
851 | } | 859 | } |
@@ -861,6 +869,52 @@ static struct proto tun_proto = { | |||
861 | .obj_size = sizeof(struct tun_sock), | 869 | .obj_size = sizeof(struct tun_sock), |
862 | }; | 870 | }; |
863 | 871 | ||
872 | static int tun_flags(struct tun_struct *tun) | ||
873 | { | ||
874 | int flags = 0; | ||
875 | |||
876 | if (tun->flags & TUN_TUN_DEV) | ||
877 | flags |= IFF_TUN; | ||
878 | else | ||
879 | flags |= IFF_TAP; | ||
880 | |||
881 | if (tun->flags & TUN_NO_PI) | ||
882 | flags |= IFF_NO_PI; | ||
883 | |||
884 | if (tun->flags & TUN_ONE_QUEUE) | ||
885 | flags |= IFF_ONE_QUEUE; | ||
886 | |||
887 | if (tun->flags & TUN_VNET_HDR) | ||
888 | flags |= IFF_VNET_HDR; | ||
889 | |||
890 | return flags; | ||
891 | } | ||
892 | |||
893 | static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr, | ||
894 | char *buf) | ||
895 | { | ||
896 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); | ||
897 | return sprintf(buf, "0x%x\n", tun_flags(tun)); | ||
898 | } | ||
899 | |||
900 | static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr, | ||
901 | char *buf) | ||
902 | { | ||
903 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); | ||
904 | return sprintf(buf, "%d\n", tun->owner); | ||
905 | } | ||
906 | |||
907 | static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr, | ||
908 | char *buf) | ||
909 | { | ||
910 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); | ||
911 | return sprintf(buf, "%d\n", tun->group); | ||
912 | } | ||
913 | |||
914 | static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); | ||
915 | static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL); | ||
916 | static DEVICE_ATTR(group, 0444, tun_show_group, NULL); | ||
917 | |||
864 | static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | 918 | static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) |
865 | { | 919 | { |
866 | struct sock *sk; | 920 | struct sock *sk; |
@@ -870,6 +924,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
870 | 924 | ||
871 | dev = __dev_get_by_name(net, ifr->ifr_name); | 925 | dev = __dev_get_by_name(net, ifr->ifr_name); |
872 | if (dev) { | 926 | if (dev) { |
927 | if (ifr->ifr_flags & IFF_TUN_EXCL) | ||
928 | return -EBUSY; | ||
873 | if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) | 929 | if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) |
874 | tun = netdev_priv(dev); | 930 | tun = netdev_priv(dev); |
875 | else if ((ifr->ifr_flags & IFF_TAP) && dev->netdev_ops == &tap_netdev_ops) | 931 | else if ((ifr->ifr_flags & IFF_TAP) && dev->netdev_ops == &tap_netdev_ops) |
@@ -944,6 +1000,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
944 | if (err < 0) | 1000 | if (err < 0) |
945 | goto err_free_sk; | 1001 | goto err_free_sk; |
946 | 1002 | ||
1003 | if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) || | ||
1004 | device_create_file(&tun->dev->dev, &dev_attr_owner) || | ||
1005 | device_create_file(&tun->dev->dev, &dev_attr_group)) | ||
1006 | printk(KERN_ERR "Failed to create tun sysfs files\n"); | ||
1007 | |||
947 | sk->sk_destruct = tun_sock_destruct; | 1008 | sk->sk_destruct = tun_sock_destruct; |
948 | 1009 | ||
949 | err = tun_attach(tun, file); | 1010 | err = tun_attach(tun, file); |
@@ -996,21 +1057,7 @@ static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
996 | 1057 | ||
997 | strcpy(ifr->ifr_name, tun->dev->name); | 1058 | strcpy(ifr->ifr_name, tun->dev->name); |
998 | 1059 | ||
999 | ifr->ifr_flags = 0; | 1060 | ifr->ifr_flags = tun_flags(tun); |
1000 | |||
1001 | if (ifr->ifr_flags & TUN_TUN_DEV) | ||
1002 | ifr->ifr_flags |= IFF_TUN; | ||
1003 | else | ||
1004 | ifr->ifr_flags |= IFF_TAP; | ||
1005 | |||
1006 | if (tun->flags & TUN_NO_PI) | ||
1007 | ifr->ifr_flags |= IFF_NO_PI; | ||
1008 | |||
1009 | if (tun->flags & TUN_ONE_QUEUE) | ||
1010 | ifr->ifr_flags |= IFF_ONE_QUEUE; | ||
1011 | |||
1012 | if (tun->flags & TUN_VNET_HDR) | ||
1013 | ifr->ifr_flags |= IFF_VNET_HDR; | ||
1014 | 1061 | ||
1015 | tun_put(tun); | 1062 | tun_put(tun); |
1016 | return 0; | 1063 | return 0; |
@@ -1275,21 +1322,22 @@ static int tun_chr_open(struct inode *inode, struct file * file) | |||
1275 | static int tun_chr_close(struct inode *inode, struct file *file) | 1322 | static int tun_chr_close(struct inode *inode, struct file *file) |
1276 | { | 1323 | { |
1277 | struct tun_file *tfile = file->private_data; | 1324 | struct tun_file *tfile = file->private_data; |
1278 | struct tun_struct *tun = __tun_get(tfile); | 1325 | struct tun_struct *tun; |
1279 | 1326 | ||
1280 | 1327 | ||
1328 | rtnl_lock(); | ||
1329 | tun = __tun_get(tfile); | ||
1281 | if (tun) { | 1330 | if (tun) { |
1282 | DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); | 1331 | DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); |
1283 | 1332 | ||
1284 | rtnl_lock(); | ||
1285 | __tun_detach(tun); | 1333 | __tun_detach(tun); |
1286 | 1334 | ||
1287 | /* If desireable, unregister the netdevice. */ | 1335 | /* If desireable, unregister the netdevice. */ |
1288 | if (!(tun->flags & TUN_PERSIST)) | 1336 | if (!(tun->flags & TUN_PERSIST)) |
1289 | unregister_netdevice(tun->dev); | 1337 | unregister_netdevice(tun->dev); |
1290 | 1338 | ||
1291 | rtnl_unlock(); | ||
1292 | } | 1339 | } |
1340 | rtnl_unlock(); | ||
1293 | 1341 | ||
1294 | tun = tfile->tun; | 1342 | tun = tfile->tun; |
1295 | if (tun) | 1343 | if (tun) |