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
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ 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>
  34   35  
  35   36  int
  36   37  dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
  37   38  {
  38   39          zoneid_t        zid = getzoneid();
  39   40          boolean_t       local;
  40   41          int             err;
  41   42  
  42   43          /*
  43   44           * Check whether this client belongs to the zone of this dlp. Note that
  44   45           * a global zone client is allowed to open a local zone dlp.
  45   46           */
  46   47          if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
  47   48                  return (ENOENT);
  48   49  
  49   50          /*
  50   51           * mac_start() is required for non-legacy MACs to show accurate
  51   52           * kstats even before the interface is brought up. For legacy
  52   53           * drivers, this is not needed. Further, calling mac_start() for
  53   54           * legacy drivers would make the shared-lower-stream to stay in
  54   55           * the DL_IDLE state, which in turn causes performance regression.
  55   56           */
  56   57          if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) &&
  57   58              ((err = mac_start(dlp->dl_mh)) != 0)) {
  58   59                  return (err);
  59   60          }
  60   61  
  61   62          local = (zid == dlp->dl_zid);
  62   63          dlp->dl_zone_ref += (local ? 1 : 0);
  63   64  
  64   65          /*
  65   66           * Cache a copy of the MAC interface handle, a pointer to the
  66   67           * immutable MAC info.
  67   68           */
  68   69          dsp->ds_dlp = dlp;
  69   70          dsp->ds_mh = dlp->dl_mh;
  70   71          dsp->ds_mch = dlp->dl_mch;
  71   72          dsp->ds_mip = dlp->dl_mip;
  72   73          dsp->ds_ddh = ddh;
  73   74          dsp->ds_local = local;
  74   75  
  
    | 
      ↓ 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.
  96   96           * Note that we must remove multicast address before
  97   97           * mac_unicast_remove() (called by dls_active_clear()) because
  98   98           * mac_multicast_remove() relies on the unicast flows on the mac
  99   99           * client.
 100  100           */
 101  101          for (p = dsp->ds_dmap; p != NULL; p = nextp) {
 102  102                  (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
 103  103                  nextp = p->dma_nextp;
 104  104                  kmem_free(p, sizeof (dls_multicst_addr_t));
 105  105          }
 106  106          dsp->ds_dmap = NULL;
 107  107  
 108  108          dls_active_clear(dsp, B_TRUE);
 109  109  
 110  110          /*
 111  111           * If the dld_str_t is bound then unbind it.
  
    | 
      ↓ 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;
 135  133  
 136  134          dsp->ds_dlp = NULL;
 137  135  
 138  136          if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
 139  137                  mac_stop(dsp->ds_mh);
 140  138  
 141  139          /*
 142  140           * Release our reference to the dls_link_t allowing that to be
 143  141           * destroyed if there are no more dls_impl_t.
 144  142           */
 145  143          dls_link_rele(dlp);
 146  144  }
 147  145  
 148  146  int
 149  147  dls_bind(dld_str_t *dsp, uint32_t sap)
 150  148  {
 151  149          uint32_t        dls_sap;
 152  150  
 153  151          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 154  152  
 155  153          /*
 156  154           * Check to see the value is legal for the media type.
 157  155           */
 158  156          if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap))
 159  157                  return (EINVAL);
 160  158  
 161  159          if (dsp->ds_promisc & DLS_PROMISC_SAP)
 162  160                  dls_sap = DLS_SAP_PROMISC;
 163  161  
 164  162          /*
 165  163           * Set up the dld_str_t to mark it as able to receive packets.
 166  164           */
 167  165          dsp->ds_sap = sap;
 168  166  
 169  167          /*
 170  168           * The MAC layer does the VLAN demultiplexing and will only pass up
 171  169           * untagged packets to non-promiscuous primary MAC clients. In order to
 172  170           * support the binding to the VLAN SAP which is required by DLPI, dls
 173  171           * needs to get a copy of all tagged packets when the client binds to
 174  172           * the VLAN SAP. We do this by registering a separate promiscuous
 175  173           * callback for each dls client binding to that SAP.
 176  174           *
 177  175           * Note: even though there are two promiscuous handles in dld_str_t,
 178  176           * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
 179  177           * to receive VLAN pkt when promiscuous mode is not on. Only one of
 180  178           * them can be non-NULL at the same time, to avoid receiving dup copies
 181  179           * of pkts.
 182  180           */
 183  181          if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
 184  182                  int err;
 185  183  
 186  184                  if (dsp->ds_vlan_mph != NULL)
 187  185                          return (EINVAL);
 188  186                  err = mac_promisc_add(dsp->ds_mch,
 189  187                      MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 190  188                      &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
 191  189  
 192  190                  if (err == 0 && dsp->ds_nonip &&
 193  191                      dsp->ds_dlp->dl_nonip_cnt++ == 0)
 194  192                          mac_rx_bypass_disable(dsp->ds_mch);
 195  193  
 196  194                  return (err);
 197  195          }
 198  196  
 199  197          /*
 200  198           * Now bind the dld_str_t by adding it into the hash table in the
 201  199           * dls_link_t.
 202  200           */
 203  201          dls_link_add(dsp->ds_dlp, dls_sap, dsp);
 204  202          if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0)
 205  203                  mac_rx_bypass_disable(dsp->ds_mch);
 206  204  
 207  205          return (0);
 208  206  }
 209  207  
 210  208  void
 211  209  dls_unbind(dld_str_t *dsp)
 212  210  {
 213  211          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 214  212  
 215  213          if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0)
 216  214                  mac_rx_bypass_enable(dsp->ds_mch);
 217  215  
 218  216          /*
 219  217           * For VLAN SAP, there was a promisc handle registered when dls_bind.
 220  218           * When unbind this dls link, we need to remove the promisc handle.
 221  219           * See comments in dls_bind().
 222  220           */
 223  221          if (dsp->ds_vlan_mph != NULL) {
 224  222                  mac_promisc_remove(dsp->ds_vlan_mph);
 225  223                  dsp->ds_vlan_mph = NULL;
 226  224                  return;
  
    | 
      ↓ 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;
 301  315          dls_multicst_addr_t     *p;
 302  316          uint_t                  addr_length;
 303  317  
 304  318          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 305  319  
 306  320          /*
 307  321           * Check whether the address is in the list of enabled addresses for
 308  322           * this dld_str_t.
 309  323           */
 310  324          addr_length = dsp->ds_mip->mi_addr_length;
 311  325  
 312  326          /*
 313  327           * Protect against concurrent access of ds_dmap by data threads using
 314  328           * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
 315  329           * remove operations. Dropping the ds_rw_lock across mac calls is thus
 316  330           * ok and is also required by the locking protocol.
 317  331           */
 318  332          rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 319  333          for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
 320  334                  if (bcmp(addr, p->dma_addr, addr_length) == 0) {
 321  335                          /*
 322  336                           * It is there so there's nothing to do.
 323  337                           */
 324  338                          err = 0;
 325  339                          goto done;
 326  340                  }
 327  341          }
 328  342  
 329  343          /*
 330  344           * Allocate a new list item and add it to the list.
 331  345           */
 332  346          p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
 333  347          bcopy(addr, p->dma_addr, addr_length);
 334  348          *pp = p;
 335  349          rw_exit(&dsp->ds_rw_lock);
 336  350  
 337  351          /*
 338  352           * Enable the address at the MAC.
 339  353           */
 340  354          err = mac_multicast_add(dsp->ds_mch, addr);
 341  355          if (err == 0)
 342  356                  return (0);
 343  357  
 344  358          /* Undo the operation as it has failed */
 345  359          rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 346  360          ASSERT(*pp == p && p->dma_nextp == NULL);
 347  361          *pp = NULL;
 348  362          kmem_free(p, sizeof (dls_multicst_addr_t));
 349  363  done:
 350  364          rw_exit(&dsp->ds_rw_lock);
 351  365          return (err);
 352  366  }
 353  367  
 354  368  int
 355  369  dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
 356  370  {
 357  371          dls_multicst_addr_t     **pp;
 358  372          dls_multicst_addr_t     *p;
 359  373          uint_t                  addr_length;
 360  374  
 361  375          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 362  376  
 363  377          /*
 364  378           * Find the address in the list of enabled addresses for this
 365  379           * dld_str_t.
 366  380           */
 367  381          addr_length = dsp->ds_mip->mi_addr_length;
 368  382  
 369  383          /*
 370  384           * Protect against concurrent access to ds_dmap by data threads using
 371  385           * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
 372  386           * remove operations. Dropping the ds_rw_lock across mac calls is thus
 373  387           * ok and is also required by the locking protocol.
 374  388           */
 375  389          rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 376  390          for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
 377  391                  if (bcmp(addr, p->dma_addr, addr_length) == 0)
 378  392                          break;
 379  393          }
 380  394  
 381  395          /*
 382  396           * If we walked to the end of the list then the given address is
 383  397           * not currently enabled for this dld_str_t.
 384  398           */
 385  399          if (p == NULL) {
 386  400                  rw_exit(&dsp->ds_rw_lock);
 387  401                  return (ENOENT);
 388  402          }
 389  403  
 390  404          /*
 391  405           * Remove the address from the list.
 392  406           */
 393  407          *pp = p->dma_nextp;
 394  408          rw_exit(&dsp->ds_rw_lock);
 395  409  
 396  410          /*
 397  411           * Disable the address at the MAC.
 398  412           */
 399  413          mac_multicast_remove(dsp->ds_mch, addr);
 400  414          kmem_free(p, sizeof (dls_multicst_addr_t));
 401  415          return (0);
 402  416  }
 403  417  
 404  418  mblk_t *
 405  419  dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
 406  420      mblk_t **payloadp)
 407  421  {
 408  422          uint16_t vid;
 409  423          size_t extra_len;
 410  424          uint16_t mac_sap;
 411  425          mblk_t *mp, *payload;
 412  426          boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
 413  427          struct ether_vlan_header *evhp;
 414  428  
 415  429          vid = mac_client_vid(dsp->ds_mch);
 416  430          payload = (payloadp == NULL) ? NULL : (*payloadp);
 417  431  
 418  432          /*
 419  433           * In the case of Ethernet, we need to tell mac_header() if we need
 420  434           * extra room beyond the Ethernet header for a VLAN header.  We'll
 421  435           * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
 422  436           * (because such streams will be handling VLAN headers on their own)
 423  437           * and one of the following conditions is satisfied:
 424  438           *
 425  439           * - This is a VLAN stream
 426  440           * - This is a physical stream, the priority is not 0, and user
 427  441           *   priority tagging is allowed.
 428  442           */
 429  443          if (is_ethernet && sap != ETHERTYPE_VLAN &&
 430  444              (vid != VLAN_ID_NONE ||
 431  445              (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
 432  446                  extra_len = sizeof (struct ether_vlan_header) -
 433  447                      sizeof (struct ether_header);
 434  448                  mac_sap = ETHERTYPE_VLAN;
 435  449          } else {
 436  450                  extra_len = 0;
 437  451                  mac_sap = sap;
 438  452          }
 439  453  
 440  454          mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
 441  455          if (mp == NULL)
 442  456                  return (NULL);
 443  457  
 444  458          if ((vid == VLAN_ID_NONE && (pri == 0 ||
 445  459              dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
 446  460                  return (mp);
 447  461  
 448  462          /*
 449  463           * Fill in the tag information.
 450  464           */
 451  465          ASSERT(MBLKL(mp) == sizeof (struct ether_header));
 452  466          if (extra_len != 0) {
 453  467                  mp->b_wptr += extra_len;
 454  468                  evhp = (struct ether_vlan_header *)mp->b_rptr;
 455  469                  evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
 456  470                  evhp->ether_type = htons(sap);
 457  471          } else {
 458  472                  /*
 459  473                   * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
 460  474                   * in the payload. Update the priority.
 461  475                   */
 462  476                  struct ether_vlan_extinfo *extinfo;
 463  477                  size_t len = sizeof (struct ether_vlan_extinfo);
 464  478  
 465  479                  ASSERT(sap == ETHERTYPE_VLAN);
 466  480                  ASSERT(payload != NULL);
 467  481  
 468  482                  if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
 469  483                          mblk_t *newmp;
 470  484  
 471  485                          /*
 472  486                           * Because some DLS consumers only check the db_ref
 473  487                           * count of the first mblk, we pullup 'payload' into
 474  488                           * a single mblk.
 475  489                           */
 476  490                          newmp = msgpullup(payload, -1);
 477  491                          if ((newmp == NULL) || (MBLKL(newmp) < len)) {
 478  492                                  freemsg(newmp);
 479  493                                  freemsg(mp);
 480  494                                  return (NULL);
 481  495                          } else {
 482  496                                  freemsg(payload);
 483  497                                  *payloadp = payload = newmp;
 484  498                          }
 485  499                  }
 486  500  
 487  501                  extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
 488  502                  extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
 489  503                      VLAN_ID(ntohs(extinfo->ether_tci))));
 490  504          }
 491  505          return (mp);
 492  506  }
 493  507  
 494  508  void
 495  509  dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
 496  510  {
 497  511          mutex_enter(&dsp->ds_lock);
 498  512          dsp->ds_rx = rx;
 499  513          dsp->ds_rx_arg = arg;
 500  514          mutex_exit(&dsp->ds_lock);
 501  515  }
 502  516  
 503  517  static boolean_t
 504  518  dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 505  519      void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
 506  520  {
 507  521          dls_multicst_addr_t     *dmap;
 508  522          size_t                  addr_length = dsp->ds_mip->mi_addr_length;
 509  523  
 510  524          /*
 511  525           * We must not accept packets if the dld_str_t is not marked as bound
 512  526           * or is being removed.
 513  527           */
 514  528          if (dsp->ds_dlstate != DL_IDLE)
 515  529                  goto refuse;
 516  530  
 517  531          if (dsp->ds_promisc != 0) {
 518  532                  /*
 519  533                   * Filter out packets that arrived from the data path
 520  534                   * (i_dls_link_rx) when promisc mode is on.
 521  535                   */
 522  536                  if (!promisc)
 523  537                          goto refuse;
 524  538                  /*
 525  539                   * If the dls_impl_t is in 'all physical' mode then
 526  540                   * always accept.
 527  541                   */
 528  542                  if (dsp->ds_promisc & DLS_PROMISC_PHYS)
 529  543                          goto accept;
 530  544  
 531  545                  /*
 532  546                   * Loopback packets i.e. packets sent out by DLS on a given
 533  547                   * mac end point, will be accepted back by DLS on loopback
 534  548                   * from the mac, only in the 'all physical' mode which has been
 535  549                   * covered by the previous check above
 536  550                   */
 537  551                  if (promisc_loopback)
 538  552                          goto refuse;
 539  553          }
 540  554  
 541  555          switch (mhip->mhi_dsttype) {
 542  556          case MAC_ADDRTYPE_UNICAST:
 543  557          case MAC_ADDRTYPE_BROADCAST:
 544  558                  /*
 545  559                   * We can accept unicast and broadcast packets because
 546  560                   * filtering is already done by the mac layer.
 547  561                   */
 548  562                  goto accept;
 549  563          case MAC_ADDRTYPE_MULTICAST:
 550  564                  /*
 551  565                   * Additional filtering is needed for multicast addresses
 552  566                   * because different streams may be interested in different
 553  567                   * addresses.
 554  568                   */
 555  569                  if (dsp->ds_promisc & DLS_PROMISC_MULTI)
 556  570                          goto accept;
 557  571  
 558  572                  rw_enter(&dsp->ds_rw_lock, RW_READER);
 559  573                  for (dmap = dsp->ds_dmap; dmap != NULL;
 560  574                      dmap = dmap->dma_nextp) {
 561  575                          if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
 562  576                              addr_length) == 0) {
 563  577                                  rw_exit(&dsp->ds_rw_lock);
 564  578                                  goto accept;
 565  579                          }
 566  580                  }
 567  581                  rw_exit(&dsp->ds_rw_lock);
 568  582                  break;
 569  583          }
 570  584  
 571  585  refuse:
 572  586          return (B_FALSE);
 573  587  
 574  588  accept:
 575  589          /*
 576  590           * the returned ds_rx and ds_rx_arg will always be in sync.
 577  591           */
 578  592          mutex_enter(&dsp->ds_lock);
 579  593          *ds_rx = dsp->ds_rx;
 580  594          *ds_rx_arg = dsp->ds_rx_arg;
 581  595          mutex_exit(&dsp->ds_lock);
 582  596  
 583  597          return (B_TRUE);
 584  598  }
 585  599  
 586  600  /* ARGSUSED */
 587  601  boolean_t
 588  602  dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 589  603      void **ds_rx_arg)
 590  604  {
 591  605          return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
 592  606              B_FALSE));
 593  607  }
 594  608  
 595  609  boolean_t
 596  610  dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 597  611      void **ds_rx_arg, boolean_t loopback)
 598  612  {
 599  613          return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
 600  614              loopback));
 601  615  }
 602  616  
 603  617  int
 604  618  dls_mac_active_set(dls_link_t *dlp)
 605  619  {
 606  620          int err = 0;
 607  621  
 608  622          /*
 609  623           * First client; add the primary unicast address.
 610  624           */
 611  625          if (dlp->dl_nactive == 0) {
 612  626                  /*
 613  627                   * First client; add the primary unicast address.
 614  628                   */
 615  629                  mac_diag_t diag;
 616  630  
 617  631                  /* request the primary MAC address */
 618  632                  if ((err = mac_unicast_add(dlp->dl_mch, NULL,
 619  633                      MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
 620  634                      MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0,
 621  635                      &diag)) != 0) {
 622  636                          return (err);
 623  637                  }
 624  638  
 625  639                  /*
 626  640                   * Set the function to start receiving packets.
 627  641                   */
 628  642                  mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
 629  643          }
 630  644          dlp->dl_nactive++;
 631  645          return (0);
 632  646  }
 633  647  
 634  648  void
 635  649  dls_mac_active_clear(dls_link_t *dlp)
 636  650  {
 637  651          if (--dlp->dl_nactive == 0) {
 638  652                  ASSERT(dlp->dl_mah != NULL);
 639  653                  (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
 640  654                  dlp->dl_mah = NULL;
 641  655                  mac_rx_clear(dlp->dl_mch);
 642  656          }
 643  657  }
 644  658  
 645  659  int
 646  660  dls_active_set(dld_str_t *dsp)
 647  661  {
 648  662          int err = 0;
 649  663  
 650  664          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 651  665  
 652  666          if (dsp->ds_passivestate == DLD_PASSIVE)
 653  667                  return (0);
 654  668  
 655  669          /* If we're already active, then there's nothing more to do. */
 656  670          if ((dsp->ds_nactive == 0) &&
 657  671              ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
 658  672                  /* except for ENXIO all other errors are mapped to EBUSY */
 659  673                  if (err != ENXIO)
 660  674                          return (EBUSY);
 661  675                  return (err);
 662  676          }
 663  677  
 664  678          dsp->ds_passivestate = DLD_ACTIVE;
 665  679          dsp->ds_nactive++;
 666  680          return (0);
 667  681  }
 668  682  
 669  683  /*
 670  684   * Note that dls_active_set() is called whenever an active operation
 671  685   * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
 672  686   * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
 673  687   * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
 674  688   * a stream is closed without every active operation being undone and we
 675  689   * need to clear all the "active" states by calling
 676  690   * dls_active_clear(dsp, B_TRUE).
 677  691   */
 678  692  void
 679  693  dls_active_clear(dld_str_t *dsp, boolean_t all)
 680  694  {
 681  695          ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 682  696  
 683  697          if (dsp->ds_passivestate == DLD_PASSIVE)
 684  698                  return;
 685  699  
 686  700          if (all && dsp->ds_nactive == 0)
 687  701                  return;
 688  702  
 689  703          ASSERT(dsp->ds_nactive > 0);
 690  704  
 691  705          dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
 692  706          if (dsp->ds_nactive != 0)
 693  707                  return;
 694  708  
 695  709          ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
 696  710          dls_mac_active_clear(dsp->ds_dlp);
 697  711          dsp->ds_passivestate = DLD_UNINITIALIZED;
 698  712  }
  
    | 
      ↓ open down ↓ | 
    398 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX