diff options
Diffstat (limited to 'net/atm/resources.c')
| -rw-r--r-- | net/atm/resources.c | 419 |
1 files changed, 198 insertions, 221 deletions
diff --git a/net/atm/resources.c b/net/atm/resources.c index 56b7322ff461..d29e58261511 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | * 2002/01 - don't free the whole struct sock on sk->destruct time, | 7 | * 2002/01 - don't free the whole struct sock on sk->destruct time, |
| 8 | * use the default destruct function initialized by sock_init_data */ | 8 | * use the default destruct function initialized by sock_init_data */ |
| 9 | 9 | ||
| 10 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ | ||
| 10 | 11 | ||
| 11 | #include <linux/ctype.h> | 12 | #include <linux/ctype.h> |
| 12 | #include <linux/string.h> | 13 | #include <linux/string.h> |
| @@ -18,6 +19,7 @@ | |||
| 18 | #include <linux/capability.h> | 19 | #include <linux/capability.h> |
| 19 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
| 20 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
| 22 | #include <linux/slab.h> | ||
| 21 | 23 | ||
| 22 | #include <net/sock.h> /* for struct sock */ | 24 | #include <net/sock.h> /* for struct sock */ |
| 23 | 25 | ||
| @@ -70,7 +72,7 @@ struct atm_dev *atm_dev_lookup(int number) | |||
| 70 | mutex_unlock(&atm_dev_mutex); | 72 | mutex_unlock(&atm_dev_mutex); |
| 71 | return dev; | 73 | return dev; |
| 72 | } | 74 | } |
| 73 | 75 | EXPORT_SYMBOL(atm_dev_lookup); | |
| 74 | 76 | ||
| 75 | struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | 77 | struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, |
| 76 | int number, unsigned long *flags) | 78 | int number, unsigned long *flags) |
| @@ -79,13 +81,13 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
| 79 | 81 | ||
| 80 | dev = __alloc_atm_dev(type); | 82 | dev = __alloc_atm_dev(type); |
| 81 | if (!dev) { | 83 | if (!dev) { |
| 82 | printk(KERN_ERR "atm_dev_register: no space for dev %s\n", | 84 | pr_err("no space for dev %s\n", type); |
| 83 | type); | ||
| 84 | return NULL; | 85 | return NULL; |
| 85 | } | 86 | } |
| 86 | mutex_lock(&atm_dev_mutex); | 87 | mutex_lock(&atm_dev_mutex); |
| 87 | if (number != -1) { | 88 | if (number != -1) { |
| 88 | if ((inuse = __atm_dev_lookup(number))) { | 89 | inuse = __atm_dev_lookup(number); |
| 90 | if (inuse) { | ||
| 89 | atm_dev_put(inuse); | 91 | atm_dev_put(inuse); |
| 90 | mutex_unlock(&atm_dev_mutex); | 92 | mutex_unlock(&atm_dev_mutex); |
| 91 | kfree(dev); | 93 | kfree(dev); |
| @@ -109,16 +111,12 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
| 109 | atomic_set(&dev->refcnt, 1); | 111 | atomic_set(&dev->refcnt, 1); |
| 110 | 112 | ||
| 111 | if (atm_proc_dev_register(dev) < 0) { | 113 | if (atm_proc_dev_register(dev) < 0) { |
| 112 | printk(KERN_ERR "atm_dev_register: " | 114 | pr_err("atm_proc_dev_register failed for dev %s\n", type); |
| 113 | "atm_proc_dev_register failed for dev %s\n", | ||
| 114 | type); | ||
| 115 | goto out_fail; | 115 | goto out_fail; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | if (atm_register_sysfs(dev) < 0) { | 118 | if (atm_register_sysfs(dev) < 0) { |
| 119 | printk(KERN_ERR "atm_dev_register: " | 119 | pr_err("atm_register_sysfs failed for dev %s\n", type); |
| 120 | "atm_register_sysfs failed for dev %s\n", | ||
| 121 | type); | ||
| 122 | atm_proc_dev_deregister(dev); | 120 | atm_proc_dev_deregister(dev); |
| 123 | goto out_fail; | 121 | goto out_fail; |
| 124 | } | 122 | } |
| @@ -134,7 +132,7 @@ out_fail: | |||
| 134 | dev = NULL; | 132 | dev = NULL; |
| 135 | goto out; | 133 | goto out; |
| 136 | } | 134 | } |
| 137 | 135 | EXPORT_SYMBOL(atm_dev_register); | |
| 138 | 136 | ||
| 139 | void atm_dev_deregister(struct atm_dev *dev) | 137 | void atm_dev_deregister(struct atm_dev *dev) |
| 140 | { | 138 | { |
| @@ -156,7 +154,7 @@ void atm_dev_deregister(struct atm_dev *dev) | |||
| 156 | 154 | ||
| 157 | atm_dev_put(dev); | 155 | atm_dev_put(dev); |
| 158 | } | 156 | } |
| 159 | 157 | EXPORT_SYMBOL(atm_dev_deregister); | |
| 160 | 158 | ||
| 161 | static void copy_aal_stats(struct k_atm_aal_stats *from, | 159 | static void copy_aal_stats(struct k_atm_aal_stats *from, |
| 162 | struct atm_aal_stats *to) | 160 | struct atm_aal_stats *to) |
| @@ -166,7 +164,6 @@ static void copy_aal_stats(struct k_atm_aal_stats *from, | |||
| 166 | #undef __HANDLE_ITEM | 164 | #undef __HANDLE_ITEM |
| 167 | } | 165 | } |
| 168 | 166 | ||
| 169 | |||
| 170 | static void subtract_aal_stats(struct k_atm_aal_stats *from, | 167 | static void subtract_aal_stats(struct k_atm_aal_stats *from, |
| 171 | struct atm_aal_stats *to) | 168 | struct atm_aal_stats *to) |
| 172 | { | 169 | { |
| @@ -175,8 +172,8 @@ static void subtract_aal_stats(struct k_atm_aal_stats *from, | |||
| 175 | #undef __HANDLE_ITEM | 172 | #undef __HANDLE_ITEM |
| 176 | } | 173 | } |
| 177 | 174 | ||
| 178 | 175 | static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, | |
| 179 | static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, int zero) | 176 | int zero) |
| 180 | { | 177 | { |
| 181 | struct atm_dev_stats tmp; | 178 | struct atm_dev_stats tmp; |
| 182 | int error = 0; | 179 | int error = 0; |
| @@ -194,7 +191,6 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in | |||
| 194 | return error ? -EFAULT : 0; | 191 | return error ? -EFAULT : 0; |
| 195 | } | 192 | } |
| 196 | 193 | ||
| 197 | |||
| 198 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) | 194 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) |
| 199 | { | 195 | { |
| 200 | void __user *buf; | 196 | void __user *buf; |
| @@ -210,50 +206,49 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) | |||
| 210 | #endif | 206 | #endif |
| 211 | 207 | ||
| 212 | switch (cmd) { | 208 | switch (cmd) { |
| 213 | case ATM_GETNAMES: | 209 | case ATM_GETNAMES: |
| 214 | 210 | if (compat) { | |
| 215 | if (compat) { | ||
| 216 | #ifdef CONFIG_COMPAT | 211 | #ifdef CONFIG_COMPAT |
| 217 | struct compat_atm_iobuf __user *ciobuf = arg; | 212 | struct compat_atm_iobuf __user *ciobuf = arg; |
| 218 | compat_uptr_t cbuf; | 213 | compat_uptr_t cbuf; |
| 219 | iobuf_len = &ciobuf->length; | 214 | iobuf_len = &ciobuf->length; |
| 220 | if (get_user(cbuf, &ciobuf->buffer)) | 215 | if (get_user(cbuf, &ciobuf->buffer)) |
| 221 | return -EFAULT; | 216 | return -EFAULT; |
| 222 | buf = compat_ptr(cbuf); | 217 | buf = compat_ptr(cbuf); |
| 223 | #endif | 218 | #endif |
| 224 | } else { | 219 | } else { |
| 225 | struct atm_iobuf __user *iobuf = arg; | 220 | struct atm_iobuf __user *iobuf = arg; |
| 226 | iobuf_len = &iobuf->length; | 221 | iobuf_len = &iobuf->length; |
| 227 | if (get_user(buf, &iobuf->buffer)) | 222 | if (get_user(buf, &iobuf->buffer)) |
| 228 | return -EFAULT; | ||
| 229 | } | ||
| 230 | if (get_user(len, iobuf_len)) | ||
| 231 | return -EFAULT; | 223 | return -EFAULT; |
| 232 | mutex_lock(&atm_dev_mutex); | 224 | } |
| 233 | list_for_each(p, &atm_devs) | 225 | if (get_user(len, iobuf_len)) |
| 234 | size += sizeof(int); | 226 | return -EFAULT; |
| 235 | if (size > len) { | 227 | mutex_lock(&atm_dev_mutex); |
| 236 | mutex_unlock(&atm_dev_mutex); | 228 | list_for_each(p, &atm_devs) |
| 237 | return -E2BIG; | 229 | size += sizeof(int); |
| 238 | } | 230 | if (size > len) { |
| 239 | tmp_buf = kmalloc(size, GFP_ATOMIC); | 231 | mutex_unlock(&atm_dev_mutex); |
| 240 | if (!tmp_buf) { | 232 | return -E2BIG; |
| 241 | mutex_unlock(&atm_dev_mutex); | 233 | } |
| 242 | return -ENOMEM; | 234 | tmp_buf = kmalloc(size, GFP_ATOMIC); |
| 243 | } | 235 | if (!tmp_buf) { |
| 244 | tmp_p = tmp_buf; | ||
| 245 | list_for_each(p, &atm_devs) { | ||
| 246 | dev = list_entry(p, struct atm_dev, dev_list); | ||
| 247 | *tmp_p++ = dev->number; | ||
| 248 | } | ||
| 249 | mutex_unlock(&atm_dev_mutex); | 236 | mutex_unlock(&atm_dev_mutex); |
| 250 | error = ((copy_to_user(buf, tmp_buf, size)) || | 237 | return -ENOMEM; |
| 251 | put_user(size, iobuf_len)) | 238 | } |
| 252 | ? -EFAULT : 0; | 239 | tmp_p = tmp_buf; |
| 253 | kfree(tmp_buf); | 240 | list_for_each(p, &atm_devs) { |
| 254 | return error; | 241 | dev = list_entry(p, struct atm_dev, dev_list); |
| 255 | default: | 242 | *tmp_p++ = dev->number; |
| 256 | break; | 243 | } |
| 244 | mutex_unlock(&atm_dev_mutex); | ||
| 245 | error = ((copy_to_user(buf, tmp_buf, size)) || | ||
| 246 | put_user(size, iobuf_len)) | ||
| 247 | ? -EFAULT : 0; | ||
| 248 | kfree(tmp_buf); | ||
| 249 | return error; | ||
| 250 | default: | ||
| 251 | break; | ||
| 257 | } | 252 | } |
| 258 | 253 | ||
| 259 | if (compat) { | 254 | if (compat) { |
| @@ -282,166 +277,167 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) | |||
| 282 | if (get_user(number, &sioc->number)) | 277 | if (get_user(number, &sioc->number)) |
| 283 | return -EFAULT; | 278 | return -EFAULT; |
| 284 | } | 279 | } |
| 285 | if (!(dev = try_then_request_module(atm_dev_lookup(number), | 280 | |
| 286 | "atm-device-%d", number))) | 281 | dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", |
| 282 | number); | ||
| 283 | if (!dev) | ||
| 287 | return -ENODEV; | 284 | return -ENODEV; |
| 288 | 285 | ||
| 289 | switch (cmd) { | 286 | switch (cmd) { |
| 290 | case ATM_GETTYPE: | 287 | case ATM_GETTYPE: |
| 291 | size = strlen(dev->type) + 1; | 288 | size = strlen(dev->type) + 1; |
| 292 | if (copy_to_user(buf, dev->type, size)) { | 289 | if (copy_to_user(buf, dev->type, size)) { |
| 293 | error = -EFAULT; | 290 | error = -EFAULT; |
| 294 | goto done; | 291 | goto done; |
| 295 | } | 292 | } |
| 296 | break; | 293 | break; |
| 297 | case ATM_GETESI: | 294 | case ATM_GETESI: |
| 298 | size = ESI_LEN; | 295 | size = ESI_LEN; |
| 299 | if (copy_to_user(buf, dev->esi, size)) { | 296 | if (copy_to_user(buf, dev->esi, size)) { |
| 300 | error = -EFAULT; | 297 | error = -EFAULT; |
| 301 | goto done; | 298 | goto done; |
| 302 | } | 299 | } |
| 303 | break; | 300 | break; |
| 304 | case ATM_SETESI: | 301 | case ATM_SETESI: |
| 305 | { | 302 | { |
| 306 | int i; | 303 | int i; |
| 307 | 304 | ||
| 308 | for (i = 0; i < ESI_LEN; i++) | 305 | for (i = 0; i < ESI_LEN; i++) |
| 309 | if (dev->esi[i]) { | 306 | if (dev->esi[i]) { |
| 310 | error = -EEXIST; | 307 | error = -EEXIST; |
| 311 | goto done; | ||
| 312 | } | ||
| 313 | } | ||
| 314 | /* fall through */ | ||
| 315 | case ATM_SETESIF: | ||
| 316 | { | ||
| 317 | unsigned char esi[ESI_LEN]; | ||
| 318 | |||
| 319 | if (!capable(CAP_NET_ADMIN)) { | ||
| 320 | error = -EPERM; | ||
| 321 | goto done; | ||
| 322 | } | ||
| 323 | if (copy_from_user(esi, buf, ESI_LEN)) { | ||
| 324 | error = -EFAULT; | ||
| 325 | goto done; | ||
| 326 | } | ||
| 327 | memcpy(dev->esi, esi, ESI_LEN); | ||
| 328 | error = ESI_LEN; | ||
| 329 | goto done; | ||
| 330 | } | ||
| 331 | case ATM_GETSTATZ: | ||
| 332 | if (!capable(CAP_NET_ADMIN)) { | ||
| 333 | error = -EPERM; | ||
| 334 | goto done; | ||
| 335 | } | ||
| 336 | /* fall through */ | ||
| 337 | case ATM_GETSTAT: | ||
| 338 | size = sizeof(struct atm_dev_stats); | ||
| 339 | error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); | ||
| 340 | if (error) | ||
| 341 | goto done; | ||
| 342 | break; | ||
| 343 | case ATM_GETCIRANGE: | ||
| 344 | size = sizeof(struct atm_cirange); | ||
| 345 | if (copy_to_user(buf, &dev->ci_range, size)) { | ||
| 346 | error = -EFAULT; | ||
| 347 | goto done; | ||
| 348 | } | ||
| 349 | break; | ||
| 350 | case ATM_GETLINKRATE: | ||
| 351 | size = sizeof(int); | ||
| 352 | if (copy_to_user(buf, &dev->link_rate, size)) { | ||
| 353 | error = -EFAULT; | ||
| 354 | goto done; | ||
| 355 | } | ||
| 356 | break; | ||
| 357 | case ATM_RSTADDR: | ||
| 358 | if (!capable(CAP_NET_ADMIN)) { | ||
| 359 | error = -EPERM; | ||
| 360 | goto done; | ||
| 361 | } | ||
| 362 | atm_reset_addr(dev, ATM_ADDR_LOCAL); | ||
| 363 | break; | ||
| 364 | case ATM_ADDADDR: | ||
| 365 | case ATM_DELADDR: | ||
| 366 | case ATM_ADDLECSADDR: | ||
| 367 | case ATM_DELLECSADDR: | ||
| 368 | if (!capable(CAP_NET_ADMIN)) { | ||
| 369 | error = -EPERM; | ||
| 370 | goto done; | ||
| 371 | } | ||
| 372 | { | ||
| 373 | struct sockaddr_atmsvc addr; | ||
| 374 | |||
| 375 | if (copy_from_user(&addr, buf, sizeof(addr))) { | ||
| 376 | error = -EFAULT; | ||
| 377 | goto done; | ||
| 378 | } | ||
| 379 | if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) | ||
| 380 | error = atm_add_addr(dev, &addr, | ||
| 381 | (cmd == ATM_ADDADDR ? | ||
| 382 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
| 383 | else | ||
| 384 | error = atm_del_addr(dev, &addr, | ||
| 385 | (cmd == ATM_DELADDR ? | ||
| 386 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
| 387 | goto done; | 308 | goto done; |
| 388 | } | 309 | } |
| 389 | case ATM_GETADDR: | 310 | } |
| 390 | case ATM_GETLECSADDR: | 311 | /* fall through */ |
| 391 | error = atm_get_addr(dev, buf, len, | 312 | case ATM_SETESIF: |
| 392 | (cmd == ATM_GETADDR ? | 313 | { |
| 314 | unsigned char esi[ESI_LEN]; | ||
| 315 | |||
| 316 | if (!capable(CAP_NET_ADMIN)) { | ||
| 317 | error = -EPERM; | ||
| 318 | goto done; | ||
| 319 | } | ||
| 320 | if (copy_from_user(esi, buf, ESI_LEN)) { | ||
| 321 | error = -EFAULT; | ||
| 322 | goto done; | ||
| 323 | } | ||
| 324 | memcpy(dev->esi, esi, ESI_LEN); | ||
| 325 | error = ESI_LEN; | ||
| 326 | goto done; | ||
| 327 | } | ||
| 328 | case ATM_GETSTATZ: | ||
| 329 | if (!capable(CAP_NET_ADMIN)) { | ||
| 330 | error = -EPERM; | ||
| 331 | goto done; | ||
| 332 | } | ||
| 333 | /* fall through */ | ||
| 334 | case ATM_GETSTAT: | ||
| 335 | size = sizeof(struct atm_dev_stats); | ||
| 336 | error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); | ||
| 337 | if (error) | ||
| 338 | goto done; | ||
| 339 | break; | ||
| 340 | case ATM_GETCIRANGE: | ||
| 341 | size = sizeof(struct atm_cirange); | ||
| 342 | if (copy_to_user(buf, &dev->ci_range, size)) { | ||
| 343 | error = -EFAULT; | ||
| 344 | goto done; | ||
| 345 | } | ||
| 346 | break; | ||
| 347 | case ATM_GETLINKRATE: | ||
| 348 | size = sizeof(int); | ||
| 349 | if (copy_to_user(buf, &dev->link_rate, size)) { | ||
| 350 | error = -EFAULT; | ||
| 351 | goto done; | ||
| 352 | } | ||
| 353 | break; | ||
| 354 | case ATM_RSTADDR: | ||
| 355 | if (!capable(CAP_NET_ADMIN)) { | ||
| 356 | error = -EPERM; | ||
| 357 | goto done; | ||
| 358 | } | ||
| 359 | atm_reset_addr(dev, ATM_ADDR_LOCAL); | ||
| 360 | break; | ||
| 361 | case ATM_ADDADDR: | ||
| 362 | case ATM_DELADDR: | ||
| 363 | case ATM_ADDLECSADDR: | ||
| 364 | case ATM_DELLECSADDR: | ||
| 365 | { | ||
| 366 | struct sockaddr_atmsvc addr; | ||
| 367 | |||
| 368 | if (!capable(CAP_NET_ADMIN)) { | ||
| 369 | error = -EPERM; | ||
| 370 | goto done; | ||
| 371 | } | ||
| 372 | |||
| 373 | if (copy_from_user(&addr, buf, sizeof(addr))) { | ||
| 374 | error = -EFAULT; | ||
| 375 | goto done; | ||
| 376 | } | ||
| 377 | if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) | ||
| 378 | error = atm_add_addr(dev, &addr, | ||
| 379 | (cmd == ATM_ADDADDR ? | ||
| 393 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | 380 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); |
| 394 | if (error < 0) | 381 | else |
| 395 | goto done; | 382 | error = atm_del_addr(dev, &addr, |
| 396 | size = error; | 383 | (cmd == ATM_DELADDR ? |
| 397 | /* may return 0, but later on size == 0 means "don't | 384 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); |
| 398 | write the length" */ | 385 | goto done; |
| 399 | error = put_user(size, sioc_len) | 386 | } |
| 400 | ? -EFAULT : 0; | 387 | case ATM_GETADDR: |
| 388 | case ATM_GETLECSADDR: | ||
| 389 | error = atm_get_addr(dev, buf, len, | ||
| 390 | (cmd == ATM_GETADDR ? | ||
| 391 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
| 392 | if (error < 0) | ||
| 393 | goto done; | ||
| 394 | size = error; | ||
| 395 | /* may return 0, but later on size == 0 means "don't | ||
| 396 | write the length" */ | ||
| 397 | error = put_user(size, sioc_len) ? -EFAULT : 0; | ||
| 398 | goto done; | ||
| 399 | case ATM_SETLOOP: | ||
| 400 | if (__ATM_LM_XTRMT((int) (unsigned long) buf) && | ||
| 401 | __ATM_LM_XTLOC((int) (unsigned long) buf) > | ||
| 402 | __ATM_LM_XTRMT((int) (unsigned long) buf)) { | ||
| 403 | error = -EINVAL; | ||
| 404 | goto done; | ||
| 405 | } | ||
| 406 | /* fall through */ | ||
| 407 | case ATM_SETCIRANGE: | ||
| 408 | case SONET_GETSTATZ: | ||
| 409 | case SONET_SETDIAG: | ||
| 410 | case SONET_CLRDIAG: | ||
| 411 | case SONET_SETFRAMING: | ||
| 412 | if (!capable(CAP_NET_ADMIN)) { | ||
| 413 | error = -EPERM; | ||
| 401 | goto done; | 414 | goto done; |
| 402 | case ATM_SETLOOP: | 415 | } |
| 403 | if (__ATM_LM_XTRMT((int) (unsigned long) buf) && | 416 | /* fall through */ |
| 404 | __ATM_LM_XTLOC((int) (unsigned long) buf) > | 417 | default: |
| 405 | __ATM_LM_XTRMT((int) (unsigned long) buf)) { | 418 | if (compat) { |
| 419 | #ifdef CONFIG_COMPAT | ||
| 420 | if (!dev->ops->compat_ioctl) { | ||
| 406 | error = -EINVAL; | 421 | error = -EINVAL; |
| 407 | goto done; | 422 | goto done; |
| 408 | } | 423 | } |
| 409 | /* fall through */ | 424 | size = dev->ops->compat_ioctl(dev, cmd, buf); |
| 410 | case ATM_SETCIRANGE: | ||
| 411 | case SONET_GETSTATZ: | ||
| 412 | case SONET_SETDIAG: | ||
| 413 | case SONET_CLRDIAG: | ||
| 414 | case SONET_SETFRAMING: | ||
| 415 | if (!capable(CAP_NET_ADMIN)) { | ||
| 416 | error = -EPERM; | ||
| 417 | goto done; | ||
| 418 | } | ||
| 419 | /* fall through */ | ||
| 420 | default: | ||
| 421 | if (compat) { | ||
| 422 | #ifdef CONFIG_COMPAT | ||
| 423 | if (!dev->ops->compat_ioctl) { | ||
| 424 | error = -EINVAL; | ||
| 425 | goto done; | ||
| 426 | } | ||
| 427 | size = dev->ops->compat_ioctl(dev, cmd, buf); | ||
| 428 | #endif | 425 | #endif |
| 429 | } else { | 426 | } else { |
| 430 | if (!dev->ops->ioctl) { | 427 | if (!dev->ops->ioctl) { |
| 431 | error = -EINVAL; | 428 | error = -EINVAL; |
| 432 | goto done; | ||
| 433 | } | ||
| 434 | size = dev->ops->ioctl(dev, cmd, buf); | ||
| 435 | } | ||
| 436 | if (size < 0) { | ||
| 437 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); | ||
| 438 | goto done; | 429 | goto done; |
| 439 | } | 430 | } |
| 431 | size = dev->ops->ioctl(dev, cmd, buf); | ||
| 432 | } | ||
| 433 | if (size < 0) { | ||
| 434 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); | ||
| 435 | goto done; | ||
| 436 | } | ||
| 440 | } | 437 | } |
| 441 | 438 | ||
| 442 | if (size) | 439 | if (size) |
| 443 | error = put_user(size, sioc_len) | 440 | error = put_user(size, sioc_len) ? -EFAULT : 0; |
| 444 | ? -EFAULT : 0; | ||
| 445 | else | 441 | else |
| 446 | error = 0; | 442 | error = 0; |
| 447 | done: | 443 | done: |
| @@ -449,21 +445,10 @@ done: | |||
| 449 | return error; | 445 | return error; |
| 450 | } | 446 | } |
| 451 | 447 | ||
| 452 | static __inline__ void *dev_get_idx(loff_t left) | ||
| 453 | { | ||
| 454 | struct list_head *p; | ||
| 455 | |||
| 456 | list_for_each(p, &atm_devs) { | ||
| 457 | if (!--left) | ||
| 458 | break; | ||
| 459 | } | ||
| 460 | return (p != &atm_devs) ? p : NULL; | ||
| 461 | } | ||
| 462 | |||
| 463 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) | 448 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) |
| 464 | { | 449 | { |
| 465 | mutex_lock(&atm_dev_mutex); | 450 | mutex_lock(&atm_dev_mutex); |
| 466 | return *pos ? dev_get_idx(*pos) : SEQ_START_TOKEN; | 451 | return seq_list_start_head(&atm_devs, *pos); |
| 467 | } | 452 | } |
| 468 | 453 | ||
| 469 | void atm_dev_seq_stop(struct seq_file *seq, void *v) | 454 | void atm_dev_seq_stop(struct seq_file *seq, void *v) |
| @@ -473,13 +458,5 @@ void atm_dev_seq_stop(struct seq_file *seq, void *v) | |||
| 473 | 458 | ||
| 474 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 459 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
| 475 | { | 460 | { |
| 476 | ++*pos; | 461 | return seq_list_next(v, &atm_devs, pos); |
| 477 | v = (v == SEQ_START_TOKEN) | ||
| 478 | ? atm_devs.next : ((struct list_head *)v)->next; | ||
| 479 | return (v == &atm_devs) ? NULL : v; | ||
| 480 | } | 462 | } |
| 481 | |||
| 482 | |||
| 483 | EXPORT_SYMBOL(atm_dev_register); | ||
| 484 | EXPORT_SYMBOL(atm_dev_deregister); | ||
| 485 | EXPORT_SYMBOL(atm_dev_lookup); | ||
