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

Collapse All | Expand All

(-)sys/netinet6/in6_ifattach.c (-25 / +11 lines)
Lines 854-889 Link Here
854
static void
854
static void
855
in6_purgemaddrs(struct ifnet *ifp)
855
in6_purgemaddrs(struct ifnet *ifp)
856
{
856
{
857
	struct in6_multi_head	 purgeinms;
857
	struct in6_multi_head inmh;
858
	struct in6_multi	*inm;
859
	struct ifmultiaddr	*ifma, *next;
860
858
861
	SLIST_INIT(&purgeinms);
859
	SLIST_INIT(&inmh);
862
	IN6_MULTI_LOCK();
860
	IN6_MULTI_LOCK();
863
	IN6_MULTI_LIST_LOCK();
861
	IN6_MULTI_LIST_LOCK();
864
	IF_ADDR_WLOCK(ifp);
862
	mld_ifdetach(ifp, &inmh);
863
	IN6_MULTI_LIST_UNLOCK();
864
	IN6_MULTI_UNLOCK();
865
	in6m_release_list_deferred(&inmh);
866
865
	/*
867
	/*
866
	 * Extract list of in6_multi associated with the detaching ifp
868
	 * Make sure all multicast deletions invoking if_ioctl() are
867
	 * which the PF_INET6 layer is about to release.
869
	 * completed before returning. Else we risk accessing a freed
870
	 * ifnet structure pointer.
868
	 */
871
	 */
869
 restart:
872
	in6m_release_wait();
870
	CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
871
		if (ifma->ifma_addr->sa_family != AF_INET6 ||
872
		    ifma->ifma_protospec == NULL)
873
			continue;
874
		inm = (struct in6_multi *)ifma->ifma_protospec;
875
		in6m_disconnect(inm);
876
		in6m_rele_locked(&purgeinms, inm);
877
		if (__predict_false(ifma6_restart)) {
878
			ifma6_restart = false;
879
			goto restart;
880
		}
881
	}
882
	IF_ADDR_WUNLOCK(ifp);
883
	mld_ifdetach(ifp);
884
	IN6_MULTI_LIST_UNLOCK();
885
	IN6_MULTI_UNLOCK();
886
	in6m_release_list_deferred(&purgeinms);
887
}
873
}
888
874
889
void
875
void
(-)sys/netinet6/in6_mcast.c (-35 / +39 lines)
Lines 190-196 Link Here
190
    CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip6_mcast_filters,
190
    CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip6_mcast_filters,
191
    "Per-interface stack-wide source filters");
191
    "Per-interface stack-wide source filters");
192
192
193
int ifma6_restart = 0;
194
#ifdef KTR
193
#ifdef KTR
195
/*
194
/*
196
 * Inline function which wraps assertions for a valid ifp.
195
 * Inline function which wraps assertions for a valid ifp.
Lines 405-410 Link Here
405
in6_getmulti(struct ifnet *ifp, const struct in6_addr *group,
404
in6_getmulti(struct ifnet *ifp, const struct in6_addr *group,
406
    struct in6_multi **pinm)
405
    struct in6_multi **pinm)
407
{
406
{
407
	struct epoch_tracker	 et;
408
	struct sockaddr_in6	 gsin6;
408
	struct sockaddr_in6	 gsin6;
409
	struct ifmultiaddr	*ifma;
409
	struct ifmultiaddr	*ifma;
410
	struct in6_multi	*inm;
410
	struct in6_multi	*inm;
Lines 420-426 Link Here
420
	IN6_MULTI_LOCK_ASSERT();
420
	IN6_MULTI_LOCK_ASSERT();
421
	IN6_MULTI_LIST_LOCK();
421
	IN6_MULTI_LIST_LOCK();
422
	IF_ADDR_WLOCK(ifp);
422
	IF_ADDR_WLOCK(ifp);
423
	NET_EPOCH_ENTER(et);
423
	inm = in6m_lookup_locked(ifp, group);
424
	inm = in6m_lookup_locked(ifp, group);
425
	NET_EPOCH_EXIT(et);
426
424
	if (inm != NULL) {
427
	if (inm != NULL) {
425
		/*
428
		/*
426
		 * If we already joined this group, just bump the
429
		 * If we already joined this group, just bump the
Lines 572-578 Link Here
572
	in6m_init, NULL);
575
	in6m_init, NULL);
573
#endif
576
#endif
574
577
575
576
void
578
void
577
in6m_release_list_deferred(struct in6_multi_head *inmh)
579
in6m_release_list_deferred(struct in6_multi_head *inmh)
578
{
580
{
Lines 585-592 Link Here
585
}
587
}
586
588
587
void
589
void
588
in6m_disconnect(struct in6_multi *inm)
590
in6m_release_wait(void)
589
{
591
{
592
	/* wait for all jobs to complete */
593
	gtaskqueue_drain_all(free_gtask.gt_taskqueue);
