Lines Matching +full:atomic +full:- +full:threshold +full:- +full:us
1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2007-2009 Bruce Simpson.
157 * System-wide globals.
160 * queue. The IGMP subsystem lock ends up being system-wide for the moment,
173 * per-link state iterators.
187 * to a vnet in ifp->if_vnet.
201 * VIMAGE-wide globals.
203 * The IGMPv3 timers themselves need to run per-image, however, for
211 * IGMP for IPv4 does not force link-local addresses to be used for each
213 * Obviously the IGMPv3 per-interface state has per-vimage granularity
221 VNET_DEFINE_STATIC(int, state_change_timers_running); /* IGMPv3 state-change
290 "Rate limit for IGMPv3 Group-and-Source queries in seconds");
293 * Non-virtualized sysctls.
297 "Per-interface IGMPv3 state");
304 m->m_pkthdr.PH_loc.ptr = ifp->if_vnet;
306 m->m_pkthdr.rcvif = ifp;
307 m->m_pkthdr.flowid = ifp->if_index;
314 m->m_pkthdr.PH_loc.ptr = NULL;
315 m->m_pkthdr.flowid = 0;
331 KASSERT(curvnet == (m->m_pkthdr.PH_loc.ptr),
335 return (m->m_pkthdr.flowid);
352 if (req->oldptr != NULL) {
353 if (req->oldlen < sizeof(struct igmpstat))
368 req->validlen = sizeof(struct igmpstat);
371 if (req->newptr != NULL) {
372 if (req->newlen < sizeof(struct igmpstat))
417 if (error || !req->newptr)
436 * Retrieve or set threshold between group-source queries in seconds.
456 if (error || !req->newptr)
459 if (i < -1 || i >= 60) {
494 if (req->newptr != NULL)
516 if (ifp == igi->igi_ifp) {
519 info.igi_version = igi->igi_version;
520 info.igi_v1_timer = igi->igi_v1_timer;
521 info.igi_v2_timer = igi->igi_v2_timer;
522 info.igi_v3_timer = igi->igi_v3_timer;
523 info.igi_flags = igi->igi_flags;
524 info.igi_rv = igi->igi_rv;
525 info.igi_qi = igi->igi_qi;
526 info.igi_qri = igi->igi_qri;
527 info.igi_uri = igi->igi_uri;
554 m->m_flags |= M_IGMP_LOOP;
556 if (--limit == 0)
565 * Reports are ALWAYS suppressed for ALL-HOSTS (224.0.0.1).
567 * disabled for all groups in the 224.0.0.0/24 link-local scope. However,
572 * should be suppressed, or non-zero if reports should be issued.
596 p->ipopt_dst.s_addr = INADDR_ANY;
597 p->ipopt_list[0] = (char)IPOPT_RA; /* Router Alert Option */
598 p->ipopt_list[1] = 0x04; /* 4 bytes long */
599 p->ipopt_list[2] = IPOPT_EOL; /* End of IP option list */
600 p->ipopt_list[3] = 0x00; /* pad byte */
601 m->m_len = sizeof(p->ipopt_dst) + p->ipopt_list[1];
615 __func__, ifp, ifp->if_xname);
620 if (!(ifp->if_flags & IFF_MULTICAST))
621 igi->igi_flags |= IGIF_SILENT;
642 igi->igi_ifp = ifp;
643 igi->igi_version = V_igmp_default_version;
644 igi->igi_flags = 0;
645 igi->igi_rv = IGMP_RV_INIT;
646 igi->igi_qi = IGMP_QI_INIT;
647 igi->igi_qri = IGMP_QRI_INIT;
648 igi->igi_uri = IGMP_URI_INIT;
649 mbufq_init(&igi->igi_gq, IGMP_MAX_RESPONSE_PACKETS);
654 ifp, ifp->if_xname);
678 ifp->if_xname);
683 igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp;
684 if (igi->igi_version == IGMP_VERSION_3) {
687 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
691 if (inm->inm_state == IGMP_LEAVING_MEMBER)
711 __func__, ifp, ifp->if_xname);
724 __func__, ifp, ifp->if_xname);
729 if (igi->igi_ifp == ifp) {
733 mbufq_drain(&igi->igi_gq);
744 * Return non-zero if the message should be dropped.
763 * XXX SMPng: unlocked increments in igmpstat assumed atomic.
765 if (!in_allhosts(ip->ip_dst) || !in_nullhost(igmp->igmp_group)) {
774 igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp;
777 if (igi->igi_flags & IGIF_LOOPBACK) {
779 ifp, ifp->if_xname);
788 CTR2(KTR_IGMPV3, "process v1 query on ifp %p(%s)", ifp, ifp->if_xname);
795 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
799 if (inm->inm_timer != 0)
801 switch (inm->inm_state) {
812 inm->inm_state = IGMP_REPORTING_MEMBER;
813 inm->inm_timer = IGMP_RANDOM_DELAY(
830 * Process a received IGMPv2 general or group-specific query.
848 * XXX SMPng: unlocked increments in igmpstat assumed atomic.
850 if (in_nullhost(igmp->igmp_group)) {
853 * If this was not sent to the all-hosts group, ignore it.
855 if (!in_allhosts(ip->ip_dst))
860 /* IGMPv2 Group-Specific Query. */
867 igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp;
870 if (igi->igi_flags & IGIF_LOOPBACK) {
872 ifp, ifp->if_xname);
879 if (igi->igi_version == IGMP_VERSION_1)
884 timer = igmp->igmp_code * IGMP_FASTHZ / IGMP_TIMER_SCALE;
894 ifp, ifp->if_xname);
895 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
903 * Group-specific IGMPv2 query, we need only
906 inm = inm_lookup(ifp, igmp->igmp_group);
910 ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname);
927 * below the threshold, reset it.
932 * for group and group-source query responses.
942 ntohl(inm->inm_addr.s_addr), inm->inm_ifp->if_xname, timer);
946 switch (inm->inm_state) {
951 if (inm->inm_timer != 0 &&
952 inm->inm_timer <= timer) {
963 CTR1(KTR_IGMPV3, "%s: ->REPORTING", __func__);
964 inm->inm_state = IGMP_REPORTING_MEMBER;
965 inm->inm_timer = IGMP_RANDOM_DELAY(timer);
969 CTR1(KTR_IGMPV3, "%s: ->AWAKENING", __func__);
970 inm->inm_state = IGMP_AWAKENING_MEMBER;
978 * Process a received IGMPv3 general, group-specific or
979 * group-and-source-specific query.
996 CTR2(KTR_IGMPV3, "process v3 query on ifp %p(%s)", ifp, ifp->if_xname);
998 maxresp = igmpv3->igmp_code; /* in 1/10ths of a second */
1000 maxresp = IGMP_MANT(igmpv3->igmp_code) <<
1001 (IGMP_EXP(igmpv3->igmp_code) + 3);
1005 * Robustness must never be less than 2 for on-wire IGMPv3.
1010 qrv = IGMP_QRV(igmpv3->igmp_misc);
1017 qqi = igmpv3->igmp_qqi;
1019 qqi = IGMP_MANT(igmpv3->igmp_qqi) <<
1020 (IGMP_EXP(igmpv3->igmp_qqi) + 3);
1027 nsrc = ntohs(igmpv3->igmp_numsrc);
1034 if (in_nullhost(igmpv3->igmp_group)) {
1043 if (!in_allhosts(ip->ip_dst) || nsrc > 0) {
1049 /* Group or group-source specific query. */
1059 igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp;
1062 if (igi->igi_flags & IGIF_LOOPBACK) {
1064 ifp, ifp->if_xname);
1074 if (igi->igi_version != IGMP_VERSION_3) {
1076 igi->igi_version, ifp, ifp->if_xname);
1081 igi->igi_rv = qrv;
1082 igi->igi_qi = qqi;
1083 igi->igi_qri = maxresp;
1090 * Schedule a current-state report on this ifp for
1098 ifp, ifp->if_xname);
1099 if (igi->igi_v3_timer == 0 || igi->igi_v3_timer >= timer) {
1100 igi->igi_v3_timer = IGMP_RANDOM_DELAY(timer);
1105 * Group-source-specific queries are throttled on
1106 * a per-group basis to defeat denial-of-service attempts.
1110 inm = inm_lookup(ifp, igmpv3->igmp_group);
1114 if (!ratecheck(&inm->inm_lastgsrtv,
1123 ntohl(igmpv3->igmp_group.s_addr), ifp, ifp->if_xname);
1129 * group-specific or group-and-source query.
1131 if (igi->igi_v3_timer == 0 || igi->igi_v3_timer >= timer)
1143 * Process a received IGMPv3 group-specific or group-and-source-specific
1159 switch (inm->inm_state) {
1175 nsrc = ntohs(igmpv3->igmp_numsrc);
1178 * Deal with group-specific queries upfront.
1180 * source-list state if it exists, and schedule a query response
1181 * for this group-specific query.
1184 if (inm->inm_state == IGMP_G_QUERY_PENDING_MEMBER ||
1185 inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER) {
1187 timer = min(inm->inm_timer, timer);
1189 inm->inm_state = IGMP_G_QUERY_PENDING_MEMBER;
1190 inm->inm_timer = IGMP_RANDOM_DELAY(timer);
1196 * Deal with the case where a group-and-source-specific query has
1197 * been received but a group-specific query is already pending.
1199 if (inm->inm_state == IGMP_G_QUERY_PENDING_MEMBER) {
1200 timer = min(inm->inm_timer, timer);
1201 inm->inm_timer = IGMP_RANDOM_DELAY(timer);
1207 * Finally, deal with the case where a group-and-source-specific
1208 * query has been received, where a response to a previous g-s-r
1210 * In this case, we need to parse the source-list which the Querier
1211 * has provided us with and check if we have any source list filter
1214 * If we do, we must record them and schedule a current-state
1220 if (inm->inm_nsrc > 0) {
1227 retval = inm_record_source(inm, ap->s_addr);
1235 inm->inm_state = IGMP_SG_QUERY_PENDING_MEMBER;
1236 inm->inm_timer = IGMP_RANDOM_DELAY(timer);
1258 if (ifp->if_flags & IFF_LOOPBACK)
1261 if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
1262 !in_hosteq(igmp->igmp_group, ip->ip_dst)) {
1274 if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) {
1277 ip->ip_src.s_addr = htonl(ia->ia_subnet);
1281 ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname);
1289 inm = inm_lookup(ifp, igmp->igmp_group);
1293 igi = inm->inm_igi;
1307 if (igi->igi_version == IGMP_VERSION_3) {
1313 inm->inm_timer = 0;
1315 switch (inm->inm_state) {
1324 ntohl(igmp->igmp_group.s_addr), ifp,
1325 ifp->if_xname);
1327 inm->inm_state = IGMP_SLEEPING_MEMBER;
1332 ntohl(igmp->igmp_group.s_addr), ifp,
1333 ifp->if_xname);
1334 if (igi->igi_version == IGMP_VERSION_1)
1335 inm->inm_state = IGMP_LAZY_MEMBER;
1336 else if (igi->igi_version == IGMP_VERSION_2)
1337 inm->inm_state = IGMP_SLEEPING_MEMBER;
1370 if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr)) {
1376 if (ifp->if_flags & IFF_LOOPBACK) {
1380 if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
1381 !in_hosteq(igmp->igmp_group, ip->ip_dst)) {
1393 if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) {
1395 ip->ip_src.s_addr = htonl(ia->ia_subnet);
1399 ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname);
1408 inm = inm_lookup(ifp, igmp->igmp_group);
1412 igi = inm->inm_igi;
1422 if (igi->igi_version == IGMP_VERSION_3) {
1428 inm->inm_timer = 0;
1430 switch (inm->inm_state) {
1440 ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname);
1442 inm->inm_state = IGMP_LAZY_MEMBER;
1472 ifp = m->m_pkthdr.rcvif;
1480 igmplen = ntohs(ip->ip_len) - iphlen;
1500 if ((!M_WRITABLE(m) || m->m_len < minlen) &&
1510 m->m_data += iphlen;
1511 m->m_len -= iphlen;
1518 m->m_data -= iphlen;
1519 m->m_len += iphlen;
1522 * IGMP control traffic is link-scope, and must have a TTL of 1.
1526 if (igmp->igmp_type != IGMP_DVMRP && ip->ip_ttl != 1) {
1532 switch (igmp->igmp_type) {
1535 if (igmp->igmp_code == 0)
1578 nsrc = ntohs(igmpv3->igmp_numsrc);
1580 UINT16_MAX - iphlen - IGMP_V3_QUERY_MINLEN) {
1592 m->m_len < igmpv3len) &&
1674 * Fast timeout handler (per-vnet).
1681 struct mbufq scq; /* State-change packets */
1715 if (igi->igi_v3_timer == 0) {
1717 } else if (--igi->igi_v3_timer == 0) {
1735 * IGMPv1/v2/v3 host report and state-change timer processing.
1739 ifp = igi->igi_ifp;
1741 if (igi->igi_version == IGMP_VERSION_3) {
1742 loop = (igi->igi_flags & IGIF_LOOPBACK) ? 1 : 0;
1743 uri_fasthz = IGMP_RANDOM_DELAY(igi->igi_uri *
1750 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1754 switch (igi->igi_version) {
1758 igi->igi_version);
1768 if (igi->igi_version == IGMP_VERSION_3) {
1797 if (inm->inm_timer == 0) {
1799 } else if (--inm->inm_timer == 0) {
1806 switch (inm->inm_state) {
1816 inm->inm_state = IGMP_IDLE_MEMBER;
1852 * timer active. This is a no-op in this function; it is easier
1853 * to deal with it here than to complicate the slow-timeout path.
1855 if (inm->inm_timer == 0) {
1857 } else if (--inm->inm_timer == 0) {
1863 if (inm->inm_sctimer == 0) {
1865 } else if (--inm->inm_sctimer == 0) {
1876 switch (inm->inm_state) {
1887 * Respond to a previously pending Group-Specific
1888 * or Group-and-Source-Specific query by enqueueing
1889 * the appropriate Current-State report for
1896 (inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER));
1899 inm->inm_state = IGMP_REPORTING_MEMBER;
1908 * State-change retransmission timer fired.
1910 * set the global pending state-change flag, and
1913 if (--inm->inm_scrv > 0) {
1914 inm->inm_sctimer = uri_fasthz;
1918 * Retransmit the previously computed state-change
1922 * a state-change.
1927 CTR3(KTR_IGMPV3, "%s: T1 -> T0 for 0x%08x/%s", __func__,
1928 ntohl(inm->inm_addr.s_addr),
1929 inm->inm_ifp->if_xname);
1938 if (inm->inm_state == IGMP_LEAVING_MEMBER &&
1939 inm->inm_scrv == 0) {
1940 inm->inm_state = IGMP_NOT_MEMBER;
1963 KASSERT(inm->inm_igi->igi_version == IGMP_VERSION_3,
1966 if (inm->inm_state != IGMP_G_QUERY_PENDING_MEMBER ||
1967 inm->inm_state != IGMP_SG_QUERY_PENDING_MEMBER)
1970 if (inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER)
1973 inm->inm_timer = 0;
1974 inm->inm_state = IGMP_REPORTING_MEMBER;
1989 version, igi->igi_ifp, igi->igi_ifp->if_xname);
1996 old_version_timer = igi->igi_rv * igi->igi_qi + igi->igi_qri;
2000 igi->igi_v1_timer = old_version_timer;
2001 igi->igi_v2_timer = 0;
2003 igi->igi_v1_timer = 0;
2004 igi->igi_v2_timer = old_version_timer;
2008 if (igi->igi_v1_timer == 0 && igi->igi_v2_timer > 0) {
2009 if (igi->igi_version != IGMP_VERSION_2) {
2010 igi->igi_version = IGMP_VERSION_2;
2013 } else if (igi->igi_v1_timer > 0) {
2014 if (igi->igi_version != IGMP_VERSION_1) {
2015 igi->igi_version = IGMP_VERSION_1;
2023 * joined on it; state-change, general-query, and group-query timers.
2039 igi->igi_ifp, igi->igi_ifp->if_xname);
2052 igi->igi_v3_timer = 0;
2055 * Now clear the current-state and state-change report timers
2058 ifp = igi->igi_ifp;
2060 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2064 switch (inm->inm_state) {
2082 * message is sent upstream to the old querier --
2092 inm->inm_state = IGMP_REPORTING_MEMBER;
2096 * Always clear state-change and group report timers.
2097 * Free any pending IGMPv3 state-change records.
2099 inm->inm_sctimer = 0;
2100 inm->inm_timer = 0;
2101 mbufq_drain(&inm->inm_scq);
2118 if (igi->igi_v1_timer == 0 && igi->igi_v2_timer == 0) {
2125 igi->igi_version != IGMP_VERSION_3) {
2127 "%s: transition from v%d -> v%d on %p(%s)",
2128 __func__, igi->igi_version, IGMP_VERSION_3,
2129 igi->igi_ifp, igi->igi_ifp->if_xname);
2130 igi->igi_version = IGMP_VERSION_3;
2132 } else if (igi->igi_v1_timer == 0 && igi->igi_v2_timer > 0) {
2143 "%s: transition from v%d -> v%d on %p(%s)",
2144 __func__, igi->igi_version, IGMP_VERSION_3,
2145 igi->igi_ifp, igi->igi_ifp->if_xname);
2146 igi->igi_v2_timer = 0;
2147 igi->igi_version = IGMP_VERSION_3;
2149 --igi->igi_v2_timer;
2151 igi->igi_version != IGMP_VERSION_2) {
2153 "%s: transition from v%d -> v%d on %p(%s)",
2154 __func__, igi->igi_version, IGMP_VERSION_2,
2155 igi->igi_ifp, igi->igi_ifp->if_xname);
2156 igi->igi_version = IGMP_VERSION_2;
2160 } else if (igi->igi_v1_timer > 0) {
2172 "%s: transition from v%d -> v%d on %p(%s)",
2173 __func__, igi->igi_version, IGMP_VERSION_3,
2174 igi->igi_ifp, igi->igi_ifp->if_xname);
2175 igi->igi_v1_timer = 0;
2176 igi->igi_version = IGMP_VERSION_3;
2178 --igi->igi_v1_timer;
2180 if (igi->igi_v2_timer > 0) {
2183 __func__, igi->igi_ifp, igi->igi_ifp->if_xname);
2184 igi->igi_v2_timer = 0;
2214 * Per-vnet slowtimo handler.
2246 ifp = inm->inm_ifp;
2253 m->m_pkthdr.len = sizeof(struct ip) + sizeof(struct igmp);
2255 m->m_data += sizeof(struct ip);
2256 m->m_len = sizeof(struct igmp);
2259 igmp->igmp_type = type;
2260 igmp->igmp_code = 0;
2261 igmp->igmp_group = inm->inm_addr;
2262 igmp->igmp_cksum = 0;
2263 igmp->igmp_cksum = in_cksum(m, sizeof(struct igmp));
2265 m->m_data -= sizeof(struct ip);
2266 m->m_len += sizeof(struct ip);
2269 ip->ip_tos = 0;
2270 ip->ip_len = htons(sizeof(struct ip) + sizeof(struct igmp));
2271 ip->ip_off = 0;
2272 ip->ip_p = IPPROTO_IGMP;
2273 ip->ip_src.s_addr = INADDR_ANY;
2276 ip->ip_dst.s_addr = htonl(INADDR_ALLRTRS_GROUP);
2278 ip->ip_dst = inm->inm_addr;
2282 m->m_flags |= M_IGMPV2;
2283 if (inm->inm_igi->igi_flags & IGIF_LOOPBACK)
2284 m->m_flags |= M_IGMP_LOOP;
2300 * has been any change between T0 (when the last state-change was issued)
2325 * Try to detect if the upper layer just asked us to change state
2328 KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__));
2329 ifp = inm->inm_ifma->ifma_ifp;
2336 KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__));
2340 igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp;
2348 if (inm->inm_st[1].iss_fmode != inm->inm_st[0].iss_fmode) {
2349 CTR3(KTR_IGMPV3, "%s: inm transition %d -> %d", __func__,
2350 inm->inm_st[0].iss_fmode, inm->inm_st[1].iss_fmode);
2351 if (inm->inm_st[0].iss_fmode == MCAST_UNDEFINED) {
2355 } else if (inm->inm_st[1].iss_fmode == MCAST_UNDEFINED) {
2378 * IGMPv3 will schedule an IGMPv3 state-change report containing the
2389 ntohl(inm->inm_addr.s_addr), inm->inm_ifp, inm->inm_ifp->if_xname);
2394 ifp = inm->inm_ifp;
2399 KASSERT(igi && igi->igi_ifp == ifp, ("%s: inconsistent ifp", __func__));
2410 if ((ifp->if_flags & IFF_LOOPBACK) ||
2411 (igi->igi_flags & IGIF_SILENT) ||
2412 !igmp_isgroupreported(inm->inm_addr)) {
2415 inm->inm_state = IGMP_SILENT_MEMBER;
2416 inm->inm_timer = 0;
2424 if (igi->igi_version == IGMP_VERSION_3 &&
2425 inm->inm_state == IGMP_LEAVING_MEMBER) {
2426 MPASS(inm->inm_refcount > 1);
2429 inm->inm_state = IGMP_REPORTING_MEMBER;
2431 switch (igi->igi_version) {
2434 inm->inm_state = IGMP_IDLE_MEMBER;
2436 (igi->igi_version == IGMP_VERSION_2) ?
2440 inm->inm_timer = IGMP_RANDOM_DELAY(
2454 * Immediately enqueue a State-Change Report for
2459 mq = &inm->inm_scq;
2466 error = retval * -1;
2471 * Schedule transmission of pending state-change
2474 * giving us an opportunity to merge the reports.
2476 if (igi->igi_flags & IGIF_LOOPBACK) {
2477 inm->inm_scrv = 1;
2479 KASSERT(igi->igi_rv > 1,
2481 igi->igi_rv));
2482 inm->inm_scrv = igi->igi_rv;
2484 inm->inm_sctimer = 1;
2493 * Only update the T0 state if state change is atomic,
2499 CTR3(KTR_IGMPV3, "%s: T1 -> T0 for 0x%08x/%s", __func__,
2500 ntohl(inm->inm_addr.s_addr), inm->inm_ifp->if_xname);
2507 * Issue an intermediate state change during the IGMP life-cycle.
2516 ntohl(inm->inm_addr.s_addr), inm->inm_ifp, inm->inm_ifp->if_xname);
2518 ifp = inm->inm_ifp;
2523 KASSERT(igi && igi->igi_ifp == ifp, ("%s: inconsistent ifp", __func__));
2525 if ((ifp->if_flags & IFF_LOOPBACK) ||
2526 (igi->igi_flags & IGIF_SILENT) ||
2527 !igmp_isgroupreported(inm->inm_addr) ||
2528 (igi->igi_version != IGMP_VERSION_3)) {
2529 if (!igmp_isgroupreported(inm->inm_addr)) {
2535 CTR3(KTR_IGMPV3, "%s: T1 -> T0 for 0x%08x/%s", __func__,
2536 ntohl(inm->inm_addr.s_addr), inm->inm_ifp->if_xname);
2540 mbufq_drain(&inm->inm_scq);
2542 retval = igmp_v3_enqueue_group_record(&inm->inm_scq, inm, 1, 0, 0);
2545 return (-retval);
2548 * If record(s) were enqueued, start the state-change
2551 inm->inm_scrv = ((igi->igi_flags & IGIF_LOOPBACK) ? 1 : igi->igi_rv);
2552 inm->inm_sctimer = 1;
2564 * IGMPv3 enqueues a state-change report containing a transition
2575 __func__, ntohl(inm->inm_addr.s_addr), inm->inm_ifp,
2576 inm->inm_ifp->if_xname);
2581 switch (inm->inm_state) {
2593 if (igi->igi_version == IGMP_VERSION_2) {
2595 if (inm->inm_state == IGMP_G_QUERY_PENDING_MEMBER ||
2596 inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER)
2601 inm->inm_state = IGMP_NOT_MEMBER;
2602 } else if (igi->igi_version == IGMP_VERSION_3) {
2605 * Immediately enqueue a state-change report
2607 * giving us an opportunity to merge reports.
2609 mbufq_drain(&inm->inm_scq);
2610 inm->inm_timer = 0;
2611 if (igi->igi_flags & IGIF_LOOPBACK) {
2612 inm->inm_scrv = 1;
2614 inm->inm_scrv = igi->igi_rv;
2618 ntohl(inm->inm_addr.s_addr),
2619 inm->inm_ifp->if_xname, inm->inm_scrv);
2620 if (inm->inm_scrv == 0) {
2621 inm->inm_state = IGMP_NOT_MEMBER;
2622 inm->inm_sctimer = 0;
2629 &inm->inm_scq, inm, 1, 0, 0);
2634 inm->inm_state = IGMP_LEAVING_MEMBER;
2635 inm->inm_sctimer = 1;
2651 CTR3(KTR_IGMPV3, "%s: T1 -> T0 for 0x%08x/%s", __func__,
2652 ntohl(inm->inm_addr.s_addr), inm->inm_ifp->if_xname);
2653 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED;
2655 __func__, ntohl(inm->inm_addr.s_addr),
2656 inm->inm_ifp->if_xname);
2664 * split out, and the multiple-tree-walks coalesced into a single
2667 * If is_state_change is zero, a current-state record is appended.
2668 * If is_state_change is non-zero, a state-change report is appended.
2670 * If is_group_query is non-zero, an mbuf packet chain is allocated.
2676 * If is_source_query is non-zero, each source is checked to see if
2677 * it was recorded for a Group-Source query, and will be omitted if
2678 * it is not both in-mode and recorded.
2707 ifp = inm->inm_ifp;
2718 mode = inm->inm_st[1].iss_fmode;
2721 * If we did not transition out of ASM mode during t0->t1,
2725 if (inm->inm_st[0].iss_asm > 0 && inm->inm_st[1].iss_asm > 0 &&
2726 inm->inm_nsrc == 0)
2732 * If the mode did not change, and there are non-ASM
2740 if (mode != inm->inm_st[0].iss_fmode) {
2767 KASSERT(inm->inm_st[1].iss_asm == 0,
2769 __func__, inm, inm->inm_st[1].iss_asm));
2781 ntohl(inm->inm_addr.s_addr), inm->inm_ifp->if_xname);
2795 igmp_rec_type_to_str(type), ntohl(inm->inm_addr.s_addr),
2796 inm->inm_ifp->if_xname);
2809 (m0->m_pkthdr.vt_nrecs + 1 <= IGMP_V3_REPORT_MAXRECS) &&
2810 (m0->m_pkthdr.len + minrec0len) <
2811 (ifp->if_mtu - IGMP_LEADINGSPACE)) {
2812 m0srcs = (ifp->if_mtu - m0->m_pkthdr.len -
2819 return (-ENOMEM);
2822 m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE -
2827 m->m_data += IGMP_LEADINGSPACE;
2835 return (-ENOMEM);
2849 ig.ig_group = inm->inm_addr;
2854 return (-ENOMEM);
2865 * Only append sources which are in-mode at t1. If we are
2869 * to a group-source query.
2875 md->m_len - nbytes);
2882 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, nims) {
2884 ims->ims_haddr);
2892 if (is_source_query && ims->ims_stp == 0) {
2898 naddr = htonl(ims->ims_haddr);
2904 return (-ENOMEM);
2913 pig->ig_numsrc = htons(msrcs);
2929 m->m_pkthdr.vt_nrecs = 1;
2932 m->m_pkthdr.vt_nrecs++;
2948 return (-ENOMEM);
2952 m->m_data += IGMP_LEADINGSPACE;
2959 return (-ENOMEM);
2969 return (-ENOMEM);
2971 m->m_pkthdr.vt_nrecs = 1;
2974 m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE -
2980 ims->ims_haddr);
2987 if (is_source_query && ims->ims_stp == 0) {
2993 naddr = htonl(ims->ims_haddr);
2999 return (-ENOMEM);
3005 pig->ig_numsrc = htons(msrcs);
3030 * Source list filter state is held in an RB-tree. When the filter list
3035 * As we may potentially queue two record types, and the entire R-B tree
3041 * which makes things easier on us, and it may or may not be harder on
3068 if (inm->inm_nsrc == 0 ||
3069 (inm->inm_st[0].iss_asm > 0 && inm->inm_st[1].iss_asm > 0))
3072 ifp = inm->inm_ifp; /* interface */
3073 mode = inm->inm_st[1].iss_fmode; /* filter mode at t1 */
3078 nbytes = 0; /* # of bytes appended to group's state-change queue */
3090 * The first kind of source we encounter tells us which
3099 (m0->m_pkthdr.vt_nrecs + 1 <=
3101 (m0->m_pkthdr.len + MINRECLEN) <
3102 (ifp->if_mtu - IGMP_LEADINGSPACE)) {
3104 m0srcs = (ifp->if_mtu - m0->m_pkthdr.len -
3112 m->m_data += IGMP_LEADINGSPACE;
3121 return (-ENOMEM);
3123 m->m_pkthdr.vt_nrecs = 0;
3125 m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE -
3140 ig.ig_group = inm->inm_addr;
3146 return (-ENOMEM);
3151 md = m_getptr(m, npbytes -
3159 uint8_t *) + md->m_len -
3166 * Only report deltas in-mode at t1.
3173 nims = RB_MIN(ip_msource_tree, &inm->inm_srcs);
3176 __func__, ims->ims_haddr);
3200 naddr = htonl(ims->ims_haddr);
3207 return (-ENOMEM);
3221 npbytes -= sizeof(struct igmp_grouprec);
3228 "%s: m_adj(m, -ig)", __func__);
3229 m_adj(m, -((int)sizeof(
3236 pig->ig_type = IGMP_ALLOW_NEW_SOURCES;
3238 pig->ig_type = IGMP_BLOCK_OLD_SOURCES;
3239 pig->ig_numsrc = htons(rsrcs);
3244 m->m_pkthdr.vt_nrecs++;
3263 struct mbuf *m; /* pending state-change */
3264 struct mbuf *m0; /* copy of pending state-change */
3265 struct mbuf *mt; /* last state-change in packet */
3278 * copy of each queued state-change message before merging.
3280 if (inm->inm_scrv > 0)
3283 gq = &inm->inm_scq;
3306 if ((mt->m_pkthdr.vt_nrecs +
3307 m->m_pkthdr.vt_nrecs <=
3309 (mt->m_pkthdr.len + recslen <=
3310 (inm->inm_ifp->if_mtu - IGMP_LEADINGSPACE)))
3318 mt = m->m_nextpkt;
3328 m = m0->m_nextpkt;
3334 m0->m_nextpkt = NULL;
3335 m = m->m_nextpkt;
3349 m0->m_flags &= ~M_PKTHDR;
3350 mt->m_pkthdr.len += recslen;
3351 mt->m_pkthdr.vt_nrecs +=
3352 m0->m_pkthdr.vt_nrecs;
3354 mtl->m_next = m0;
3376 KASSERT(igi->igi_version == IGMP_VERSION_3,
3377 ("%s: called when version %d", __func__, igi->igi_version));
3385 if (!mbufq_empty(&igi->igi_gq))
3388 ifp = igi->igi_ifp;
3390 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3394 KASSERT(ifp == inm->inm_ifp,
3397 switch (inm->inm_state) {
3406 inm->inm_state = IGMP_REPORTING_MEMBER;
3407 retval = igmp_v3_enqueue_group_record(&igi->igi_gq,
3420 loop = (igi->igi_flags & IGIF_LOOPBACK) ? 1 : 0;
3421 igmp_dispatch_queue(&igi->igi_gq, IGMP_MAX_RESPONSE_BURST, loop);
3426 if (mbufq_first(&igi->igi_gq) != NULL) {
3427 igi->igi_v3_timer = 1 + IGMP_RANDOM_DELAY(
3439 * VIMAGE: Needs to store/restore vnet pointer on a per-mbuf-chain basis.
3441 * a link and uses a link-scope multicast address.
3460 CURVNET_SET((struct vnet *)(m->m_pkthdr.PH_loc.ptr));
3480 imo.imo_multicast_vif = -1;
3489 if (m->m_flags & M_IGMP_LOOP)
3494 if (m->m_flags & M_IGMPV2) {
3508 m0->m_pkthdr.rcvif = V_loif;
3534 * will however be re-computed.
3546 KASSERT((m->m_flags & M_PKTHDR),
3552 if (m->m_flags & M_IGMPV3_HDR) {
3553 igmpreclen -= hdrlen;
3558 m->m_flags |= M_IGMPV3_HDR;
3563 m->m_data += sizeof(struct ip);
3564 m->m_len -= sizeof(struct ip);
3567 igmp->ir_type = IGMP_v3_HOST_MEMBERSHIP_REPORT;
3568 igmp->ir_rsv1 = 0;
3569 igmp->ir_rsv2 = 0;
3570 igmp->ir_numgrps = htons(m->m_pkthdr.vt_nrecs);
3571 igmp->ir_cksum = 0;
3572 igmp->ir_cksum = in_cksum(m, sizeof(struct igmp_report) + igmpreclen);
3573 m->m_pkthdr.vt_nrecs = 0;
3575 m->m_data -= sizeof(struct ip);
3576 m->m_len += sizeof(struct ip);
3579 ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
3580 ip->ip_len = htons(hdrlen + igmpreclen);
3581 ip->ip_off = htons(IP_DF);
3582 ip->ip_p = IPPROTO_IGMP;
3583 ip->ip_sum = 0;
3585 ip->ip_src.s_addr = INADDR_ANY;
3587 if (m->m_flags & M_IGMP_LOOP) {
3592 ip->ip_src = ia->ia_addr.sin_addr;
3595 ip->ip_dst.s_addr = htonl(INADDR_ALLRPTS_GROUP);
3668 db_printf(" ifp %p\n", igi->igi_ifp);
3669 db_printf(" version %u\n", igi->igi_version);
3670 db_printf(" v1_timer %u\n", igi->igi_v1_timer);
3671 db_printf(" v2_timer %u\n", igi->igi_v2_timer);
3672 db_printf(" v3_timer %u\n", igi->igi_v3_timer);
3673 db_printf(" flags %#x\n", igi->igi_flags);
3674 db_printf(" rv %u\n", igi->igi_rv);
3675 db_printf(" qi %u\n", igi->igi_qi);
3676 db_printf(" qri %u\n", igi->igi_qri);
3677 db_printf(" uri %u\n", igi->igi_uri);