Print this page
1918 stack overflow from mac_promisc_dispatch()
*** 19,28 ****
--- 19,29 ----
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
*/
/*
* Data-Link Services Module
*/
*** 80,90 ****
dls_close(dld_str_t *dsp)
{
dls_link_t *dlp = dsp->ds_dlp;
dls_multicst_addr_t *p;
dls_multicst_addr_t *nextp;
- uint32_t old_flags;
ASSERT(dsp->ds_datathr_cnt == 0);
ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
if (dsp->ds_local)
--- 81,90 ----
*** 117,129 ****
/*
* If the MAC has been set in promiscuous mode then disable it.
* This needs to be done before resetting ds_rx.
*/
! old_flags = dsp->ds_promisc;
! dsp->ds_promisc = 0;
! (void) dls_promisc(dsp, old_flags);
/*
* At this point we have cutoff inbound packet flow from the mac
* for this 'dsp'. The dls_link_remove above cut off packets meant
* for us and waited for upcalls to finish. Similarly the dls_promisc
--- 117,127 ----
/*
* If the MAC has been set in promiscuous mode then disable it.
* This needs to be done before resetting ds_rx.
*/
! (void) dls_promisc(dsp, 0);
/*
* At this point we have cutoff inbound packet flow from the mac
* for this 'dsp'. The dls_link_remove above cut off packets meant
* for us and waited for upcalls to finish. Similarly the dls_promisc
*** 232,295 ****
*/
dls_link_remove(dsp->ds_dlp, dsp);
dsp->ds_sap = 0;
}
int
! dls_promisc(dld_str_t *dsp, uint32_t old_flags)
{
int err = 0;
ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
! ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
DLS_PROMISC_PHYS)));
! if (old_flags == 0 && dsp->ds_promisc != 0) {
/*
* If only DLS_PROMISC_SAP, we don't turn on the
* physical promisc mode
*/
err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
dls_rx_promisc, dsp, &dsp->ds_mph,
! (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 :
MAC_PROMISC_FLAGS_NO_PHYS);
! if (err != 0)
return (err);
/* Remove vlan promisc handle to avoid sending dup copy up */
if (dsp->ds_vlan_mph != NULL) {
mac_promisc_remove(dsp->ds_vlan_mph);
dsp->ds_vlan_mph = NULL;
}
! } else if (old_flags != 0 && dsp->ds_promisc == 0) {
ASSERT(dsp->ds_mph != NULL);
mac_promisc_remove(dsp->ds_mph);
dsp->ds_mph = NULL;
if (dsp->ds_sap == ETHERTYPE_VLAN &&
dsp->ds_dlstate != DL_UNBOUND) {
- int err;
-
if (dsp->ds_vlan_mph != NULL)
return (EINVAL);
err = mac_promisc_add(dsp->ds_mch,
MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
&dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
- return (err);
}
! } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 &&
! dsp->ds_promisc != old_flags) {
/*
* If the old flag is PROMISC_SAP, but the current flag has
* changed to some new non-zero value, we need to turn the
* physical promiscuous mode.
*/
ASSERT(dsp->ds_mph != NULL);
mac_promisc_remove(dsp->ds_mph);
err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
dls_rx_promisc, dsp, &dsp->ds_mph, 0);
}
return (err);
}
--- 230,309 ----
*/
dls_link_remove(dsp->ds_dlp, dsp);
dsp->ds_sap = 0;
}
+ /*
+ * In order to prevent promiscuous-mode processing with dsp->ds_promisc
+ * set to inaccurate values, this function sets dsp->ds_promisc with new
+ * flags. For enabling (mac_promisc_add), the flags are set prior to the
+ * actual enabling. For disabling (mac_promisc_remove), the flags are set
+ * after the actual disabling.
+ */
int
! dls_promisc(dld_str_t *dsp, uint32_t new_flags)
{
int err = 0;
+ uint32_t old_flags = dsp->ds_promisc;
ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
! ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
DLS_PROMISC_PHYS)));
! if (dsp->ds_promisc == 0 && new_flags != 0) {
/*
* If only DLS_PROMISC_SAP, we don't turn on the
* physical promisc mode
*/
+ dsp->ds_promisc = new_flags;
err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
dls_rx_promisc, dsp, &dsp->ds_mph,
! (new_flags != DLS_PROMISC_SAP) ? 0 :
MAC_PROMISC_FLAGS_NO_PHYS);
! if (err != 0) {
! dsp->ds_promisc = old_flags;
return (err);
+ }
/* Remove vlan promisc handle to avoid sending dup copy up */
if (dsp->ds_vlan_mph != NULL) {
mac_promisc_remove(dsp->ds_vlan_mph);
dsp->ds_vlan_mph = NULL;
}
! } else if (dsp->ds_promisc != 0 && new_flags == 0) {
ASSERT(dsp->ds_mph != NULL);
mac_promisc_remove(dsp->ds_mph);
+ dsp->ds_promisc = new_flags;
dsp->ds_mph = NULL;
if (dsp->ds_sap == ETHERTYPE_VLAN &&
dsp->ds_dlstate != DL_UNBOUND) {
if (dsp->ds_vlan_mph != NULL)
return (EINVAL);
err = mac_promisc_add(dsp->ds_mch,
MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
&dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
}
! } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
! new_flags != dsp->ds_promisc) {
/*
* If the old flag is PROMISC_SAP, but the current flag has
* changed to some new non-zero value, we need to turn the
* physical promiscuous mode.
*/
ASSERT(dsp->ds_mph != NULL);
mac_promisc_remove(dsp->ds_mph);
+ /* Honors both after-remove and before-add semantics! */
+ dsp->ds_promisc = new_flags;
err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
dls_rx_promisc, dsp, &dsp->ds_mph, 0);
+ if (err != 0)
+ dsp->ds_promisc = old_flags;
+ } else {
+ /* No adding or removing, but record the new flags anyway. */
+ dsp->ds_promisc = new_flags;
}
return (err);
}