* Leave a multicast group; real entry point. * All source filters will be expunged. * * Only preserves atomicity at inm level. * * Holding the write lock for the INP which contains imf * is highly advisable. We can't assert for it as imf does not * contain a back-pointer to the owning inp. * * Note: This is not the same as in6m_release(*) as this function also * makes a state change down
| 1322 | * makes a state change downcall into MLD. |
| 1323 | */ |
| 1324 | int |
| 1325 | in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) |
| 1326 | { |
| 1327 | struct in6_multi_head inmh; |
| 1328 | struct in6_mfilter timf; |
| 1329 | struct ifnet *ifp; |
| 1330 | int error; |
| 1331 | #ifdef KTR |
| 1332 | char ip6tbuf[INET6_ADDRSTRLEN]; |
| 1333 | #endif |
| 1334 | |
| 1335 | error = 0; |
| 1336 | |
| 1337 | IN6_MULTI_LOCK_ASSERT(); |
| 1338 | |
| 1339 | CTR5(KTR_MLD, "%s: leave inm %p, %s/%s, imf %p", __func__, |
| 1340 | inm, ip6_sprintf(ip6tbuf, &inm->in6m_addr), |
| 1341 | (in6m_is_ifp_detached(inm) ? "null" : if_name(inm->in6m_ifp)), |
| 1342 | imf); |
| 1343 | |
| 1344 | /* |
| 1345 | * If no imf was specified (i.e. kernel consumer), |
| 1346 | * fake one up and assume it is an ASM join. |
| 1347 | */ |
| 1348 | if (imf == NULL) { |
| 1349 | im6f_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED); |
| 1350 | imf = &timf; |
| 1351 | } |
| 1352 | |
| 1353 | /* |
| 1354 | * Begin state merge transaction at MLD layer. |
| 1355 | * |
| 1356 | * As this particular invocation should not cause any memory |
| 1357 | * to be allocated, and there is no opportunity to roll back |
| 1358 | * the transaction, it MUST NOT fail. |
| 1359 | */ |
| 1360 | |
| 1361 | ifp = inm->in6m_ifp; |
| 1362 | IN6_MULTI_LIST_LOCK(); |
| 1363 | CTR1(KTR_MLD, "%s: merge inm state", __func__); |
| 1364 | error = in6m_merge(inm, imf); |
| 1365 | KASSERT(error == 0, ("%s: failed to merge inm state", __func__)); |
| 1366 | |
| 1367 | CTR1(KTR_MLD, "%s: doing mld downcall", __func__); |
| 1368 | error = 0; |
| 1369 | if (ifp) |
| 1370 | error = mld_change_state(inm, 0); |
| 1371 | if (error) |
| 1372 | CTR1(KTR_MLD, "%s: failed mld downcall", __func__); |
| 1373 | |
| 1374 | CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm); |
| 1375 | if (ifp) |
| 1376 | IF_ADDR_WLOCK(ifp); |
| 1377 | |
| 1378 | SLIST_INIT(&inmh); |
| 1379 | if (inm->in6m_refcount == 1) |
| 1380 | in6m_disconnect_locked(&inmh, inm); |
| 1381 | in6m_rele_locked(&inmh, inm); |
no test coverage detected