* Register an additional multicast address with a network interface. * * - If the address is already present, bump the reference count on the * address and return. * - If the address is not link-layer, look up a link layer address. * - Allocate address structures for one or both addresses, and attach to the * multicast address list on the interface. If automatically adding a link * l
| 3438 | * address reference, if desired. |
| 3439 | */ |
| 3440 | int |
| 3441 | if_addmulti(struct ifnet *ifp, struct sockaddr *sa, |
| 3442 | struct ifmultiaddr **retifma) |
| 3443 | { |
| 3444 | struct ifmultiaddr *ifma, *ll_ifma; |
| 3445 | struct sockaddr *llsa; |
| 3446 | struct sockaddr_dl sdl; |
| 3447 | int error; |
| 3448 | |
| 3449 | #ifdef INET |
| 3450 | IN_MULTI_LIST_UNLOCK_ASSERT(); |
| 3451 | #endif |
| 3452 | #ifdef INET6 |
| 3453 | IN6_MULTI_LIST_UNLOCK_ASSERT(); |
| 3454 | #endif |
| 3455 | /* |
| 3456 | * If the address is already present, return a new reference to it; |
| 3457 | * otherwise, allocate storage and set up a new address. |
| 3458 | */ |
| 3459 | IF_ADDR_WLOCK(ifp); |
| 3460 | ifma = if_findmulti(ifp, sa); |
| 3461 | if (ifma != NULL) { |
| 3462 | ifma->ifma_refcount++; |
| 3463 | if (retifma != NULL) |
| 3464 | *retifma = ifma; |
| 3465 | IF_ADDR_WUNLOCK(ifp); |
| 3466 | return (0); |
| 3467 | } |
| 3468 | |
| 3469 | /* |
| 3470 | * The address isn't already present; resolve the protocol address |
| 3471 | * into a link layer address, and then look that up, bump its |
| 3472 | * refcount or allocate an ifma for that also. |
| 3473 | * Most link layer resolving functions returns address data which |
| 3474 | * fits inside default sockaddr_dl structure. However callback |
| 3475 | * can allocate another sockaddr structure, in that case we need to |
| 3476 | * free it later. |
| 3477 | */ |
| 3478 | llsa = NULL; |
| 3479 | ll_ifma = NULL; |
| 3480 | if (ifp->if_resolvemulti != NULL) { |
| 3481 | /* Provide called function with buffer size information */ |
| 3482 | sdl.sdl_len = sizeof(sdl); |
| 3483 | llsa = (struct sockaddr *)&sdl; |
| 3484 | error = ifp->if_resolvemulti(ifp, &llsa, sa); |
| 3485 | if (error) |
| 3486 | goto unlock_out; |
| 3487 | } |
| 3488 | |
| 3489 | /* |
| 3490 | * Allocate the new address. Don't hook it up yet, as we may also |
| 3491 | * need to allocate a link layer multicast address. |
| 3492 | */ |
| 3493 | ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT); |
| 3494 | if (ifma == NULL) { |
| 3495 | error = ENOMEM; |
| 3496 | goto free_llsa_out; |
| 3497 | } |
no test coverage detected