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 --- |