* Find and return a reference to an in6_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 IN6_MULTI lock is held across the call. * Return 0 if successful, otherwise return an appropriate error code. */
| 354 | * Return 0 if successful, otherwise return an appropriate error code. |
| 355 | */ |
| 356 | static int |
| 357 | in6_getmulti(struct ifnet *ifp, const struct in6_addr *group, |
| 358 | struct in6_multi **pinm) |
| 359 | { |
| 360 | struct epoch_tracker et; |
| 361 | struct sockaddr_in6 gsin6; |
| 362 | struct ifmultiaddr *ifma; |
| 363 | struct in6_multi *inm; |
| 364 | int error; |
| 365 | |
| 366 | error = 0; |
| 367 | |
| 368 | /* |
| 369 | * XXX: Accesses to ifma_protospec must be covered by IF_ADDR_LOCK; |
| 370 | * if_addmulti() takes this mutex itself, so we must drop and |
| 371 | * re-acquire around the call. |
| 372 | */ |
| 373 | IN6_MULTI_LOCK_ASSERT(); |
| 374 | IN6_MULTI_LIST_LOCK(); |
| 375 | IF_ADDR_WLOCK(ifp); |
| 376 | NET_EPOCH_ENTER(et); |
| 377 | inm = in6m_lookup_locked(ifp, group); |
| 378 | NET_EPOCH_EXIT(et); |
| 379 | |
| 380 | if (inm != NULL) { |
| 381 | /* |
| 382 | * If we already joined this group, just bump the |
| 383 | * refcount and return it. |
| 384 | */ |
| 385 | KASSERT(inm->in6m_refcount >= 1, |
| 386 | ("%s: bad refcount %d", __func__, inm->in6m_refcount)); |
| 387 | in6m_acquire_locked(inm); |
| 388 | *pinm = inm; |
| 389 | goto out_locked; |
| 390 | } |
| 391 | |
| 392 | memset(&gsin6, 0, sizeof(gsin6)); |
| 393 | gsin6.sin6_family = AF_INET6; |
| 394 | gsin6.sin6_len = sizeof(struct sockaddr_in6); |
| 395 | gsin6.sin6_addr = *group; |
| 396 | |
| 397 | /* |
| 398 | * Check if a link-layer group is already associated |
| 399 | * with this network-layer group on the given ifnet. |
| 400 | */ |
| 401 | IN6_MULTI_LIST_UNLOCK(); |
| 402 | IF_ADDR_WUNLOCK(ifp); |
| 403 | error = if_addmulti(ifp, (struct sockaddr *)&gsin6, &ifma); |
| 404 | if (error != 0) |
| 405 | return (error); |
| 406 | IN6_MULTI_LIST_LOCK(); |
| 407 | IF_ADDR_WLOCK(ifp); |
| 408 | |
| 409 | /* |
| 410 | * If something other than netinet6 is occupying the link-layer |
| 411 | * group, print a meaningful error message and back out of |
| 412 | * the allocation. |
| 413 | * Otherwise, bump the refcount on the existing network-layer |
no test coverage detected