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 / +43 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 497-502 Link Here
497
	inm->in6m_mli = MLD_IFINFO(ifp);
500
	inm->in6m_mli = MLD_IFINFO(ifp);
498
	inm->in6m_ifma = ifma;
501
	inm->in6m_ifma = ifma;
499
	inm->in6m_refcount = 1;
502
	inm->in6m_refcount = 1;
503
	in6m_trace("alloc", inm);
500
	inm->in6m_state = MLD_NOT_MEMBER;
504
	inm->in6m_state = MLD_NOT_MEMBER;
501
	mbufq_init(&inm->in6m_scq, MLD_MAX_STATE_CHANGES);
505
	mbufq_init(&inm->in6m_scq, MLD_MAX_STATE_CHANGES);
502
506
Lines 525-530 Link Here
525
	struct ifmultiaddr *ifma;
529
	struct ifmultiaddr *ifma;
526
	struct ifnet *ifp;
530
	struct ifnet *ifp;
527
531
532
	in6m_trace("release", inm);
533
528
	CTR2(KTR_MLD, "%s: refcount is %d", __func__, inm->in6m_refcount);
534
	CTR2(KTR_MLD, "%s: refcount is %d", __func__, inm->in6m_refcount);
529
535
530
	MPASS(inm->in6m_refcount == 0);
536
	MPASS(inm->in6m_refcount == 0);
Lines 572-578 Link Here
572
	in6m_init, NULL);
578
	in6m_init, NULL);
573
#endif
579
#endif
574
580
575
576
void
581
void
577
in6m_release_list_deferred(struct in6_multi_head *inmh)
582
in6m_release_list_deferred(struct in6_multi_head *inmh)
578
{
583
{
Lines 585-592 Link Here
585
}
590
}
586
591
587
void
592
void
588
in6m_disconnect(struct in6_multi *inm)
593
in6m_release_wait(void)
589
{
594
{
595
	/* wait for all jobs to complete */
596
	gtaskqueue_drain_all(free_gtask.gt_taskqueue);
597
}
598
599
void
600
in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm)
601
{
590
	struct ifnet *ifp;
602
	struct ifnet *ifp;
591
	struct ifaddr *ifa;
603
	struct ifaddr *ifa;
592
	struct in6_ifaddr *ifa6;
604
	struct in6_ifaddr *ifa6;
Lines 593-602 Link Here
593
	struct in6_multi_mship *imm, *imm_tmp;
605
	struct in6_multi_mship *imm, *imm_tmp;
594
	struct ifmultiaddr *ifma, *ll_ifma;
606
	struct ifmultiaddr *ifma, *ll_ifma;
595
607
608
	IN6_MULTI_LIST_LOCK_ASSERT();
609
596
	ifp = inm->in6m_ifp;
610
	ifp = inm->in6m_ifp;
611
	if (ifp == NULL)
612
		return;		/* already called */
597
613
598
	if (ifp == NULL)
599
		return;
600
	inm->in6m_ifp = NULL;
614
	inm->in6m_ifp = NULL;
601
	IF_ADDR_WLOCK_ASSERT(ifp);
615
	IF_ADDR_WLOCK_ASSERT(ifp);
602
	ifma = inm->in6m_ifma;
616
	ifma = inm->in6m_ifma;
Lines 615-621 Link Here
615
		MPASS(ll_ifma->ifma_llifma == NULL);
629
		MPASS(ll_ifma->ifma_llifma == NULL);
616
		MPASS(ll_ifma->ifma_ifp == ifp);
630
		MPASS(ll_ifma->ifma_ifp == ifp);
617
		if (--ll_ifma->ifma_refcount == 0) {
631
		if (--ll_ifma->ifma_refcount == 0) {
618
			ifma6_restart = true;
619
			if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
632
			if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
620
				CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
633
				CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
621
				ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
634
				ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
Lines 633-660 Link Here
633
			if (inm == imm->i6mm_maddr) {
646
			if (inm == imm->i6mm_maddr) {
634
				LIST_REMOVE(imm, i6mm_chain);
647
				LIST_REMOVE(imm, i6mm_chain);
635
				free(imm, M_IP6MADDR);
648
				free(imm, M_IP6MADDR);
649
				in6m_rele_locked(inmh, inm);
636
			}
650
			}
637
		}
651
		}
638
	}
