|
Lines 243-248
Link Here
|
| 243 |
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN, |
243 |
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN, |
| 244 |
&mld_v1enable, 0, "Enable fallback to MLDv1"); |
244 |
&mld_v1enable, 0, "Enable fallback to MLDv1"); |
| 245 |
|
245 |
|
|
|
246 |
static int mld_v2enable = 1; |
| 247 |
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_RWTUN, |
| 248 |
&mld_v2enable, 0, "Enable MLDv2"); |
| 249 |
|
| 246 |
static int mld_use_allow = 1; |
250 |
static int mld_use_allow = 1; |
| 247 |
SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN, |
251 |
SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN, |
| 248 |
&mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves"); |
252 |
&mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves"); |
|
Lines 533-577
Link Here
|
| 533 |
* XXX This routine is also bitten by unlocked ifma_protospec access. |
537 |
* XXX This routine is also bitten by unlocked ifma_protospec access. |
| 534 |
*/ |
538 |
*/ |
| 535 |
void |
539 |
void |
| 536 |
mld_ifdetach(struct ifnet *ifp) |
540 |
mld_ifdetach(struct ifnet *ifp, struct in6_multi_head *inmh) |
| 537 |
{ |
541 |
{ |
|
|
542 |
struct epoch_tracker et; |
| 538 |
struct mld_ifsoftc *mli; |
543 |
struct mld_ifsoftc *mli; |
| 539 |
struct ifmultiaddr *ifma, *next; |
544 |
struct ifmultiaddr *ifma; |
| 540 |
struct in6_multi *inm; |
545 |
struct in6_multi *inm; |
| 541 |
struct in6_multi_head inmh; |
|
|
| 542 |
|
546 |
|
| 543 |
CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, |
547 |
CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, |
| 544 |
if_name(ifp)); |
548 |
if_name(ifp)); |
| 545 |
|
549 |
|
| 546 |
SLIST_INIT(&inmh); |
|
|
| 547 |
IN6_MULTI_LIST_LOCK_ASSERT(); |
550 |
IN6_MULTI_LIST_LOCK_ASSERT(); |
| 548 |
MLD_LOCK(); |
551 |
MLD_LOCK(); |
| 549 |
|
552 |
|
| 550 |
mli = MLD_IFINFO(ifp); |
553 |
mli = MLD_IFINFO(ifp); |
| 551 |
if (mli->mli_version == MLD_VERSION_2) { |
554 |
IF_ADDR_WLOCK(ifp); |
| 552 |
IF_ADDR_WLOCK(ifp); |
555 |
/* |
| 553 |
restart: |
556 |
* Extract list of in6_multi associated with the detaching ifp |
| 554 |
CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { |
557 |
* which the PF_INET6 layer is about to release. |
| 555 |
if (ifma->ifma_addr->sa_family != AF_INET6 || |
558 |
*/ |
| 556 |
ifma->ifma_protospec == NULL) |
559 |
NET_EPOCH_ENTER(et); |
| 557 |
continue; |
560 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
| 558 |
inm = (struct in6_multi *)ifma->ifma_protospec; |
561 |
inm = in6m_ifmultiaddr_get_inm(ifma); |
|
|
562 |
if (inm == NULL) |
| 563 |
continue; |
| 564 |
in6m_disconnect_locked(inmh, inm); |
| 565 |
|
| 566 |
if (mli->mli_version == MLD_VERSION_2) { |
| 567 |
in6m_clear_recorded(inm); |
| 568 |
|
| 569 |
/* |
| 570 |
* We need to release the final reference held |
| 571 |
* for issuing the INCLUDE {}. |
| 572 |
*/ |
| 559 |
if (inm->in6m_state == MLD_LEAVING_MEMBER) { |
573 |
if (inm->in6m_state == MLD_LEAVING_MEMBER) { |
| 560 |
in6m_disconnect(inm); |
574 |
inm->in6m_state = MLD_NOT_MEMBER; |
| 561 |
in6m_rele_locked(&inmh, inm); |
575 |
in6m_rele_locked(inmh, inm); |
| 562 |
ifma->ifma_protospec = NULL; |
|
|
| 563 |
} |
576 |
} |
| 564 |
in6m_clear_recorded(inm); |
|
|
| 565 |
if (__predict_false(ifma6_restart)) { |
| 566 |
ifma6_restart = false; |
| 567 |
goto restart; |
| 568 |
} |
| 569 |
} |
577 |
} |
| 570 |
IF_ADDR_WUNLOCK(ifp); |
|
|
| 571 |
} |
578 |
} |
| 572 |
|
579 |
NET_EPOCH_EXIT(et); |
|
|
580 |
IF_ADDR_WUNLOCK(ifp); |
| 573 |
MLD_UNLOCK(); |
581 |
MLD_UNLOCK(); |
| 574 |
in6m_release_list_deferred(&inmh); |
|
|
| 575 |
} |
582 |
} |
| 576 |
|
583 |
|
| 577 |
/* |
584 |
/* |
|
Lines 705-714
Link Here
|
| 705 |
CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)", |
712 |
CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)", |
| 706 |
ifp, if_name(ifp)); |
713 |
ifp, if_name(ifp)); |
| 707 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
714 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
| 708 |
if (ifma->ifma_addr->sa_family != AF_INET6 || |
715 |
inm = in6m_ifmultiaddr_get_inm(ifma); |
| 709 |
ifma->ifma_protospec == NULL) |
716 |
if (inm == NULL) |
| 710 |
continue; |
717 |
continue; |
| 711 |
inm = (struct in6_multi *)ifma->ifma_protospec; |
|
|
| 712 |
mld_v1_update_group(inm, timer); |
718 |
mld_v1_update_group(inm, timer); |
| 713 |
} |
719 |
} |
| 714 |
} else { |
720 |
} else { |
|
Lines 819-824
Link Here
|
| 819 |
|
825 |
|
| 820 |
is_general_query = 0; |
826 |
is_general_query = 0; |
| 821 |
|
827 |
|
|
|
828 |
if (!mld_v2enable) { |
| 829 |
CTR3(KTR_MLD, "ignore v2 query %s on ifp %p(%s)", |
| 830 |
ip6_sprintf(ip6tbuf, &mld->mld_addr), |
| 831 |
ifp, if_name(ifp)); |
| 832 |
return (0); |
| 833 |
} |
| 834 |
|
| 822 |
/* |
835 |
/* |
| 823 |
* RFC3810 Section 6.2: MLD queries must originate from |
836 |
* RFC3810 Section 6.2: MLD queries must originate from |
| 824 |
* a router's link-local address. |
837 |
* a router's link-local address. |
|
Lines 1332-1346
Link Here
|
| 1332 |
static void |
1345 |
static void |
| 1333 |
mld_fasttimo_vnet(void) |
1346 |
mld_fasttimo_vnet(void) |
| 1334 |
{ |
1347 |
{ |
|
|
1348 |
struct in6_multi_head inmh; |
| 1349 |
struct epoch_tracker et; |
| 1335 |
struct mbufq scq; /* State-change packets */ |
1350 |
struct mbufq scq; /* State-change packets */ |
| 1336 |
struct mbufq qrq; /* Query response packets */ |
1351 |
struct mbufq qrq; /* Query response packets */ |
| 1337 |
struct ifnet *ifp; |
1352 |
struct ifnet *ifp; |
| 1338 |
struct mld_ifsoftc *mli; |
1353 |
struct mld_ifsoftc *mli; |
| 1339 |
struct ifmultiaddr *ifma, *next; |
1354 |
struct ifmultiaddr *ifma; |
| 1340 |
struct in6_multi *inm, *tinm; |
1355 |
struct in6_multi *inm, *tinm; |
| 1341 |
struct in6_multi_head inmh; |
|
|
| 1342 |
int uri_fasthz; |
1356 |
int uri_fasthz; |
| 1343 |
|
1357 |
|
|
|
1358 |
SLIST_INIT(&inmh); |
| 1344 |
uri_fasthz = 0; |
1359 |
uri_fasthz = 0; |
| 1345 |
|
1360 |
|
| 1346 |
/* |
1361 |
/* |
|
Lines 1353-1359
Link Here
|
| 1353 |
!V_state_change_timers_running6) |
1368 |
!V_state_change_timers_running6) |
| 1354 |
return; |
1369 |
return; |
| 1355 |
|
1370 |
|
| 1356 |
SLIST_INIT(&inmh); |
|
|
| 1357 |
IN6_MULTI_LIST_LOCK(); |
1371 |
IN6_MULTI_LIST_LOCK(); |
| 1358 |
MLD_LOCK(); |
1372 |
MLD_LOCK(); |
| 1359 |
|
1373 |
|
|
Lines 1399-1410
Link Here
|
| 1399 |
} |
1413 |
} |
| 1400 |
|
1414 |
|
| 1401 |
IF_ADDR_WLOCK(ifp); |
1415 |
IF_ADDR_WLOCK(ifp); |
| 1402 |
restart: |
1416 |
NET_EPOCH_ENTER(et); |
| 1403 |
CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { |
1417 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
| 1404 |
if (ifma->ifma_addr->sa_family != AF_INET6 || |
1418 |
inm = in6m_ifmultiaddr_get_inm(ifma); |
| 1405 |
ifma->ifma_protospec == NULL) |
1419 |
if (inm == NULL) |
| 1406 |
continue; |
1420 |
continue; |
| 1407 |
inm = (struct in6_multi *)ifma->ifma_protospec; |
|
|
| 1408 |
switch (mli->mli_version) { |
1421 |
switch (mli->mli_version) { |
| 1409 |
case MLD_VERSION_1: |
1422 |
case MLD_VERSION_1: |
| 1410 |
mld_v1_process_group_timer(&inmh, inm); |
1423 |
mld_v1_process_group_timer(&inmh, inm); |
|
Lines 1414-1424
Link Here
|
| 1414 |
&scq, inm, uri_fasthz); |
1427 |
&scq, inm, uri_fasthz); |
| 1415 |
break; |
1428 |
break; |
| 1416 |
} |
1429 |
} |
| 1417 |
if (__predict_false(ifma6_restart)) { |
|
|
| 1418 |
ifma6_restart = false; |
| 1419 |
goto restart; |
| 1420 |
} |
| 1421 |
} |
1430 |
} |
|
|
1431 |
NET_EPOCH_EXIT(et); |
| 1422 |
IF_ADDR_WUNLOCK(ifp); |
1432 |
IF_ADDR_WUNLOCK(ifp); |
| 1423 |
|
1433 |
|
| 1424 |
switch (mli->mli_version) { |
1434 |
switch (mli->mli_version) { |
|
Lines 1488-1495
Link Here
|
| 1488 |
case MLD_REPORTING_MEMBER: |
1498 |
case MLD_REPORTING_MEMBER: |
| 1489 |
if (report_timer_expired) { |
1499 |
if (report_timer_expired) { |
| 1490 |
inm->in6m_state = MLD_IDLE_MEMBER; |
1500 |
inm->in6m_state = MLD_IDLE_MEMBER; |
| 1491 |
in6m_disconnect(inm); |
1501 |
in6m_disconnect_locked(inmh, inm); |
| 1492 |
in6m_rele_locked(inmh, inm); |
|
|
| 1493 |
} |
1502 |
} |
| 1494 |
break; |
1503 |
break; |
| 1495 |
case MLD_G_QUERY_PENDING_MEMBER: |
1504 |
case MLD_G_QUERY_PENDING_MEMBER: |
|
Lines 1613-1619
Link Here
|
| 1613 |
if (inm->in6m_state == MLD_LEAVING_MEMBER && |
1622 |
if (inm->in6m_state == MLD_LEAVING_MEMBER && |
| 1614 |
inm->in6m_scrv == 0) { |
1623 |
inm->in6m_scrv == 0) { |
| 1615 |
inm->in6m_state = MLD_NOT_MEMBER; |
1624 |
inm->in6m_state = MLD_NOT_MEMBER; |
| 1616 |
in6m_disconnect(inm); |
1625 |
in6m_disconnect_locked(inmh, inm); |
| 1617 |
in6m_rele_locked(inmh, inm); |
1626 |
in6m_rele_locked(inmh, inm); |
| 1618 |
} |
1627 |
} |
| 1619 |
} |
1628 |
} |
|
Lines 1658-1667
Link Here
|
| 1658 |
static void |
1667 |
static void |
| 1659 |
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) |
1668 |
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) |
| 1660 |
{ |
1669 |
{ |
| 1661 |
struct ifmultiaddr *ifma, *next; |
1670 |
struct epoch_tracker et; |
|
|
1671 |
struct in6_multi_head inmh; |
| 1672 |
struct ifmultiaddr *ifma; |
| 1662 |
struct ifnet *ifp; |
1673 |
struct ifnet *ifp; |
| 1663 |
struct in6_multi *inm; |
1674 |
struct in6_multi *inm; |
| 1664 |
struct in6_multi_head inmh; |
|
|
| 1665 |
|
1675 |
|
| 1666 |
CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__, |
1676 |
CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__, |
| 1667 |
mli->mli_ifp, if_name(mli->mli_ifp)); |
1677 |
mli->mli_ifp, if_name(mli->mli_ifp)); |
|
Lines 1684-1695
Link Here
|
| 1684 |
ifp = mli->mli_ifp; |
1694 |
ifp = mli->mli_ifp; |
| 1685 |
|
1695 |
|
| 1686 |
IF_ADDR_WLOCK(ifp); |
1696 |
IF_ADDR_WLOCK(ifp); |
| 1687 |
restart: |
1697 |
NET_EPOCH_ENTER(et); |
| 1688 |
CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { |
1698 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
| 1689 |
if (ifma->ifma_addr->sa_family != AF_INET6 || |
1699 |
inm = in6m_ifmultiaddr_get_inm(ifma); |
| 1690 |
ifma->ifma_protospec == NULL) |
1700 |
if (inm == NULL) |
| 1691 |
continue; |
1701 |
continue; |
| 1692 |
inm = (struct in6_multi *)ifma->ifma_protospec; |
|
|
| 1693 |
switch (inm->in6m_state) { |
1702 |
switch (inm->in6m_state) { |
| 1694 |
case MLD_NOT_MEMBER: |
1703 |
case MLD_NOT_MEMBER: |
| 1695 |
case MLD_SILENT_MEMBER: |
1704 |
case MLD_SILENT_MEMBER: |
|
Lines 1704-1712
Link Here
|
| 1704 |
* version, we need to release the final |
1713 |
* version, we need to release the final |
| 1705 |
* reference held for issuing the INCLUDE {}. |
1714 |
* reference held for issuing the INCLUDE {}. |
| 1706 |
*/ |
1715 |
*/ |
| 1707 |
in6m_disconnect(inm); |
|
|
| 1708 |
in6m_rele_locked(&inmh, inm); |
1716 |
in6m_rele_locked(&inmh, inm); |
| 1709 |
ifma->ifma_protospec = NULL; |
|
|
| 1710 |
/* FALLTHROUGH */ |
1717 |
/* FALLTHROUGH */ |
| 1711 |
case MLD_G_QUERY_PENDING_MEMBER: |
1718 |
case MLD_G_QUERY_PENDING_MEMBER: |
| 1712 |
case MLD_SG_QUERY_PENDING_MEMBER: |
1719 |
case MLD_SG_QUERY_PENDING_MEMBER: |
|
Lines 1722-1732
Link Here
|
| 1722 |
mbufq_drain(&inm->in6m_scq); |
1729 |
mbufq_drain(&inm->in6m_scq); |
| 1723 |
break; |
1730 |
break; |
| 1724 |
} |
1731 |
} |
| 1725 |
if (__predict_false(ifma6_restart)) { |
|
|
| 1726 |
ifma6_restart = false; |
| 1727 |
goto restart; |
| 1728 |
} |
| 1729 |
} |
1732 |
} |
|
|
1733 |
NET_EPOCH_EXIT(et); |
| 1730 |
IF_ADDR_WUNLOCK(ifp); |
1734 |
IF_ADDR_WUNLOCK(ifp); |
| 1731 |
in6m_release_list_deferred(&inmh); |
1735 |
in6m_release_list_deferred(&inmh); |
| 1732 |
} |
1736 |
} |
|
Lines 1899-1904
Link Here
|
| 1899 |
error = 0; |
1903 |
error = 0; |
| 1900 |
|
1904 |
|
| 1901 |
/* |
1905 |
/* |
|
|
1906 |
* Check if the in6_multi has already been disconnected. |
| 1907 |
*/ |
| 1908 |
if (inm->in6m_ifp == NULL) { |
| 1909 |
CTR1(KTR_MLD, "%s: inm is disconnected", __func__); |
| 1910 |
return (0); |
| 1911 |
} |
| 1912 |
|
| 1913 |
/* |
| 1902 |
* Try to detect if the upper layer just asked us to change state |
1914 |
* Try to detect if the upper layer just asked us to change state |
| 1903 |
* for an interface which has now gone away. |
1915 |
* for an interface which has now gone away. |
| 1904 |
*/ |
1916 |
*/ |
|
Lines 2007-2013
Link Here
|
| 2007 |
*/ |
2019 |
*/ |
| 2008 |
if (mli->mli_version == MLD_VERSION_2 && |
2020 |
if (mli->mli_version == MLD_VERSION_2 && |
| 2009 |
inm->in6m_state == MLD_LEAVING_MEMBER) { |
2021 |
inm->in6m_state == MLD_LEAVING_MEMBER) { |
|
|
2022 |
in6m_trace("pre leaving member", inm); |
| 2010 |
inm->in6m_refcount--; |
2023 |
inm->in6m_refcount--; |
|
|
2024 |
MPASS(inm->in6m_refcount > 0); |
| 2011 |
} |
2025 |
} |
| 2012 |
inm->in6m_state = MLD_REPORTING_MEMBER; |
2026 |
inm->in6m_state = MLD_REPORTING_MEMBER; |
| 2013 |
|
2027 |
|
|
Lines 3012-3022
Link Here
|
| 3012 |
|
3026 |
|
| 3013 |
NET_EPOCH_ENTER(et); |
3027 |
NET_EPOCH_ENTER(et); |
| 3014 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
3028 |
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
| 3015 |
if (ifma->ifma_addr->sa_family != AF_INET6 || |
3029 |
inm = in6m_ifmultiaddr_get_inm(ifma); |
| 3016 |
ifma->ifma_protospec == NULL) |
3030 |
if (inm == NULL) |
| 3017 |
continue; |
3031 |
continue; |
| 3018 |
|
|
|
| 3019 |
inm = (struct in6_multi *)ifma->ifma_protospec; |
| 3020 |
KASSERT(ifp == inm->in6m_ifp, |
3032 |
KASSERT(ifp == inm->in6m_ifp, |
| 3021 |
("%s: inconsistent ifp", __func__)); |
3033 |
("%s: inconsistent ifp", __func__)); |
| 3022 |
|
3034 |
|