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); | ||