594
}
595
596
void
597
in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm)
598
{
590
	struct ifnet *ifp;
599
	struct ifnet *ifp;
591
	struct ifaddr *ifa;
600
	struct ifaddr *ifa;
592
	struct in6_ifaddr *ifa6;
601
	struct in6_ifaddr *ifa6;
Lines 593-602 Link Here
593
	struct in6_multi_mship *imm, *imm_tmp;
602
	struct in6_multi_mship *imm, *imm_tmp;
594
	struct ifmultiaddr *ifma, *ll_ifma;
603
	struct ifmultiaddr *ifma, *ll_ifma;
595
604
605
	IN6_MULTI_LIST_LOCK_ASSERT();
606
596
	ifp = inm->in6m_ifp;
607
	ifp = inm->in6m_ifp;
608
	if (ifp == NULL)
609
		return;		/* already called */
597
610
598
	if (ifp == NULL)
599
		return;
600
	inm->in6m_ifp = NULL;
611
	inm->in6m_ifp = NULL;
601
	IF_ADDR_WLOCK_ASSERT(ifp);
612
	IF_ADDR_WLOCK_ASSERT(ifp);
602
	ifma = inm->in6m_ifma;
613
	ifma = inm->in6m_ifma;
Lines 615-621 Link Here
615
		MPASS(ll_ifma->ifma_llifma == NULL);
626
		MPASS(ll_ifma->ifma_llifma == NULL);
616
		MPASS(ll_ifma->ifma_ifp == ifp);
627
		MPASS(ll_ifma->ifma_ifp == ifp);
617
		if (--ll_ifma->ifma_refcount == 0) {
628
		if (--ll_ifma->ifma_refcount == 0) {
618
			ifma6_restart = true;
619
			if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
629
			if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
620
				CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
630
				CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
621
				ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
631
				ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
Lines 633-660 Link Here
633
			if (inm == imm->i6mm_maddr) {
643
			if (inm == imm->i6mm_maddr) {
634
				LIST_REMOVE(imm, i6mm_chain);
644
				LIST_REMOVE(imm, i6mm_chain);
635
				free(imm, M_IP6MADDR);
645
				free(imm, M_IP6MADDR);
646
				in6m_rele_locked(inmh, inm);
636
			}
647
			}
637
		}
648
		}
638
	}
649
	}
639
}
650
}
640
651
641
void
642
in6m_release_deferred(struct in6_multi *inm)
643
{
644
	struct in6_multi_head tmp;
645
646
	IN6_MULTI_LIST_LOCK_ASSERT();
647
	KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm));
648
	if (--inm->in6m_refcount == 0) {
649
		MPASS(inm->in6m_ifp == NULL);
650
		SLIST_INIT(&tmp);
651
		inm->in6m_ifma->ifma_protospec = NULL;
652
		MPASS(inm->in6m_ifma->ifma_llifma == NULL);
653
		SLIST_INSERT_HEAD(&tmp, inm, in6m_nrele);
654
		in6m_release_list_deferred(&tmp);
655
	}
