diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-12-04 01:12:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-04 01:12:38 -0500 |
commit | 8865c418caf4e9dd2c24bdfae3a5a4106e143e60 (patch) | |
tree | 4d7fac2c74af56c6aaf83b324b349b76c5f949d9 /net/atm/resources.c | |
parent | dcd39c90290297f6e6ed8a04bb20da7ac2b043c5 (diff) |
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 a34ba948af96..56b7322ff461 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 | |||
195 | } | 195 | } |
196 | 196 | ||
197 | 197 | ||
198 | int atm_dev_ioctl(unsigned int cmd, void __user *arg) | 198 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) |
199 | { | 199 | { |
200 | void __user *buf; | 200 | void __user *buf; |
201 | int error, len, number, size = 0; | 201 | int error, len, number, size = 0; |
202 | struct atm_dev *dev; | 202 | struct atm_dev *dev; |
203 | struct list_head *p; | 203 | struct list_head *p; |
204 | int *tmp_buf, *tmp_p; | 204 | int *tmp_buf, *tmp_p; |
205 | struct atm_iobuf __user *iobuf = arg; | 205 | int __user *sioc_len; |
206 | struct atmif_sioc __user *sioc = arg; | 206 | int __user *iobuf_len; |
207 | |||
208 | #ifndef CONFIG_COMPAT | ||
209 | compat = 0; /* Just so the compiler _knows_ */ | ||
210 | #endif | ||
211 | |||
207 | switch (cmd) { | 212 | switch (cmd) { |
208 | case ATM_GETNAMES: | 213 | case ATM_GETNAMES: |
209 | if (get_user(buf, &iobuf->buffer)) | 214 | |
210 | return -EFAULT; | 215 | if (compat) { |
211 | if (get_user(len, &iobuf->length)) | 216 | #ifdef CONFIG_COMPAT |
217 | struct compat_atm_iobuf __user *ciobuf = arg; | ||
218 | compat_uptr_t cbuf; | ||
219 | iobuf_len = &ciobuf->length; | ||
220 | if (get_user(cbuf, &ciobuf->buffer)) | ||
221 | return -EFAULT; | ||
222 | buf = compat_ptr(cbuf); | ||
223 | #endif | ||
224 | } else { | ||
225 | struct atm_iobuf __user *iobuf = arg; | ||
226 | iobuf_len = &iobuf->length; | ||
227 | if (get_user(buf, &iobuf->buffer)) | ||
228 | return -EFAULT; | ||
229 | } | ||
230 | if (get_user(len, iobuf_len)) | ||
212 | return -EFAULT; | 231 | return -EFAULT; |
213 | mutex_lock(&atm_dev_mutex); | 232 | mutex_lock(&atm_dev_mutex); |
214 | list_for_each(p, &atm_devs) | 233 | list_for_each(p, &atm_devs) |
@@ -229,7 +248,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
229 | } | 248 | } |
230 | mutex_unlock(&atm_dev_mutex); | 249 | mutex_unlock(&atm_dev_mutex); |
231 | error = ((copy_to_user(buf, tmp_buf, size)) || | 250 | error = ((copy_to_user(buf, tmp_buf, size)) || |
232 | put_user(size, &iobuf->length)) | 251 | put_user(size, iobuf_len)) |
233 | ? -EFAULT : 0; | 252 | ? -EFAULT : 0; |
234 | kfree(tmp_buf); | 253 | kfree(tmp_buf); |
235 | return error; | 254 | return error; |
@@ -237,13 +256,32 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
237 | break; | 256 | break; |
238 | } | 257 | } |
239 | 258 | ||
240 | if (get_user(buf, &sioc->arg)) | 259 | if (compat) { |
241 | return -EFAULT; | 260 | #ifdef CONFIG_COMPAT |
242 | if (get_user(len, &sioc->length)) | 261 | struct compat_atmif_sioc __user *csioc = arg; |
243 | return -EFAULT; | 262 | compat_uptr_t carg; |
244 | if (get_user(number, &sioc->number)) | 263 | |
245 | return -EFAULT; | 264 | sioc_len = &csioc->length; |
246 | 265 | if (get_user(carg, &csioc->arg)) | |
266 | return -EFAULT; | ||
267 | buf = compat_ptr(carg); | ||
268 | |||
269 | if (get_user(len, &csioc->length)) | ||
270 | return -EFAULT; | ||
271 | if (get_user(number, &csioc->number)) | ||
272 | return -EFAULT; | ||
273 | #endif | ||
274 | } else { | ||
275 | struct atmif_sioc __user *sioc = arg; | ||
276 | |||
277 | sioc_len = &sioc->length; | ||
278 | if (get_user(buf, &sioc->arg)) | ||
279 | return -EFAULT; | ||
280 | if (get_user(len, &sioc->length)) | ||
281 | return -EFAULT; | ||
282 | if (get_user(number, &sioc->number)) | ||
283 | return -EFAULT; | ||
284 | } | ||
247 | if (!(dev = try_then_request_module(atm_dev_lookup(number), | 285 | if (!(dev = try_then_request_module(atm_dev_lookup(number), |
248 | "atm-device-%d", number))) | 286 | "atm-device-%d", number))) |
249 | return -ENODEV; | 287 | return -ENODEV; |
@@ -358,7 +396,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
358 | size = error; | 396 | size = error; |
359 | /* may return 0, but later on size == 0 means "don't | 397 | /* may return 0, but later on size == 0 means "don't |
360 | write the length" */ | 398 | write the length" */ |
361 | error = put_user(size, &sioc->length) | 399 | error = put_user(size, sioc_len) |
362 | ? -EFAULT : 0; | 400 | ? -EFAULT : 0; |
363 | goto done; | 401 | goto done; |
364 | case ATM_SETLOOP: | 402 | case ATM_SETLOOP: |
@@ -380,11 +418,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
380 | } | 418 | } |
381 | /* fall through */ | 419 | /* fall through */ |
382 | default: | 420 | default: |
383 | if (!dev->ops->ioctl) { | 421 | if (compat) { |
384 | error = -EINVAL; | 422 | #ifdef CONFIG_COMPAT |
385 | goto done; | 423 | if (!dev->ops->compat_ioctl) { |
424 | error = -EINVAL; | ||
425 | goto done; | ||
426 | } | ||
427 | size = dev->ops->compat_ioctl(dev, cmd, buf); | ||
428 | #endif | ||
429 | } else { | ||
430 | if (!dev->ops->ioctl) { | ||
431 | error = -EINVAL; | ||
432 | goto done; | ||
433 | } | ||
434 | size = dev->ops->ioctl(dev, cmd, buf); | ||
386 | } | 435 | } |
387 | size = dev->ops->ioctl(dev, cmd, buf); | ||
388 | if (size < 0) { | 436 | if (size < 0) { |
389 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); | 437 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); |
390 | goto done; | 438 | goto done; |
@@ -392,7 +440,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
392 | } | 440 | } |
393 | 441 | ||
394 | if (size) | 442 | if (size) |
395 | error = put_user(size, &sioc->length) | 443 | error = put_user(size, sioc_len) |
396 | ? -EFAULT : 0; | 444 | ? -EFAULT : 0; |
397 | else | 445 | else |
398 | error = 0; | 446 | error = 0; |