View | Details | Raw Unified | Return to bug 233535 | Differences between
and this patch

Collapse All | Expand All

(-)sys/netinet6/in6_ifattach.c (-1 / +8 lines)
Lines 870-876 Link Here
870
		    ifma->ifma_protospec == NULL)
870
		    ifma->ifma_protospec == NULL)
871
			continue;
871
			continue;
872
		inm = (struct in6_multi *)ifma->ifma_protospec;
872
		inm = (struct in6_multi *)ifma->ifma_protospec;
873
		in6m_disconnect(inm);
873
		in6m_disconnect_locked(&purgeinms, inm);
874
		in6m_rele_locked(&purgeinms, inm);
874
		in6m_rele_locked(&purgeinms, inm);
875
		if (__predict_false(ifma6_restart)) {
875
		if (__predict_false(ifma6_restart)) {
876
			ifma6_restart = false;
876
			ifma6_restart = false;
Lines 882-887 Link Here
882
	IN6_MULTI_LIST_UNLOCK();
882
	IN6_MULTI_LIST_UNLOCK();
883
	IN6_MULTI_UNLOCK();
883
	IN6_MULTI_UNLOCK();
884
	in6m_release_list_deferred(&purgeinms);
884
	in6m_release_list_deferred(&purgeinms);
885
886
	/*
887
	 * Make sure all multicast deletions invoking if_ioctl() are
888
	 * completed before returning. Else we risk accessing a freed
889
	 * ifnet structure pointer.
890
	 */
891
	in6m_release_wait();
885
}
892
}
886
893
887
void
894
void
(-)sys/netinet6/in6_mcast.c (-6 / +23 lines)
Lines 585-592 Link Here
585
}
585
}
586
586
587
void
587
void
588
in6m_disconnect(struct in6_multi *inm)
588
in6m_release_wait(void)
589
{
589
{
590
	/* wait for all jobs to complete */
591
	gtaskqueue_drain_all(free_gtask.gt_taskqueue);
592
}
593
594
void
595
in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm)
596
{
590
	struct ifnet *ifp;
597
	struct ifnet *ifp;
591
	struct ifaddr *ifa;
598
	struct ifaddr *ifa;
592
	struct in6_ifaddr *ifa6;
599
	struct in6_ifaddr *ifa6;
Lines 593-602 Link Here
593
	struct in6_multi_mship *imm, *imm_tmp;
600
	struct in6_multi_mship *imm, *imm_tmp;
594
	struct ifmultiaddr *ifma, *ll_ifma;
601
	struct ifmultiaddr *ifma, *ll_ifma;
595
602
603
	IN6_MULTI_LIST_LOCK_ASSERT();
604
596
	ifp = inm->in6m_ifp;
605
	ifp = inm->in6m_ifp;
606
	if (ifp == NULL)
607
		return;		/* already called */
597
608
598
	if (ifp == NULL)
599
		return;
600
	inm->in6m_ifp = NULL;
609
	inm->in6m_ifp = NULL;
601
	IF_ADDR_WLOCK_ASSERT(ifp);
610
	IF_ADDR_WLOCK_ASSERT(ifp);
602
	ifma = inm->in6m_ifma;
611
	ifma = inm->in6m_ifma;
Lines 633-638 Link Here
633
			if (inm == imm->i6mm_maddr) {
642
			if (inm == imm->i6mm_maddr) {
634
				LIST_REMOVE(imm, i6mm_chain);
643
				LIST_REMOVE(imm, i6mm_chain);
635
				free(imm, M_IP6MADDR);
644
				free(imm, M_IP6MADDR);
645
				in6m_rele_locked(inmh, inm);
636
			}
646
			}
637
		}
647
		}
638
	}
648
	}
Lines 1324-1330 Link Here
1324
				break;
1334
				break;
1325
			}
1335
			}
1326
		}
1336
		}
1327
		in6m_disconnect(inm);
1337
		in6m_disconnect_locked(NULL, inm);
1328
		in6m_release_deferred(inm);
1338
		in6m_release_deferred(inm);
1329
		IF_ADDR_RUNLOCK(ifp);
1339
		IF_ADDR_RUNLOCK(ifp);
1330
	} else {
1340
	} else {
Lines 1413-1420 Link Here
1413
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
1423
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
1414
	if (ifp)
1424
	if (ifp)
1415
		IF_ADDR_WLOCK(ifp);
1425
		IF_ADDR_WLOCK(ifp);
1416
	if (inm->in6m_refcount == 1 && inm->in6m_ifp != NULL)
1426
1417
		in6m_disconnect(inm);
1427
	if (inm->in6m_refcount == 1) {
1428
		/*
1429
		 * When there is only one reference left, the "inm"
1430
		 * cannot be on any membership lists. It is therefore
1431
		 * safe to pass NULL to the "inmh" freelist pointer.
1432
		 */
1433
		in6m_disconnect_locked(NULL, inm);
1434
	}
1418
	in6m_release_deferred(inm);
1435
	in6m_release_deferred(inm);
1419
	if (ifp)
1436
	if (ifp)
1420
		IF_ADDR_WUNLOCK(ifp);
1437
		IF_ADDR_WUNLOCK(ifp);
(-)sys/netinet6/in6_var.h (-1 / +3 lines)
Lines 670-677 Link Here
670
	}			in6m_st[2];	/* state at t0, t1 */
670
	}			in6m_st[2];	/* state at t0, t1 */
