diff options
-rw-r--r-- | drivers/net/tun.c | 49 | ||||
-rw-r--r-- | include/linux/if_tun.h | 7 |
2 files changed, 56 insertions, 0 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3bb991fd2b51..a314955e6994 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -611,6 +611,46 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
611 | return err; | 611 | return err; |
612 | } | 612 | } |
613 | 613 | ||
614 | /* This is like a cut-down ethtool ops, except done via tun fd so no | ||
615 | * privs required. */ | ||
616 | static int set_offload(struct net_device *dev, unsigned long arg) | ||
617 | { | ||
618 | unsigned int old_features, features; | ||
619 | |||
620 | old_features = dev->features; | ||
621 | /* Unset features, set them as we chew on the arg. */ | ||
622 | features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST | ||
623 | |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6)); | ||
624 | |||
625 | if (arg & TUN_F_CSUM) { | ||
626 | features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; | ||
627 | arg &= ~TUN_F_CSUM; | ||
628 | |||
629 | if (arg & (TUN_F_TSO4|TUN_F_TSO6)) { | ||
630 | if (arg & TUN_F_TSO_ECN) { | ||
631 | features |= NETIF_F_TSO_ECN; | ||
632 | arg &= ~TUN_F_TSO_ECN; | ||
633 | } | ||
634 | if (arg & TUN_F_TSO4) | ||
635 | features |= NETIF_F_TSO; | ||
636 | if (arg & TUN_F_TSO6) | ||
637 | features |= NETIF_F_TSO6; | ||
638 | arg &= ~(TUN_F_TSO4|TUN_F_TSO6); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | /* This gives the user a way to test for new features in future by | ||
643 | * trying to set them. */ | ||
644 | if (arg) | ||
645 | return -EINVAL; | ||
646 | |||
647 | dev->features = features; | ||
648 | if (old_features != dev->features) | ||
649 | netdev_features_change(dev); | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
614 | static int tun_chr_ioctl(struct inode *inode, struct file *file, | 654 | static int tun_chr_ioctl(struct inode *inode, struct file *file, |
615 | unsigned int cmd, unsigned long arg) | 655 | unsigned int cmd, unsigned long arg) |
616 | { | 656 | { |
@@ -715,6 +755,15 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
715 | break; | 755 | break; |
716 | #endif | 756 | #endif |
717 | 757 | ||
758 | case TUNSETOFFLOAD: | ||
759 | { | ||
760 | int ret; | ||
761 | rtnl_lock(); | ||
762 | ret = set_offload(tun->dev, arg); | ||
763 | rtnl_unlock(); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
718 | case SIOCGIFFLAGS: | 767 | case SIOCGIFFLAGS: |
719 | ifr.ifr_flags = tun->if_flags; | 768 | ifr.ifr_flags = tun->if_flags; |
720 | if (copy_to_user( argp, &ifr, sizeof ifr)) | 769 | if (copy_to_user( argp, &ifr, sizeof ifr)) |
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 94f76a112303..3f0a0995d449 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h | |||
@@ -41,6 +41,7 @@ | |||
41 | #define TUNSETLINK _IOW('T', 205, int) | 41 | #define TUNSETLINK _IOW('T', 205, int) |
42 | #define TUNSETGROUP _IOW('T', 206, int) | 42 | #define TUNSETGROUP _IOW('T', 206, int) |
43 | #define TUNGETFEATURES _IOR('T', 207, unsigned int) | 43 | #define TUNGETFEATURES _IOR('T', 207, unsigned int) |
44 | #define TUNSETOFFLOAD _IOW('T', 208, unsigned int) | ||
44 | 45 | ||
45 | /* TUNSETIFF ifr flags */ | 46 | /* TUNSETIFF ifr flags */ |
46 | #define IFF_TUN 0x0001 | 47 | #define IFF_TUN 0x0001 |
@@ -48,6 +49,12 @@ | |||
48 | #define IFF_NO_PI 0x1000 | 49 | #define IFF_NO_PI 0x1000 |
49 | #define IFF_ONE_QUEUE 0x2000 | 50 | #define IFF_ONE_QUEUE 0x2000 |
50 | 51 | ||
52 | /* Features for GSO (TUNSETOFFLOAD). */ | ||
53 | #define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ | ||
54 | #define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ | ||
55 | #define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ | ||
56 | #define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ | ||
57 | |||
51 | struct tun_pi { | 58 | struct tun_pi { |
52 | unsigned short flags; | 59 | unsigned short flags; |
53 | __be16 proto; | 60 | __be16 proto; |