Deleted Added
full compact
mld6.c (192562) mld6.c (192923)
1/*-
2 * Copyright (c) 2009 Bruce Simpson.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.

--- 50 unchanged lines hidden (view full) ---

59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
64 */
65
66#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2009 Bruce Simpson.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.

--- 50 unchanged lines hidden (view full) ---

59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
64 */
65
66#include <sys/cdefs.h>
67__FBSDID("$FreeBSD: head/sys/netinet6/mld6.c 192562 2009-05-21 18:05:17Z bms $");
67__FBSDID("$FreeBSD: head/sys/netinet6/mld6.c 192923 2009-05-27 18:57:13Z bms $");
68
69#include "opt_inet.h"
70#include "opt_inet6.h"
71
72#include <sys/param.h>
73#include <sys/systm.h>
74#include <sys/mbuf.h>
75#include <sys/socket.h>

--- 41 unchanged lines hidden (view full) ---

117#ifdef KTR
118static char * mld_rec_type_to_str(const int);
119#endif
120static void mld_set_version(struct mld_ifinfo *, const int);
121static void mld_slowtimo_vnet(void);
122static void mld_sysinit(void);
123static void mld_sysuninit(void);
124static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *,
68
69#include "opt_inet.h"
70#include "opt_inet6.h"
71
72#include <sys/param.h>
73#include <sys/systm.h>
74#include <sys/mbuf.h>
75#include <sys/socket.h>

--- 41 unchanged lines hidden (view full) ---

117#ifdef KTR
118static char * mld_rec_type_to_str(const int);
119#endif
120static void mld_set_version(struct mld_ifinfo *, const int);
121static void mld_slowtimo_vnet(void);
122static void mld_sysinit(void);
123static void mld_sysuninit(void);
124static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *,
125 const struct mld_hdr *);
125 /*const*/ struct mld_hdr *);
126static int mld_v1_input_report(struct ifnet *, const struct ip6_hdr *,
126static int mld_v1_input_report(struct ifnet *, const struct ip6_hdr *,
127 const struct mld_hdr *);
127 /*const*/ struct mld_hdr *);
128static void mld_v1_process_group_timer(struct in6_multi *, const int);
129static void mld_v1_process_querier_timers(struct mld_ifinfo *);
130static int mld_v1_transmit_report(struct in6_multi *, const int);
131static void mld_v1_update_group(struct in6_multi *, const int);
132static void mld_v2_cancel_link_timers(struct mld_ifinfo *);
133static void mld_v2_dispatch_general_query(struct mld_ifinfo *);
134static struct mbuf *
135 mld_v2_encap_report(struct ifnet *, struct mbuf *);

--- 98 unchanged lines hidden (view full) ---

234 "Rate limit for MLDv2 Group-and-Source queries in seconds");
235
236/*
237 * Non-virtualized sysctls.
238 */
239SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo, CTLFLAG_RD | CTLFLAG_MPSAFE,
240 sysctl_mld_ifinfo, "Per-interface MLDv2 state");
241
128static void mld_v1_process_group_timer(struct in6_multi *, const int);
129static void mld_v1_process_querier_timers(struct mld_ifinfo *);
130static int mld_v1_transmit_report(struct in6_multi *, const int);
131static void mld_v1_update_group(struct in6_multi *, const int);
132static void mld_v2_cancel_link_timers(struct mld_ifinfo *);
133static void mld_v2_dispatch_general_query(struct mld_ifinfo *);
134static struct mbuf *
135 mld_v2_encap_report(struct ifnet *, struct mbuf *);

--- 98 unchanged lines hidden (view full) ---

234 "Rate limit for MLDv2 Group-and-Source queries in seconds");
235
236/*
237 * Non-virtualized sysctls.
238 */
239SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo, CTLFLAG_RD | CTLFLAG_MPSAFE,
240 sysctl_mld_ifinfo, "Per-interface MLDv2 state");
241
242static int mld_v1enable = 1;
243SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RW,
244 &mld_v1enable, 0, "Enable fallback to MLDv1");
245TUNABLE_INT("net.inet6.mld.v1enable", &mld_v1enable);
246
242/*
243 * Packed Router Alert option structure declaration.
244 */
245struct mld_raopt {
246 struct ip6_hbh hbh;
247 struct ip6_opt pad;
248 struct ip6_opt_router ra;
249} __packed;

--- 360 unchanged lines hidden (view full) ---

610#ifdef INVARIANTS
611 panic("%s: mld_ifinfo not found for ifp %p\n", __func__, ifp);
612#endif
613}
614
615/*
616 * Process a received MLDv1 general or address-specific query.
617 * Assumes that the query header has been pulled up to sizeof(mld_hdr).
247/*
248 * Packed Router Alert option structure declaration.
249 */
250struct mld_raopt {
251 struct ip6_hbh hbh;
252 struct ip6_opt pad;
253 struct ip6_opt_router ra;
254} __packed;

