Print this page
1918 stack overflow from mac_promisc_dispatch()

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/dls/dls.c
          +++ new/usr/src/uts/common/io/dls/dls.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * Data-Link Services Module
  28   29   */
  29   30  
  30   31  #include        <sys/strsun.h>
  31   32  #include        <sys/vlan.h>
  32   33  #include        <sys/dld_impl.h>
  33   34  #include        <sys/mac_client_priv.h>
↓ open down ↓ 41 lines elided ↑ open up ↑
  75   76          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  76   77          return (0);
  77   78  }
  78   79  
  79   80  void
  80   81  dls_close(dld_str_t *dsp)
  81   82  {
  82   83          dls_link_t              *dlp = dsp->ds_dlp;
  83   84          dls_multicst_addr_t     *p;
  84   85          dls_multicst_addr_t     *nextp;
  85      -        uint32_t                old_flags;
  86   86  
  87   87          ASSERT(dsp->ds_datathr_cnt == 0);
  88   88          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  89   89  
  90   90          if (dsp->ds_local)
  91   91                  dlp->dl_zone_ref--;
  92   92          dsp->ds_local = B_FALSE;
  93   93  
  94   94          /*
  95   95           * Walk the list of multicast addresses, disabling each at the MAC.
↓ open down ↓ 16 lines elided ↑ open up ↑
 112  112           */
 113  113          if (dsp->ds_dlstate == DL_IDLE) {
 114  114                  dls_unbind(dsp);
 115  115                  dsp->ds_dlstate = DL_UNBOUND;
 116  116          }
 117  117  
 118  118          /*
 119  119           * If the MAC has been set in promiscuous mode then disable it.
 120  120           * This needs to be done before resetting ds_rx.
 121  121           */
 122      -        old_flags = dsp->ds_promisc;
 123      -        dsp->ds_promisc = 0;
 124      -        (void) dls_promisc(dsp, old_flags);
      122 +        (void) dls_promisc(dsp, 0);
 125  123  
 126  124          /*
 127  125           * At this point we have cutoff inbound packet flow from the mac
 128  126           * for this 'dsp'. The dls_link_remove above cut off packets meant
 129  127           * for us and waited for upcalls to finish. Similarly the dls_promisc
 130  128           * reset above waited for promisc callbacks to finish. Now we can
 131  129           * safely reset ds_rx to NULL
 132  130           */
 133  131          dsp->ds_rx = NULL;
 134  132          dsp->ds_rx_arg = NULL;
↓ open down ↓ 92 lines elided ↑ open up ↑
 227  225          }
 228  226  
 229  227          /*
 230  228           * Unbind the dld_str_t by removing it from the hash table in the
 231  229           * dls_link_t.
 232  230           */
 233  231          dls_link_remove(dsp->ds_dlp, dsp);
 234  232          dsp->ds_sap = 0;
 235  233  }
 236  234  
      235 +/*
      236 + * In order to prevent promiscuous-mode processing with dsp->ds_promisc
      237 + * set to inaccurate values, this function sets dsp->ds_promisc with new
      238 + * flags.  For enabling (mac_promisc_add), the flags are set prior to the
      239 + * actual enabling.  For disabling (mac_promisc_remove), the flags are set
      240 + * after the actual disabling.
      241 + */
 237  242  int
 238      -dls_promisc(dld_str_t *dsp, uint32_t old_flags)
      243 +dls_promisc(dld_str_t *dsp, uint32_t new_flags)
 239  244  {
 240      -        int             err = 0;
      245 +        int err = 0;
      246 +        uint32_t old_flags = dsp->ds_promisc;
 241  247  
 242  248          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 243      -        ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
      249 +        ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
 244  250              DLS_PROMISC_PHYS)));
 245  251  
 246      -        if (old_flags == 0 && dsp->ds_promisc != 0) {
      252 +        if (dsp->ds_promisc == 0 && new_flags != 0) {
 247  253                  /*
 248  254                   * If only DLS_PROMISC_SAP, we don't turn on the
 249  255                   * physical promisc mode
 250  256                   */
      257 +                dsp->ds_promisc = new_flags;
 251  258                  err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
 252  259                      dls_rx_promisc, dsp, &dsp->ds_mph,
 253      -                    (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 :
      260 +                    (new_flags != DLS_PROMISC_SAP) ? 0 :
 254  261                      MAC_PROMISC_FLAGS_NO_PHYS);
 255      -                if (err != 0)
      262 +                if (err != 0) {
      263 +                        dsp->ds_promisc = old_flags;
 256  264                          return (err);
      265 +                }
 257  266  
 258  267                  /* Remove vlan promisc handle to avoid sending dup copy up */
 259  268                  if (dsp->ds_vlan_mph != NULL) {
 260  269                          mac_promisc_remove(dsp->ds_vlan_mph);
 261  270                          dsp->ds_vlan_mph = NULL;
 262  271                  }
 263      -        } else if (old_flags != 0 && dsp->ds_promisc == 0) {
      272 +        } else if (dsp->ds_promisc != 0 && new_flags == 0) {
 264  273                  ASSERT(dsp->ds_mph != NULL);
 265  274  
 266  275                  mac_promisc_remove(dsp->ds_mph);
      276 +                dsp->ds_promisc = new_flags;
 267  277                  dsp->ds_mph = NULL;
 268  278  
 269  279                  if (dsp->ds_sap == ETHERTYPE_VLAN &&
 270  280                      dsp->ds_dlstate != DL_UNBOUND) {
 271      -                        int err;
 272      -
 273  281                          if (dsp->ds_vlan_mph != NULL)
 274  282                                  return (EINVAL);
 275  283                          err = mac_promisc_add(dsp->ds_mch,
 276  284                              MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 277  285                              &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
 278      -                        return (err);
 279  286                  }
 280      -        } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 &&
 281      -            dsp->ds_promisc != old_flags) {
      287 +        } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
      288 +            new_flags != dsp->ds_promisc) {
 282  289                  /*
 283  290                   * If the old flag is PROMISC_SAP, but the current flag has
 284  291                   * changed to some new non-zero value, we need to turn the
 285  292                   * physical promiscuous mode.
 286  293                   */
 287  294                  ASSERT(dsp->ds_mph != NULL);
 288  295                  mac_promisc_remove(dsp->ds_mph);
      296 +                /* Honors both after-remove and before-add semantics! */
      297 +                dsp->ds_promisc = new_flags;
 289  298                  err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
 290  299                      dls_rx_promisc, dsp, &dsp->ds_mph, 0);
      300 +                if (err != 0)
      301 +                        dsp->ds_promisc = old_flags;
      302 +        } else {
      303 +                /* No adding or removing, but record the new flags anyway. */
      304 +                dsp->ds_promisc = new_flags;
 291  305          }
 292  306  
 293  307          return (err);
 294  308  }
 295  309  
 296  310  int
 297  311  dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
 298  312  {
 299  313          int                     err;
 300  314          dls_multicst_addr_t     **pp;
↓ open down ↓ 398 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX