diff options
-rw-r--r-- | drivers/net/tun.c | 156 |
1 files changed, 104 insertions, 52 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8743de9d2572..d3a665d2f7b8 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -87,9 +87,13 @@ struct tap_filter { | |||
87 | unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; | 87 | unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; |
88 | }; | 88 | }; |
89 | 89 | ||
90 | struct tun_file { | ||
91 | struct tun_struct *tun; | ||
92 | }; | ||
93 | |||
90 | struct tun_struct { | 94 | struct tun_struct { |
95 | struct tun_file *tfile; | ||
91 | unsigned int flags; | 96 | unsigned int flags; |
92 | int attached; | ||
93 | uid_t owner; | 97 | uid_t owner; |
94 | gid_t group; | 98 | gid_t group; |
95 | 99 | ||
@@ -108,14 +112,15 @@ struct tun_struct { | |||
108 | 112 | ||
109 | static int tun_attach(struct tun_struct *tun, struct file *file) | 113 | static int tun_attach(struct tun_struct *tun, struct file *file) |
110 | { | 114 | { |
115 | struct tun_file *tfile = file->private_data; | ||
111 | const struct cred *cred = current_cred(); | 116 | const struct cred *cred = current_cred(); |
112 | 117 | ||
113 | ASSERT_RTNL(); | 118 | ASSERT_RTNL(); |
114 | 119 | ||
115 | if (file->private_data) | 120 | if (tfile->tun) |
116 | return -EINVAL; | 121 | return -EINVAL; |
117 | 122 | ||
118 | if (tun->attached) | 123 | if (tun->tfile) |
119 | return -EBUSY; | 124 | return -EBUSY; |
120 | 125 | ||
121 | /* Check permissions */ | 126 | /* Check permissions */ |
@@ -124,13 +129,41 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
124 | !capable(CAP_NET_ADMIN)) | 129 | !capable(CAP_NET_ADMIN)) |
125 | return -EPERM; | 130 | return -EPERM; |
126 | 131 | ||
127 | file->private_data = tun; | 132 | tfile->tun = tun; |
128 | tun->attached = 1; | 133 | tun->tfile = tfile; |
129 | get_net(dev_net(tun->dev)); | 134 | get_net(dev_net(tun->dev)); |
130 | 135 | ||
131 | return 0; | 136 | return 0; |
132 | } | 137 | } |
133 | 138 | ||
139 | static void __tun_detach(struct tun_struct *tun) | ||
140 | { | ||
141 | struct tun_file *tfile = tun->tfile; | ||
142 | |||
143 | /* Detach from net device */ | ||
144 | tfile->tun = NULL; | ||
145 | tun->tfile = NULL; | ||
146 | put_net(dev_net(tun->dev)); | ||
147 | |||
148 | /* Drop read queue */ | ||
149 | skb_queue_purge(&tun->readq); | ||
150 | } | ||
151 | |||
152 | static struct tun_struct *__tun_get(struct tun_file *tfile) | ||
153 | { | ||
154 | return tfile->tun; | ||
155 | } | ||
156 | |||
157 | static struct tun_struct *tun_get(struct file *file) | ||
158 | { | ||
159 | return __tun_get(file->private_data); | ||
160 | } | ||
161 | |||
162 | static void tun_put(struct tun_struct *tun) | ||
163 | { | ||
164 | /* Noop for now */ | ||
165 | } | ||
166 | |||
134 | /* TAP filterting */ | 167 | /* TAP filterting */ |
135 | static void addr_hash_set(u32 *mask, const u8 *addr) | 168 | static void addr_hash_set(u32 *mask, const u8 *addr) |
136 | { | 169 | { |
@@ -261,7 +294,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
261 | DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len); | 294 | DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len); |
262 | 295 | ||
263 | /* Drop packet if interface is not attached */ | 296 | /* Drop packet if interface is not attached */ |
264 | if (!tun->attached) | 297 | if (!tun->tfile) |
265 | goto drop; | 298 | goto drop; |
266 | 299 | ||
267 | /* Drop if the filter does not like it. | 300 | /* Drop if the filter does not like it. |
@@ -378,7 +411,7 @@ static void tun_net_init(struct net_device *dev) | |||
378 | /* Poll */ | 411 | /* Poll */ |
379 | static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | 412 | static unsigned int tun_chr_poll(struct file *file, poll_table * wait) |
380 | { | 413 | { |
381 | struct tun_struct *tun = file->private_data; | 414 | struct tun_struct *tun = tun_get(file); |
382 | unsigned int mask = POLLOUT | POLLWRNORM; | 415 | unsigned int mask = POLLOUT | POLLWRNORM; |
383 | 416 | ||
384 | if (!tun) | 417 | if (!tun) |
@@ -391,6 +424,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | |||
391 | if (!skb_queue_empty(&tun->readq)) | 424 | if (!skb_queue_empty(&tun->readq)) |
392 | mask |= POLLIN | POLLRDNORM; | 425 | mask |= POLLIN | POLLRDNORM; |
393 | 426 | ||
427 | tun_put(tun); | ||
394 | return mask; | 428 | return mask; |
395 | } | 429 | } |
396 | 430 | ||
@@ -575,14 +609,18 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, | |||
575 | static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, | 609 | static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, |
576 | unsigned long count, loff_t pos) | 610 | unsigned long count, loff_t pos) |
577 | { | 611 | { |
578 | struct tun_struct *tun = iocb->ki_filp->private_data; | 612 | struct tun_struct *tun = tun_get(iocb->ki_filp); |
613 | ssize_t result; | ||
579 | 614 | ||
580 | if (!tun) | 615 | if (!tun) |
581 | return -EBADFD; | 616 | return -EBADFD; |
582 | 617 | ||
583 | DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); | 618 | DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); |
584 | 619 | ||
585 | return tun_get_user(tun, (struct iovec *) iv, iov_length(iv, count)); | 620 | result = tun_get_user(tun, (struct iovec *) iv, iov_length(iv, count)); |
621 | |||
622 | tun_put(tun); | ||
623 | return result; | ||
586 | } | 624 | } |
587 | 625 | ||
588 | /* Put packet to the user space buffer */ | 626 | /* Put packet to the user space buffer */ |
@@ -655,7 +693,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
655 | unsigned long count, loff_t pos) | 693 | unsigned long count, loff_t pos) |
656 | { | 694 | { |
657 | struct file *file = iocb->ki_filp; | 695 | struct file *file = iocb->ki_filp; |
658 | struct tun_struct *tun = file->private_data; | 696 | struct tun_struct *tun = tun_get(file); |
659 | DECLARE_WAITQUEUE(wait, current); | 697 | DECLARE_WAITQUEUE(wait, current); |
660 | struct sk_buff *skb; | 698 | struct sk_buff *skb; |
661 | ssize_t len, ret = 0; | 699 | ssize_t len, ret = 0; |
@@ -666,8 +704,10 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
666 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); | 704 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); |
667 | 705 | ||
668 | len = iov_length(iv, count); | 706 | len = iov_length(iv, count); |
669 | if (len < 0) | 707 | if (len < 0) { |
670 | return -EINVAL; | 708 | ret = -EINVAL; |
709 | goto out; | ||
710 | } | ||
671 | 711 | ||
672 | add_wait_queue(&tun->read_wait, &wait); | 712 | add_wait_queue(&tun->read_wait, &wait); |
673 | while (len) { | 713 | while (len) { |
@@ -698,6 +738,8 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
698 | current->state = TASK_RUNNING; | 738 | current->state = TASK_RUNNING; |
699 | remove_wait_queue(&tun->read_wait, &wait); | 739 | remove_wait_queue(&tun->read_wait, &wait); |
700 | 740 | ||
741 | out: | ||
742 | tun_put(tun); | ||
701 | return ret; | 743 | return ret; |
702 | } | 744 | } |
703 | 745 | ||
@@ -822,7 +864,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
822 | 864 | ||
823 | static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) | 865 | static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) |
824 | { | 866 | { |
825 | struct tun_struct *tun = file->private_data; | 867 | struct tun_struct *tun = tun_get(file); |
826 | 868 | ||
827 | if (!tun) | 869 | if (!tun) |
828 | return -EBADFD; | 870 | return -EBADFD; |
@@ -847,6 +889,7 @@ static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
847 | if (tun->flags & TUN_VNET_HDR) | 889 | if (tun->flags & TUN_VNET_HDR) |
848 | ifr->ifr_flags |= IFF_VNET_HDR; | 890 | ifr->ifr_flags |= IFF_VNET_HDR; |
849 | 891 | ||
892 | tun_put(tun); | ||
850 | return 0; | 893 | return 0; |
851 | } | 894 | } |
852 | 895 | ||
@@ -893,7 +936,7 @@ static int set_offload(struct net_device *dev, unsigned long arg) | |||
893 | static int tun_chr_ioctl(struct inode *inode, struct file *file, | 936 | static int tun_chr_ioctl(struct inode *inode, struct file *file, |
894 | unsigned int cmd, unsigned long arg) | 937 | unsigned int cmd, unsigned long arg) |
895 | { | 938 | { |
896 | struct tun_struct *tun = file->private_data; | 939 | struct tun_struct *tun; |
897 | void __user* argp = (void __user*)arg; | 940 | void __user* argp = (void __user*)arg; |
898 | struct ifreq ifr; | 941 | struct ifreq ifr; |
899 | int ret; | 942 | int ret; |
@@ -902,6 +945,16 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
902 | if (copy_from_user(&ifr, argp, sizeof ifr)) | 945 | if (copy_from_user(&ifr, argp, sizeof ifr)) |
903 | return -EFAULT; | 946 | return -EFAULT; |
904 | 947 | ||
948 | if (cmd == TUNGETFEATURES) { | ||
949 | /* Currently this just means: "what IFF flags are valid?". | ||
950 | * This is needed because we never checked for invalid flags on | ||
951 | * TUNSETIFF. */ | ||
952 | return put_user(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE | | ||
953 | IFF_VNET_HDR, | ||
954 | (unsigned int __user*)argp); | ||
955 | } | ||
956 | |||
957 | tun = tun_get(file); | ||
905 | if (cmd == TUNSETIFF && !tun) { | 958 | if (cmd == TUNSETIFF && !tun) { |
906 | int err; | 959 | int err; |
907 | 960 | ||
@@ -919,28 +972,21 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
919 | return 0; | 972 | return 0; |
920 | } | 973 | } |
921 | 974 | ||
922 | if (cmd == TUNGETFEATURES) { | ||
923 | /* Currently this just means: "what IFF flags are valid?". | ||
924 | * This is needed because we never checked for invalid flags on | ||
925 | * TUNSETIFF. */ | ||
926 | return put_user(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE | | ||
927 | IFF_VNET_HDR, | ||
928 | (unsigned int __user*)argp); | ||
929 | } | ||
930 | 975 | ||
931 | if (!tun) | 976 | if (!tun) |
932 | return -EBADFD; | 977 | return -EBADFD; |
933 | 978 | ||
934 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); | 979 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); |
935 | 980 | ||
981 | ret = 0; | ||
936 | switch (cmd) { | 982 | switch (cmd) { |
937 | case TUNGETIFF: | 983 | case TUNGETIFF: |
938 | ret = tun_get_iff(current->nsproxy->net_ns, file, &ifr); | 984 | ret = tun_get_iff(current->nsproxy->net_ns, file, &ifr); |
939 | if (ret) | 985 | if (ret) |
940 | return ret; | 986 | break; |
941 | 987 | ||
942 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 988 | if (copy_to_user(argp, &ifr, sizeof(ifr))) |
943 | return -EFAULT; | 989 | ret = -EFAULT; |
944 | break; | 990 | break; |
945 | 991 | ||
946 | case TUNSETNOCSUM: | 992 | case TUNSETNOCSUM: |
@@ -992,7 +1038,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
992 | ret = 0; | 1038 | ret = 0; |
993 | } | 1039 | } |
994 | rtnl_unlock(); | 1040 | rtnl_unlock(); |
995 | return ret; | 1041 | break; |
996 | 1042 | ||
997 | #ifdef TUN_DEBUG | 1043 | #ifdef TUN_DEBUG |
998 | case TUNSETDEBUG: | 1044 | case TUNSETDEBUG: |
@@ -1003,24 +1049,25 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1003 | rtnl_lock(); | 1049 | rtnl_lock(); |
1004 | ret = set_offload(tun->dev, arg); | 1050 | ret = set_offload(tun->dev, arg); |
1005 | rtnl_unlock(); | 1051 | rtnl_unlock(); |
1006 | return ret; | 1052 | break; |
1007 | 1053 | ||
1008 | case TUNSETTXFILTER: | 1054 | case TUNSETTXFILTER: |
1009 | /* Can be set only for TAPs */ | 1055 | /* Can be set only for TAPs */ |
1056 | ret = -EINVAL; | ||
1010 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) | 1057 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) |
1011 | return -EINVAL; | 1058 | break; |
1012 | rtnl_lock(); | 1059 | rtnl_lock(); |
1013 | ret = update_filter(&tun->txflt, (void __user *)arg); | 1060 | ret = update_filter(&tun->txflt, (void __user *)arg); |
1014 | rtnl_unlock(); | 1061 | rtnl_unlock(); |
1015 | return ret; | 1062 | break; |
1016 | 1063 | ||
1017 | case SIOCGIFHWADDR: | 1064 | case SIOCGIFHWADDR: |
1018 | /* Get hw addres */ | 1065 | /* Get hw addres */ |
1019 | memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); | 1066 | memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); |
1020 | ifr.ifr_hwaddr.sa_family = tun->dev->type; | 1067 | ifr.ifr_hwaddr.sa_family = tun->dev->type; |
1021 | if (copy_to_user(argp, &ifr, sizeof ifr)) | 1068 | if (copy_to_user(argp, &ifr, sizeof ifr)) |
1022 | return -EFAULT; | 1069 | ret = -EFAULT; |
1023 | return 0; | 1070 | break; |
1024 | 1071 | ||
1025 | case SIOCSIFHWADDR: | 1072 | case SIOCSIFHWADDR: |
1026 | /* Set hw address */ | 1073 | /* Set hw address */ |
@@ -1030,18 +1077,19 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1030 | rtnl_lock(); | 1077 | rtnl_lock(); |
1031 | ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); | 1078 | ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); |
1032 | rtnl_unlock(); | 1079 | rtnl_unlock(); |
1033 | return ret; | 1080 | break; |
1034 | |||
1035 | default: | 1081 | default: |
1036 | return -EINVAL; | 1082 | ret = -EINVAL; |
1083 | break; | ||
1037 | }; | 1084 | }; |
1038 | 1085 | ||
1039 | return 0; | 1086 | tun_put(tun); |
1087 | return ret; | ||
1040 | } | 1088 | } |
1041 | 1089 | ||
1042 | static int tun_chr_fasync(int fd, struct file *file, int on) | 1090 | static int tun_chr_fasync(int fd, struct file *file, int on) |
1043 | { | 1091 | { |
1044 | struct tun_struct *tun = file->private_data; | 1092 | struct tun_struct *tun = tun_get(file); |
1045 | int ret; | 1093 | int ret; |
1046 | 1094 | ||
1047 | if (!tun) | 1095 | if (!tun) |
@@ -1063,40 +1111,44 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
1063 | ret = 0; | 1111 | ret = 0; |
1064 | out: | 1112 | out: |
1065 | unlock_kernel(); | 1113 | unlock_kernel(); |
1114 | tun_put(tun); | ||
1066 | return ret; | 1115 | return ret; |
1067 | } | 1116 | } |
1068 | 1117 | ||
1069 | static int tun_chr_open(struct inode *inode, struct file * file) | 1118 | static int tun_chr_open(struct inode *inode, struct file * file) |
1070 | { | 1119 | { |
1120 | struct tun_file *tfile; | ||
1071 | cycle_kernel_lock(); | 1121 | cycle_kernel_lock(); |
1072 | DBG1(KERN_INFO "tunX: tun_chr_open\n"); | 1122 | DBG1(KERN_INFO "tunX: tun_chr_open\n"); |
1073 | file->private_data = NULL; | 1123 | |
1124 | tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); | ||
1125 | if (!tfile) | ||
1126 | return -ENOMEM; | ||
1127 | tfile->tun = NULL; | ||
1128 | file->private_data = tfile; | ||
1074 | return 0; | 1129 | return 0; |
1075 | } | 1130 | } |
1076 | 1131 | ||
1077 | static int tun_chr_close(struct inode *inode, struct file *file) | 1132 | static int tun_chr_close(struct inode *inode, struct file *file) |
1078 | { | 1133 | { |
1079 | struct tun_struct *tun = file->private_data; | 1134 | struct tun_file *tfile = file->private_data; |
1080 | 1135 | struct tun_struct *tun = __tun_get(tfile); | |
1081 | if (!tun) | ||
1082 | return 0; | ||
1083 | 1136 | ||
1084 | DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); | ||
1085 | 1137 | ||
1086 | rtnl_lock(); | 1138 | if (tun) { |
1139 | DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); | ||
1087 | 1140 | ||
1088 | /* Detach from net device */ | 1141 | rtnl_lock(); |
1089 | file->private_data = NULL; | 1142 | __tun_detach(tun); |
1090 | tun->attached = 0; | ||
1091 | put_net(dev_net(tun->dev)); | ||
1092 | 1143 | ||
1093 | /* Drop read queue */ | 1144 | /* If desireable, unregister the netdevice. */ |
1094 | skb_queue_purge(&tun->readq); | 1145 | if (!(tun->flags & TUN_PERSIST)) |
1146 | unregister_netdevice(tun->dev); | ||
1095 | 1147 | ||
1096 | if (!(tun->flags & TUN_PERSIST)) | 1148 | rtnl_unlock(); |
1097 | unregister_netdevice(tun->dev); | 1149 | } |
1098 | 1150 | ||
1099 | rtnl_unlock(); | 1151 | kfree(tfile); |
1100 | 1152 | ||
1101 | return 0; | 1153 | return 0; |
1102 | } | 1154 | } |
@@ -1177,7 +1229,7 @@ static void tun_set_msglevel(struct net_device *dev, u32 value) | |||
1177 | static u32 tun_get_link(struct net_device *dev) | 1229 | static u32 tun_get_link(struct net_device *dev) |
1178 | { | 1230 | { |
1179 | struct tun_struct *tun = netdev_priv(dev); | 1231 | struct tun_struct *tun = netdev_priv(dev); |
1180 | return tun->attached; | 1232 | return !!tun->tfile; |
1181 | } | 1233 | } |
1182 | 1234 | ||
1183 | static u32 tun_get_rx_csum(struct net_device *dev) | 1235 | static u32 tun_get_rx_csum(struct net_device *dev) |