--- 360 unchanged lines hidden (view full) ---

615#ifdef INVARIANTS
616 panic("%s: mld_ifinfo not found for ifp %p\n", __func__, ifp);
617#endif
618}
619
620/*
621 * Process a received MLDv1 general or address-specific query.
622 * Assumes that the query header has been pulled up to sizeof(mld_hdr).
623 *
624 * NOTE: Can't be fully const correct as we temporarily embed scope ID in
625 * mld_addr. This is OK as we own the mbuf chain.
618 */
619static int
620mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
626 */
627static int
628mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
621 const struct mld_hdr *mld)
629 /*const*/ struct mld_hdr *mld)
622{
623 struct ifmultiaddr *ifma;
624 struct mld_ifinfo *mli;
625 struct in6_multi *inm;
630{
631 struct ifmultiaddr *ifma;
632 struct mld_ifinfo *mli;
633 struct in6_multi *inm;
634 int is_general_query;
626 uint16_t timer;
627#ifdef KTR
628 char ip6tbuf[INET6_ADDRSTRLEN];
629#endif
630
635 uint16_t timer;
636#ifdef KTR
637 char ip6tbuf[INET6_ADDRSTRLEN];
638#endif
639
640 is_general_query = 0;
641
642 if (!mld_v1enable) {
643 CTR3(KTR_MLD, "ignore v1 query %s on ifp %p(%s)",
644 ip6_sprintf(ip6tbuf, &mld->mld_addr),
645 ifp, ifp->if_xname);
646 return (0);
647 }
648
649 /*
650 * RFC3810 Section 6.2: MLD queries must originate from
651 * a router's link-local address.
652 */
653 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
654 CTR3(KTR_MLD, "ignore v1 query src %s on ifp %p(%s)",
655 ip6_sprintf(ip6tbuf, &ip6->ip6_src),
656 ifp, ifp->if_xname);
657 return (0);
658 }
659
660 /*
661 * Do address field validation upfront before we accept
662 * the query.
663 */
664 if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
665 /*
666 * MLDv1 General Query.
667 * If this was not sent to the all-nodes group, ignore it.
668 */
669 struct in6_addr dst;
670
671 dst = ip6->ip6_dst;
672 in6_clearscope(&dst);
673 if (!IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes))
674 return (EINVAL);
675 is_general_query = 1;
676 } else {
677 /*
678 * Embed scope ID of receiving interface in MLD query for
679 * lookup whilst we don't hold other locks.
680 */
681 in6_setscope(&mld->mld_addr, ifp, NULL);
682 }
683
631 IN6_MULTI_LOCK();
632 MLD_LOCK();
633 IF_ADDR_LOCK(ifp);
634
684 IN6_MULTI_LOCK();
685 MLD_LOCK();
686 IF_ADDR_LOCK(ifp);
687
635 mli = MLD_IFINFO(ifp);
636 KASSERT(mli != NULL, ("%s: no mld_ifinfo for ifp %p", __func__, ifp));
637
638 /*
639 * Switch to MLDv1 host compatibility mode.
640 */
688 /*
689 * Switch to MLDv1 host compatibility mode.
690 */
691 mli = MLD_IFINFO(ifp);
692 KASSERT(mli != NULL, ("%s: no mld_ifinfo for ifp %p", __func__, ifp));
641 mld_set_version(mli, MLD_VERSION_1);
642
693 mld_set_version(mli, MLD_VERSION_1);
694
643 timer = ntohs(mld->mld_maxdelay) * PR_FASTHZ / MLD_TIMER_SCALE;
695 timer = (ntohs(mld->mld_maxdelay) * PR_FASTHZ) / MLD_TIMER_SCALE;
644 if (timer == 0)
645 timer = 1;
646
696 if (timer == 0)
697 timer = 1;
698
647 if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
699 if (is_general_query) {
648 /*
700 /*
701 * For each reporting group joined on this
702 * interface, kick the report timer.
703 */
704 CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)",
705 ifp, ifp->if_xname);
706 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
707 if (ifma->ifma_addr->sa_family != AF_INET6 ||
708 ifma->ifma_protospec == NULL)
709 continue;
710 inm = (struct in6_multi *)ifma->ifma_protospec;
711 mld_v1_update_group(inm, timer);
712 }
713 } else {
714 /*
649 * MLDv1 Group-Specific Query.
650 * If this is a group-specific MLDv1 query, we need only
651 * look up the single group to process it.
652 */
653 inm = in6m_lookup_locked(ifp, &mld->mld_addr);
654 if (inm != NULL) {
655 CTR3(KTR_MLD, "process v1 query %s on ifp %p(%s)",
656 ip6_sprintf(ip6tbuf, &mld->mld_addr),
657 ifp, ifp->if_xname);
658 mld_v1_update_group(inm, timer);
659 }
715 * MLDv1 Group-Specific Query.
716 * If this is a group-specific MLDv1 query, we need only
717 * look up the single group to process it.
718 */
719 inm = in6m_lookup_locked(ifp, &mld->mld_addr);
720 if (inm != NULL) {
721 CTR3(KTR_MLD, "process v1 query %s on ifp %p(%s)",
722 ip6_sprintf(ip6tbuf, &mld->mld_addr),
723 ifp, ifp->if_xname);
724 mld_v1_update_group(inm, timer);
725 }
660 } else {
661 /*
662 * MLDv1 General Query.
663 * If this was not sent to the all-nodes group, ignore it.
664 */
665 struct in6_addr dst;
666
667 dst = ip6->ip6_dst;
668 in6_clearscope(&dst);
669 if (IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes)) {
670 /*
671 * For each reporting group joined on this
672 * interface, kick the report timer.
673 */
674 CTR2(KTR_MLD,
675 "process v1 general query on ifp %p(%s)",
676 ifp, ifp->if_xname);
677
678 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
679 if (ifma->ifma_addr->sa_family != AF_INET6 ||
680 ifma->ifma_protospec == NULL)
681 continue;
682 inm = (struct in6_multi *)ifma->ifma_protospec;
683 mld_v1_update_group(inm, timer);
684 }
685 }
726 /* XXX Clear embedded scope ID as userland won't expect it. */
727 in6_clearscope(&mld->mld_addr);
686 }
687
688 IF_ADDR_UNLOCK(ifp);
689 MLD_UNLOCK();
690 IN6_MULTI_UNLOCK();
691
692 return (0);
693}

