* Perform the final leave for an IGMP group. * * When leaving a group: * IGMPv1 does nothing. * IGMPv2 sends a host leave message, if and only if we are the reporter. * IGMPv3 enqueues a state-change report containing a transition * to INCLUDE {} for immediate transmission. */
| 2565 | * to INCLUDE {} for immediate transmission. |
| 2566 | */ |
| 2567 | static void |
| 2568 | igmp_final_leave(struct in_multi *inm, struct igmp_ifsoftc *igi) |
| 2569 | { |
| 2570 | int syncstates; |
| 2571 | |
| 2572 | syncstates = 1; |
| 2573 | |
| 2574 | CTR4(KTR_IGMPV3, "%s: final leave 0x%08x on ifp %p(%s)", |
| 2575 | __func__, ntohl(inm->inm_addr.s_addr), inm->inm_ifp, |
| 2576 | inm->inm_ifp->if_xname); |
| 2577 | |
| 2578 | IN_MULTI_LIST_LOCK_ASSERT(); |
| 2579 | IGMP_LOCK_ASSERT(); |
| 2580 | |
| 2581 | switch (inm->inm_state) { |
| 2582 | case IGMP_NOT_MEMBER: |
| 2583 | case IGMP_SILENT_MEMBER: |
| 2584 | case IGMP_LEAVING_MEMBER: |
| 2585 | /* Already leaving or left; do nothing. */ |
| 2586 | CTR1(KTR_IGMPV3, |
| 2587 | "%s: not kicking state machine for silent group", __func__); |
| 2588 | break; |
| 2589 | case IGMP_REPORTING_MEMBER: |
| 2590 | case IGMP_IDLE_MEMBER: |
| 2591 | case IGMP_G_QUERY_PENDING_MEMBER: |
| 2592 | case IGMP_SG_QUERY_PENDING_MEMBER: |
| 2593 | if (igi->igi_version == IGMP_VERSION_2) { |
| 2594 | #ifdef INVARIANTS |
| 2595 | if (inm->inm_state == IGMP_G_QUERY_PENDING_MEMBER || |
| 2596 | inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER) |
| 2597 | panic("%s: IGMPv3 state reached, not IGMPv3 mode", |
| 2598 | __func__); |
| 2599 | #endif |
| 2600 | igmp_v1v2_queue_report(inm, IGMP_HOST_LEAVE_MESSAGE); |
| 2601 | inm->inm_state = IGMP_NOT_MEMBER; |
| 2602 | } else if (igi->igi_version == IGMP_VERSION_3) { |
| 2603 | /* |
| 2604 | * Stop group timer and all pending reports. |
| 2605 | * Immediately enqueue a state-change report |
| 2606 | * TO_IN {} to be sent on the next fast timeout, |
| 2607 | * giving us an opportunity to merge reports. |
| 2608 | */ |
| 2609 | mbufq_drain(&inm->inm_scq); |
| 2610 | inm->inm_timer = 0; |
| 2611 | if (igi->igi_flags & IGIF_LOOPBACK) { |
| 2612 | inm->inm_scrv = 1; |
| 2613 | } else { |
| 2614 | inm->inm_scrv = igi->igi_rv; |
| 2615 | } |
| 2616 | CTR4(KTR_IGMPV3, "%s: Leaving 0x%08x/%s with %d " |
| 2617 | "pending retransmissions.", __func__, |
| 2618 | ntohl(inm->inm_addr.s_addr), |
| 2619 | inm->inm_ifp->if_xname, inm->inm_scrv); |
| 2620 | if (inm->inm_scrv == 0) { |
| 2621 | inm->inm_state = IGMP_NOT_MEMBER; |
| 2622 | inm->inm_sctimer = 0; |
| 2623 | } else { |
| 2624 | int retval __unused; |
no test coverage detected