* Process a received IGMPv2 general or group-specific query. */
| 838 | * Process a received IGMPv2 general or group-specific query. |
| 839 | */ |
| 840 | static int |
| 841 | igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip, |
| 842 | const struct igmp *igmp) |
| 843 | { |
| 844 | struct ifmultiaddr *ifma; |
| 845 | struct igmp_ifsoftc *igi; |
| 846 | struct in_multi *inm; |
| 847 | int is_general_query; |
| 848 | uint16_t timer; |
| 849 | |
| 850 | NET_EPOCH_ASSERT(); |
| 851 | |
| 852 | is_general_query = 0; |
| 853 | |
| 854 | /* |
| 855 | * Validate address fields upfront. |
| 856 | * XXX SMPng: unlocked increments in igmpstat assumed atomic. |
| 857 | */ |
| 858 | if (in_nullhost(igmp->igmp_group)) { |
| 859 | /* |
| 860 | * IGMPv2 General Query. |
| 861 | * If this was not sent to the all-hosts group, ignore it. |
| 862 | */ |
| 863 | if (!in_allhosts(ip->ip_dst)) |
| 864 | return (0); |
| 865 | IGMPSTAT_INC(igps_rcv_gen_queries); |
| 866 | is_general_query = 1; |
| 867 | } else { |
| 868 | /* IGMPv2 Group-Specific Query. */ |
| 869 | IGMPSTAT_INC(igps_rcv_group_queries); |
| 870 | } |
| 871 | |
| 872 | IN_MULTI_LIST_LOCK(); |
| 873 | IGMP_LOCK(); |
| 874 | |
| 875 | igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; |
| 876 | KASSERT(igi != NULL, ("%s: no igmp_ifsoftc for ifp %p", __func__, ifp)); |
| 877 | |
| 878 | if (igi->igi_flags & IGIF_LOOPBACK) { |
| 879 | CTR2(KTR_IGMPV3, "ignore v2 query on IGIF_LOOPBACK ifp %p(%s)", |
| 880 | ifp, ifp->if_xname); |
| 881 | goto out_locked; |
| 882 | } |
| 883 | |
| 884 | /* |
| 885 | * Ignore v2 query if in v1 Compatibility Mode. |
| 886 | */ |
| 887 | if (igi->igi_version == IGMP_VERSION_1) |
| 888 | goto out_locked; |
| 889 | |
| 890 | igmp_set_version(igi, IGMP_VERSION_2); |
| 891 | |
| 892 | timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE; |
| 893 | if (timer == 0) |
| 894 | timer = 1; |
| 895 | |
| 896 | if (is_general_query) { |
| 897 | /* |
no test coverage detected