* Process a state change from the upper layer for the given IPv4 group. * * Each socket holds a reference on the in_multi in its own ip_moptions. * The socket layer will have made the necessary updates to.the group * state, it is now up to IGMP to issue a state change report if there * has been any change between T0 (when the last state-change was issued) * and T1 (now). * * We use the IGM
| 2315 | * is called from the socket option handlers. |
| 2316 | */ |
| 2317 | int |
| 2318 | igmp_change_state(struct in_multi *inm) |
| 2319 | { |
| 2320 | struct igmp_ifsoftc *igi; |
| 2321 | struct ifnet *ifp; |
| 2322 | int error; |
| 2323 | |
| 2324 | error = 0; |
| 2325 | IN_MULTI_LOCK_ASSERT(); |
| 2326 | /* |
| 2327 | * Try to detect if the upper layer just asked us to change state |
| 2328 | * for an interface which has now gone away. |
| 2329 | */ |
| 2330 | KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__)); |
| 2331 | ifp = inm->inm_ifma->ifma_ifp; |
| 2332 | /* |
| 2333 | * Sanity check that netinet's notion of ifp is the |
| 2334 | * same as net's. |
| 2335 | */ |
| 2336 | KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); |
| 2337 | |
| 2338 | IGMP_LOCK(); |
| 2339 | |
| 2340 | igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; |
| 2341 | KASSERT(igi != NULL, ("%s: no igmp_ifsoftc for ifp %p", __func__, ifp)); |
| 2342 | |
| 2343 | /* |
| 2344 | * If we detect a state transition to or from MCAST_UNDEFINED |
| 2345 | * for this group, then we are starting or finishing an IGMP |
| 2346 | * life cycle for this group. |
| 2347 | */ |
| 2348 | if (inm->inm_st[1].iss_fmode != inm->inm_st[0].iss_fmode) { |
| 2349 | CTR3(KTR_IGMPV3, "%s: inm transition %d -> %d", __func__, |
| 2350 | inm->inm_st[0].iss_fmode, inm->inm_st[1].iss_fmode); |
| 2351 | if (inm->inm_st[0].iss_fmode == MCAST_UNDEFINED) { |
| 2352 | CTR1(KTR_IGMPV3, "%s: initial join", __func__); |
| 2353 | error = igmp_initial_join(inm, igi); |
| 2354 | goto out_locked; |
| 2355 | } else if (inm->inm_st[1].iss_fmode == MCAST_UNDEFINED) { |
| 2356 | CTR1(KTR_IGMPV3, "%s: final leave", __func__); |
| 2357 | igmp_final_leave(inm, igi); |
| 2358 | goto out_locked; |
| 2359 | } |
| 2360 | } else { |
| 2361 | CTR1(KTR_IGMPV3, "%s: filter set change", __func__); |
| 2362 | } |
| 2363 | |
| 2364 | error = igmp_handle_state_change(inm, igi); |
| 2365 | |
| 2366 | out_locked: |
| 2367 | IGMP_UNLOCK(); |
| 2368 | return (error); |
| 2369 | } |
| 2370 | |
| 2371 | /* |
| 2372 | * Perform the initial join for an IGMP group. |
no test coverage detected