diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 93 |
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e470ae59d405..06a039414628 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -111,6 +111,7 @@ do { \ | |||
111 | #define TUN_FASYNC IFF_ATTACH_QUEUE | 111 | #define TUN_FASYNC IFF_ATTACH_QUEUE |
112 | /* High bits in flags field are unused. */ | 112 | /* High bits in flags field are unused. */ |
113 | #define TUN_VNET_LE 0x80000000 | 113 | #define TUN_VNET_LE 0x80000000 |
114 | #define TUN_VNET_BE 0x40000000 | ||
114 | 115 | ||
115 | #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ | 116 | #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ |
116 | IFF_MULTI_QUEUE) | 117 | IFF_MULTI_QUEUE) |
@@ -146,7 +147,6 @@ struct tun_file { | |||
146 | struct socket socket; | 147 | struct socket socket; |
147 | struct socket_wq wq; | 148 | struct socket_wq wq; |
148 | struct tun_struct __rcu *tun; | 149 | struct tun_struct __rcu *tun; |
149 | struct net *net; | ||
150 | struct fasync_struct *fasync; | 150 | struct fasync_struct *fasync; |
151 | /* only used for fasnyc */ | 151 | /* only used for fasnyc */ |
152 | unsigned int flags; | 152 | unsigned int flags; |
@@ -206,14 +206,68 @@ struct tun_struct { | |||
206 | u32 flow_count; | 206 | u32 flow_count; |
207 | }; | 207 | }; |
208 | 208 | ||
209 | #ifdef CONFIG_TUN_VNET_CROSS_LE | ||
210 | static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) | ||
211 | { | ||
212 | return tun->flags & TUN_VNET_BE ? false : | ||
213 | virtio_legacy_is_little_endian(); | ||
214 | } | ||
215 | |||
216 | static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) | ||
217 | { | ||
218 | int be = !!(tun->flags & TUN_VNET_BE); | ||
219 | |||
220 | if (put_user(be, argp)) | ||
221 | return -EFAULT; | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) | ||
227 | { | ||
228 | int be; | ||
229 | |||
230 | if (get_user(be, argp)) | ||
231 | return -EFAULT; | ||
232 | |||
233 | if (be) | ||
234 | tun->flags |= TUN_VNET_BE; | ||
235 | else | ||
236 | tun->flags &= ~TUN_VNET_BE; | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | #else | ||
241 | static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) | ||
242 | { | ||
243 | return virtio_legacy_is_little_endian(); | ||
244 | } | ||
245 | |||
246 | static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) | ||
247 | { | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | |||
251 | static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) | ||
252 | { | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | #endif /* CONFIG_TUN_VNET_CROSS_LE */ | ||
256 | |||
257 | static inline bool tun_is_little_endian(struct tun_struct *tun) | ||
258 | { | ||
259 | return tun->flags & TUN_VNET_LE || | ||
260 | tun_legacy_is_little_endian(tun); | ||
261 | } | ||
262 | |||
209 | static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) | 263 | static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) |
210 | { | 264 | { |
211 | return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val); | 265 | return __virtio16_to_cpu(tun_is_little_endian(tun), val); |
212 | } | 266 | } |
213 | 267 | ||
214 | static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) | 268 | static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) |
215 | { | 269 | { |
216 | return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val); | 270 | return __cpu_to_virtio16(tun_is_little_endian(tun), val); |
217 | } | 271 | } |
218 | 272 | ||
219 | static inline u32 tun_hashfn(u32 rxhash) | 273 | static inline u32 tun_hashfn(u32 rxhash) |
@@ -493,10 +547,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
493 | tun->dev->reg_state == NETREG_REGISTERED) | 547 | tun->dev->reg_state == NETREG_REGISTERED) |
494 | unregister_netdevice(tun->dev); | 548 | unregister_netdevice(tun->dev); |
495 | } | 549 | } |
496 | 550 | sock_put(&tfile->sk); | |
497 | BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED, | ||
498 | &tfile->socket.flags)); | ||
499 | sk_release_kernel(&tfile->sk); | ||
500 | } | 551 | } |
501 | } | 552 | } |
502 | 553 | ||
@@ -1492,18 +1543,10 @@ out: | |||
1492 | return ret; | 1543 | return ret; |
1493 | } | 1544 | } |
1494 | 1545 | ||
1495 | static int tun_release(struct socket *sock) | ||
1496 | { | ||
1497 | if (sock->sk) | ||
1498 | sock_put(sock->sk); | ||
1499 | return 0; | ||
1500 | } | ||
1501 | |||
1502 | /* Ops structure to mimic raw sockets with tun */ | 1546 | /* Ops structure to mimic raw sockets with tun */ |
1503 | static const struct proto_ops tun_socket_ops = { | 1547 | static const struct proto_ops tun_socket_ops = { |
1504 | .sendmsg = tun_sendmsg, | 1548 | .sendmsg = tun_sendmsg, |
1505 | .recvmsg = tun_recvmsg, | 1549 | .recvmsg = tun_recvmsg, |
1506 | .release = tun_release, | ||
1507 | }; | 1550 | }; |
1508 | 1551 | ||
1509 | static struct proto tun_proto = { | 1552 | static struct proto tun_proto = { |
@@ -1865,7 +1908,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1865 | if (cmd == TUNSETIFF && !tun) { | 1908 | if (cmd == TUNSETIFF && !tun) { |
1866 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; | 1909 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; |
1867 | 1910 | ||
1868 | ret = tun_set_iff(tfile->net, file, &ifr); | 1911 | ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr); |
1869 | 1912 | ||
1870 | if (ret) | 1913 | if (ret) |
1871 | goto unlock; | 1914 | goto unlock; |
@@ -2056,6 +2099,14 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
2056 | tun->flags &= ~TUN_VNET_LE; | 2099 | tun->flags &= ~TUN_VNET_LE; |
2057 | break; | 2100 | break; |
2058 | 2101 | ||
2102 | case TUNGETVNETBE: | ||
2103 | ret = tun_get_vnet_be(tun, argp); | ||
2104 | break; | ||
2105 | |||
2106 | case TUNSETVNETBE: | ||
2107 | ret = tun_set_vnet_be(tun, argp); | ||
2108 | break; | ||
2109 | |||
2059 | case TUNATTACHFILTER: | 2110 | case TUNATTACHFILTER: |
2060 | /* Can be set only for TAPs */ | 2111 | /* Can be set only for TAPs */ |
2061 | ret = -EINVAL; | 2112 | ret = -EINVAL; |
@@ -2154,16 +2205,16 @@ out: | |||
2154 | 2205 | ||
2155 | static int tun_chr_open(struct inode *inode, struct file * file) | 2206 | static int tun_chr_open(struct inode *inode, struct file * file) |
2156 | { | 2207 | { |
2208 | struct net *net = current->nsproxy->net_ns; | ||
2157 | struct tun_file *tfile; | 2209 | struct tun_file *tfile; |
2158 | 2210 | ||
2159 | DBG1(KERN_INFO, "tunX: tun_chr_open\n"); | 2211 | DBG1(KERN_INFO, "tunX: tun_chr_open\n"); |
2160 | 2212 | ||
2161 | tfile = (struct tun_file *)sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, | 2213 | tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, |
2162 | &tun_proto); | 2214 | &tun_proto, 0); |
2163 | if (!tfile) | 2215 | if (!tfile) |
2164 | return -ENOMEM; | 2216 | return -ENOMEM; |
2165 | RCU_INIT_POINTER(tfile->tun, NULL); | 2217 | RCU_INIT_POINTER(tfile->tun, NULL); |
2166 | tfile->net = get_net(current->nsproxy->net_ns); | ||
2167 | tfile->flags = 0; | 2218 | tfile->flags = 0; |
2168 | tfile->ifindex = 0; | 2219 | tfile->ifindex = 0; |
2169 | 2220 | ||
@@ -2174,13 +2225,11 @@ static int tun_chr_open(struct inode *inode, struct file * file) | |||
2174 | tfile->socket.ops = &tun_socket_ops; | 2225 | tfile->socket.ops = &tun_socket_ops; |
2175 | 2226 | ||
2176 | sock_init_data(&tfile->socket, &tfile->sk); | 2227 | sock_init_data(&tfile->socket, &tfile->sk); |
2177 | sk_change_net(&tfile->sk, tfile->net); | ||
2178 | 2228 | ||
2179 | tfile->sk.sk_write_space = tun_sock_write_space; | 2229 | tfile->sk.sk_write_space = tun_sock_write_space; |
2180 | tfile->sk.sk_sndbuf = INT_MAX; | 2230 | tfile->sk.sk_sndbuf = INT_MAX; |
2181 | 2231 | ||
2182 | file->private_data = tfile; | 2232 | file->private_data = tfile; |
2183 | set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags); | ||
2184 | INIT_LIST_HEAD(&tfile->next); | 2233 | INIT_LIST_HEAD(&tfile->next); |
2185 | 2234 | ||
2186 | sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); | 2235 | sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); |
@@ -2191,10 +2240,8 @@ static int tun_chr_open(struct inode *inode, struct file * file) | |||
2191 | static int tun_chr_close(struct inode *inode, struct file *file) | 2240 | static int tun_chr_close(struct inode *inode, struct file *file) |
2192 | { | 2241 | { |
2193 | struct tun_file *tfile = file->private_data; | 2242 | struct tun_file *tfile = file->private_data; |
2194 | struct net *net = tfile->net; | ||
2195 | 2243 | ||
2196 | tun_detach(tfile, true); | 2244 | tun_detach(tfile, true); |
2197 | put_net(net); | ||
2198 | 2245 | ||
2199 | return 0; | 2246 | return 0; |
2200 | } | 2247 | } |