Print this page
1918 stack overflow from mac_promisc_dispatch()


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.

  24  */
  25 
  26 /*
  27  * Data-Link Services Module
  28  */
  29 
  30 #include        <sys/strsun.h>
  31 #include        <sys/vlan.h>
  32 #include        <sys/dld_impl.h>
  33 #include        <sys/mac_client_priv.h>
  34 
  35 int
  36 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
  37 {
  38         zoneid_t        zid = getzoneid();
  39         boolean_t       local;
  40         int             err;
  41 
  42         /*
  43          * Check whether this client belongs to the zone of this dlp. Note that


  65          * Cache a copy of the MAC interface handle, a pointer to the
  66          * immutable MAC info.
  67          */
  68         dsp->ds_dlp = dlp;
  69         dsp->ds_mh = dlp->dl_mh;
  70         dsp->ds_mch = dlp->dl_mch;
  71         dsp->ds_mip = dlp->dl_mip;
  72         dsp->ds_ddh = ddh;
  73         dsp->ds_local = local;
  74 
  75         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  76         return (0);
  77 }
  78 
  79 void
  80 dls_close(dld_str_t *dsp)
  81 {
  82         dls_link_t              *dlp = dsp->ds_dlp;
  83         dls_multicst_addr_t     *p;
  84         dls_multicst_addr_t     *nextp;
  85         uint32_t                old_flags;
  86 
  87         ASSERT(dsp->ds_datathr_cnt == 0);
  88         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  89 
  90         if (dsp->ds_local)
  91                 dlp->dl_zone_ref--;
  92         dsp->ds_local = B_FALSE;
  93 
  94         /*
  95          * Walk the list of multicast addresses, disabling each at the MAC.
  96          * Note that we must remove multicast address before
  97          * mac_unicast_remove() (called by dls_active_clear()) because
  98          * mac_multicast_remove() relies on the unicast flows on the mac
  99          * client.
 100          */
 101         for (p = dsp->ds_dmap; p != NULL; p = nextp) {
 102                 (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
 103                 nextp = p->dma_nextp;
 104                 kmem_free(p, sizeof (dls_multicst_addr_t));
 105         }
 106         dsp->ds_dmap = NULL;
 107 
 108         dls_active_clear(dsp, B_TRUE);
 109 
 110         /*
 111          * If the dld_str_t is bound then unbind it.
 112          */
 113         if (dsp->ds_dlstate == DL_IDLE) {
 114                 dls_unbind(dsp);
 115                 dsp->ds_dlstate = DL_UNBOUND;
 116         }
 117 
 118         /*
 119          * If the MAC has been set in promiscuous mode then disable it.
 120          * This needs to be done before resetting ds_rx.
 121          */
 122         old_flags = dsp->ds_promisc;
 123         dsp->ds_promisc = 0;
 124         (void) dls_promisc(dsp, old_flags);
 125 
 126         /*
 127          * At this point we have cutoff inbound packet flow from the mac
 128          * for this 'dsp'. The dls_link_remove above cut off packets meant
 129          * for us and waited for upcalls to finish. Similarly the dls_promisc
 130          * reset above waited for promisc callbacks to finish. Now we can
 131          * safely reset ds_rx to NULL
 132          */
 133         dsp->ds_rx = NULL;
 134         dsp->ds_rx_arg = NULL;
 135 
 136         dsp->ds_dlp = NULL;
 137 
 138         if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
 139                 mac_stop(dsp->ds_mh);
 140 
 141         /*
 142          * Release our reference to the dls_link_t allowing that to be
 143          * destroyed if there are no more dls_impl_t.
 144          */


 217 
 218         /*
 219          * For VLAN SAP, there was a promisc handle registered when dls_bind.
 220          * When unbind this dls link, we need to remove the promisc handle.
 221          * See comments in dls_bind().
 222          */
 223         if (dsp->ds_vlan_mph != NULL) {
 224                 mac_promisc_remove(dsp->ds_vlan_mph);
 225                 dsp->ds_vlan_mph = NULL;
 226                 return;
 227         }
 228 
 229         /*
 230          * Unbind the dld_str_t by removing it from the hash table in the
 231          * dls_link_t.
 232          */
 233         dls_link_remove(dsp->ds_dlp, dsp);
 234         dsp->ds_sap = 0;
 235 }
 236 







 237 int
 238 dls_promisc(dld_str_t *dsp, uint32_t old_flags)
 239 {
 240         int             err = 0;

 241 
 242         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 243         ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
 244             DLS_PROMISC_PHYS)));
 245 
 246         if (old_flags == 0 && dsp->ds_promisc != 0) {
 247                 /*
 248                  * If only DLS_PROMISC_SAP, we don't turn on the
 249                  * physical promisc mode
 250                  */

 251                 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
 252                     dls_rx_promisc, dsp, &dsp->ds_mph,
 253                     (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 :
 254                     MAC_PROMISC_FLAGS_NO_PHYS);
 255                 if (err != 0)

 256                         return (err);

 257 
 258                 /* Remove vlan promisc handle to avoid sending dup copy up */
 259                 if (dsp->ds_vlan_mph != NULL) {
 260                         mac_promisc_remove(dsp->ds_vlan_mph);
 261                         dsp->ds_vlan_mph = NULL;
 262                 }
 263         } else if (old_flags != 0 && dsp->ds_promisc == 0) {
 264                 ASSERT(dsp->ds_mph != NULL);
 265 
 266                 mac_promisc_remove(dsp->ds_mph);

 267                 dsp->ds_mph = NULL;
 268 
 269                 if (dsp->ds_sap == ETHERTYPE_VLAN &&
 270                     dsp->ds_dlstate != DL_UNBOUND) {
 271                         int err;
 272 
 273                         if (dsp->ds_vlan_mph != NULL)
 274                                 return (EINVAL);
 275                         err = mac_promisc_add(dsp->ds_mch,
 276                             MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 277                             &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
 278                         return (err);
 279                 }
 280         } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 &&
 281             dsp->ds_promisc != old_flags) {
 282                 /*
 283                  * If the old flag is PROMISC_SAP, but the current flag has
 284                  * changed to some new non-zero value, we need to turn the
 285                  * physical promiscuous mode.
 286                  */
 287                 ASSERT(dsp->ds_mph != NULL);
 288                 mac_promisc_remove(dsp->ds_mph);


 289                 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
 290                     dls_rx_promisc, dsp, &dsp->ds_mph, 0);





 291         }
 292 
 293         return (err);
 294 }
 295 
 296 int
 297 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
 298 {
 299         int                     err;
 300         dls_multicst_addr_t     **pp;
 301         dls_multicst_addr_t     *p;
 302         uint_t                  addr_length;
 303 
 304         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 305 
 306         /*
 307          * Check whether the address is in the list of enabled addresses for
 308          * this dld_str_t.
 309          */
 310         addr_length = dsp->ds_mip->mi_addr_length;




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 /*
  28  * Data-Link Services Module
  29  */
  30 
  31 #include        <sys/strsun.h>
  32 #include        <sys/vlan.h>
  33 #include        <sys/dld_impl.h>
  34 #include        <sys/mac_client_priv.h>
  35 
  36 int
  37 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
  38 {
  39         zoneid_t        zid = getzoneid();
  40         boolean_t       local;
  41         int             err;
  42 
  43         /*
  44          * Check whether this client belongs to the zone of this dlp. Note that


  66          * Cache a copy of the MAC interface handle, a pointer to the
  67          * immutable MAC info.
  68          */
  69         dsp->ds_dlp = dlp;
  70         dsp->ds_mh = dlp->dl_mh;
  71         dsp->ds_mch = dlp->dl_mch;
  72         dsp->ds_mip = dlp->dl_mip;
  73         dsp->ds_ddh = ddh;
  74         dsp->ds_local = local;
  75 
  76         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  77         return (0);
  78 }
  79 
  80 void
  81 dls_close(dld_str_t *dsp)
  82 {
  83         dls_link_t              *dlp = dsp->ds_dlp;
  84         dls_multicst_addr_t     *p;
  85         dls_multicst_addr_t     *nextp;

  86 
  87         ASSERT(dsp->ds_datathr_cnt == 0);
  88         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  89 
  90         if (dsp->ds_local)
  91                 dlp->dl_zone_ref--;
  92         dsp->ds_local = B_FALSE;
  93 
  94         /*
  95          * Walk the list of multicast addresses, disabling each at the MAC.
  96          * Note that we must remove multicast address before
  97          * mac_unicast_remove() (called by dls_active_clear()) because
  98          * mac_multicast_remove() relies on the unicast flows on the mac
  99          * client.
 100          */
 101         for (p = dsp->ds_dmap; p != NULL; p = nextp) {
 102                 (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
 103                 nextp = p->dma_nextp;
 104                 kmem_free(p, sizeof (dls_multicst_addr_t));
 105         }
 106         dsp->ds_dmap = NULL;
 107 
 108         dls_active_clear(dsp, B_TRUE);
 109 
 110         /*
 111          * If the dld_str_t is bound then unbind it.
 112          */
 113         if (dsp->ds_dlstate == DL_IDLE) {
 114                 dls_unbind(dsp);
 115                 dsp->ds_dlstate = DL_UNBOUND;
 116         }
 117 
 118         /*
 119          * If the MAC has been set in promiscuous mode then disable it.
 120          * This needs to be done before resetting ds_rx.
 121          */
 122         (void) dls_promisc(dsp, 0);


 123 
 124         /*
 125          * At this point we have cutoff inbound packet flow from the mac
 126          * for this 'dsp'. The dls_link_remove above cut off packets meant
 127          * for us and waited for upcalls to finish. Similarly the dls_promisc
 128          * reset above waited for promisc callbacks to finish. Now we can
 129          * safely reset ds_rx to NULL
 130          */
 131         dsp->ds_rx = NULL;
 132         dsp->ds_rx_arg = NULL;
 133 
 134         dsp->ds_dlp = NULL;
 135 
 136         if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
 137                 mac_stop(dsp->ds_mh);
 138 
 139         /*
 140          * Release our reference to the dls_link_t allowing that to be
 141          * destroyed if there are no more dls_impl_t.
 142          */


 215 
 216         /*
 217          * For VLAN SAP, there was a promisc handle registered when dls_bind.
 218          * When unbind this dls link, we need to remove the promisc handle.
 219          * See comments in dls_bind().
 220          */
 221         if (dsp->ds_vlan_mph != NULL) {
 222                 mac_promisc_remove(dsp->ds_vlan_mph);
 223                 dsp->ds_vlan_mph = NULL;
 224                 return;
 225         }
 226 
 227         /*
 228          * Unbind the dld_str_t by removing it from the hash table in the
 229          * dls_link_t.
 230          */
 231         dls_link_remove(dsp->ds_dlp, dsp);
 232         dsp->ds_sap = 0;
 233 }
 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  */
 242 int
 243 dls_promisc(dld_str_t *dsp, uint32_t new_flags)
 244 {
 245         int err = 0;
 246         uint32_t old_flags = dsp->ds_promisc;
 247 
 248         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 249         ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
 250             DLS_PROMISC_PHYS)));
 251 
 252         if (dsp->ds_promisc == 0 && new_flags != 0) {
 253                 /*
 254                  * If only DLS_PROMISC_SAP, we don't turn on the
 255                  * physical promisc mode
 256                  */
 257                 dsp->ds_promisc = new_flags;
 258                 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
 259                     dls_rx_promisc, dsp, &dsp->ds_mph,
 260                     (new_flags != DLS_PROMISC_SAP) ? 0 :
 261                     MAC_PROMISC_FLAGS_NO_PHYS);
 262                 if (err != 0) {
 263                         dsp->ds_promisc = old_flags;
 264                         return (err);
 265                 }
 266 
 267                 /* Remove vlan promisc handle to avoid sending dup copy up */
 268                 if (dsp->ds_vlan_mph != NULL) {
 269                         mac_promisc_remove(dsp->ds_vlan_mph);
 270                         dsp->ds_vlan_mph = NULL;
 271                 }
 272         } else if (dsp->ds_promisc != 0 && new_flags == 0) {
 273                 ASSERT(dsp->ds_mph != NULL);
 274 
 275                 mac_promisc_remove(dsp->ds_mph);
 276                 dsp->ds_promisc = new_flags;
 277                 dsp->ds_mph = NULL;
 278 
 279                 if (dsp->ds_sap == ETHERTYPE_VLAN &&
 280                     dsp->ds_dlstate != DL_UNBOUND) {


 281                         if (dsp->ds_vlan_mph != NULL)
 282                                 return (EINVAL);
 283                         err = mac_promisc_add(dsp->ds_mch,
 284                             MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 285                             &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);

 286                 }
 287         } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
 288             new_flags != dsp->ds_promisc) {
 289                 /*
 290                  * If the old flag is PROMISC_SAP, but the current flag has
 291                  * changed to some new non-zero value, we need to turn the
 292                  * physical promiscuous mode.
 293                  */
 294                 ASSERT(dsp->ds_mph != NULL);
 295                 mac_promisc_remove(dsp->ds_mph);
 296                 /* Honors both after-remove and before-add semantics! */
 297                 dsp->ds_promisc = new_flags;
 298                 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
 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;
 305         }
 306 
 307         return (err);
 308 }
 309 
 310 int
 311 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
 312 {
 313         int                     err;
 314         dls_multicst_addr_t     **pp;
 315         dls_multicst_addr_t     *p;
 316         uint_t                  addr_length;
 317 
 318         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 319 
 320         /*
 321          * Check whether the address is in the list of enabled addresses for
 322          * this dld_str_t.
 323          */
 324         addr_length = dsp->ds_mip->mi_addr_length;