652
	}
639
}
653
}
640
654
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
655
static void
659
in6m_release_task(void *arg __unused)
656
in6m_release_task(void *arg __unused)
660
{
657
{
Lines 1254-1259 Link Here
1254
    /*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
1251
    /*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
1255
    const int delay)
1252
    const int delay)
1256
{
1253
{
1254
	struct in6_multi_head    inmh;
1257
	struct in6_mfilter	 timf;
1255
	struct in6_mfilter	 timf;
1258
	struct in6_multi	*inm;
1256
	struct in6_multi	*inm;
1259
	struct ifmultiaddr *ifma;
1257
	struct ifmultiaddr *ifma;
Lines 1261-1266 Link Here
1261
#ifdef KTR
1259
#ifdef KTR
1262
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1260
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1263
#endif
1261
#endif
1262
	SLIST_INIT(&inmh);
1264
1263
1265
	/*
1264
	/*
1266
	 * Sanity: Check scope zone ID was set for ifp, if and
1265
	 * Sanity: Check scope zone ID was set for ifp, if and
Lines 1324-1336 Link Here
1324
				break;
1323
				break;
1325
			}
1324
			}
1326
		}
1325
		}
1327
		in6m_disconnect(inm);
1326
		in6m_disconnect_locked(&inmh, inm);
1328
		in6m_release_deferred(inm);
1327
		in6m_rele_locked(&inmh, inm);
1329
		NET_EPOCH_EXIT(et);
1328
		NET_EPOCH_EXIT(et);
1330
	} else {
1329
	} else {
1331
		*pinm = inm;
1330
		*pinm = inm;
1332
	}
1331
	}
1333
	IN6_MULTI_LIST_UNLOCK();
1332
	IN6_MULTI_LIST_UNLOCK();
1333
	in6m_release_list_deferred(&inmh);
1334
	return (error);
1334
	return (error);
1335
}
1335
}
1336
1336
Lines 1364-1369 Link Here
1364
int
1364
int
1365
in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
1365
in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
1366
{
1366
{
1367
	struct in6_multi_head	 inmh;
1367
	struct in6_mfilter	 timf;
1368
	struct in6_mfilter	 timf;
1368
	struct ifnet *ifp;
1369
	struct ifnet *ifp;
1369
	int			 error;
1370
	int			 error;
Lines 1371-1376 Link Here
1371
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1372
	char			 ip6tbuf[INET6_ADDRSTRLEN];
1372
#endif
1373
#endif
1373
1374
1375
	SLIST_INIT(&inmh);
1374
	error = 0;
1376
	error = 0;
1375
1377
1376
	IN6_MULTI_LOCK_ASSERT();
1378
	IN6_MULTI_LOCK_ASSERT();
Lines 1413-1429 Link Here
1413
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
1415
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
1414
	if (ifp)
1416
	if (ifp)
1415
		IF_ADDR_WLOCK(ifp);
1417
		IF_ADDR_WLOCK(ifp);
1416
	if (inm->in6m_refcount == 1 && inm->in6m_ifp != NULL)
1418
1417
		in6m_disconnect(inm);
1419
	in6m_trace("leave group locked", inm);
1418
	in6m_release_deferred(inm);
1420
	if (inm->in6m_refcount == 1)
1421
		in6m_disconnect_locked(&inmh, inm);
1422
	in6m_rele_locked(&inmh, inm);
1419
	if (ifp)
1423
	if (ifp)
1420
		IF_ADDR_WUNLOCK(ifp);
1424
		IF_ADDR_WUNLOCK(ifp);
1421
	IN6_MULTI_LIST_UNLOCK();
1425
	IN6_MULTI_LIST_UNLOCK();
1422
1426
	in6m_release_list_deferred(&inmh);
1423
	return (error);
1427
	return (error);
1424
}
1428
}
1425
1429
1426
1427
/*
1430
/*
1428
 * Block or unblock an ASM multicast source on an inpcb.
1431
 * Block or unblock an ASM multicast source on an inpcb.
1429
 * This implements the delta-based API described in RFC 3678.
1432
 * This implements the delta-based API described in RFC 3678.
Lines 1933-1938 Link Here
1933
static int
1936
static int
1934
in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
1937
in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
1935
{
1938
{
1939
	struct in6_multi_head		 inmh;
1936
	struct group_source_req		 gsr;
1940
	struct group_source_req		 gsr;
1937
	sockunion_t			*gsa, *ssa;
1941
	sockunion_t			*gsa, *ssa;
1938
	struct ifnet			*ifp;
1942
	struct ifnet			*ifp;
Lines 1943-1948 Link Here
1943
	size_t				 idx;
1947
	size_t				 idx;
1944
	int				 error, is_new;
1948
	int				 error, is_new;
1945
1949
1950
	SLIST_INIT(&inmh);
1946
	ifp = NULL;
1951
	ifp = NULL;
1947
	imf = NULL;
1952
	imf = NULL;
1948
	lims = NULL;
1953
	lims = NULL;
Lines 2178-2184 Link Here
2178
			IN6_MULTI_UNLOCK();
2183
			IN6_MULTI_UNLOCK();
2179
			goto out_im6o_free;
2184
			goto out_im6o_free;
2180
		}
2185
		}
2181
		in6m_acquire(inm);
2186
		/*
2187
		 * NOTE: Refcount from in6_joingroup_locked()
2188
		 * is protecting membership.
2189
		 */
2182
		imo->im6o_membership[idx] = inm;
2190
		imo->im6o_membership[idx] = inm;
2183
	} else {
2191
	} else {
2184
		CTR1(KTR_MLD, "%s: merge inm state", __func__);
2192
		CTR1(KTR_MLD, "%s: merge inm state", __func__);
Lines 2216-2222 Link Here
2216
		inm = imo->im6o_membership[idx];
2224
		inm = imo->im6o_membership[idx];
2217
		if (inm != NULL) {
2225
		if (inm != NULL) {
2218
			IN6_MULTI_LIST_LOCK();
2226
			IN6_MULTI_LIST_LOCK();
2219
			in6m_release_deferred(inm);
2227
			in6m_rele_locked(&inmh, inm);
2220
			IN6_MULTI_LIST_UNLOCK();
2228
			IN6_MULTI_LIST_UNLOCK();
2221
		}
2229
		}
2222
		imo->im6o_membership[idx] = NULL;
2230
		imo->im6o_membership[idx] = NULL;
Lines 2225-2230 Link Here
2225
2233
2226
out_in6p_locked:
2234
out_in6p_locked:
2227
	INP_WUNLOCK(inp);
2235
	INP_WUNLOCK(inp);
2236
	in6m_release_list_deferred(&inmh);
2228
	return (error);
2237
	return (error);
2229
}
2238
}
2230
2239
Lines 2869-2878 Link Here
2869
	IN6_MULTI_LIST_LOCK();
