diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4fdfa2ae5418..01e99f22210e 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> |
@@ -1110,8 +1110,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) | |||
1110 | return 0; | 1110 | return 0; |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | static long tun_chr_ioctl(struct file *file, unsigned int cmd, | 1113 | static long __tun_chr_ioctl(struct file *file, unsigned int cmd, |
1114 | unsigned long arg) | 1114 | unsigned long arg, int ifreq_len) |
1115 | { | 1115 | { |
1116 | struct tun_file *tfile = file->private_data; | 1116 | struct tun_file *tfile = file->private_data; |
1117 | struct tun_struct *tun; | 1117 | struct tun_struct *tun; |
@@ -1121,7 +1121,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1121 | int ret; | 1121 | int ret; |
1122 | 1122 | ||
1123 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) | 1123 | if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) |
1124 | if (copy_from_user(&ifr, argp, sizeof ifr)) | 1124 | if (copy_from_user(&ifr, argp, ifreq_len)) |
1125 | return -EFAULT; | 1125 | return -EFAULT; |
1126 | 1126 | ||
1127 | if (cmd == TUNGETFEATURES) { | 1127 | if (cmd == TUNGETFEATURES) { |
@@ -1144,7 +1144,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1144 | if (ret) | 1144 | if (ret) |
1145 | goto unlock; | 1145 | goto unlock; |
1146 | 1146 | ||
1147 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 1147 | if (copy_to_user(argp, &ifr, ifreq_len)) |
1148 | ret = -EFAULT; | 1148 | ret = -EFAULT; |
1149 | goto unlock; | 1149 | goto unlock; |
1150 | } | 1150 | } |
@@ -1162,7 +1162,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1162 | if (ret) | 1162 | if (ret) |
1163 | break; | 1163 | break; |
1164 | 1164 | ||
1165 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 1165 | if (copy_to_user(argp, &ifr, ifreq_len)) |
1166 | ret = -EFAULT; | 1166 | ret = -EFAULT; |
1167 | break; | 1167 | break; |
1168 | 1168 | ||
@@ -1236,7 +1236,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1236 | /* Get hw addres */ | 1236 | /* Get hw addres */ |
1237 | memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); | 1237 | memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); |
1238 | ifr.ifr_hwaddr.sa_family = tun->dev->type; | 1238 | ifr.ifr_hwaddr.sa_family = tun->dev->type; |
1239 | if (copy_to_user(argp, &ifr, sizeof ifr)) | 1239 | if (copy_to_user(argp, &ifr, ifreq_len)) |
1240 | ret = -EFAULT; | 1240 | ret = -EFAULT; |
1241 | break; | 1241 | break; |
1242 | 1242 | ||
@@ -1275,6 +1275,41 @@ unlock: | |||
1275 | return ret; | 1275 | return ret; |
1276 | } | 1276 | } |
1277 | 1277 | ||
1278 | static long tun_chr_ioctl(struct file *file, | ||
1279 | unsigned int cmd, unsigned long arg) | ||
1280 | { | ||
1281 | return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq)); | ||
1282 | } | ||
1283 | |||
1284 | #ifdef CONFIG_COMPAT | ||
1285 | static long tun_chr_compat_ioctl(struct file *file, | ||
1286 | unsigned int cmd, unsigned long arg) | ||
1287 | { | ||
1288 | switch (cmd) { | ||
1289 | case TUNSETIFF: | ||
1290 | case TUNGETIFF: | ||
1291 | case TUNSETTXFILTER: | ||
1292 | case TUNGETSNDBUF: | ||
1293 | case TUNSETSNDBUF: | ||
1294 | case SIOCGIFHWADDR: | ||
1295 | case SIOCSIFHWADDR: | ||
1296 | arg = (unsigned long)compat_ptr(arg); | ||
1297 | break; | ||
1298 | default: | ||
1299 | arg = (compat_ulong_t)arg; | ||
1300 | break; | ||
1301 | } | ||
1302 | |||
1303 | /* | ||
1304 | * compat_ifreq is shorter than ifreq, so we must not access beyond | ||
1305 | * the end of that structure. All fields that are used in this | ||
1306 | * driver are compatible though, we don't need to convert the | ||
1307 | * contents. | ||
1308 | */ | ||
1309 | return __tun_chr_ioctl(file, cmd, arg, sizeof(struct compat_ifreq)); | ||
1310 | } | ||
1311 | #endif /* CONFIG_COMPAT */ | ||
1312 | |||
1278 | static int tun_chr_fasync(int fd, struct file *file, int on) | 1313 | static int tun_chr_fasync(int fd, struct file *file, int on) |
1279 | { | 1314 | { |
1280 | struct tun_struct *tun = tun_get(file); | 1315 | struct tun_struct *tun = tun_get(file); |
@@ -1285,7 +1320,6 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
1285 | 1320 | ||
1286 | DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on); | 1321 | DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on); |
1287 | 1322 | ||
1288 | lock_kernel(); | ||
1289 | if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) | 1323 | if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) |
1290 | goto out; | 1324 | goto out; |
1291 | 1325 | ||
@@ -1298,7 +1332,6 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
1298 | tun->flags &= ~TUN_FASYNC; | 1332 | tun->flags &= ~TUN_FASYNC; |
1299 | ret = 0; | 1333 | ret = 0; |
1300 | out: | 1334 | out: |
1301 | unlock_kernel(); | ||
1302 | tun_put(tun); | 1335 | tun_put(tun); |
1303 | return ret; | 1336 | return ret; |
1304 | } | 1337 | } |
@@ -1306,7 +1339,7 @@ out: | |||
1306 | static int tun_chr_open(struct inode *inode, struct file * file) | 1339 | static int tun_chr_open(struct inode *inode, struct file * file) |
1307 | { | 1340 | { |
1308 | struct tun_file *tfile; | 1341 | struct tun_file *tfile; |
1309 | cycle_kernel_lock(); | 1342 | |
1310 | DBG1(KERN_INFO "tunX: tun_chr_open\n"); | 1343 | DBG1(KERN_INFO "tunX: tun_chr_open\n"); |
1311 | 1344 | ||
1312 | tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); | 1345 | tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); |
@@ -1359,7 +1392,10 @@ static const struct file_operations tun_fops = { | |||
1359 | .write = do_sync_write, | 1392 | .write = do_sync_write, |
1360 | .aio_write = tun_chr_aio_write, | 1393 | .aio_write = tun_chr_aio_write, |
1361 | .poll = tun_chr_poll, | 1394 | .poll = tun_chr_poll, |
1362 | .unlocked_ioctl = tun_chr_ioctl, | 1395 | .unlocked_ioctl = tun_chr_ioctl, |
1396 | #ifdef CONFIG_COMPAT | ||
1397 | .compat_ioctl = tun_chr_compat_ioctl, | ||
1398 | #endif | ||
1363 | .open = tun_chr_open, | 1399 | .open = tun_chr_open, |
1364 | .release = tun_chr_close, | 1400 | .release = tun_chr_close, |
1365 | .fasync = tun_chr_fasync | 1401 | .fasync = tun_chr_fasync |