diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-12-03 22:12:38 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-03 22:12:38 -0800 |
commit | 8865c418caf4e9dd2c24bdfae3a5a4106e143e60 (patch) | |
tree | 4d7fac2c74af56c6aaf83b324b349b76c5f949d9 /net/atm/resources.c | |
parent | dcd39c90290297f6e6ed8a04bb20da7ac2b043c5 (diff) | |
download | linux-3.10-8865c418caf4e9dd2c24bdfae3a5a4106e143e60.tar.gz linux-3.10-8865c418caf4e9dd2c24bdfae3a5a4106e143e60.tar.bz2 linux-3.10-8865c418caf4e9dd2c24bdfae3a5a4106e143e60.zip |
atm: 32-bit ioctl compatibility
We lack compat ioctl support through most of the ATM code. This patch
deals with most of it, and I can now at least use BR2684 and PPPoATM
with 32-bit userspace.
I haven't added a .compat_ioctl method to struct atm_ioctl, because
AFAICT none of the current users need any conversion -- so we can just
call the ->ioctl() method in every case. I looked at br2684, clip, lec,
mpc, pppoatm and atmtcp.
In svc_compat_ioctl() the only mangling which is needed is to change
COMPAT_ATM_ADDPARTY to ATM_ADDPARTY. Although it's defined as
_IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf)
it doesn't actually _take_ a struct atm_iobuf as an argument -- it takes
a struct sockaddr_atmsvc, which _is_ the same between 32-bit and 64-bit
code, so doesn't need conversion.
Almost all of vcc_ioctl() would have been identical, so I converted that
into a core do_vcc_ioctl() function with an 'int compat' argument.
I've done the same with atm_dev_ioctl(), where there _are_ a few
differences, but still it's relatively contained and there would
otherwise have been a lot of duplication.
I haven't done any of the actual device-specific ioctls, although I've
added a compat_ioctl method to struct atmdev_ops.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm/resources.c')
-rw-r--r-- | net/atm/resources.c | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/net/atm/resources.c b/net/atm/resources.c index a34ba948af9..56b7322ff46 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -195,20 +195,39 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in } -int atm_dev_ioctl(unsigned int cmd, void __user *arg) +int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) { void __user *buf; int error, len, number, size = 0; struct atm_dev *dev; struct list_head *p; int *tmp_buf, *tmp_p; - struct atm_iobuf __user *iobuf = arg; - struct atmif_sioc __user *sioc = arg; + int __user *sioc_len; + int __user *iobuf_len; + +#ifndef CONFIG_COMPAT + compat = 0; /* Just so the compiler _knows_ */ +#endif + switch (cmd) { case ATM_GETNAMES: - if (get_user(buf, &iobuf->buffer)) - return -EFAULT; - if (get_user(len, &iobuf->length)) + + if (compat) { +#ifdef CONFIG_COMPAT + struct compat_atm_iobuf __user *ciobuf = arg; + compat_uptr_t cbuf; + iobuf_len = &ciobuf->length; + if (get_user(cbuf, &ciobuf->buffer)) + return -EFAULT; + buf = compat_ptr(cbuf); +#endif + } else { + struct atm_iobuf __user *iobuf = arg; + iobuf_len = &iobuf->length; + if (get_user(buf, &iobuf->buffer)) + return -EFAULT; + } + if (get_user(len, iobuf_len)) return -EFAULT; mutex_lock(&atm_dev_mutex); list_for_each(p, &atm_devs) @@ -229,7 +248,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) } mutex_unlock(&atm_dev_mutex); error = ((copy_to_user(buf, tmp_buf, size)) || - put_user(size, &iobuf->length)) + put_user(size, iobuf_len)) ? -EFAULT : 0; kfree(tmp_buf); return error; @@ -237,13 +256,32 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) break; } - if (get_user(buf, &sioc->arg)) - return -EFAULT; - if (get_user(len, &sioc->length)) - return -EFAULT; - if (get_user(number, &sioc->number)) - return -EFAULT; - + if (compat) { +#ifdef CONFIG_COMPAT + struct compat_atmif_sioc __user *csioc = arg; + compat_uptr_t carg; + + sioc_len = &csioc->length; + if (get_user(carg, &csioc->arg)) + return -EFAULT; + buf = compat_ptr(carg); + + if (get_user(len, &csioc->length)) + return -EFAULT; + if (get_user(number, &csioc->number)) + return -EFAULT; +#endif + } else { + struct atmif_sioc __user *sioc = arg; + + sioc_len = &sioc->length; + if (get_user(buf, &sioc->arg)) + return -EFAULT; + if (get_user(len, &sioc->length)) + return -EFAULT; + if (get_user(number, &sioc->number)) + return -EFAULT; + } if (!(dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", number))) return -ENODEV; @@ -358,7 +396,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) size = error; /* may return 0, but later on size == 0 means "don't write the length" */ - error = put_user(size, &sioc->length) + error = put_user(size, sioc_len) ? -EFAULT : 0; goto done; case ATM_SETLOOP: @@ -380,11 +418,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) } /* fall through */ default: - if (!dev->ops->ioctl) { - error = -EINVAL; - goto done; + if (compat) { +#ifdef CONFIG_COMPAT + if (!dev->ops->compat_ioctl) { + error = -EINVAL; + goto done; + } + size = dev->ops->compat_ioctl(dev, cmd, buf); +#endif + } else { + if (!dev->ops->ioctl) { + error = -EINVAL; + goto done; + } + size = dev->ops->ioctl(dev, cmd, buf); } - size = dev->ops->ioctl(dev, cmd, buf); if (size < 0) { error = (size == -ENOIOCTLCMD ? -EINVAL : size); goto done; @@ -392,7 +440,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) } if (size) - error = put_user(size, &sioc->length) + error = put_user(size, sioc_len) ? -EFAULT : 0; else error = 0; |