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 257176 2013-10-26 17:58:36Z glebius $");
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)
1429{
1430 int iphlen;
1431 struct ifnet *ifp;
1432 struct igmp *igmp;
1433 struct ip *ip;
1434 int igmplen;
1435 int minlen;
1436 int queryver;
1437
1438 CTR3(KTR_IGMPV3, "%s: called w/mbuf (%p,%d)", __func__, m, off);
1439
1440 ifp = m->m_pkthdr.rcvif;
1441
1442 IGMPSTAT_INC(igps_rcv_total);
1443
1444 ip = mtod(m, struct ip *);
1445 iphlen = off;
1446 igmplen = ntohs(ip->ip_len) - off;
1447
1448 /*
1449 * Validate lengths.
1450 */
1451 if (igmplen < IGMP_MINLEN) {
1452 IGMPSTAT_INC(igps_rcv_tooshort);
1453 m_freem(m);
1454 return;
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);
1469 return;
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);
1482 return;
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);
1495 return;
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);
1510 return;
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);
1520 return;
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);
1530 return;
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);
1549 return;
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);
1561 return;
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);
1567 return;
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);
1579 return;
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);
1590 return;
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 */
1611 rip_input(m, off);
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 ---