--- 70 unchanged lines hidden (view full) ---

764mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
765 struct mbuf *m, const int off, const int icmp6len)
766{
767 INIT_VNET_INET6(curvnet);
768 struct mld_ifinfo *mli;
769 struct mldv2_query *mld;
770 struct in6_multi *inm;
771 uint32_t maxdelay, nsrc, qqi;
728 }
729
730 IF_ADDR_UNLOCK(ifp);
731 MLD_UNLOCK();
732 IN6_MULTI_UNLOCK();
733
734 return (0);
735}

--- 70 unchanged lines hidden (view full) ---

806mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
807 struct mbuf *m, const int off, const int icmp6len)
808{
809 INIT_VNET_INET6(curvnet);
810 struct mld_ifinfo *mli;
811 struct mldv2_query *mld;
812 struct in6_multi *inm;
813 uint32_t maxdelay, nsrc, qqi;
814 int is_general_query;
772 uint16_t timer;
773 uint8_t qrv;
815 uint16_t timer;
816 uint8_t qrv;
817#ifdef KTR
818 char ip6tbuf[INET6_ADDRSTRLEN];
819#endif
774
820
775 CTR2(KTR_MLD, "process v2 query on ifp %p(%s)", ifp, ifp->if_xname);
821 is_general_query = 0;
776
822
823 /*
824 * RFC3810 Section 6.2: MLD queries must originate from
825 * a router's link-local address.
826 */
827 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
828 CTR3(KTR_MLD, "ignore v1 query src %s on ifp %p(%s)",
829 ip6_sprintf(ip6tbuf, &ip6->ip6_src),
830 ifp, ifp->if_xname);
831 return (0);
832 }
833
834 CTR2(KTR_MLD, "input v2 query on ifp %p(%s)", ifp, ifp->if_xname);
835
777 mld = (struct mldv2_query *)(mtod(m, uint8_t *) + off);
778
779 maxdelay = ntohs(mld->mld_maxdelay); /* in 1/10ths of a second */
780 if (maxdelay >= 32678) {
836 mld = (struct mldv2_query *)(mtod(m, uint8_t *) + off);
837
838 maxdelay = ntohs(mld->mld_maxdelay); /* in 1/10ths of a second */
839 if (maxdelay >= 32678) {
781 maxdelay = (MLD_MRC_MANT(mld->mld_maxdelay) | 0x1000) <<
782 (MLD_MRC_EXP(mld->mld_maxdelay) + 3);
840 maxdelay = (MLD_MRC_MANT(maxdelay) | 0x1000) <<
841 (MLD_MRC_EXP(maxdelay) + 3);
783 }
842 }
843 timer = (maxdelay * PR_FASTHZ) / MLD_TIMER_SCALE;
844 if (timer == 0)
845 timer = 1;
784
785 qrv = MLD_QRV(mld->mld_misc);
786 if (qrv < 2) {
787 CTR3(KTR_MLD, "%s: clamping qrv %d to %d", __func__,
788 qrv, MLD_RV_INIT);
789 qrv = MLD_RV_INIT;
790 }
791
792 qqi = mld->mld_qqi;
793 if (qqi >= 128) {
794 qqi = MLD_QQIC_MANT(mld->mld_qqi) <<
795 (MLD_QQIC_EXP(mld->mld_qqi) + 3);
796 }
797
846
847 qrv = MLD_QRV(mld->mld_misc);
848 if (qrv < 2) {
849 CTR3(KTR_MLD, "%s: clamping qrv %d to %d", __func__,
850 qrv, MLD_RV_INIT);
851 qrv = MLD_RV_INIT;
852 }
853
854 qqi = mld->mld_qqi;
855 if (qqi >= 128) {
856 qqi = MLD_QQIC_MANT(mld->mld_qqi) <<
857 (MLD_QQIC_EXP(mld->mld_qqi) + 3);
858 }
859
798 timer = maxdelay * PR_FASTHZ / MLD_TIMER_SCALE;
799 if (timer == 0)
800 timer = 1;
801
802 nsrc = ntohs(mld->mld_numsrc);
803 if (nsrc > MLD_MAX_GS_SOURCES)
804 return (EMSGSIZE);
805 if (icmp6len < sizeof(struct mldv2_query) +
806 (nsrc * sizeof(struct in6_addr)))
807 return (EMSGSIZE);
808
860 nsrc = ntohs(mld->mld_numsrc);
861 if (nsrc > MLD_MAX_GS_SOURCES)
862 return (EMSGSIZE);
863 if (icmp6len < sizeof(struct mldv2_query) +
864 (nsrc * sizeof(struct in6_addr)))
865 return (EMSGSIZE);
866
867 /*
868 * Do further input validation upfront to avoid resetting timers
869 * should we need to discard this query.
870 */
871 if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
872 /*
873 * General Queries SHOULD be directed to ff02::1.
874 * A general query with a source list has undefined
875 * behaviour; discard it.
876 */
877 struct in6_addr dst;
878
879 dst = ip6->ip6_dst;
880 in6_clearscope(&dst);
881 if (!IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes) ||
882 nsrc > 0)
883 return (EINVAL);
884 is_general_query = 1;
885 } else {
886 /*
887 * Embed scope ID of receiving interface in MLD query for
888 * lookup whilst we don't hold other locks (due to KAME
889 * locking lameness). We own this mbuf chain just now.
890 */
891 in6_setscope(&mld->mld_addr, ifp, NULL);
892 }
893
809 IN6_MULTI_LOCK();
810 MLD_LOCK();
811 IF_ADDR_LOCK(ifp);
812
813 mli = MLD_IFINFO(ifp);
814 KASSERT(mli != NULL, ("%s: no mld_ifinfo for ifp %p", __func__, ifp));
815
894 IN6_MULTI_LOCK();
895 MLD_LOCK();
896 IF_ADDR_LOCK(ifp);
897
898 mli = MLD_IFINFO(ifp);
899 KASSERT(mli != NULL, ("%s: no mld_ifinfo for ifp %p", __func__, ifp));
900
816 mld_set_version(mli, MLD_VERSION_2);
901 /*
902 * Discard the v2 query if we're in Compatibility Mode.
903 * The RFC is pretty clear that hosts need to stay in MLDv1 mode
904 * until the Old Version Querier Present timer expires.
905 */
906 if (mli->mli_version != MLD_VERSION_2)
907 goto out_locked;
817
908
909 mld_set_version(mli, MLD_VERSION_2);
818 mli->mli_rv = qrv;
819 mli->mli_qi = qqi;
820 mli->mli_qri = maxdelay;
821
822 CTR4(KTR_MLD, "%s: qrv %d qi %d maxdelay %d", __func__, qrv, qqi,
823 maxdelay);
824
910 mli->mli_rv = qrv;
911 mli->mli_qi = qqi;
912 mli->mli_qri = maxdelay;
913
914 CTR4(KTR_MLD, "%s: qrv %d qi %d maxdelay %d", __func__, qrv, qqi,
915 maxdelay);
916
825 if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
917 if (is_general_query) {
826 /*
827 * MLDv2 General Query.
828 *
829 * Schedule a current-state report on this ifp for
830 * all groups, possibly containing source lists.
831 *
918 /*
919 * MLDv2 General Query.
920 *
921 * Schedule a current-state report on this ifp for
922 * all groups, possibly containing source lists.
923 *
832 * Strip scope ID embedded by ip6_input(). We do not need
833 * to do this for the MLD payload.
834 */
835 struct in6_addr dst;
836
837 dst = ip6->ip6_dst;
838 in6_clearscope(&dst);
839 if (!IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes) ||
840 nsrc > 0) {
841 /*
842 * General Queries SHOULD be directed to ff02::1.
843 * A general query with a source list has undefined
844 * behaviour; discard it.
845 */
846 goto out_locked;
847 }
848
849 CTR2(KTR_MLD, "process v2 general query on ifp %p(%s)",
850 ifp, ifp->if_xname);
851
852 /*
853 * If there is a pending General Query response
854 * scheduled earlier than the selected delay, do
855 * not schedule any other reports.
856 * Otherwise, reset the interface timer.
857 */
924 * If there is a pending General Query response
925 * scheduled earlier than the selected delay, do
926 * not schedule any other reports.
927 * Otherwise, reset the interface timer.
928 */
929 CTR2(KTR_MLD, "process v2 general query on ifp %p(%s)",
930 ifp, ifp->if_xname);
858 if (mli->mli_v2_timer == 0 || mli->mli_v2_timer >= timer) {
859 mli->mli_v2_timer = MLD_RANDOM_DELAY(timer);
860 V_interface_timers_running6 = 1;
861 }
862 } else {
863 /*
864 * MLDv2 Group-specific or Group-and-source-specific Query.
865 *

--- 19 unchanged lines hidden (view full) ---

885 * If there is a pending General Query response
886 * scheduled sooner than the selected delay, no
887 * further report need be scheduled.
888 * Otherwise, prepare to respond to the
889 * group-specific or group-and-source query.
890 */
891 if (mli->mli_v2_timer == 0 || mli->mli_v2_timer >= timer)
892 mld_v2_process_group_query(inm, mli, timer, m, off);
931 if (mli->mli_v2_timer == 0 || mli->mli_v2_timer >= timer) {
932 mli->mli_v2_timer = MLD_RANDOM_DELAY(timer);
933 V_interface_timers_running6 = 1;
934 }
935 } else {
936 /*
937 * MLDv2 Group-specific or Group-and-source-specific Query.
938 *

--- 19 unchanged lines hidden (view full) ---

958 * If there is a pending General Query response
959 * scheduled sooner than the selected delay, no
960 * further report need be scheduled.
961 * Otherwise, prepare to respond to the
962 * group-specific or group-and-source query.
963 */
964 if (mli->mli_v2_timer == 0 || mli->mli_v2_timer >= timer)
965 mld_v2_process_group_query(inm, mli, timer, m, off);
966
967 /* XXX Clear embedded scope ID as userland won't expect it. */
968 in6_clearscope(&mld->mld_addr);
893 }
894
895out_locked:
896 IF_ADDR_UNLOCK(ifp);
897 MLD_UNLOCK();
898 IN6_MULTI_UNLOCK();
899
900 return (0);

