| 1466 | } |
| 1467 | |
| 1468 | int |
| 1469 | igmp_input(struct mbuf **mp, int *offp, int proto) |
| 1470 | { |
| 1471 | int iphlen; |
| 1472 | struct ifnet *ifp; |
| 1473 | struct igmp *igmp; |
| 1474 | struct ip *ip; |
| 1475 | struct mbuf *m; |
| 1476 | int igmplen; |
| 1477 | int minlen; |
| 1478 | int queryver; |
| 1479 | |
| 1480 | CTR3(KTR_IGMPV3, "%s: called w/mbuf (%p,%d)", __func__, *mp, *offp); |
| 1481 | |
| 1482 | m = *mp; |
| 1483 | ifp = m->m_pkthdr.rcvif; |
| 1484 | *mp = NULL; |
| 1485 | |
| 1486 | IGMPSTAT_INC(igps_rcv_total); |
| 1487 | |
| 1488 | ip = mtod(m, struct ip *); |
| 1489 | iphlen = *offp; |
| 1490 | igmplen = ntohs(ip->ip_len) - iphlen; |
| 1491 | |
| 1492 | /* |
| 1493 | * Validate lengths. |
| 1494 | */ |
| 1495 | if (igmplen < IGMP_MINLEN) { |
| 1496 | IGMPSTAT_INC(igps_rcv_tooshort); |
| 1497 | m_freem(m); |
| 1498 | return (IPPROTO_DONE); |
| 1499 | } |
| 1500 | |
| 1501 | /* |
| 1502 | * Always pullup to the minimum size for v1/v2 or v3 |
| 1503 | * to amortize calls to m_pullup(). |
| 1504 | */ |
| 1505 | minlen = iphlen; |
| 1506 | if (igmplen >= IGMP_V3_QUERY_MINLEN) |
| 1507 | minlen += IGMP_V3_QUERY_MINLEN; |
| 1508 | else |
| 1509 | minlen += IGMP_MINLEN; |
| 1510 | if ((!M_WRITABLE(m) || m->m_len < minlen) && |
| 1511 | (m = m_pullup(m, minlen)) == NULL) { |
| 1512 | IGMPSTAT_INC(igps_rcv_tooshort); |
| 1513 | return (IPPROTO_DONE); |
| 1514 | } |
| 1515 | ip = mtod(m, struct ip *); |
| 1516 | |
| 1517 | /* |
| 1518 | * Validate checksum. |
| 1519 | */ |
| 1520 | m->m_data += iphlen; |
| 1521 | m->m_len -= iphlen; |
| 1522 | igmp = mtod(m, struct igmp *); |
| 1523 | if (in_cksum(m, igmplen)) { |
| 1524 | IGMPSTAT_INC(igps_rcv_badsum); |
| 1525 | m_freem(m); |
nothing calls this directly
no test coverage detected