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); }