Deleted Added
sdiff udiff text old ( 257176 ) new ( 269699 )
full compact
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 ---