656
}
657
658
static void
652
static void
659
in6m_release_task(void *arg __unused)
653
in6m_release_task(void *arg __unused)
660
{
654
{
Lines 1254-1259 Link Here
1254
    /*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
1248
    /*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
1255
    const int delay)
1249
    const int delay)
1256
{
1250
{
1251
	struct in6_multi_head    inmh;
1257
	struct in6_mfilter	 timf;
1252
	struct in6_mfilter	 timf;
1258
	struct in6_multi	*inm;
1253
	struct in6_multi	*inm;
1259
	struct ifmultiaddr *ifma;
1254
	struct ifmultiaddr *ifma;
Lines 1261-1266 Link Here
1261
#ifdef KTR
1256
#ifdef KTR
1262
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1257
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1263
#endif
1258
#endif
1259
	SLIST_INIT(&inmh);
1264
1260
1265
	/*
1261
	/*
1266
	 * Sanity: Check scope zone ID was set for ifp, if and
1262
	 * Sanity: Check scope zone ID was set for ifp, if and
Lines 1324-1336 Link Here
1324
				break;
1320
				break;
1325
			}
1321
			}
1326
		}
1322
		}
1327
		in6m_disconnect(inm);
1323
		in6m_disconnect_locked(&inmh, inm);
1328
		in6m_release_deferred(inm);
1324
		in6m_rele_locked(&inmh, inm);
1329
		NET_EPOCH_EXIT(et);
1325
		NET_EPOCH_EXIT(et);
1330
	} else {
1326
	} else {
1331
		*pinm = inm;
1327
		*pinm = inm;
1332
	}
1328
	}
1333
	IN6_MULTI_LIST_UNLOCK();
1329
	IN6_MULTI_LIST_UNLOCK();
1330
	in6m_release_list_deferred(&inmh);
1334
	return (error);
1331
	return (error);
1335
}
1332
}
1336
1333
Lines 1364-1369 Link Here
1364
int
1361
int
1365
in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
1362
in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
1366
{
1363
{
1364
	struct in6_multi_head	 inmh;
1367
	struct in6_mfilter	 timf;
1365
	struct in6_mfilter	 timf;
1368
	struct ifnet *ifp;
1366
	struct ifnet *ifp;
1369
	int			 error;
1367
	int			 error;
Lines 1371-1376 Link Here
1371
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1369
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1372
#endif
1370
#endif
1373
1371
1372
	SLIST_INIT(&inmh);
1374
	error = 0;
1373
	error = 0;
1375
1374
1376
	IN6_MULTI_LOCK_ASSERT();
1375
	IN6_MULTI_LOCK_ASSERT();
Lines 1413-1429 Link Here
1413
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
1412
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
1414
	if (ifp)
1413
	if (ifp)
1415
		IF_ADDR_WLOCK(ifp);
1414
		IF_ADDR_WLOCK(ifp);
1416
	if (inm->in6m_refcount == 1 && inm->in6m_ifp != NULL)
1415
1417
		in6m_disconnect(inm);
1416
	if (inm->in6m_refcount == 1)
1418
	in6m_release_deferred(inm);
1417
		in6m_disconnect_locked(&inmh, inm);
1418
	in6m_rele_locked(&inmh, inm);
1419
	if (ifp)
1419
	if (ifp)
1420
		IF_ADDR_WUNLOCK(ifp);
1420
		IF_ADDR_WUNLOCK(ifp);
1421
	IN6_MULTI_LIST_UNLOCK();
1421
	IN6_MULTI_LIST_UNLOCK();
1422
1422
	in6m_release_list_deferred(&inmh);
1423
	return (error);
1423
	return (error);
1424
}
1424
}
1425
1425
1426
1427
/*
1426
/*
1428
 * Block or unblock an ASM multicast source on an inpcb.
1427
 * Block or unblock an ASM multicast source on an inpcb.
1429
 * This implements the delta-based API described in RFC 3678.
1428
 * This implements the delta-based API described in RFC 3678.
Lines 1933-1938 Link Here
1933
static int
1932
static int
1934
in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
1933
in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
1935
{
1934
{
1935
	struct in6_multi_head		 inmh;
1936
	struct group_source_req		 gsr;
1936
	struct group_source_req		 gsr;
1937
	sockunion_t			*gsa, *ssa;
1937
	sockunion_t			*gsa, *ssa;
1938
	struct ifnet			*ifp;
1938
	struct ifnet			*ifp;
Lines 1943-1948 Link Here
1943
	size_t				 idx;
1943
	size_t				 idx;
1944
	int				 error, is_new;
1944
	int				 error, is_new;
1945
1945
1946
	SLIST_INIT(&inmh);
1946
	ifp = NULL;
1947
	ifp = NULL;
1947
	imf = NULL;
1948
	imf = NULL;
1948
	lims = NULL;
1949
	lims = NULL;
Lines 2178-2184 Link Here
2178
			IN6_MULTI_UNLOCK();
2179
			IN6_MULTI_UNLOCK();
2179
			goto out_im6o_free;
2180
			goto out_im6o_free;
2180
		}
2181
		}
2181
		in6m_acquire(inm);
2182
		/*
2183
		 * NOTE: Refcount from in6_joingroup_locked()
2184
		 * is protecting membership.
2185
		 */
2182
		imo->im6o_membership[idx] = inm;
2186
		imo->im6o_membership[idx] = inm;
2183
	} else {
2187
	} else {
2184
		CTR1(KTR_MLD, "%s: merge inm state", __func__);
2188
		CTR1(KTR_MLD, "%s: merge inm state", __func__);
Lines 2216-2222 Link Here
2216
		inm = imo->im6o_membership[idx];
2220
		inm = imo->im6o_membership[idx];
2217
		if (inm != NULL) {
2221
		if (inm != NULL) {
2218
			IN6_MULTI_LIST_LOCK();
2222
			IN6_MULTI_LIST_LOCK();
2219
			in6m_release_deferred(inm);
2223
			in6m_rele_locked(&inmh, inm);
2220
			IN6_MULTI_LIST_UNLOCK();
2224
			IN6_MULTI_LIST_UNLOCK();
2221
		}
2225
		}
2222
		imo->im6o_membership[idx] = NULL;
2226
		imo->im6o_membership[idx] = NULL;
Lines 2225-2230 Link Here
2225
2229
2226
out_in6p_locked:
2230
out_in6p_locked:
2227
	INP_WUNLOCK(inp);
2231
	INP_WUNLOCK(inp);
2232
	in6m_release_list_deferred(&inmh);
2228
	return (error);
2233
	return (error);
2229
}
2234
}
2230
2235
Lines 2869-2878 Link Here
2869
	IN6_MULTI_LIST_LOCK();
2874
	IN6_MULTI_LIST_LOCK();
2870
	NET_EPOCH_ENTER(et);
2875
	NET_EPOCH_ENTER(et);
2871
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2876
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2872
		if (ifma->ifma_addr->sa_family != AF_INET6 ||
2877
		inm = in6m_ifmultiaddr_get_inm(ifma);
2873
		    ifma->ifma_protospec == NULL)
2878
		if (inm == NULL)
2874
			continue;
2879
			continue;
2875
		inm = (struct in6_multi *)ifma->ifma_protospec;
2876
		if (!IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &mcaddr))
2880
		if (!IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &mcaddr))
2877
			continue;
2881
			continue;
2878
		fmode = inm->in6m_st[1].iss_fmode;
2882
		fmode = inm->in6m_st[1].iss_fmode;
(-)sys/netinet6/in6_var.h (-16 / +25 lines)
Lines 645-650 Link Here
645
	/* New fields for MLDv2 follow. */