2878
	IN6_MULTI_LIST_LOCK();
2870
	NET_EPOCH_ENTER(et);
2879
	NET_EPOCH_ENTER(et);
2871
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2880
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2872
		if (ifma->ifma_addr->sa_family != AF_INET6 ||
2881
		inm = in6m_ifmultiaddr_get_inm(ifma);
2873
		    ifma->ifma_protospec == NULL)
2882
		if (inm == NULL)
2874
			continue;
2883
			continue;
2875
		inm = (struct in6_multi *)ifma->ifma_protospec;
2876
		if (!IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &mcaddr))
2884
		if (!IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &mcaddr))
2877
			continue;
2885
			continue;
2878
		fmode = inm->in6m_st[1].iss_fmode;
2886
		fmode = inm->in6m_st[1].iss_fmode;
(-)sys/netinet6/in6_var.h (-16 / +37 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
675
#include <sys/kdb.h>
676
677
static inline void
678
in6m_trace(const char *desc, struct in6_multi *inm)
679
{
680
	printf("INM=%p REF=%d %s\n", inm, inm->in6m_refcount, desc);
681
	kdb_backtrace();
682
}
683
675
/*
684
/*
676
 * Helper function to derive the filter mode on a source entry
685
 * Helper function to derive the filter mode on a source entry
677
 * from its internal counters. Predicates are:
686
 * from its internal counters. Predicates are:
Lines 713-725 Link Here
713
#define	IN6_MULTI_LOCK_ASSERT()	sx_assert(&in6_multi_sx, SA_XLOCKED)
722
#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)
723
#define	IN6_MULTI_UNLOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XUNLOCKED)
715
724
725
/*
726
 * Get the in6_multi pointer from a ifmultiaddr.
727
 * Returns NULL if ifmultiaddr is no longer valid.
728
 */
729
static __inline struct in6_multi *
730
in6m_ifmultiaddr_get_inm(struct ifmultiaddr *ifma)
731
{
716
732
733
	NET_EPOCH_ASSERT();
734
735
	return ((ifma->ifma_addr->sa_family != AF_INET6 ||	
736
	    (ifma->ifma_flags & IFMA_F_ENQUEUED) == 0) ? NULL :
737
	    ifma->ifma_protospec);
738
}
739
717
/*
740
/*
718
 * Look up an in6_multi record for an IPv6 multicast address
741
 * Look up an in6_multi record for an IPv6 multicast address
719
 * on the interface ifp.
742
 * on the interface ifp.
720
 * If no record found, return NULL.
743
 * If no record found, return NULL.
721
 *
722
 * SMPng: The IN6_MULTI_LOCK and IF_ADDR_LOCK on ifp must be held.
723
 */
744
 */
724
static __inline struct in6_multi *
745
static __inline struct in6_multi *
725
in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr)
746
in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr)
Lines 727-744 Link Here
727
	struct ifmultiaddr *ifma;
