1/*- 2 * Copyright (c) 2007-2009 Bruce Simpson. 3 * Copyright (c) 1988 Stephen Deering. 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Stephen Deering of Stanford University. --- 34 unchanged lines hidden (view full) --- 43 * Modified by Bill Fenner, Xerox PARC, Feb 1995. 44 * Modified to fully comply to IGMPv2 by Bill Fenner, Oct 1995. 45 * Significantly rewritten for IGMPv3, VIMAGE, and SMP by Bruce Simpson. 46 * 47 * MULTICAST Revision: 3.5.1.4 48 */ 49 50#include <sys/cdefs.h> |
51__FBSDID("$FreeBSD: head/sys/netinet/igmp.c 269699 2014-08-08 01:57:15Z kevlo $"); |
52 53#include <sys/param.h> 54#include <sys/systm.h> 55#include <sys/module.h> 56#include <sys/malloc.h> 57#include <sys/mbuf.h> 58#include <sys/socket.h> 59#include <sys/protosw.h> --- 1359 unchanged lines hidden (view full) --- 1419 } 1420 1421out_locked: 1422 IN_MULTI_UNLOCK(); 1423 1424 return (0); 1425} 1426 |
1427int 1428igmp_input(struct mbuf **mp, int *offp, int proto) |
1429{ 1430 int iphlen; 1431 struct ifnet *ifp; 1432 struct igmp *igmp; 1433 struct ip *ip; |
1434 struct mbuf *m; |
1435 int igmplen; 1436 int minlen; 1437 int queryver; 1438 1439 CTR3(KTR_IGMPV3, "%s: called w/mbuf (%p,%d)", __func__, m, off); 1440 |
1441 m = *mp; |
1442 ifp = m->m_pkthdr.rcvif; |
1443 *mp = NULL; |
1444 1445 IGMPSTAT_INC(igps_rcv_total); 1446 1447 ip = mtod(m, struct ip *); |
1448 iphlen = *offp; 1449 igmplen = ntohs(ip->ip_len) - iphlen; |
1450 1451 /* 1452 * Validate lengths. 1453 */ 1454 if (igmplen < IGMP_MINLEN) { 1455 IGMPSTAT_INC(igps_rcv_tooshort); 1456 m_freem(m); |
1457 return (IPPROTO_DONE); |
1458 } 1459 1460 /* 1461 * Always pullup to the minimum size for v1/v2 or v3 1462 * to amortize calls to m_pullup(). 1463 */ 1464 minlen = iphlen; 1465 if (igmplen >= IGMP_V3_QUERY_MINLEN) 1466 minlen += IGMP_V3_QUERY_MINLEN; 1467 else 1468 minlen += IGMP_MINLEN; 1469 if ((m->m_flags & M_EXT || m->m_len < minlen) && 1470 (m = m_pullup(m, minlen)) == 0) { 1471 IGMPSTAT_INC(igps_rcv_tooshort); |
1472 return (IPPROTO_DONE); |
1473 } 1474 ip = mtod(m, struct ip *); 1475 1476 /* 1477 * Validate checksum. 1478 */ 1479 m->m_data += iphlen; 1480 m->m_len -= iphlen; 1481 igmp = mtod(m, struct igmp *); 1482 if (in_cksum(m, igmplen)) { 1483 IGMPSTAT_INC(igps_rcv_badsum); 1484 m_freem(m); |
1485 return (IPPROTO_DONE); |
1486 } 1487 m->m_data -= iphlen; 1488 m->m_len += iphlen; 1489 1490 /* 1491 * IGMP control traffic is link-scope, and must have a TTL of 1. 1492 * DVMRP traffic (e.g. mrinfo, mtrace) is an exception; 1493 * probe packets may come from beyond the LAN. 1494 */ 1495 if (igmp->igmp_type != IGMP_DVMRP && ip->ip_ttl != 1) { 1496 IGMPSTAT_INC(igps_rcv_badttl); 1497 m_freem(m); |
1498 return (IPPROTO_DONE); |
1499 } 1500 1501 switch (igmp->igmp_type) { 1502 case IGMP_HOST_MEMBERSHIP_QUERY: 1503 if (igmplen == IGMP_MINLEN) { 1504 if (igmp->igmp_code == 0) 1505 queryver = IGMP_VERSION_1; 1506 else 1507 queryver = IGMP_VERSION_2; 1508 } else if (igmplen >= IGMP_V3_QUERY_MINLEN) { 1509 queryver = IGMP_VERSION_3; 1510 } else { 1511 IGMPSTAT_INC(igps_rcv_tooshort); 1512 m_freem(m); |
1513 return (IPPROTO_DONE); |
1514 } 1515 1516 switch (queryver) { 1517 case IGMP_VERSION_1: 1518 IGMPSTAT_INC(igps_rcv_v1v2_queries); 1519 if (!V_igmp_v1enable) 1520 break; 1521 if (igmp_input_v1_query(ifp, ip, igmp) != 0) { 1522 m_freem(m); |
1523 return (IPPROTO_DONE); |
1524 } 1525 break; 1526 1527 case IGMP_VERSION_2: 1528 IGMPSTAT_INC(igps_rcv_v1v2_queries); 1529 if (!V_igmp_v2enable) 1530 break; 1531 if (igmp_input_v2_query(ifp, ip, igmp) != 0) { 1532 m_freem(m); |
1533 return (IPPROTO_DONE); |
1534 } 1535 break; 1536 1537 case IGMP_VERSION_3: { 1538 struct igmpv3 *igmpv3; 1539 uint16_t igmpv3len; 1540 uint16_t srclen; 1541 int nsrc; 1542 1543 IGMPSTAT_INC(igps_rcv_v3_queries); 1544 igmpv3 = (struct igmpv3 *)igmp; 1545 /* 1546 * Validate length based on source count. 1547 */ 1548 nsrc = ntohs(igmpv3->igmp_numsrc); 1549 srclen = sizeof(struct in_addr) * nsrc; 1550 if (nsrc * sizeof(in_addr_t) > srclen) { 1551 IGMPSTAT_INC(igps_rcv_tooshort); |
1552 return (IPPROTO_DONE); |
1553 } 1554 /* 1555 * m_pullup() may modify m, so pullup in 1556 * this scope. 1557 */ 1558 igmpv3len = iphlen + IGMP_V3_QUERY_MINLEN + 1559 srclen; 1560 if ((m->m_flags & M_EXT || 1561 m->m_len < igmpv3len) && 1562 (m = m_pullup(m, igmpv3len)) == NULL) { 1563 IGMPSTAT_INC(igps_rcv_tooshort); |
1564 return (IPPROTO_DONE); |
1565 } 1566 igmpv3 = (struct igmpv3 *)(mtod(m, uint8_t *) 1567 + iphlen); 1568 if (igmp_input_v3_query(ifp, ip, igmpv3) != 0) { 1569 m_freem(m); |
1570 return (IPPROTO_DONE); |
1571 } 1572 } 1573 break; 1574 } 1575 break; 1576 1577 case IGMP_v1_HOST_MEMBERSHIP_REPORT: 1578 if (!V_igmp_v1enable) 1579 break; 1580 if (igmp_input_v1_report(ifp, ip, igmp) != 0) { 1581 m_freem(m); |
1582 return (IPPROTO_DONE); |
1583 } 1584 break; 1585 1586 case IGMP_v2_HOST_MEMBERSHIP_REPORT: 1587 if (!V_igmp_v2enable) 1588 break; 1589 if (!ip_checkrouteralert(m)) 1590 IGMPSTAT_INC(igps_rcv_nora); 1591 if (igmp_input_v2_report(ifp, ip, igmp) != 0) { 1592 m_freem(m); |
1593 return (IPPROTO_DONE); |
1594 } 1595 break; 1596 1597 case IGMP_v3_HOST_MEMBERSHIP_REPORT: 1598 /* 1599 * Hosts do not need to process IGMPv3 membership reports, 1600 * as report suppression is no longer required. 1601 */ --- 4 unchanged lines hidden (view full) --- 1606 default: 1607 break; 1608 } 1609 1610 /* 1611 * Pass all valid IGMP packets up to any process(es) listening on a 1612 * raw IGMP socket. 1613 */ |
1614 *mp = m; 1615 return (rip_input(mp, offp, proto)); |
1616} 1617 1618 1619/* 1620 * Fast timeout handler (global). 1621 * VIMAGE: Timeout handlers are expected to service all vimages. 1622 */ 1623void --- 2032 unchanged lines hidden --- |