645
	/* New fields for MLDv2 follow. */
646
	struct mld_ifsoftc	*in6m_mli;	/* MLD info */
646
	struct mld_ifsoftc	*in6m_mli;	/* MLD info */
647
	SLIST_ENTRY(in6_multi)	 in6m_nrele;	/* to-be-released by MLD */
647
	SLIST_ENTRY(in6_multi)	 in6m_nrele;	/* to-be-released by MLD */
648
  	SLIST_ENTRY(in6_multi)	 in6m_defer;	/* deferred MLDv1 */
648
	struct ip6_msource_tree	 in6m_srcs;	/* tree of sources */
649
	struct ip6_msource_tree	 in6m_srcs;	/* tree of sources */
649
	u_long			 in6m_nsrc;	/* # of tree entries */
650
	u_long			 in6m_nsrc;	/* # of tree entries */
650
651
Lines 670-677 Link Here
670
	}			in6m_st[2];	/* state at t0, t1 */
671
	}			in6m_st[2];	/* state at t0, t1 */
671
};
672
};
672
673
673
void in6m_disconnect(struct in6_multi *inm);
674
void in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm);
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 713-725 Link Here
713
#define	IN6_MULTI_LOCK_ASSERT()	sx_assert(&in6_multi_sx, SA_XLOCKED)
714
#define	IN6_MULTI_LOCK_ASSERT()	sx_assert(&in6_multi_sx, SA_XLOCKED)
714
#define	IN6_MULTI_UNLOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XUNLOCKED)
715
#define	IN6_MULTI_UNLOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XUNLOCKED)
715
716
717
/*
718
 * Get the in6_multi pointer from a ifmultiaddr.
719
 * Returns NULL if ifmultiaddr is no longer valid.
720
 */
721
static __inline struct in6_multi *
722
in6m_ifmultiaddr_get_inm(struct ifmultiaddr *ifma)
723
{
716
724
725
	NET_EPOCH_ASSERT();
726
727
	return ((ifma->ifma_addr->sa_family != AF_INET6 ||	
728
	    (ifma->ifma_flags & IFMA_F_ENQUEUED) == 0) ? NULL :
729
	    ifma->ifma_protospec);
730
}
731
717
/*
732
/*
718
 * Look up an in6_multi record for an IPv6 multicast address
733
 * Look up an in6_multi record for an IPv6 multicast address
719
 * on the interface ifp.
734
 * on the interface ifp.
720
 * If no record found, return NULL.
735
 * If no record found, return NULL.
721
 *
722
 * SMPng: The IN6_MULTI_LOCK and IF_ADDR_LOCK on ifp must be held.
723
 */
736
 */
724
static __inline struct in6_multi *
737
static __inline struct in6_multi *
725
in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr)
738
in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr)
Lines 727-744 Link Here
727
	struct ifmultiaddr *ifma;
740
	struct ifmultiaddr *ifma;
728
	struct in6_multi *inm;
741
	struct in6_multi *inm;
729
742
730
	inm = NULL;
743
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
731
	CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
744
		inm = in6m_ifmultiaddr_get_inm(ifma);
732
		if (ifma->ifma_addr->sa_family == AF_INET6) {
745
		if (inm == NULL)
733
			inm = (struct in6_multi *)ifma->ifma_protospec;
746
			continue;
734
			if (inm == NULL)
747
		if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr))
735
				continue;
748
			return (inm);
736
			if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr))
737
				break;
738
			inm = NULL;
739
		}
740
	}
749
	}
741
	return (inm);
750
	return (NULL);
742
}
751
}
743
752
744
/*
753
/*
Lines 809-816 Link Here
809
void	in6m_commit(struct in6_multi *);
818
void	in6m_commit(struct in6_multi *);
810
void	in6m_print(const struct in6_multi *);
819
void	in6m_print(const struct in6_multi *);
811
int	in6m_record_source(struct in6_multi *, const struct in6_addr *);
820
int	in6m_record_source(struct in6_multi *, const struct in6_addr *);
812
void	in6m_release_deferred(struct in6_multi *);
813
void	in6m_release_list_deferred(struct in6_multi_head *);
821
void	in6m_release_list_deferred(struct in6_multi_head *);
822
void	in6m_release_wait(void);
814
void	ip6_freemoptions(struct ip6_moptions *);
823
void	ip6_freemoptions(struct ip6_moptions *);
815
int	ip6_getmoptions(struct inpcb *, struct sockopt *);
824
int	ip6_getmoptions(struct inpcb *, struct sockopt *);
816
int	ip6_setmoptions(struct inpcb *, struct sockopt *);
825
int	ip6_setmoptions(struct inpcb *, struct sockopt *);
(-)sys/netinet6/mld6.c (-74 / +80 lines)
Lines 110-116 Link Here
110
static void	mld_dispatch_packet(struct mbuf *);
110
static void	mld_dispatch_packet(struct mbuf *);
111
static void	mld_dispatch_queue(struct mbufq *, int);
111
static void	mld_dispatch_queue(struct mbufq *, int);
112
static void	mld_final_leave(struct in6_multi *, struct mld_ifsoftc *);
112
static void	mld_final_leave(struct in6_multi *, struct mld_ifsoftc *);
113
static void	mld_fasttimo_vnet(void);
113
static void	mld_fasttimo_vnet(struct in6_multi_head *inmh);
114
static int	mld_handle_state_change(struct in6_multi *,
114
static int	mld_handle_state_change(struct in6_multi *,
115
		    struct mld_ifsoftc *);
115
		    struct mld_ifsoftc *);
116
static int	mld_initial_join(struct in6_multi *, struct mld_ifsoftc *,
116
static int	mld_initial_join(struct in6_multi *, struct mld_ifsoftc *,
Lines 243-248 Link Here
243
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN,
243
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN,
244
    &mld_v1enable, 0, "Enable fallback to MLDv1");
244
    &mld_v1enable, 0, "Enable fallback to MLDv1");
245
245
246
static int	mld_v2enable = 1;
247
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_RWTUN,
248
    &mld_v2enable, 0, "Enable MLDv2");
249
246
static int	mld_use_allow = 1;
250
static int	mld_use_allow = 1;
247
SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN,
251
SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN,
248
    &mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
252
    &mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
Lines 533-577 Link Here
533
 * XXX This routine is also bitten by unlocked ifma_protospec access.
537
 * XXX This routine is also bitten by unlocked ifma_protospec access.
534
 */