748
	struct ifmultiaddr *ifma;
728
	struct in6_multi *inm;
749
	struct in6_multi *inm;
729
750
730
	inm = NULL;
751
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
731
	CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
752
		inm = in6m_ifmultiaddr_get_inm(ifma);
732
		if (ifma->ifma_addr->sa_family == AF_INET6) {
753
		if (inm == NULL)
733
			inm = (struct in6_multi *)ifma->ifma_protospec;
754
			continue;
734
			if (inm == NULL)
755
		if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr))
735
				continue;
756
			return (inm);
736
			if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr))
737
				break;
738
			inm = NULL;
739
		}
740
	}
757
	}
741
	return (inm);
758
	return (NULL);
742
}
759
}
743
760
744
/*
761
/*
Lines 768-773 Link Here
768
785
769
	IN6_MULTI_LIST_LOCK_ASSERT();
786
	IN6_MULTI_LIST_LOCK_ASSERT();
770
	++inm->in6m_refcount;
787
	++inm->in6m_refcount;
788
789
	in6m_trace("post acquire", inm);
771
}
790
}
772
791
773
static __inline void
792
static __inline void
Lines 784-789 Link Here
784
	KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm));
803
	KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm));
785
	IN6_MULTI_LIST_LOCK_ASSERT();
804
	IN6_MULTI_LIST_LOCK_ASSERT();
786
805
806
	in6m_trace("pre release", inm);
807
787
	if (--inm->in6m_refcount == 0) {
808
	if (--inm->in6m_refcount == 0) {
788
		MPASS(inm->in6m_ifp == NULL);
809
		MPASS(inm->in6m_ifp == NULL);
789
		inm->in6m_ifma->ifma_protospec = NULL;
810
		inm->in6m_ifma->ifma_protospec = NULL;
Lines 809-816 Link Here
809
void	in6m_commit(struct in6_multi *);
830
void	in6m_commit(struct in6_multi *);
810
void	in6m_print(const struct in6_multi *);
831
void	in6m_print(const struct in6_multi *);
811
int	in6m_record_source(struct in6_multi *, const struct in6_addr *);
832
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 *);
833
void	in6m_release_list_deferred(struct in6_multi_head *);
834
void	in6m_release_wait(void);
814
void	ip6_freemoptions(struct ip6_moptions *);
835
void	ip6_freemoptions(struct ip6_moptions *);
815
int	ip6_getmoptions(struct inpcb *, struct sockopt *);
836
int	ip6_getmoptions(struct inpcb *, struct sockopt *);
816
int	ip6_setmoptions(struct inpcb *, struct sockopt *);
837
int	ip6_setmoptions(struct inpcb *, struct sockopt *);
(-)sys/netinet6/mld6.c (-73 / +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 1332-1344 Link Here
1332
static void
1349
static void
1333
mld_fasttimo_vnet(void)
1350
mld_fasttimo_vnet(void)
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-1424 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
		}
1433
		NET_EPOCH_EXIT(et);
1422
		IF_ADDR_WUNLOCK(ifp);
1434
		IF_ADDR_WUNLOCK(ifp);
1423
1435
1424
		switch (mli->mli_version) {
1436
		switch (mli->mli_version) {
Lines 1431-1439 Link Here
1431
			 * IF_ADDR_LOCK internally as well as
1443
			 * IF_ADDR_LOCK internally as well as
1432
			 * ip6_output() to transmit a packet.
1444
			 * ip6_output() to transmit a packet.
1433
			 */
