* Provide list of interface cloners to userspace. */
| 476 | * Provide list of interface cloners to userspace. |
| 477 | */ |
| 478 | int |
| 479 | if_clone_list(struct if_clonereq *ifcr) |
| 480 | { |
| 481 | char *buf, *dst, *outbuf = NULL; |
| 482 | struct if_clone *ifc; |
| 483 | int buf_count, count, err = 0; |
| 484 | |
| 485 | if (ifcr->ifcr_count < 0) |
| 486 | return (EINVAL); |
| 487 | |
| 488 | IF_CLONERS_LOCK(); |
| 489 | /* |
| 490 | * Set our internal output buffer size. We could end up not |
| 491 | * reporting a cloner that is added between the unlock and lock |
| 492 | * below, but that's not a major problem. Not caping our |
| 493 | * allocation to the number of cloners actually in the system |
| 494 | * could be because that would let arbitrary users cause us to |
| 495 | * allocate arbitrary amounts of kernel memory. |
| 496 | */ |
| 497 | buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? |
| 498 | V_if_cloners_count : ifcr->ifcr_count; |
| 499 | IF_CLONERS_UNLOCK(); |
| 500 | |
| 501 | outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); |
| 502 | |
| 503 | IF_CLONERS_LOCK(); |
| 504 | |
| 505 | ifcr->ifcr_total = V_if_cloners_count; |
| 506 | if ((dst = ifcr->ifcr_buffer) == NULL) { |
| 507 | /* Just asking how many there are. */ |
| 508 | goto done; |
| 509 | } |
| 510 | count = (V_if_cloners_count < buf_count) ? |
| 511 | V_if_cloners_count : buf_count; |
| 512 | |
| 513 | for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; |
| 514 | ifc != NULL && count != 0; |
| 515 | ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { |
| 516 | strlcpy(buf, ifc->ifc_name, IFNAMSIZ); |
| 517 | } |
| 518 | |
| 519 | done: |
| 520 | IF_CLONERS_UNLOCK(); |
| 521 | if (err == 0 && dst != NULL) |
| 522 | err = copyout(outbuf, dst, buf_count*IFNAMSIZ); |
| 523 | if (outbuf != NULL) |
| 524 | free(outbuf, M_CLONE); |
| 525 | return (err); |
| 526 | } |
| 527 | |
| 528 | /* |
| 529 | * if_clone_findifc() looks up ifnet from the current |