538
 */
535
void
539
void
536
mld_ifdetach(struct ifnet *ifp)
540
mld_ifdetach(struct ifnet *ifp, struct in6_multi_head *inmh)
537
{
541
{
542
	struct epoch_tracker     et;
538
	struct mld_ifsoftc	*mli;
543
	struct mld_ifsoftc	*mli;
539
	struct ifmultiaddr	*ifma, *next;
544
	struct ifmultiaddr	*ifma;
540
	struct in6_multi	*inm;
545
	struct in6_multi	*inm;
541
	struct in6_multi_head inmh;
542
546
543
	CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp,
547
	CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp,
544
	    if_name(ifp));
548
	    if_name(ifp));
545
549
546
	SLIST_INIT(&inmh);
547
	IN6_MULTI_LIST_LOCK_ASSERT();
550
	IN6_MULTI_LIST_LOCK_ASSERT();
548
	MLD_LOCK();
551
	MLD_LOCK();
549
552
550
	mli = MLD_IFINFO(ifp);
553
	mli = MLD_IFINFO(ifp);
551
	if (mli->mli_version == MLD_VERSION_2) {
554
	IF_ADDR_WLOCK(ifp);
552
		IF_ADDR_WLOCK(ifp);
555
	/*
553
	restart:
556
	 * Extract list of in6_multi associated with the detaching ifp
554
		CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
557
	 * which the PF_INET6 layer is about to release.
555
			if (ifma->ifma_addr->sa_family != AF_INET6 ||
558
	 */
556
			    ifma->ifma_protospec == NULL)
559
	NET_EPOCH_ENTER(et);
557
				continue;
560
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
558
			inm = (struct in6_multi *)ifma->ifma_protospec;
561
		inm = in6m_ifmultiaddr_get_inm(ifma);
562
		if (inm == NULL)
563
			continue;
564
		in6m_disconnect_locked(inmh, inm);
565
566
		if (mli->mli_version == MLD_VERSION_2) {
567
			in6m_clear_recorded(inm);
568
569
			/*
570
			 * We need to release the final reference held
571
			 * for issuing the INCLUDE {}.
572
			 */
559
			if (inm->in6m_state == MLD_LEAVING_MEMBER) {
573
			if (inm->in6m_state == MLD_LEAVING_MEMBER) {
560
				in6m_disconnect(inm);
574
				inm->in6m_state = MLD_NOT_MEMBER;
561
				in6m_rele_locked(&inmh, inm);
575
				in6m_rele_locked(inmh, inm);
562
				ifma->ifma_protospec = NULL;
563
			}
576
			}
564
			in6m_clear_recorded(inm);
565
			if (__predict_false(ifma6_restart)) {
566
				ifma6_restart = false;
567
				goto restart;
568
			}
569
		}
577
		}
570
		IF_ADDR_WUNLOCK(ifp);
571
	}
578
	}
572
579
	NET_EPOCH_EXIT(et);
580
	IF_ADDR_WUNLOCK(ifp);
573
	MLD_UNLOCK();
581
	MLD_UNLOCK();
574
	in6m_release_list_deferred(&inmh);
