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 --- |