* Process a received IGMPv2 host membership report. * * NOTE: 0.0.0.0 workaround breaks const correctness. */
| 1365 | * NOTE: 0.0.0.0 workaround breaks const correctness. |
| 1366 | */ |
| 1367 | static int |
| 1368 | igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, |
| 1369 | /*const*/ struct igmp *igmp) |
| 1370 | { |
| 1371 | struct rm_priotracker in_ifa_tracker; |
| 1372 | struct in_ifaddr *ia; |
| 1373 | struct in_multi *inm; |
| 1374 | |
| 1375 | /* |
| 1376 | * Make sure we don't hear our own membership report. Fast |
| 1377 | * leave requires knowing that we are the only member of a |
| 1378 | * group. |
| 1379 | */ |
| 1380 | IFP_TO_IA(ifp, ia, &in_ifa_tracker); |
| 1381 | if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr)) { |
| 1382 | return (0); |
| 1383 | } |
| 1384 | |
| 1385 | IGMPSTAT_INC(igps_rcv_reports); |
| 1386 | |
| 1387 | if (ifp->if_flags & IFF_LOOPBACK) { |
| 1388 | return (0); |
| 1389 | } |
| 1390 | |
| 1391 | if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) || |
| 1392 | !in_hosteq(igmp->igmp_group, ip->ip_dst)) { |
| 1393 | IGMPSTAT_INC(igps_rcv_badreports); |
| 1394 | return (EINVAL); |
| 1395 | } |
| 1396 | |
| 1397 | /* |
| 1398 | * RFC 3376, Section 4.2.13, 9.2, 9.3: |
| 1399 | * Booting clients may use the source address 0.0.0.0. Some |
| 1400 | * IGMP daemons may not know how to use IP_RECVIF to determine |
| 1401 | * the interface upon which this message was received. |
| 1402 | * Replace 0.0.0.0 with the subnet address if told to do so. |
| 1403 | */ |
| 1404 | if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) { |
| 1405 | if (ia != NULL) |
| 1406 | ip->ip_src.s_addr = htonl(ia->ia_subnet); |
| 1407 | } |
| 1408 | |
| 1409 | CTR3(KTR_IGMPV3, "process v2 report 0x%08x on ifp %p(%s)", |
| 1410 | ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname); |
| 1411 | |
| 1412 | /* |
| 1413 | * IGMPv2 report suppression. |
| 1414 | * If we are a member of this group, and our membership should be |
| 1415 | * reported, and our group timer is pending or about to be reset, |
| 1416 | * stop our group timer by transitioning to the 'lazy' state. |
| 1417 | */ |
| 1418 | IN_MULTI_LIST_LOCK(); |
| 1419 | inm = inm_lookup(ifp, igmp->igmp_group); |
| 1420 | if (inm != NULL) { |
| 1421 | struct igmp_ifsoftc *igi; |
| 1422 | |
| 1423 | igi = inm->inm_igi; |
| 1424 | KASSERT(igi != NULL, ("%s: no igi for ifp %p", __func__, ifp)); |
no test coverage detected