575
}
582
}
576
583
577
/*
584
/*
Lines 705-714 Link Here
705
		CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)",
712
		CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)",
706
			 ifp, if_name(ifp));
713
			 ifp, if_name(ifp));
707
		CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
714
		CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
708
			if (ifma->ifma_addr->sa_family != AF_INET6 ||
715
			inm = in6m_ifmultiaddr_get_inm(ifma);
709
			    ifma->ifma_protospec == NULL)
716
			if (inm == NULL)
710
				continue;
717
				continue;
711
			inm = (struct in6_multi *)ifma->ifma_protospec;
712
			mld_v1_update_group(inm, timer);
718
			mld_v1_update_group(inm, timer);
713
		}
719
		}
714
	} else {
720
	} else {
Lines 819-824 Link Here
819
825
820
	is_general_query = 0;
826
	is_general_query = 0;
821
827
828
	if (!mld_v2enable) {
829
		CTR3(KTR_MLD, "ignore v2 query %s on ifp %p(%s)",
830
		    ip6_sprintf(ip6tbuf, &mld->mld_addr),
831
		    ifp, if_name(ifp));
832
		return (0);
833
	}
834
822
	/*
835
	/*
823
	 * RFC3810 Section 6.2: MLD queries must originate from
836
	 * RFC3810 Section 6.2: MLD queries must originate from
824
	 * a router's link-local address.
837
	 * a router's link-local address.
Lines 1313-1327 Link Here
1313
void
1326
void
1314
mld_fasttimo(void)
1327
mld_fasttimo(void)
1315
{
1328
{
1329
  	struct in6_multi_head inmh;
1316
	VNET_ITERATOR_DECL(vnet_iter);
1330
	VNET_ITERATOR_DECL(vnet_iter);
1317
1331
1332
	SLIST_INIT(&inmh);
1333
	
1318
	VNET_LIST_RLOCK_NOSLEEP();
1334
	VNET_LIST_RLOCK_NOSLEEP();
1319
	VNET_FOREACH(vnet_iter) {
1335
	VNET_FOREACH(vnet_iter) {
1320
		CURVNET_SET(vnet_iter);
1336
		CURVNET_SET(vnet_iter);
1321
		mld_fasttimo_vnet();
1337
		mld_fasttimo_vnet(&inmh);
1322
		CURVNET_RESTORE();
1338
		CURVNET_RESTORE();
1323
	}
1339
	}
1324
	VNET_LIST_RUNLOCK_NOSLEEP();
1340
	VNET_LIST_RUNLOCK_NOSLEEP();
1341
	in6m_release_list_deferred(&inmh);
1325
}
1342
}
1326
1343
1327
/*
1344
/*
Lines 1330-1344 Link Here
1330
 * VIMAGE: Assume caller has set up our curvnet.
1347
 * VIMAGE: Assume caller has set up our curvnet.
1331
 */
1348
 */
1332
static void
1349
static void
1333
mld_fasttimo_vnet(void)
1350
mld_fasttimo_vnet(struct in6_multi_head *inmh)
1334
{
1351
{
1352
	struct epoch_tracker     et;
1335
	struct mbufq		 scq;	/* State-change packets */
1353
	struct mbufq		 scq;	/* State-change packets */
1336
	struct mbufq		 qrq;	/* Query response packets */
1354
	struct mbufq		 qrq;	/* Query response packets */
1337
	struct ifnet		*ifp;
1355
	struct ifnet		*ifp;
1338
	struct mld_ifsoftc	*mli;
1356
	struct mld_ifsoftc	*mli;
1339
	struct ifmultiaddr	*ifma, *next;
1357
	struct ifmultiaddr	*ifma;
1340
	struct in6_multi	*inm, *tinm;
1358
	struct in6_multi	*inm;
1341
	struct in6_multi_head inmh;
1342
	int			 uri_fasthz;
1359
	int			 uri_fasthz;
1343
1360
1344
	uri_fasthz = 0;
1361
	uri_fasthz = 0;
Lines 1353-1359 Link Here
1353
	    !V_state_change_timers_running6)
1370
	    !V_state_change_timers_running6)
1354
		return;
1371
		return;
1355
1372
1356
	SLIST_INIT(&inmh);
1357
	IN6_MULTI_LIST_LOCK();
1373
	IN6_MULTI_LIST_LOCK();
1358
	MLD_LOCK();
1374
	MLD_LOCK();
1359
1375
Lines 1399-1423 Link Here
1399
		}
1415
		}
1400
1416
1401
		IF_ADDR_WLOCK(ifp);
1417
		IF_ADDR_WLOCK(ifp);
1402
	restart:
1418
		NET_EPOCH_ENTER(et);
1403
		CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
1419
		CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1404
			if (ifma->ifma_addr->sa_family != AF_INET6 ||
1420
			inm = in6m_ifmultiaddr_get_inm(ifma);
1405
			    ifma->ifma_protospec == NULL)
1421
			if (inm == NULL)
1406
				continue;
1422
				continue;
1407
			inm = (struct in6_multi *)ifma->ifma_protospec;
1408
			switch (mli->mli_version) {
1423
			switch (mli->mli_version) {
1409
			case MLD_VERSION_1:
1424
			case MLD_VERSION_1:
1410
				mld_v1_process_group_timer(&inmh, inm);
1425
				mld_v1_process_group_timer(inmh, inm);
1411
				break;
1426
				break;
1412
			case MLD_VERSION_2:
1427
			case MLD_VERSION_2:
1413
				mld_v2_process_group_timers(&inmh, &qrq,
1428
				mld_v2_process_group_timers(inmh, &qrq,
1414
				    &scq, inm, uri_fasthz);
1429
				    &scq, inm, uri_fasthz);
1415
				break;
1430
				break;
1416
			}
1431
			}
1417
			if (__predict_false(ifma6_restart)) {
1418
				ifma6_restart = false;
1419
				goto restart;
1420
			}
1421
		}
1432
		}
1422
		IF_ADDR_WUNLOCK(ifp);
1433
		IF_ADDR_WUNLOCK(ifp);
