Deleted Added
full compact
igmp.c (257176) igmp.c (269699)
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>
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 257176 2013-10-26 17:58:36Z glebius $");
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
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
1427void
1428igmp_input(struct mbuf *m, int off)
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;
1429{
1430 int iphlen;
1431 struct ifnet *ifp;
1432 struct igmp *igmp;
1433 struct ip *ip;
1434 struct mbuf *m;
1434 int igmplen;
1435 int minlen;
1436 int queryver;
1437
1438 CTR3(KTR_IGMPV3, "%s: called w/mbuf (%p,%d)", __func__, m, off);
1439
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;
1440 ifp = m->m_pkthdr.rcvif;
1442 ifp = m->m_pkthdr.rcvif;
1443 *mp = NULL;
1441
1442 IGMPSTAT_INC(igps_rcv_total);
1443
1444 ip = mtod(m, struct ip *);
1444
1445 IGMPSTAT_INC(igps_rcv_total);
1446
1447 ip = mtod(m, struct ip *);
1445 iphlen = off;
1446 igmplen = ntohs(ip->ip_len) - off;
1448 iphlen = *offp;
1449 igmplen = ntohs(ip->ip_len) - iphlen;
1447
1448 /*
1449 * Validate lengths.
1450 */
1451 if (igmplen < IGMP_MINLEN) {
1452 IGMPSTAT_INC(igps_rcv_tooshort);
1453 m_freem(m);
1450
1451 /*
1452 * Validate lengths.
1453 */
1454 if (igmplen < IGMP_MINLEN) {
1455 IGMPSTAT_INC(igps_rcv_tooshort);
1456 m_freem(m);
1454 return;
1457 return (IPPROTO_DONE);
1455 }
1456
1457 /*
1458 * Always pullup to the minimum size for v1/v2 or v3
1459 * to amortize calls to m_pullup().
1460 */
1461 minlen = iphlen;
1462 if (igmplen >= IGMP_V3_QUERY_MINLEN)
1463 minlen += IGMP_V3_QUERY_MINLEN;
1464 else
1465 minlen += IGMP_MINLEN;
1466 if ((m->m_flags & M_EXT || m->m_len < minlen) &&
1467 (m = m_pullup(m, minlen)) == 0) {
1468 IGMPSTAT_INC(igps_rcv_tooshort);
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);
1469 return;
1472 return (IPPROTO_DONE);
1470 }
1471 ip = mtod(m, struct ip *);
1472
1473 /*
1474 * Validate checksum.
1475 */
1476 m->m_data += iphlen;
1477 m->m_len -= iphlen;
1478 igmp = mtod(m, struct igmp *);
1479 if (in_cksum(m, igmplen)) {
1480 IGMPSTAT_INC(igps_rcv_badsum);
1481 m_freem(m);
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);
1482 return;
1485 return (IPPROTO_DONE);
1483 }
1484 m->m_data -= iphlen;
1485 m->m_len += iphlen;
1486
1487 /*
1488 * IGMP control traffic is link-scope, and must have a TTL of 1.
1489 * DVMRP traffic (e.g. mrinfo, mtrace) is an exception;
1490 * probe packets may come from beyond the LAN.
1491 */
1492 if (igmp->igmp_type != IGMP_DVMRP && ip->ip_ttl != 1) {
1493 IGMPSTAT_INC(igps_rcv_badttl);
1494 m_freem(m);
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);
1495 return;
1498 return (IPPROTO_DONE);
1496 }
1497
1498 switch (igmp->igmp_type) {
1499 case IGMP_HOST_MEMBERSHIP_QUERY:
1500 if (igmplen == IGMP_MINLEN) {
1501 if (igmp->igmp_code == 0)
1502 queryver = IGMP_VERSION_1;
1503 else
1504 queryver = IGMP_VERSION_2;
1505 } else if (igmplen >= IGMP_V3_QUERY_MINLEN) {
1506 queryver = IGMP_VERSION_3;
1507 } else {
1508 IGMPSTAT_INC(igps_rcv_tooshort);
1509 m_freem(m);
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);
1510 return;
1513 return (IPPROTO_DONE);
1511 }
1512
1513 switch (queryver) {
1514 case IGMP_VERSION_1:
1515 IGMPSTAT_INC(igps_rcv_v1v2_queries);
1516 if (!V_igmp_v1enable)
1517 break;
1518 if (igmp_input_v1_query(ifp, ip, igmp) != 0) {
1519 m_freem(m);
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);
1520 return;
1523 return (IPPROTO_DONE);
1521 }
1522 break;
1523
1524 case IGMP_VERSION_2:
1525 IGMPSTAT_INC(igps_rcv_v1v2_queries);
1526 if (!V_igmp_v2enable)
1527 break;
1528 if (igmp_input_v2_query(ifp, ip, igmp) != 0) {
1529 m_freem(m);
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);
1530 return;
1533 return (IPPROTO_DONE);
1531 }
1532 break;
1533
1534 case IGMP_VERSION_3: {
1535 struct igmpv3 *igmpv3;
1536 uint16_t igmpv3len;
1537 uint16_t srclen;
1538 int nsrc;
1539
1540 IGMPSTAT_INC(igps_rcv_v3_queries);
1541 igmpv3 = (struct igmpv3 *)igmp;
1542 /*
1543 * Validate length based on source count.
1544 */
1545 nsrc = ntohs(igmpv3->igmp_numsrc);
1546 srclen = sizeof(struct in_addr) * nsrc;
1547 if (nsrc * sizeof(in_addr_t) > srclen) {
1548 IGMPSTAT_INC(igps_rcv_tooshort);
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);
1549 return;
1552 return (IPPROTO_DONE);
1550 }
1551 /*
1552 * m_pullup() may modify m, so pullup in
1553 * this scope.
1554 */
1555 igmpv3len = iphlen + IGMP_V3_QUERY_MINLEN +
1556 srclen;
1557 if ((m->m_flags & M_EXT ||
1558 m->m_len < igmpv3len) &&
1559 (m = m_pullup(m, igmpv3len)) == NULL) {
1560 IGMPSTAT_INC(igps_rcv_tooshort);
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);
1561 return;
1564 return (IPPROTO_DONE);
1562 }
1563 igmpv3 = (struct igmpv3 *)(mtod(m, uint8_t *)
1564 + iphlen);
1565 if (igmp_input_v3_query(ifp, ip, igmpv3) != 0) {
1566 m_freem(m);
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);
1567 return;
1570 return (IPPROTO_DONE);
1568 }
1569 }
1570 break;
1571 }
1572 break;
1573
1574 case IGMP_v1_HOST_MEMBERSHIP_REPORT:
1575 if (!V_igmp_v1enable)
1576 break;
1577 if (igmp_input_v1_report(ifp, ip, igmp) != 0) {
1578 m_freem(m);
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);
1579 return;
1582 return (IPPROTO_DONE);
1580 }
1581 break;
1582
1583 case IGMP_v2_HOST_MEMBERSHIP_REPORT:
1584 if (!V_igmp_v2enable)
1585 break;
1586 if (!ip_checkrouteralert(m))
1587 IGMPSTAT_INC(igps_rcv_nora);
1588 if (igmp_input_v2_report(ifp, ip, igmp) != 0) {
1589 m_freem(m);
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);
1590 return;
1593 return (IPPROTO_DONE);
1591 }
1592 break;
1593
1594 case IGMP_v3_HOST_MEMBERSHIP_REPORT:
1595 /*
1596 * Hosts do not need to process IGMPv3 membership reports,
1597 * as report suppression is no longer required.
1598 */

--- 4 unchanged lines hidden (view full) ---

1603 default:
1604 break;
1605 }
1606
1607 /*
1608 * Pass all valid IGMP packets up to any process(es) listening on a
1609 * raw IGMP socket.
1610 */
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 */
1611 rip_input(m, off);
1614 *mp = m;
1615 return (rip_input(mp, offp, proto));
1612}
1613
1614
1615/*
1616 * Fast timeout handler (global).
1617 * VIMAGE: Timeout handlers are expected to service all vimages.
1618 */
1619void

--- 2032 unchanged lines hidden ---
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 ---