--- 111 unchanged lines hidden (view full) ---

1012 }
1013
1014 return (retval);
1015}
1016
1017/*
1018 * Process a received MLDv1 host membership report.
1019 * Assumes mld points to mld_hdr in pulled up mbuf chain.
969 }
970
971out_locked:
972 IF_ADDR_UNLOCK(ifp);
973 MLD_UNLOCK();
974 IN6_MULTI_UNLOCK();
975
976 return (0);

--- 111 unchanged lines hidden (view full) ---

1088 }
1089
1090 return (retval);
1091}
1092
1093/*
1094 * Process a received MLDv1 host membership report.
1095 * Assumes mld points to mld_hdr in pulled up mbuf chain.
1096 *
1097 * NOTE: Can't be fully const correct as we temporarily embed scope ID in
1098 * mld_addr. This is OK as we own the mbuf chain.
1020 */
1021static int
1022mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
1099 */
1100static int
1101mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
1023 const struct mld_hdr *mld)
1102 /*const*/ struct mld_hdr *mld)
1024{
1103{
1104 struct in6_addr src, dst;
1025 struct in6_ifaddr *ia;
1026 struct in6_multi *inm;
1105 struct in6_ifaddr *ia;
1106 struct in6_multi *inm;
1027 struct in6_addr src, dst;
1028#ifdef KTR
1029 char ip6tbuf[INET6_ADDRSTRLEN];
1030#endif
1031
1107#ifdef KTR
1108 char ip6tbuf[INET6_ADDRSTRLEN];
1109#endif
1110
1111 if (!mld_v1enable) {
1112 CTR3(KTR_MLD, "ignore v1 report %s on ifp %p(%s)",
1113 ip6_sprintf(ip6tbuf, &mld->mld_addr),
1114 ifp, ifp->if_xname);
1115 return (0);
1116 }
1117
1032 if (ifp->if_flags & IFF_LOOPBACK)
1033 return (0);
1118 if (ifp->if_flags & IFF_LOOPBACK)
1119 return (0);
1034 if (!IN6_IS_ADDR_MULTICAST(&mld->mld_addr))
1120
1121 /*
1122 * MLDv1 reports must originate from a host's link-local address,
1123 * or the unspecified address (when booting).
1124 */
1125 src = ip6->ip6_src;
1126 in6_clearscope(&src);
1127 if (!IN6_IS_SCOPE_LINKLOCAL(&src) && !IN6_IS_ADDR_UNSPECIFIED(&src)) {
1128 CTR3(KTR_MLD, "ignore v1 query src %s on ifp %p(%s)",
1129 ip6_sprintf(ip6tbuf, &ip6->ip6_src),
1130 ifp, ifp->if_xname);
1035 return (EINVAL);
1131 return (EINVAL);
1132 }
1036
1133
1134 /*
1135 * RFC2710 Section 4: MLDv1 reports must pertain to a multicast
1136 * group, and must be directed to the group itself.
1137 */
1037 dst = ip6->ip6_dst;
1038 in6_clearscope(&dst);
1138 dst = ip6->ip6_dst;
1139 in6_clearscope(&dst);
1039 if (!IN6_ARE_ADDR_EQUAL(&mld->mld_addr, &dst))
1140 if (!IN6_IS_ADDR_MULTICAST(&mld->mld_addr) ||
1141 !IN6_ARE_ADDR_EQUAL(&mld->mld_addr, &dst)) {
1142 CTR3(KTR_MLD, "ignore v1 query dst %s on ifp %p(%s)",
1143 ip6_sprintf(ip6tbuf, &ip6->ip6_dst),
1144 ifp, ifp->if_xname);
1040 return (EINVAL);
1145 return (EINVAL);
1146 }
1041
1042 /*
1043 * Make sure we don't hear our own membership report, as fast
1044 * leave requires knowing that we are the only member of a
1045 * group. Assume we used the link-local address if available,
1046 * otherwise look for ::.
1047 *
1048 * XXX Note that scope ID comparison is needed for the address
1049 * returned by in6ifa_ifpforlinklocal(), but SHOULD NOT be
1050 * performed for the on-wire address.
1051 */
1052 ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
1147
1148 /*
1149 * Make sure we don't hear our own membership report, as fast
1150 * leave requires knowing that we are the only member of a
1151 * group. Assume we used the link-local address if available,
1152 * otherwise look for ::.
1153 *
1154 * XXX Note that scope ID comparison is needed for the address
1155 * returned by in6ifa_ifpforlinklocal(), but SHOULD NOT be
1156 * performed for the on-wire address.
1157 */
1158 ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
1053 src = ip6->ip6_src;
1054 in6_clearscope(&src);
1055 if ((ia && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, IA6_IN6(ia))) ||
1056 (ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src)))
1057 return (0);
1058
1059 CTR3(KTR_MLD, "process v1 report %s on ifp %p(%s)",
1060 ip6_sprintf(ip6tbuf, &mld->mld_addr), ifp, ifp->if_xname);
1061
1159 if ((ia && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, IA6_IN6(ia))) ||
1160 (ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src)))
1161 return (0);
1162
1163 CTR3(KTR_MLD, "process v1 report %s on ifp %p(%s)",
1164 ip6_sprintf(ip6tbuf, &mld->mld_addr), ifp, ifp->if_xname);
1165
1166 /*
1167 * Embed scope ID of receiving interface in MLD query for lookup
1168 * whilst we don't hold other locks (due to KAME locking lameness).
1169 */
1170 if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr))
1171 in6_setscope(&mld->mld_addr, ifp, NULL);
1172
1062 IN6_MULTI_LOCK();
1063 MLD_LOCK();
1064 IF_ADDR_LOCK(ifp);
1065
1066 /*
1067 * MLDv1 report suppression.
1068 * If we are a member of this group, and our membership should be
1069 * reported, and our group timer is pending or about to be reset,

--- 38 unchanged lines hidden (view full) ---

1108 }
1109 }
1110
1111out_locked:
1112 MLD_UNLOCK();
1113 IF_ADDR_UNLOCK(ifp);
1114 IN6_MULTI_UNLOCK();
1115
1173 IN6_MULTI_LOCK();
1174 MLD_LOCK();
1175 IF_ADDR_LOCK(ifp);
1176
1177 /*
1178 * MLDv1 report suppression.
1179 * If we are a member of this group, and our membership should be
1180 * reported, and our group timer is pending or about to be reset,

--- 38 unchanged lines hidden (view full) ---

1219 }
1220 }
1221
1222out_locked:
1223 MLD_UNLOCK();
1224 IF_ADDR_UNLOCK(ifp);
1225 IN6_MULTI_UNLOCK();
1226
1227 /* XXX Clear embedded scope ID as userland won't expect it. */
1228 in6_clearscope(&mld->mld_addr);
1229
1116 return (0);
1117}
1118
1119/*
1120 * MLD input path.
1121 *
1122 * Assume query messages which fit in a single ICMPv6 message header
1123 * have been pulled up.

--- 27 unchanged lines hidden (view full) ---

1151 mldlen = sizeof(struct mld_hdr);
1152 }
1153 IP6_EXTHDR_GET(mld, struct mld_hdr *, m, off, mldlen);
1154 if (mld == NULL) {
1155 ICMP6STAT_INC(icp6s_badlen);
1156 return (IPPROTO_DONE);
1157 }
1158
1230 return (0);
1231}
1232
1233/*
1234 * MLD input path.
1235 *
1236 * Assume query messages which fit in a single ICMPv6 message header
1237 * have been pulled up.

--- 27 unchanged lines hidden (view full) ---

1265 mldlen = sizeof(struct mld_hdr);
1266 }
1267 IP6_EXTHDR_GET(mld, struct mld_hdr *, m, off, mldlen);
1268 if (mld == NULL) {
1269 ICMP6STAT_INC(icp6s_badlen);
1270 return (IPPROTO_DONE);
1271 }
1272
1273 /*
1274 * Userland needs to see all of this traffic for implementing
1275 * the endpoint discovery portion of multicast routing.
1276 */
1159 switch (mld->mld_type) {
1160 case MLD_LISTENER_QUERY:
1161 icmp6_ifstat_inc(ifp, ifs6_in_mldquery);
1162 if (icmp6len == sizeof(struct mld_hdr)) {
1163 if (mld_v1_input_query(ifp, ip6, mld) != 0)
1164 return (0);
1165 } else if (icmp6len >= sizeof(struct mldv2_query)) {
1166 if (mld_v2_input_query(ifp, ip6, m, off,
1167 icmp6len) != 0)
1168 return (0);
1169 }
1170 break;
1171 case MLD_LISTENER_REPORT:
1172 icmp6_ifstat_inc(ifp, ifs6_in_mldreport);
1173 if (mld_v1_input_report(ifp, ip6, mld) != 0)
1277 switch (mld->mld_type) {
1278 case MLD_LISTENER_QUERY:
1279 icmp6_ifstat_inc(ifp, ifs6_in_mldquery);
1280 if (icmp6len == sizeof(struct mld_hdr)) {
1281 if (mld_v1_input_query(ifp, ip6, mld) != 0)
1282 return (0);
1283 } else if (icmp6len >= sizeof(struct mldv2_query)) {
1284 if (mld_v2_input_query(ifp, ip6, m, off,
1285 icmp6len) != 0)
1286 return (0);
1287 }
1288 break;
1289 case MLD_LISTENER_REPORT:
1290 icmp6_ifstat_inc(ifp, ifs6_in_mldreport);
1291 if (mld_v1_input_report(ifp, ip6, mld) != 0)
1174 return (0); /* Userland needs to see it. */
1292 return (0);
1175 break;
1176 case MLDV2_LISTENER_REPORT:
1177 icmp6_ifstat_inc(ifp, ifs6_in_mldreport);
1178 break;
1179 case MLD_LISTENER_DONE:
1180 icmp6_ifstat_inc(ifp, ifs6_in_mlddone);
1181 break;
1182 default:

--- 102 unchanged lines hidden (view full) ---

1285 TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link,
1286 tifma) {
1287 if (ifma->ifma_addr->sa_family != AF_INET6 ||
1288 ifma->ifma_protospec == NULL)
1289 continue;
1290 inm = (struct in6_multi *)ifma->ifma_protospec;
1291 switch (mli->mli_version) {
1292 case MLD_VERSION_1:
1293 break;
1294 case MLDV2_LISTENER_REPORT:
1295 icmp6_ifstat_inc(ifp, ifs6_in_mldreport);
1296 break;
1297 case MLD_LISTENER_DONE:
1298 icmp6_ifstat_inc(ifp, ifs6_in_mlddone);
1299 break;
1300 default:

--- 102 unchanged lines hidden (view full) ---

1403 TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link,
1404 tifma) {
1405 if (ifma->ifma_addr->sa_family != AF_INET6 ||
1406 ifma->ifma_protospec == NULL)
1407 continue;
1408 inm = (struct in6_multi *)ifma->ifma_protospec;
1409 switch (mli->mli_version) {
1410 case MLD_VERSION_1:
1411 /*
1412 * XXX Drop IF_ADDR lock temporarily to
1413 * avoid recursion caused by a potential
1414 * call by in6ifa_ifpforlinklocal().
1415 * rwlock candidate?
1416 */
1417 IF_ADDR_UNLOCK(ifp);
1293 mld_v1_process_group_timer(inm,
1294 mli->mli_version);
1418 mld_v1_process_group_timer(inm,
1419 mli->mli_version);
1420 IF_ADDR_LOCK(ifp);
1295 break;
1296 case MLD_VERSION_2:
1297 mld_v2_process_group_timers(mli, &qrq,
1298 &scq, inm, uri_fasthz);
1299 break;
1300 }
1301 }
1302 IF_ADDR_UNLOCK(ifp);

--- 202 unchanged lines hidden (view full) ---

1505 CTR4(KTR_MLD, "%s: switching to v%d on ifp %p(%s)", __func__,
1506 version, mli->mli_ifp, mli->mli_ifp->if_xname);
1507
1508 if (version == MLD_VERSION_1) {
1509 /*
1510 * Compute the "Older Version Querier Present" timer as per
1511 * Section 9.12.
1512 */
1421 break;
1422 case MLD_VERSION_2:
1423 mld_v2_process_group_timers(mli, &qrq,
1424 &scq, inm, uri_fasthz);
1425 break;
1426 }
1427 }
1428 IF_ADDR_UNLOCK(ifp);

--- 202 unchanged lines hidden (view full) ---

1631 CTR4(KTR_MLD, "%s: switching to v%d on ifp %p(%s)", __func__,
1632 version, mli->mli_ifp, mli->mli_ifp->if_xname);
1633
1634 if (version == MLD_VERSION_1) {
1635 /*
1636 * Compute the "Older Version Querier Present" timer as per
1637 * Section 9.12.
1638 */
1513 old_version_timer = mli->mli_rv * mli->mli_qi + mli->mli_qri;
1639 old_version_timer = (mli->mli_rv * mli->mli_qi) + mli->mli_qri;
1514 old_version_timer *= PR_SLOWHZ;
1515 mli->mli_v1_timer = old_version_timer;
1516 }
1517
1518 if (mli->mli_v1_timer > 0 && mli->mli_version != MLD_VERSION_1) {
1519 mli->mli_version = MLD_VERSION_1;
1520 mld_v2_cancel_link_timers(mli);
1521 }

--- 116 unchanged lines hidden (view full) ---

1638 * See Section 9.12 of RFC 3810.
1639 */
1640static void
1641mld_v1_process_querier_timers(struct mld_ifinfo *mli)
1642{
1643
1644 MLD_LOCK_ASSERT();
1645
1640 old_version_timer *= PR_SLOWHZ;
1641 mli->mli_v1_timer = old_version_timer;
1642 }
1643
1644 if (mli->mli_v1_timer > 0 && mli->mli_version != MLD_VERSION_1) {
1645 mli->mli_version = MLD_VERSION_1;
1646 mld_v2_cancel_link_timers(mli);
1647 }

--- 116 unchanged lines hidden (view full) ---

1764 * See Section 9.12 of RFC 3810.
1765 */
1766static void
1767mld_v1_process_querier_timers(struct mld_ifinfo *mli)
1768{
1769
1770 MLD_LOCK_ASSERT();
1771
1646 if (mli->mli_v1_timer == 0 && mli->mli_version != MLD_VERSION_2) {
1772 if (mli->mli_version != MLD_VERSION_2 && --mli->mli_v1_timer == 0) {
1647 /*
1648 * MLDv1 Querier Present timer expired; revert to MLDv2.
1649 */
1650 CTR5(KTR_MLD,
1651 "%s: transition from v%d -> v%d on %p(%s)",
1652 __func__, mli->mli_version, MLD_VERSION_2,
1653 mli->mli_ifp, mli->mli_ifp->if_xname);
1654 mli->mli_version = MLD_VERSION_2;

--- 1538 unchanged lines hidden ---
1773 /*
1774 * MLDv1 Querier Present timer expired; revert to MLDv2.
1775 */
1776 CTR5(KTR_MLD,
1777 "%s: transition from v%d -> v%d on %p(%s)",
1778 __func__, mli->mli_version, MLD_VERSION_2,
1779 mli->mli_ifp, mli->mli_ifp->if_xname);
1780 mli->mli_version = MLD_VERSION_2;

--- 1538 unchanged lines hidden ---