1423
1434
Lines 1431-1439 Link Here
1431
			 * IF_ADDR_LOCK internally as well as
1442
			 * IF_ADDR_LOCK internally as well as
1432
			 * ip6_output() to transmit a packet.
1443
			 * ip6_output() to transmit a packet.
1433
			 */
1444
			 */
1434
			SLIST_FOREACH_SAFE(inm, &inmh, in6m_nrele, tinm) {
1445
			while ((inm = SLIST_FIRST(inmh)) != NULL) {
1435
				SLIST_REMOVE_HEAD(&inmh,
1446
				SLIST_REMOVE_HEAD(inmh, in6m_defer);
1436
				    in6m_nrele);
1437
				(void)mld_v1_transmit_report(inm,
1447
				(void)mld_v1_transmit_report(inm,
1438
				    MLD_LISTENER_REPORT);
1448
				    MLD_LISTENER_REPORT);
1439
			}
1449
			}
Lines 1441-1454 Link Here
1441
		case MLD_VERSION_2:
1451
		case MLD_VERSION_2:
1442
			mld_dispatch_queue(&qrq, 0);
1452
			mld_dispatch_queue(&qrq, 0);
1443
			mld_dispatch_queue(&scq, 0);
1453
			mld_dispatch_queue(&scq, 0);
1444
1445
			/*
1446
			 * Free the in_multi reference(s) for
1447
			 * this lifecycle.
1448
			 */
1449
			in6m_release_list_deferred(&inmh);
1450
			break;
1454
			break;
1451
		}
1455
		}
1456
		NET_EPOCH_EXIT(et);
1452
	}
1457
	}
1453
1458
1454
out_locked:
1459
out_locked:
Lines 1488-1495 Link Here
1488
	case MLD_REPORTING_MEMBER:
1493
	case MLD_REPORTING_MEMBER:
1489
		if (report_timer_expired) {
1494
		if (report_timer_expired) {
1490
			inm->in6m_state = MLD_IDLE_MEMBER;
1495
			inm->in6m_state = MLD_IDLE_MEMBER;
1491
			in6m_disconnect(inm);
1496
			SLIST_INSERT_HEAD(inmh, inm, in6m_defer);
1492
			in6m_rele_locked(inmh, inm);
1493
		}
1497
		}
1494
		break;
1498
		break;
1495
	case MLD_G_QUERY_PENDING_MEMBER:
1499
	case MLD_G_QUERY_PENDING_MEMBER:
Lines 1613-1619 Link Here
1613
			if (inm->in6m_state == MLD_LEAVING_MEMBER &&
1617
			if (inm->in6m_state == MLD_LEAVING_MEMBER &&
1614
			    inm->in6m_scrv == 0) {
1618
			    inm->in6m_scrv == 0) {
1615
				inm->in6m_state = MLD_NOT_MEMBER;
1619
				inm->in6m_state = MLD_NOT_MEMBER;
1616
				in6m_disconnect(inm);
1620
				in6m_disconnect_locked(inmh, inm);
1617
				in6m_rele_locked(inmh, inm);
1621
				in6m_rele_locked(inmh, inm);
1618
			}
1622
			}
1619
		}
1623
		}
Lines 1658-1667 Link Here
1658
static void
1662
static void
1659
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
1663
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
1660
{
1664
{
1661
	struct ifmultiaddr	*ifma, *next;
1665
	struct epoch_tracker	 et;
1666
	struct in6_multi_head	 inmh;
1667
	struct ifmultiaddr	*ifma;
1662
	struct ifnet		*ifp;
1668
	struct ifnet		*ifp;
1663
	struct in6_multi	*inm;
1669
	struct in6_multi	*inm;
1664
	struct in6_multi_head inmh;
1665
1670
1666
	CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__,
1671
	CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__,
1667
	    mli->mli_ifp, if_name(mli->mli_ifp));
1672
	    mli->mli_ifp, if_name(mli->mli_ifp));
Lines 1684-1695 Link Here
1684
	ifp = mli->mli_ifp;
1689
	ifp = mli->mli_ifp;
1685
1690
1686
	IF_ADDR_WLOCK(ifp);
1691
	IF_ADDR_WLOCK(ifp);
1687
 restart:
1692
	NET_EPOCH_ENTER(et);
1688
	CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
1693
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1689
		if (ifma->ifma_addr->sa_family != AF_INET6 ||
1694
		inm = in6m_ifmultiaddr_get_inm(ifma);
1690
		    ifma->ifma_protospec == NULL)
1695
		if (inm == NULL)
1691
			continue;
1696
			continue;
1692
		inm = (struct in6_multi *)ifma->ifma_protospec;