671
};
671
};
672
672
673
void in6m_disconnect(struct in6_multi *inm);
673
void in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm);
674
extern int ifma6_restart;
674
extern int ifma6_restart;
675
675
/*
676
/*
676
 * Helper function to derive the filter mode on a source entry
677
 * Helper function to derive the filter mode on a source entry
677
 * from its internal counters. Predicates are:
678
 * from its internal counters. Predicates are:
Lines 810-815 Link Here
810
int	in6m_record_source(struct in6_multi *, const struct in6_addr *);
811
int	in6m_record_source(struct in6_multi *, const struct in6_addr *);
811
void	in6m_release_deferred(struct in6_multi *);
812
void	in6m_release_deferred(struct in6_multi *);
812
void	in6m_release_list_deferred(struct in6_multi_head *);
813
void	in6m_release_list_deferred(struct in6_multi_head *);
814
void	in6m_release_wait(void);
813
void	ip6_freemoptions(struct ip6_moptions *);
815
void	ip6_freemoptions(struct ip6_moptions *);
814
int	ip6_getmoptions(struct inpcb *, struct sockopt *);
816
int	ip6_getmoptions(struct inpcb *, struct sockopt *);
815
int	ip6_setmoptions(struct inpcb *, struct sockopt *);
817
int	ip6_setmoptions(struct inpcb *, struct sockopt *);
(-)sys/netinet6/mld6.c (-5 / +13 lines)
Lines 557-563 Link Here
557
				continue;
557
				continue;
558
			inm = (struct in6_multi *)ifma->ifma_protospec;
558
			inm = (struct in6_multi *)ifma->ifma_protospec;
559
			if (inm->in6m_state == MLD_LEAVING_MEMBER) {
559
			if (inm->in6m_state == MLD_LEAVING_MEMBER) {
560
				in6m_disconnect(inm);
560
				in6m_disconnect_locked(&inmh, inm);
561
				in6m_rele_locked(&inmh, inm);
561
				in6m_rele_locked(&inmh, inm);
562
				ifma->ifma_protospec = NULL;
562
				ifma->ifma_protospec = NULL;
563
			}
563
			}
Lines 1484-1491 Link Here
1484
	case MLD_REPORTING_MEMBER:
1484
	case MLD_REPORTING_MEMBER:
1485
		if (report_timer_expired) {
1485
		if (report_timer_expired) {
1486
			inm->in6m_state = MLD_IDLE_MEMBER;
1486
			inm->in6m_state = MLD_IDLE_MEMBER;
1487
			in6m_disconnect(inm);
1487
			in6m_disconnect_locked(inmh, inm);
1488
			in6m_rele_locked(inmh, inm);
1489
		}
1488
		}
1490
		break;
1489
		break;
1491
	case MLD_G_QUERY_PENDING_MEMBER:
1490
	case MLD_G_QUERY_PENDING_MEMBER:
Lines 1609-1615 Link Here
1609
			if (inm->in6m_state == MLD_LEAVING_MEMBER &&
1608
			if (inm->in6m_state == MLD_LEAVING_MEMBER &&
1610
			    inm->in6m_scrv == 0) {
1609
			    inm->in6m_scrv == 0) {
1611
				inm->in6m_state = MLD_NOT_MEMBER;
1610
				inm->in6m_state = MLD_NOT_MEMBER;
1612
				in6m_disconnect(inm);
1611
				in6m_disconnect_locked(inmh, inm);
1613
				in6m_rele_locked(inmh, inm);
1612
				in6m_rele_locked(inmh, inm);
1614
			}
1613
			}
1615
		}
1614
		}
Lines 1700-1706 Link Here
1700
			 * version, we need to release the final
1699
			 * version, we need to release the final
1701
			 * reference held for issuing the INCLUDE {}.
1700
			 * reference held for issuing the INCLUDE {}.
1702
			 */
1701
			 */
1703
			in6m_disconnect(inm);
1702
			in6m_disconnect_locked(&inmh, inm);
1704
			in6m_rele_locked(&inmh, inm);
1703
			in6m_rele_locked(&inmh, inm);
1705
			ifma->ifma_protospec = NULL;
1704
			ifma->ifma_protospec = NULL;
1706
			/* FALLTHROUGH */
1705
			/* FALLTHROUGH */
Lines 1895-1900 Link Here
1895
	error = 0;
1894
	error = 0;
1896
1895
1897
	/*
1896
	/*
1897
	 * Check if the in6_multi has already been disconnected.
1898
	 */
1899
	if (inm->in6m_ifp == NULL) {
1900
	  	CTR1(KTR_MLD, "%s: inm is disconnected", __func__);
1901
		return (0);
1902
	}
1903
1904
	/*
1898
	 * Try to detect if the upper layer just asked us to change state
1905
	 * Try to detect if the upper layer just asked us to change state
1899
	 * for an interface which has now gone away.
1906
	 * for an interface which has now gone away.
1900
	 */
1907
	 */
Lines 2004-2009 Link Here
2004
		if (mli->mli_version == MLD_VERSION_2 &&
2011
		if (mli->mli_version == MLD_VERSION_2 &&
2005
		    inm->in6m_state == MLD_LEAVING_MEMBER) {
2012
		    inm->in6m_state == MLD_LEAVING_MEMBER) {
2006
			inm->in6m_refcount--;
2013
			inm->in6m_refcount--;
2014
			MPASS(inm->in6m_refcount > 0);
2007
		}
2015
		}
2008
		inm->in6m_state = MLD_REPORTING_MEMBER;
2016
		inm->in6m_state = MLD_REPORTING_MEMBER;
2009
2017

Return to bug 233535