* Find and return a reference to an in_multi record for (ifp, group), * and bump its reference count. * If one does not exist, try to allocate it, and update link-layer multicast * filters on ifp to listen for group. * Assumes the IN_MULTI lock is held across the call. * Return 0 if successful, otherwise return an appropriate error code. */
| 506 | * Return 0 if successful, otherwise return an appropriate error code. |
| 507 | */ |
| 508 | static int |
| 509 | in_getmulti(struct ifnet *ifp, const struct in_addr *group, |
| 510 | struct in_multi **pinm) |
| 511 | { |
| 512 | struct sockaddr_in gsin; |
| 513 | struct ifmultiaddr *ifma; |
| 514 | struct in_ifinfo *ii; |
| 515 | struct in_multi *inm; |
| 516 | int error; |
| 517 | |
| 518 | IN_MULTI_LOCK_ASSERT(); |
| 519 | |
| 520 | ii = (struct in_ifinfo *)ifp->if_afdata[AF_INET]; |
| 521 | IN_MULTI_LIST_LOCK(); |
| 522 | inm = inm_lookup(ifp, *group); |
| 523 | if (inm != NULL) { |
| 524 | /* |
| 525 | * If we already joined this group, just bump the |
| 526 | * refcount and return it. |
| 527 | */ |
| 528 | KASSERT(inm->inm_refcount >= 1, |
| 529 | ("%s: bad refcount %d", __func__, inm->inm_refcount)); |
| 530 | inm_acquire_locked(inm); |
| 531 | *pinm = inm; |
| 532 | } |
| 533 | IN_MULTI_LIST_UNLOCK(); |
| 534 | if (inm != NULL) |
| 535 | return (0); |
| 536 | |
| 537 | memset(&gsin, 0, sizeof(gsin)); |
| 538 | gsin.sin_family = AF_INET; |
| 539 | gsin.sin_len = sizeof(struct sockaddr_in); |
| 540 | gsin.sin_addr = *group; |
| 541 | |
| 542 | /* |
| 543 | * Check if a link-layer group is already associated |
| 544 | * with this network-layer group on the given ifnet. |
| 545 | */ |
| 546 | error = if_addmulti(ifp, (struct sockaddr *)&gsin, &ifma); |
| 547 | if (error != 0) |
| 548 | return (error); |
| 549 | |
| 550 | /* XXX ifma_protospec must be covered by IF_ADDR_LOCK */ |
| 551 | IN_MULTI_LIST_LOCK(); |
| 552 | IF_ADDR_WLOCK(ifp); |
| 553 | |
| 554 | /* |
| 555 | * If something other than netinet is occupying the link-layer |
| 556 | * group, print a meaningful error message and back out of |
| 557 | * the allocation. |
| 558 | * Otherwise, bump the refcount on the existing network-layer |
| 559 | * group association and return it. |
| 560 | */ |
| 561 | if (ifma->ifma_protospec != NULL) { |
| 562 | inm = (struct in_multi *)ifma->ifma_protospec; |
| 563 | #ifdef INVARIANTS |
| 564 | KASSERT(ifma->ifma_addr != NULL, ("%s: no ifma_addr", |
| 565 | __func__)); |
no test coverage detected