1693
		switch (inm->in6m_state) {
1697
		switch (inm->in6m_state) {
1694
		case MLD_NOT_MEMBER:
1698
		case MLD_NOT_MEMBER:
1695
		case MLD_SILENT_MEMBER:
1699
		case MLD_SILENT_MEMBER:
Lines 1704-1712 Link Here
1704
			 * version, we need to release the final
1708
			 * version, we need to release the final
1705
			 * reference held for issuing the INCLUDE {}.
1709
			 * reference held for issuing the INCLUDE {}.
1706
			 */
1710
			 */
1707
			in6m_disconnect(inm);
1708
			in6m_rele_locked(&inmh, inm);
1711
			in6m_rele_locked(&inmh, inm);
1709
			ifma->ifma_protospec = NULL;
1710
			/* FALLTHROUGH */
1712
			/* FALLTHROUGH */
1711
		case MLD_G_QUERY_PENDING_MEMBER:
1713
		case MLD_G_QUERY_PENDING_MEMBER:
1712
		case MLD_SG_QUERY_PENDING_MEMBER:
1714
		case MLD_SG_QUERY_PENDING_MEMBER:
Lines 1722-1732 Link Here
1722
			mbufq_drain(&inm->in6m_scq);
1724
			mbufq_drain(&inm->in6m_scq);
1723
			break;
1725
			break;
1724
		}
1726
		}
1725
		if (__predict_false(ifma6_restart)) {
1726
			ifma6_restart = false;
1727
			goto restart;
1728
		}
1729
	}
1727
	}
1728
	NET_EPOCH_EXIT(et);
1730
	IF_ADDR_WUNLOCK(ifp);
1729
	IF_ADDR_WUNLOCK(ifp);
1731
	in6m_release_list_deferred(&inmh);
1730
	in6m_release_list_deferred(&inmh);
1732
}
1731
}
Lines 1802-1808 Link Here
1802
1801
1803
	IN6_MULTI_LIST_LOCK_ASSERT();
1802
	IN6_MULTI_LIST_LOCK_ASSERT();
1804
	MLD_LOCK_ASSERT();
1803
	MLD_LOCK_ASSERT();
1805
	
1804
1806
	ifp = in6m->in6m_ifp;
1805
	ifp = in6m->in6m_ifp;
1807
	/* in process of being freed */
1806
	/* in process of being freed */
1808
	if (ifp == NULL)
1807
	if (ifp == NULL)
Lines 1899-1904 Link Here
1899
	error = 0;
1898
	error = 0;
1900
1899
1901
	/*
1900
	/*
1901
	 * Check if the in6_multi has already been disconnected.
1902
	 */
1903
	if (inm->in6m_ifp == NULL) {
1904
	  	CTR1(KTR_MLD, "%s: inm is disconnected", __func__);
1905
		return (0);
1906
	}
1907
1908
	/*
1902
	 * Try to detect if the upper layer just asked us to change state
1909
	 * Try to detect if the upper layer just asked us to change state
1903
	 * for an interface which has now gone away.
1910
	 * for an interface which has now gone away.
1904
	 */
1911
	 */
Lines 2008-2013 Link Here
2008
		if (mli->mli_version == MLD_VERSION_2 &&
2015
		if (mli->mli_version == MLD_VERSION_2 &&
2009
		    inm->in6m_state == MLD_LEAVING_MEMBER) {
2016
		    inm->in6m_state == MLD_LEAVING_MEMBER) {
2010
			inm->in6m_refcount--;
2017
			inm->in6m_refcount--;
2018
			MPASS(inm->in6m_refcount > 0);
2011
		}
2019
		}
2012
		inm->in6m_state = MLD_REPORTING_MEMBER;
2020
		inm->in6m_state = MLD_REPORTING_MEMBER;
2013
2021
Lines 3012-3022 Link Here
3012
3020
3013
	NET_EPOCH_ENTER(et);
3021
	NET_EPOCH_ENTER(et);
3014
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3022
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3015
		if (ifma->ifma_addr->sa_family != AF_INET6 ||
3023
		inm = in6m_ifmultiaddr_get_inm(ifma);
3016
		    ifma->ifma_protospec == NULL)
3024
		if (inm == NULL)
3017
			continue;
3025
			continue;
3018
3019
		inm = (struct in6_multi *)ifma->ifma_protospec;
3020
		KASSERT(ifp == inm->in6m_ifp,
3026
		KASSERT(ifp == inm->in6m_ifp,
3021
		    ("%s: inconsistent ifp", __func__));
3027
		    ("%s: inconsistent ifp", __func__));
3022
3028
(-)sys/netinet6/mld6_var.h (-1 / +2 lines)
Lines 160-171 Link Here
160
#define MLD_IFINFO(ifp) \
160
#define MLD_IFINFO(ifp) \
161
	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->mld_ifinfo)
161
	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->mld_ifinfo)
162
162
163
struct in6_multi_head;
163
int	mld_change_state(struct in6_multi *, const int);
164
int	mld_change_state(struct in6_multi *, const int);
164
struct mld_ifsoftc *
165
struct mld_ifsoftc *
165
	mld_domifattach(struct ifnet *);
166
	mld_domifattach(struct ifnet *);
166
void	mld_domifdetach(struct ifnet *);
167
void	mld_domifdetach(struct ifnet *);
167
void	mld_fasttimo(void);
168
void	mld_fasttimo(void);
168
void	mld_ifdetach(struct ifnet *);
169
void	mld_ifdetach(struct ifnet *, struct in6_multi_head *);
169
int	mld_input(struct mbuf *, int, int);
170
int	mld_input(struct mbuf *, int, int);
170
void	mld_slowtimo(void);
171
void	mld_slowtimo(void);
171
172

Return to bug 233535