1445
			 */
1434
			SLIST_FOREACH_SAFE(inm, &inmh, in6m_nrele, tinm) {
1446
			while ((inm = SLIST_FIRST(inmh)) != NULL) {
1435
				SLIST_REMOVE_HEAD(&inmh,
1447
				SLIST_REMOVE_HEAD(inmh, in6m_nrele);
1436
				    in6m_nrele);
1437
				(void)mld_v1_transmit_report(inm,
1448
				(void)mld_v1_transmit_report(inm,
1438
				    MLD_LISTENER_REPORT);
1449
				    MLD_LISTENER_REPORT);
1439
			}
1450
			}
Lines 1441-1452 Link Here
1441
		case MLD_VERSION_2:
1452
		case MLD_VERSION_2:
1442
			mld_dispatch_queue(&qrq, 0);
1453
			mld_dispatch_queue(&qrq, 0);
1443
			mld_dispatch_queue(&scq, 0);
1454
			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;
1455
			break;
1451
		}
1456
		}
1452
	}
1457
	}
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_nrele);
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 2007-2013 Link Here
2007
		 */
2014
		 */
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) {
2017
			in6m_trace("pre leaving member", inm);
2010
			inm->in6m_refcount--;
2018
			inm->in6m_refcount--;
2019
			MPASS(inm->in6m_refcount > 0);
2011
		}
2020
		}
2012
		inm->in6m_state = MLD_REPORTING_MEMBER;
2021
		inm->in6m_state = MLD_REPORTING_MEMBER;
2013
2022
Lines 3012-3022 Link Here
3012
3021
3013
	NET_EPOCH_ENTER(et);
3022
	NET_EPOCH_ENTER(et);
3014
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3023
	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3015
		if (ifma->ifma_addr->sa_family != AF_INET6 ||
3024
		inm = in6m_ifmultiaddr_get_inm(ifma);
3016
		    ifma->ifma_protospec == NULL)
3025
		if (inm == NULL)
3017
			continue;
3026
			continue;
3018
3019
		inm = (struct in6_multi *)ifma->ifma_protospec;
3020
		KASSERT(ifp == inm->in6m_ifp,
3027
		KASSERT(ifp == inm->in6m_ifp,
3021
		    ("%s: inconsistent ifp", __func__));
3028
		    ("%s: inconsistent ifp", __func__));
3022
3029
(-)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