diff options
-rw-r--r-- | net/atm/resources.c | 390 |
1 files changed, 192 insertions, 198 deletions
diff --git a/net/atm/resources.c b/net/atm/resources.c index 0d4c0ee090db..447ed89205d8 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -71,7 +71,7 @@ struct atm_dev *atm_dev_lookup(int number) | |||
71 | mutex_unlock(&atm_dev_mutex); | 71 | mutex_unlock(&atm_dev_mutex); |
72 | return dev; | 72 | return dev; |
73 | } | 73 | } |
74 | 74 | EXPORT_SYMBOL(atm_dev_lookup); | |
75 | 75 | ||
76 | struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | 76 | struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, |
77 | int number, unsigned long *flags) | 77 | int number, unsigned long *flags) |
@@ -85,7 +85,8 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
85 | } | 85 | } |
86 | mutex_lock(&atm_dev_mutex); | 86 | mutex_lock(&atm_dev_mutex); |
87 | if (number != -1) { | 87 | if (number != -1) { |
88 | if ((inuse = __atm_dev_lookup(number))) { | 88 | inuse = __atm_dev_lookup(number); |
89 | if (inuse) { | ||
89 | atm_dev_put(inuse); | 90 | atm_dev_put(inuse); |
90 | mutex_unlock(&atm_dev_mutex); | 91 | mutex_unlock(&atm_dev_mutex); |
91 | kfree(dev); | 92 | kfree(dev); |
@@ -130,7 +131,7 @@ out_fail: | |||
130 | dev = NULL; | 131 | dev = NULL; |
131 | goto out; | 132 | goto out; |
132 | } | 133 | } |
133 | 134 | EXPORT_SYMBOL(atm_dev_register); | |
134 | 135 | ||
135 | void atm_dev_deregister(struct atm_dev *dev) | 136 | void atm_dev_deregister(struct atm_dev *dev) |
136 | { | 137 | { |
@@ -152,7 +153,7 @@ void atm_dev_deregister(struct atm_dev *dev) | |||
152 | 153 | ||
153 | atm_dev_put(dev); | 154 | atm_dev_put(dev); |
154 | } | 155 | } |
155 | 156 | EXPORT_SYMBOL(atm_dev_deregister); | |
156 | 157 | ||
157 | static void copy_aal_stats(struct k_atm_aal_stats *from, | 158 | static void copy_aal_stats(struct k_atm_aal_stats *from, |
158 | struct atm_aal_stats *to) | 159 | struct atm_aal_stats *to) |
@@ -162,7 +163,6 @@ static void copy_aal_stats(struct k_atm_aal_stats *from, | |||
162 | #undef __HANDLE_ITEM | 163 | #undef __HANDLE_ITEM |
163 | } | 164 | } |
164 | 165 | ||
165 | |||
166 | static void subtract_aal_stats(struct k_atm_aal_stats *from, | 166 | static void subtract_aal_stats(struct k_atm_aal_stats *from, |
167 | struct atm_aal_stats *to) | 167 | struct atm_aal_stats *to) |
168 | { | 168 | { |
@@ -171,8 +171,8 @@ static void subtract_aal_stats(struct k_atm_aal_stats *from, | |||
171 | #undef __HANDLE_ITEM | 171 | #undef __HANDLE_ITEM |
172 | } | 172 | } |
173 | 173 | ||
174 | 174 | static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, | |
175 | static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, int zero) | 175 | int zero) |
176 | { | 176 | { |
177 | struct atm_dev_stats tmp; | 177 | struct atm_dev_stats tmp; |
178 | int error = 0; | 178 | int error = 0; |
@@ -190,7 +190,6 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in | |||
190 | return error ? -EFAULT : 0; | 190 | return error ? -EFAULT : 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | |||
194 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) | 193 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) |
195 | { | 194 | { |
196 | void __user *buf; | 195 | void __user *buf; |
@@ -206,50 +205,49 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) | |||
206 | #endif | 205 | #endif |
207 | 206 | ||
208 | switch (cmd) { | 207 | switch (cmd) { |
209 | case ATM_GETNAMES: | 208 | case ATM_GETNAMES: |
210 | 209 | if (compat) { | |
211 | if (compat) { | ||
212 | #ifdef CONFIG_COMPAT | 210 | #ifdef CONFIG_COMPAT |
213 | struct compat_atm_iobuf __user *ciobuf = arg; | 211 | struct compat_atm_iobuf __user *ciobuf = arg; |
214 | compat_uptr_t cbuf; | 212 | compat_uptr_t cbuf; |
215 | iobuf_len = &ciobuf->length; | 213 | iobuf_len = &ciobuf->length; |
216 | if (get_user(cbuf, &ciobuf->buffer)) | 214 | if (get_user(cbuf, &ciobuf->buffer)) |
217 | return -EFAULT; | 215 | return -EFAULT; |
218 | buf = compat_ptr(cbuf); | 216 | buf = compat_ptr(cbuf); |
219 | #endif | 217 | #endif |
220 | } else { | 218 | } else { |
221 | struct atm_iobuf __user *iobuf = arg; | 219 | struct atm_iobuf __user *iobuf = arg; |
222 | iobuf_len = &iobuf->length; | 220 | iobuf_len = &iobuf->length; |
223 | if (get_user(buf, &iobuf->buffer)) | 221 | if (get_user(buf, &iobuf->buffer)) |
224 | return -EFAULT; | ||
225 | } | ||
226 | if (get_user(len, iobuf_len)) | ||
227 | return -EFAULT; | 222 | return -EFAULT; |
228 | mutex_lock(&atm_dev_mutex); | 223 | } |
229 | list_for_each(p, &atm_devs) | 224 | if (get_user(len, iobuf_len)) |
230 | size += sizeof(int); | 225 | return -EFAULT; |
231 | if (size > len) { | 226 | mutex_lock(&atm_dev_mutex); |
232 | mutex_unlock(&atm_dev_mutex); | 227 | list_for_each(p, &atm_devs) |
233 | return -E2BIG; | 228 | size += sizeof(int); |
234 | } | 229 | if (size > len) { |
235 | tmp_buf = kmalloc(size, GFP_ATOMIC); | ||
236 | if (!tmp_buf) { | ||
237 | mutex_unlock(&atm_dev_mutex); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | tmp_p = tmp_buf; | ||
241 | list_for_each(p, &atm_devs) { | ||
242 | dev = list_entry(p, struct atm_dev, dev_list); | ||
243 | *tmp_p++ = dev->number; | ||
244 | } | ||
245 | mutex_unlock(&atm_dev_mutex); | 230 | mutex_unlock(&atm_dev_mutex); |
246 | error = ((copy_to_user(buf, tmp_buf, size)) || | 231 | return -E2BIG; |
247 | put_user(size, iobuf_len)) | 232 | } |
248 | ? -EFAULT : 0; | 233 | tmp_buf = kmalloc(size, GFP_ATOMIC); |
249 | kfree(tmp_buf); | 234 | if (!tmp_buf) { |
250 | return error; | 235 | mutex_unlock(&atm_dev_mutex); |
251 | default: | 236 | return -ENOMEM; |
252 | break; | 237 | } |
238 | tmp_p = tmp_buf; | ||
239 | list_for_each(p, &atm_devs) { | ||
240 | dev = list_entry(p, struct atm_dev, dev_list); | ||
241 | *tmp_p++ = dev->number; | ||
242 | } | ||
243 | mutex_unlock(&atm_dev_mutex); | ||
244 | error = ((copy_to_user(buf, tmp_buf, size)) || | ||
245 | put_user(size, iobuf_len)) | ||
246 | ? -EFAULT : 0; | ||
247 | kfree(tmp_buf); | ||
248 | return error; | ||
249 | default: | ||
250 | break; | ||
253 | } | 251 | } |
254 | 252 | ||
255 | if (compat) { | 253 | if (compat) { |
@@ -278,166 +276,167 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) | |||
278 | if (get_user(number, &sioc->number)) | 276 | if (get_user(number, &sioc->number)) |
279 | return -EFAULT; | 277 | return -EFAULT; |
280 | } | 278 | } |
281 | if (!(dev = try_then_request_module(atm_dev_lookup(number), | 279 | |
282 | "atm-device-%d", number))) | 280 | dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", |
281 | number); | ||
282 | if (!dev) | ||
283 | return -ENODEV; | 283 | return -ENODEV; |
284 | 284 | ||
285 | switch (cmd) { | 285 | switch (cmd) { |
286 | case ATM_GETTYPE: | 286 | case ATM_GETTYPE: |
287 | size = strlen(dev->type) + 1; | 287 | size = strlen(dev->type) + 1; |
288 | if (copy_to_user(buf, dev->type, size)) { | 288 | if (copy_to_user(buf, dev->type, size)) { |
289 | error = -EFAULT; | 289 | error = -EFAULT; |
290 | goto done; | 290 | goto done; |
291 | } | 291 | } |
292 | break; | 292 | break; |
293 | case ATM_GETESI: | 293 | case ATM_GETESI: |
294 | size = ESI_LEN; | 294 | size = ESI_LEN; |
295 | if (copy_to_user(buf, dev->esi, size)) { | 295 | if (copy_to_user(buf, dev->esi, size)) { |
296 | error = -EFAULT; | 296 | error = -EFAULT; |
297 | goto done; | 297 | goto done; |
298 | } | 298 | } |
299 | break; | 299 | break; |
300 | case ATM_SETESI: | 300 | case ATM_SETESI: |
301 | { | 301 | { |
302 | int i; | 302 | int i; |
303 | 303 | ||
304 | for (i = 0; i < ESI_LEN; i++) | 304 | for (i = 0; i < ESI_LEN; i++) |
305 | if (dev->esi[i]) { | 305 | if (dev->esi[i]) { |
306 | error = -EEXIST; | 306 | error = -EEXIST; |
307 | goto done; | ||
308 | } | ||
309 | } | ||
310 | /* fall through */ | ||
311 | case ATM_SETESIF: | ||
312 | { | ||
313 | unsigned char esi[ESI_LEN]; | ||
314 | |||
315 | if (!capable(CAP_NET_ADMIN)) { | ||
316 | error = -EPERM; | ||
317 | goto done; | ||
318 | } | ||
319 | if (copy_from_user(esi, buf, ESI_LEN)) { | ||
320 | error = -EFAULT; | ||
321 | goto done; | ||
322 | } | ||
323 | memcpy(dev->esi, esi, ESI_LEN); | ||
324 | error = ESI_LEN; | ||
325 | goto done; | ||
326 | } | ||
327 | case ATM_GETSTATZ: | ||
328 | if (!capable(CAP_NET_ADMIN)) { | ||
329 | error = -EPERM; | ||
330 | goto done; | ||
331 | } | ||
332 | /* fall through */ | ||
333 | case ATM_GETSTAT: | ||
334 | size = sizeof(struct atm_dev_stats); | ||
335 | error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); | ||
336 | if (error) | ||
337 | goto done; | ||
338 | break; | ||
339 | case ATM_GETCIRANGE: | ||
340 | size = sizeof(struct atm_cirange); | ||
341 | if (copy_to_user(buf, &dev->ci_range, size)) { | ||
342 | error = -EFAULT; | ||
343 | goto done; | ||
344 | } | ||
345 | break; | ||
346 | case ATM_GETLINKRATE: | ||
347 | size = sizeof(int); | ||
348 | if (copy_to_user(buf, &dev->link_rate, size)) { | ||
349 | error = -EFAULT; | ||
350 | goto done; | ||
351 | } | ||
352 | break; | ||
353 | case ATM_RSTADDR: | ||
354 | if (!capable(CAP_NET_ADMIN)) { | ||
355 | error = -EPERM; | ||
356 | goto done; | ||
357 | } | ||
358 | atm_reset_addr(dev, ATM_ADDR_LOCAL); | ||
359 | break; | ||
360 | case ATM_ADDADDR: | ||
361 | case ATM_DELADDR: | ||
362 | case ATM_ADDLECSADDR: | ||
363 | case ATM_DELLECSADDR: | ||
364 | if (!capable(CAP_NET_ADMIN)) { | ||
365 | error = -EPERM; | ||
366 | goto done; | ||
367 | } | ||
368 | { | ||
369 | struct sockaddr_atmsvc addr; | ||
370 | |||
371 | if (copy_from_user(&addr, buf, sizeof(addr))) { | ||
372 | error = -EFAULT; | ||
373 | goto done; | ||
374 | } | ||
375 | if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) | ||
376 | error = atm_add_addr(dev, &addr, | ||
377 | (cmd == ATM_ADDADDR ? | ||
378 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
379 | else | ||
380 | error = atm_del_addr(dev, &addr, | ||
381 | (cmd == ATM_DELADDR ? | ||
382 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
383 | goto done; | 307 | goto done; |
384 | } | 308 | } |
385 | case ATM_GETADDR: | 309 | } |
386 | case ATM_GETLECSADDR: | 310 | /* fall through */ |
387 | error = atm_get_addr(dev, buf, len, | 311 | case ATM_SETESIF: |
388 | (cmd == ATM_GETADDR ? | 312 | { |
313 | unsigned char esi[ESI_LEN]; | ||
314 | |||
315 | if (!capable(CAP_NET_ADMIN)) { | ||
316 | error = -EPERM; | ||
317 | goto done; | ||
318 | } | ||
319 | if (copy_from_user(esi, buf, ESI_LEN)) { | ||
320 | error = -EFAULT; | ||
321 | goto done; | ||
322 | } | ||
323 | memcpy(dev->esi, esi, ESI_LEN); | ||
324 | error = ESI_LEN; | ||
325 | goto done; | ||
326 | } | ||
327 | case ATM_GETSTATZ: | ||
328 | if (!capable(CAP_NET_ADMIN)) { | ||
329 | error = -EPERM; | ||
330 | goto done; | ||
331 | } | ||
332 | /* fall through */ | ||
333 | case ATM_GETSTAT: | ||
334 | size = sizeof(struct atm_dev_stats); | ||
335 | error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); | ||
336 | if (error) | ||
337 | goto done; | ||
338 | break; | ||
339 | case ATM_GETCIRANGE: | ||
340 | size = sizeof(struct atm_cirange); | ||
341 | if (copy_to_user(buf, &dev->ci_range, size)) { | ||
342 | error = -EFAULT; | ||
343 | goto done; | ||
344 | } | ||
345 | break; | ||
346 | case ATM_GETLINKRATE: | ||
347 | size = sizeof(int); | ||
348 | if (copy_to_user(buf, &dev->link_rate, size)) { | ||
349 | error = -EFAULT; | ||
350 | goto done; | ||
351 | } | ||
352 | break; | ||
353 | case ATM_RSTADDR: | ||
354 | if (!capable(CAP_NET_ADMIN)) { | ||
355 | error = -EPERM; | ||
356 | goto done; | ||
357 | } | ||
358 | atm_reset_addr(dev, ATM_ADDR_LOCAL); | ||
359 | break; | ||
360 | case ATM_ADDADDR: | ||
361 | case ATM_DELADDR: | ||
362 | case ATM_ADDLECSADDR: | ||
363 | case ATM_DELLECSADDR: | ||
364 | { | ||
365 | struct sockaddr_atmsvc addr; | ||
366 | |||
367 | if (!capable(CAP_NET_ADMIN)) { | ||
368 | error = -EPERM; | ||
369 | goto done; | ||
370 | } | ||
371 | |||
372 | if (copy_from_user(&addr, buf, sizeof(addr))) { | ||
373 | error = -EFAULT; | ||
374 | goto done; | ||
375 | } | ||
376 | if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) | ||
377 | error = atm_add_addr(dev, &addr, | ||
378 | (cmd == ATM_ADDADDR ? | ||
389 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | 379 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); |
390 | if (error < 0) | 380 | else |
391 | goto done; | 381 | error = atm_del_addr(dev, &addr, |
392 | size = error; | 382 | (cmd == ATM_DELADDR ? |
393 | /* may return 0, but later on size == 0 means "don't | 383 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); |
394 | write the length" */ | 384 | goto done; |
395 | error = put_user(size, sioc_len) | 385 | } |
396 | ? -EFAULT : 0; | 386 | case ATM_GETADDR: |
387 | case ATM_GETLECSADDR: | ||
388 | error = atm_get_addr(dev, buf, len, | ||
389 | (cmd == ATM_GETADDR ? | ||
390 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
391 | if (error < 0) | ||
392 | goto done; | ||
393 | size = error; | ||
394 | /* may return 0, but later on size == 0 means "don't | ||
395 | write the length" */ | ||
396 | error = put_user(size, sioc_len) ? -EFAULT : 0; | ||
397 | goto done; | ||
398 | case ATM_SETLOOP: | ||
399 | if (__ATM_LM_XTRMT((int) (unsigned long) buf) && | ||
400 | __ATM_LM_XTLOC((int) (unsigned long) buf) > | ||
401 | __ATM_LM_XTRMT((int) (unsigned long) buf)) { | ||
402 | error = -EINVAL; | ||
397 | goto done; | 403 | goto done; |
398 | case ATM_SETLOOP: | 404 | } |
399 | if (__ATM_LM_XTRMT((int) (unsigned long) buf) && | 405 | /* fall through */ |
400 | __ATM_LM_XTLOC((int) (unsigned long) buf) > | 406 | case ATM_SETCIRANGE: |
401 | __ATM_LM_XTRMT((int) (unsigned long) buf)) { | 407 | case SONET_GETSTATZ: |
408 | case SONET_SETDIAG: | ||
409 | case SONET_CLRDIAG: | ||
410 | case SONET_SETFRAMING: | ||
411 | if (!capable(CAP_NET_ADMIN)) { | ||
412 | error = -EPERM; | ||
413 | goto done; | ||
414 | } | ||
415 | /* fall through */ | ||
416 | default: | ||
417 | if (compat) { | ||
418 | #ifdef CONFIG_COMPAT | ||
419 | if (!dev->ops->compat_ioctl) { | ||
402 | error = -EINVAL; | 420 | error = -EINVAL; |
403 | goto done; | 421 | goto done; |
404 | } | 422 | } |
405 | /* fall through */ | 423 | size = dev->ops->compat_ioctl(dev, cmd, buf); |
406 | case ATM_SETCIRANGE: | ||
407 | case SONET_GETSTATZ: | ||
408 | case SONET_SETDIAG: | ||
409 | case SONET_CLRDIAG: | ||
410 | case SONET_SETFRAMING: | ||
411 | if (!capable(CAP_NET_ADMIN)) { | ||
412 | error = -EPERM; | ||
413 | goto done; | ||
414 | } | ||
415 | /* fall through */ | ||
416 | default: | ||
417 | if (compat) { | ||
418 | #ifdef CONFIG_COMPAT | ||
419 | if (!dev->ops->compat_ioctl) { | ||
420 | error = -EINVAL; | ||
421 | goto done; | ||
422 | } | ||
423 | size = dev->ops->compat_ioctl(dev, cmd, buf); | ||
424 | #endif | 424 | #endif |
425 | } else { | 425 | } else { |
426 | if (!dev->ops->ioctl) { | 426 | if (!dev->ops->ioctl) { |
427 | error = -EINVAL; | 427 | error = -EINVAL; |
428 | goto done; | ||
429 | } | ||
430 | size = dev->ops->ioctl(dev, cmd, buf); | ||
431 | } | ||
432 | if (size < 0) { | ||
433 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); | ||
434 | goto done; | 428 | goto done; |
435 | } | 429 | } |
430 | size = dev->ops->ioctl(dev, cmd, buf); | ||
431 | } | ||
432 | if (size < 0) { | ||
433 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); | ||
434 | goto done; | ||
435 | } | ||
436 | } | 436 | } |
437 | 437 | ||
438 | if (size) | 438 | if (size) |
439 | error = put_user(size, sioc_len) | 439 | error = put_user(size, sioc_len) ? -EFAULT : 0; |
440 | ? -EFAULT : 0; | ||
441 | else | 440 | else |
442 | error = 0; | 441 | error = 0; |
443 | done: | 442 | done: |
@@ -445,7 +444,7 @@ done: | |||
445 | return error; | 444 | return error; |
446 | } | 445 | } |
447 | 446 | ||
448 | static __inline__ void *dev_get_idx(loff_t left) | 447 | static inline void *dev_get_idx(loff_t left) |
449 | { | 448 | { |
450 | struct list_head *p; | 449 | struct list_head *p; |
451 | 450 | ||
@@ -474,8 +473,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
474 | ? atm_devs.next : ((struct list_head *)v)->next; | 473 | ? atm_devs.next : ((struct list_head *)v)->next; |
475 | return (v == &atm_devs) ? NULL : v; | 474 | return (v == &atm_devs) ? NULL : v; |
476 | } | 475 | } |
477 | |||
478 | |||
479 | EXPORT_SYMBOL(atm_dev_register); | ||
480 | EXPORT_SYMBOL(atm_dev_deregister); | ||
481 | EXPORT_SYMBOL(atm_dev_lookup); | ||