From 8865c418caf4e9dd2c24bdfae3a5a4106e143e60 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 3 Dec 2008 22:12:38 -0800 Subject: 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 Signed-off-by: David S. Miller --- net/atm/resources.c | 88 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 20 deletions(-) (limited to 'net/atm/resources.c') 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; -- cgit v1.2.3