diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/tun.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 197 |
1 files changed, 163 insertions, 34 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4fdfa2ae5418..43265207d463 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -44,7 +44,6 @@ | |||
44 | #include <linux/kernel.h> | 44 | #include <linux/kernel.h> |
45 | #include <linux/major.h> | 45 | #include <linux/major.h> |
46 | #include <linux/slab.h> | 46 | #include <linux/slab.h> |
47 | #include <linux/smp_lock.h> | ||
48 | #include <linux/poll.h> | 47 | #include <linux/poll.h> |
49 | #include <linux/fcntl.h> | 48 | #include <linux/fcntl.h> |
50 | #include <linux/init.h> | 49 | #include <linux/init.h> |
@@ -54,6 +53,7 @@ | |||
54 | #include <linux/miscdevice.h> | 53 | #include <linux/miscdevice.h> |
55 | #include <linux/ethtool.h> | 54 | #include <linux/ethtool.h> |
56 | #include <linux/rtnetlink.h> | 55 | #include <linux/rtnetlink.h> |
56 | #include <linux/compat.h> | ||
57 | #include <linux/if.h> | 57 | #include <linux/if.h> |
58 | #include <linux/if_arp.h> | 58 | #include <linux/if_arp.h> |
59 | #include <linux/if_ether.h> | 59 | #include <linux/if_ether.h> |
@@ -61,6 +61,7 @@ | |||
61 | #include <linux/crc32.h> | 61 | #include <linux/crc32.h> |
62 | #include <linux/nsproxy.h> | 62 | #include <linux/nsproxy.h> |
63 | #include <linux/virtio_net.h> | 63 | #include <linux/virtio_net.h> |
64 | #include <linux/rcupdate.h> | ||
64 | #include <net/net_namespace.h> | 65 | #include <net/net_namespace.h> |
65 | #include <net/netns/generic.h> | 66 | #include <net/netns/generic.h> |
66 | #include <net/rtnetlink.h> | 67 | #include <net/rtnetlink.h> |
@@ -144,6 +145,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
144 | err = 0; | 145 | err = 0; |
145 | tfile->tun = tun; | 146 | tfile->tun = tun; |
146 | tun->tfile = tfile; | 147 | tun->tfile = tfile; |
148 | tun->socket.file = file; | ||
147 | dev_hold(tun->dev); | 149 | dev_hold(tun->dev); |
148 | sock_hold(tun->socket.sk); | 150 | sock_hold(tun->socket.sk); |
149 | atomic_inc(&tfile->count); | 151 | atomic_inc(&tfile->count); |
@@ -158,6 +160,7 @@ static void __tun_detach(struct tun_struct *tun) | |||
158 | /* Detach from net device */ | 160 | /* Detach from net device */ |
159 | netif_tx_lock_bh(tun->dev); | 161 | netif_tx_lock_bh(tun->dev); |
160 | tun->tfile = NULL; | 162 | tun->tfile = NULL; |
163 | tun->socket.file = NULL; | ||
161 | netif_tx_unlock_bh(tun->dev); | 164 | netif_tx_unlock_bh(tun->dev); |
162 | 165 | ||
163 | /* Drop read queue */ | 166 | /* Drop read queue */ |
@@ -364,6 +367,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
364 | if (!check_filter(&tun->txflt, skb)) | 367 | if (!check_filter(&tun->txflt, skb)) |
365 | goto drop; | 368 | goto drop; |
366 | 369 | ||
370 | if (tun->socket.sk->sk_filter && | ||
371 | sk_filter(tun->socket.sk, skb)) | ||
372 | goto drop; | ||
373 | |||
367 | if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) { | 374 | if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) { |
368 | if (!(tun->flags & TUN_ONE_QUEUE)) { | 375 | if (!(tun->flags & TUN_ONE_QUEUE)) { |
369 | /* Normal queueing mode. */ | 376 | /* Normal queueing mode. */ |
@@ -380,6 +387,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
380 | } | 387 | } |
381 | } | 388 | } |
382 | 389 | ||
390 | /* Orphan the skb - required as we might hang on to it | ||
391 | * for indefinite time. */ | ||
392 | skb_orphan(skb); | ||
393 | |||
383 | /* Enqueue packet */ | 394 | /* Enqueue packet */ |
384 | skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); | 395 | skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); |
385 | dev->trans_start = jiffies; | 396 | dev->trans_start = jiffies; |
@@ -387,7 +398,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | |||
387 | /* Notify and wake up reader process */ | 398 | /* Notify and wake up reader process */ |
388 | if (tun->flags & TUN_FASYNC) | 399 | if (tun->flags & TUN_FASYNC) |
389 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); | 400 | kill_fasync(&tun->fasync, SIGIO, POLL_IN); |
390 | wake_up_interruptible(&tun->socket.wait); | 401 | wake_up_interruptible_poll(&tun->socket.wait, POLLIN | |
402 | POLLRDNORM | POLLRDBAND); | ||
391 | return NETDEV_TX_OK; | 403 | return NETDEV_TX_OK; |
392 | 404 | ||
393 | drop: | 405 | drop: |
@@ -743,7 +755,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
743 | len = min_t(int, skb->len, len); | 755 | len = min_t(int, skb->len, len); |
744 | 756 | ||
745 | skb_copy_datagram_const_iovec(skb, 0, iv, total, len); | 757 | skb_copy_datagram_const_iovec(skb, 0, iv, total, len); |
746 | total += len; | 758 | total += skb->len; |
747 | 759 | ||
748 | tun->dev->stats.tx_packets++; | 760 | tun->dev->stats.tx_packets++; |
749 | tun->dev->stats.tx_bytes += len; | 761 | tun->dev->stats.tx_bytes += len; |
@@ -751,34 +763,23 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
751 | return total; | 763 | return total; |
752 | } | 764 | } |
753 | 765 | ||
754 | static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | 766 | static ssize_t tun_do_read(struct tun_struct *tun, |
755 | unsigned long count, loff_t pos) | 767 | struct kiocb *iocb, const struct iovec *iv, |
768 | ssize_t len, int noblock) | ||
756 | { | 769 | { |
757 | struct file *file = iocb->ki_filp; | ||
758 | struct tun_file *tfile = file->private_data; | ||
759 | struct tun_struct *tun = __tun_get(tfile); | ||
760 | DECLARE_WAITQUEUE(wait, current); | 770 | DECLARE_WAITQUEUE(wait, current); |
761 | struct sk_buff *skb; | 771 | struct sk_buff *skb; |
762 | ssize_t len, ret = 0; | 772 | ssize_t ret = 0; |
763 | |||
764 | if (!tun) | ||
765 | return -EBADFD; | ||
766 | 773 | ||
767 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); | 774 | DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); |
768 | 775 | ||
769 | len = iov_length(iv, count); | ||
770 | if (len < 0) { | ||
771 | ret = -EINVAL; | ||
772 | goto out; | ||
773 | } | ||
774 | |||
775 | add_wait_queue(&tun->socket.wait, &wait); | 776 | add_wait_queue(&tun->socket.wait, &wait); |
776 | while (len) { | 777 | while (len) { |
777 | current->state = TASK_INTERRUPTIBLE; | 778 | current->state = TASK_INTERRUPTIBLE; |
778 | 779 | ||
779 | /* Read frames from the queue */ | 780 | /* Read frames from the queue */ |
780 | if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) { | 781 | if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) { |
781 | if (file->f_flags & O_NONBLOCK) { | 782 | if (noblock) { |
782 | ret = -EAGAIN; | 783 | ret = -EAGAIN; |
783 | break; | 784 | break; |
784 | } | 785 | } |
@@ -805,6 +806,27 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
805 | current->state = TASK_RUNNING; | 806 | current->state = TASK_RUNNING; |
806 | remove_wait_queue(&tun->socket.wait, &wait); | 807 | remove_wait_queue(&tun->socket.wait, &wait); |
807 | 808 | ||
809 | return ret; | ||
810 | } | ||
811 | |||
812 | static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | ||
813 | unsigned long count, loff_t pos) | ||
814 | { | ||
815 | struct file *file = iocb->ki_filp; | ||
816 | struct tun_file *tfile = file->private_data; | ||
817 | struct tun_struct *tun = __tun_get(tfile); | ||
818 | ssize_t len, ret; | ||
819 | |||
820 | if (!tun) | ||
821 | return -EBADFD; | ||
822 | len = iov_length(iv, count); | ||
823 | if (len < 0) { | ||
824 | ret = -EINVAL; | ||
825 | goto out; | ||
826 | } | ||
827 | |||
828 | ret = tun_do_read(tun, iocb, iv, len, file->f_flags & O_NONBLOCK); | ||
829 | ret = min_t(ssize_t, ret, len); | ||
808 | out: | 830 | out: |
809 | tun_put(tun); | 831 | tun_put(tun); |
810 | return ret; | 832 | return ret; |
@@ -847,17 +869,49 @@ static void tun_sock_write_space(struct sock *sk) | |||
847 | return; | 869 | return; |
848 | 870 | ||
849 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | 871 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) |
850 | wake_up_interruptible_sync(sk->sk_sleep); | 872 | wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT | |
873 | POLLWRNORM | POLLWRBAND); | ||
851 | 874 | ||
852 | tun = container_of(sk, struct tun_sock, sk)->tun; | 875 | tun = tun_sk(sk)->tun; |
853 | kill_fasync(&tun->fasync, SIGIO, POLL_OUT); | 876 | kill_fasync(&tun->fasync, SIGIO, POLL_OUT); |
854 | } | 877 | } |
855 | 878 | ||
856 | static void tun_sock_destruct(struct sock *sk) | 879 | static void tun_sock_destruct(struct sock *sk) |
857 | { | 880 | { |
858 | free_netdev(container_of(sk, struct tun_sock, sk)->tun->dev); | 881 | free_netdev(tun_sk(sk)->tun->dev); |
882 | } | ||
883 | |||
884 | static int tun_sendmsg(struct kiocb *iocb, struct socket *sock, | ||
885 | struct msghdr *m, size_t total_len) | ||
886 | { | ||
887 | struct tun_struct *tun = container_of(sock, struct tun_struct, socket); | ||
888 | return tun_get_user(tun, m->msg_iov, total_len, | ||
889 | m->msg_flags & MSG_DONTWAIT); | ||
890 | } | ||
891 | |||
892 | static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
893 | struct msghdr *m, size_t total_len, | ||
894 | int flags) | ||
895 | { | ||
896 | struct tun_struct *tun = container_of(sock, struct tun_struct, socket); | ||
897 | int ret; | ||
898 | if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) | ||
899 | return -EINVAL; | ||
900 | ret = tun_do_read(tun, iocb, m->msg_iov, total_len, | ||
901 | flags & MSG_DONTWAIT); | ||
902 | if (ret > total_len) { | ||
903 | m->msg_flags |= MSG_TRUNC; | ||
904 | ret = flags & MSG_TRUNC ? ret : total_len; | ||
905 | } | ||
906 | return ret; | ||
859 | } | 907 | } |
860 | 908 | ||
909 | /* Ops structure to mimic raw sockets with tun */ | ||
910 | static const struct proto_ops tun_socket_ops = { | ||
911 | .sendmsg = tun_sendmsg, | ||
912 | .recvmsg = tun_recvmsg, | ||
913 | }; | ||
914 | |||
861 | static struct proto tun_proto = { | 915 | static struct proto tun_proto = { |
862 | .name = "tun", | 916 | .name = "tun", |
863 | .owner = THIS_MODULE, | 917 | .owner = THIS_MODULE, |
@@ -986,11 +1040,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
986 | goto err_free_dev; | 1040 | goto err_free_dev; |
987 | 1041 | ||
988 | init_waitqueue_head(&tun->socket.wait); | 1042 | init_waitqueue_head(&tun->socket.wait); |
1043 | tun->socket.ops = &tun_socket_ops; | ||
989 | sock_init_data(&tun->socket, sk); | 1044 | sock_init_data(&tun->socket, sk); |
990 | sk->sk_write_space = tun_sock_write_space; | 1045 | sk->sk_write_space = tun_sock_write_space; |
991 | sk->sk_sndbuf = INT_MAX; | 1046 | sk->sk_sndbuf = INT_MAX; |
992 | 1047 | ||
993 | container_of(sk, struct tun_sock, sk)->tun = tun; | 1048 | tun_sk(sk)->tun = tun; |
994 | 1049 | ||
995 | security_tun_dev_post_create(sk); | 1050 | security_tun_dev_post_create(sk); |
996 | 1051 | ||
@@ -1110,18 +1165,19 @@ static int set_offload(struct net_device *dev, unsigned long arg) | |||
1110 | return 0; | 1165 | return 0; |
1111 | } | 1166 | } |
1112 | 1167 | ||
1113 | static long tun_chr_ioctl(struct file *file, unsigned int cmd, | 1168 | static long __tun_chr_ioctl(struct file *file, unsigned int cmd, |
1114 | unsigned long arg) | 1169 | unsigned long arg, int ifreq_len) |
1115 | { | 1170 | { |
1116 | struct tun_file *tfile = file->private_data; | 1171 | struct tun_file *tfile = file->private_data; |
1117 | struct tun_struct *tun; | 1172 | struct tun_struct *tun; |
1118 | void __user* argp = (void __user*)arg; | 1173 | void __user* argp = (void __user*)arg; |
1174 | struct sock_fprog fprog; | ||
1119 | struct ifreq ifr; | 1175 | struct ifreq ifr; |
1120 | int sndbuf; | 1176 | int sndbuf; |
1121 | int ret; | 1177 | int ret; |
1122 | 1178 | ||
1123 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) | 1179 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) |
1124 | if (copy_from_user(&ifr, argp, sizeof ifr)) | 1180 | if (copy_from_user(&ifr, argp, ifreq_len)) |
1125 | return -EFAULT; | 1181 | return -EFAULT; |
1126 | 1182 | ||
1127 | if (cmd == TUNGETFEATURES) { | 1183 | if (cmd == TUNGETFEATURES) { |
@@ -1144,7 +1200,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1144 | if (ret) | 1200 | if (ret) |
1145 | goto unlock; | 1201 | goto unlock; |
1146 | 1202 | ||
1147 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 1203 | if (copy_to_user(argp, &ifr, ifreq_len)) |
1148 | ret = -EFAULT; | 1204 | ret = -EFAULT; |
1149 | goto unlock; | 1205 | goto unlock; |
1150 | } | 1206 | } |
@@ -1162,7 +1218,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1162 | if (ret) | 1218 | if (ret) |
1163 | break; | 1219 | break; |
1164 | 1220 | ||
1165 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 1221 | if (copy_to_user(argp, &ifr, ifreq_len)) |
1166 | ret = -EFAULT; | 1222 | ret = -EFAULT; |
1167 | break; | 1223 | break; |
1168 | 1224 | ||
@@ -1236,7 +1292,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1236 | /* Get hw addres */ | 1292 | /* Get hw addres */ |
1237 | memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); | 1293 | memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); |
1238 | ifr.ifr_hwaddr.sa_family = tun->dev->type; | 1294 | ifr.ifr_hwaddr.sa_family = tun->dev->type; |
1239 | if (copy_to_user(argp, &ifr, sizeof ifr)) | 1295 | if (copy_to_user(argp, &ifr, ifreq_len)) |
1240 | ret = -EFAULT; | 1296 | ret = -EFAULT; |
1241 | break; | 1297 | break; |
1242 | 1298 | ||
@@ -1263,6 +1319,26 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1263 | tun->socket.sk->sk_sndbuf = sndbuf; | 1319 | tun->socket.sk->sk_sndbuf = sndbuf; |
1264 | break; | 1320 | break; |
1265 | 1321 | ||
1322 | case TUNATTACHFILTER: | ||
1323 | /* Can be set only for TAPs */ | ||
1324 | ret = -EINVAL; | ||
1325 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) | ||
1326 | break; | ||
1327 | ret = -EFAULT; | ||
1328 | if (copy_from_user(&fprog, argp, sizeof(fprog))) | ||
1329 | break; | ||
1330 | |||
1331 | ret = sk_attach_filter(&fprog, tun->socket.sk); | ||
1332 | break; | ||
1333 | |||
1334 | case TUNDETACHFILTER: | ||
1335 | /* Can be set only for TAPs */ | ||
1336 | ret = -EINVAL; | ||
1337 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) | ||
1338 | break; | ||
1339 | ret = sk_detach_filter(tun->socket.sk); | ||
1340 | break; | ||
1341 | |||
1266 | default: | 1342 | default: |
1267 | ret = -EINVAL; | 1343 | ret = -EINVAL; |
1268 | break; | 1344 | break; |
@@ -1275,6 +1351,41 @@ unlock: | |||
1275 | return ret; | 1351 | return ret; |
1276 | } | 1352 | } |
1277 | 1353 | ||
1354 | static long tun_chr_ioctl(struct file *file, | ||
1355 | unsigned int cmd, unsigned long arg) | ||
1356 | { | ||
1357 | return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq)); | ||
1358 | } | ||
1359 | |||
1360 | #ifdef CONFIG_COMPAT | ||
1361 | static long tun_chr_compat_ioctl(struct file *file, | ||
1362 | unsigned int cmd, unsigned long arg) | ||
1363 | { | ||
1364 | switch (cmd) { | ||
1365 | case TUNSETIFF: | ||
1366 | case TUNGETIFF: | ||
1367 | case TUNSETTXFILTER: | ||
1368 | case TUNGETSNDBUF: | ||
1369 | case TUNSETSNDBUF: | ||
1370 | case SIOCGIFHWADDR: | ||
1371 | case SIOCSIFHWADDR: | ||
1372 | arg = (unsigned long)compat_ptr(arg); | ||
1373 | break; | ||
1374 | default: | ||
1375 | arg = (compat_ulong_t)arg; | ||
1376 | break; | ||
1377 | } | ||
1378 | |||
1379 | /* | ||
1380 | * compat_ifreq is shorter than ifreq, so we must not access beyond | ||
1381 | * the end of that structure. All fields that are used in this | ||
1382 | * driver are compatible though, we don't need to convert the | ||
1383 | * contents. | ||
1384 | */ | ||
1385 | return __tun_chr_ioctl(file, cmd, arg, sizeof(struct compat_ifreq)); | ||
1386 | } | ||
1387 | #endif /* CONFIG_COMPAT */ | ||
1388 | |||
1278 | static int tun_chr_fasync(int fd, struct file *file, int on) | 1389 | static int tun_chr_fasync(int fd, struct file *file, int on) |
1279 | { | 1390 | { |
1280 | struct tun_struct *tun = tun_get(file); | 1391 | struct tun_struct *tun = tun_get(file); |
@@ -1285,7 +1396,6 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
1285 | 1396 | ||
1286 | DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on); | 1397 | DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on); |
1287 | 1398 | ||
1288 | lock_kernel(); | ||
1289 | if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) | 1399 | if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) |
1290 | goto out; | 1400 | goto out; |
1291 | 1401 | ||
@@ -1298,7 +1408,6 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
1298 | tun->flags &= ~TUN_FASYNC; | 1408 | tun->flags &= ~TUN_FASYNC; |
1299 | ret = 0; | 1409 | ret = 0; |
1300 | out: | 1410 | out: |
1301 | unlock_kernel(); | ||
1302 | tun_put(tun); | 1411 | tun_put(tun); |
1303 | return ret; | 1412 | return ret; |
1304 | } | 1413 | } |
@@ -1306,7 +1415,7 @@ out: | |||
1306 | static int tun_chr_open(struct inode *inode, struct file * file) | 1415 | static int tun_chr_open(struct inode *inode, struct file * file) |
1307 | { | 1416 | { |
1308 | struct tun_file *tfile; | 1417 | struct tun_file *tfile; |
1309 | cycle_kernel_lock(); | 1418 | |
1310 | DBG1(KERN_INFO "tunX: tun_chr_open\n"); | 1419 | DBG1(KERN_INFO "tunX: tun_chr_open\n"); |
1311 | 1420 | ||
1312 | tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); | 1421 | tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); |
@@ -1332,7 +1441,7 @@ static int tun_chr_close(struct inode *inode, struct file *file) | |||
1332 | 1441 | ||
1333 | __tun_detach(tun); | 1442 | __tun_detach(tun); |
1334 | 1443 | ||
1335 | /* If desireable, unregister the netdevice. */ | 1444 | /* If desirable, unregister the netdevice. */ |
1336 | if (!(tun->flags & TUN_PERSIST)) { | 1445 | if (!(tun->flags & TUN_PERSIST)) { |
1337 | rtnl_lock(); | 1446 | rtnl_lock(); |
1338 | if (dev->reg_state == NETREG_REGISTERED) | 1447 | if (dev->reg_state == NETREG_REGISTERED) |
@@ -1359,7 +1468,10 @@ static const struct file_operations tun_fops = { | |||
1359 | .write = do_sync_write, | 1468 | .write = do_sync_write, |
1360 | .aio_write = tun_chr_aio_write, | 1469 | .aio_write = tun_chr_aio_write, |
1361 | .poll = tun_chr_poll, | 1470 | .poll = tun_chr_poll, |
1362 | .unlocked_ioctl = tun_chr_ioctl, | 1471 | .unlocked_ioctl = tun_chr_ioctl, |
1472 | #ifdef CONFIG_COMPAT | ||
1473 | .compat_ioctl = tun_chr_compat_ioctl, | ||
1474 | #endif | ||
1363 | .open = tun_chr_open, | 1475 | .open = tun_chr_open, |
1364 | .release = tun_chr_close, | 1476 | .release = tun_chr_close, |
1365 | .fasync = tun_chr_fasync | 1477 | .fasync = tun_chr_fasync |
@@ -1489,6 +1601,23 @@ static void tun_cleanup(void) | |||
1489 | rtnl_link_unregister(&tun_link_ops); | 1601 | rtnl_link_unregister(&tun_link_ops); |
1490 | } | 1602 | } |
1491 | 1603 | ||
1604 | /* Get an underlying socket object from tun file. Returns error unless file is | ||
1605 | * attached to a device. The returned object works like a packet socket, it | ||
1606 | * can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for | ||
1607 | * holding a reference to the file for as long as the socket is in use. */ | ||
1608 | struct socket *tun_get_socket(struct file *file) | ||
1609 | { | ||
1610 | struct tun_struct *tun; | ||
1611 | if (file->f_op != &tun_fops) | ||
1612 | return ERR_PTR(-EINVAL); | ||
1613 | tun = tun_get(file); | ||
1614 | if (!tun) | ||
1615 | return ERR_PTR(-EBADFD); | ||
1616 | tun_put(tun); | ||
1617 | return &tun->socket; | ||
1618 | } | ||
1619 | EXPORT_SYMBOL_GPL(tun_get_socket); | ||
1620 | |||
1492 | module_init(tun_init); | 1621 | module_init(tun_init); |
1493 | module_exit(tun_cleanup); | 1622 | module_exit(tun_cleanup); |
1494 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | 1623 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |