1 /*
   2  * CDDL HEADER START
   3  *
   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 2012, Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 /*
  28  * Copyright (c) 2013 Joyent, Inc.  All rights reserved.
  29  */
  30 
  31 /*
  32  * Data-Link Services Module
  33  */
  34 
  35 #include        <sys/strsun.h>
  36 #include        <sys/vlan.h>
  37 #include        <sys/dld_impl.h>
  38 #include        <sys/mac_client_priv.h>
  39 
  40 int
  41 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
  42 {
  43         zoneid_t        zid = getzoneid();
  44         boolean_t       local;
  45         int             err;
  46 
  47         /*
  48          * Check whether this client belongs to the zone of this dlp. Note that
  49          * a global zone client is allowed to open a local zone dlp.
  50          */
  51         if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
  52                 return (ENOENT);
  53 
  54         /*
  55          * mac_start() is required for non-legacy MACs to show accurate
  56          * kstats even before the interface is brought up. For legacy
  57          * drivers, this is not needed. Further, calling mac_start() for
  58          * legacy drivers would make the shared-lower-stream to stay in
  59          * the DL_IDLE state, which in turn causes performance regression.
  60          */
  61         if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) &&
  62             ((err = mac_start(dlp->dl_mh)) != 0)) {
  63                 return (err);
  64         }
  65 
  66         local = (zid == dlp->dl_zid);
  67         dlp->dl_zone_ref += (local ? 1 : 0);
  68 
  69         /*
  70          * Cache a copy of the MAC interface handle, a pointer to the
  71          * immutable MAC info.
  72          */
  73         dsp->ds_dlp = dlp;
  74         dsp->ds_mh = dlp->dl_mh;
  75         dsp->ds_mch = dlp->dl_mch;
  76         dsp->ds_mip = dlp->dl_mip;
  77         dsp->ds_ddh = ddh;
  78         dsp->ds_local = local;
  79 
  80         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  81         return (0);
  82 }
  83 
  84 void
  85 dls_close(dld_str_t *dsp)
  86 {
  87         dls_link_t              *dlp = dsp->ds_dlp;
  88         dls_multicst_addr_t     *p;
  89         dls_multicst_addr_t     *nextp;
  90 
  91         ASSERT(dsp->ds_datathr_cnt == 0);
  92         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
  93 
  94         if (dsp->ds_local)
  95                 dlp->dl_zone_ref--;
  96         dsp->ds_local = B_FALSE;
  97 
  98         /*
  99          * Walk the list of multicast addresses, disabling each at the MAC.
 100          * Note that we must remove multicast address before
 101          * mac_unicast_remove() (called by dls_active_clear()) because
 102          * mac_multicast_remove() relies on the unicast flows on the mac
 103          * client.
 104          */
 105         for (p = dsp->ds_dmap; p != NULL; p = nextp) {
 106                 (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
 107                 nextp = p->dma_nextp;
 108                 kmem_free(p, sizeof (dls_multicst_addr_t));
 109         }
 110         dsp->ds_dmap = NULL;
 111 
 112         dls_active_clear(dsp, B_TRUE);
 113 
 114         /*
 115          * If the dld_str_t is bound then unbind it.
 116          */
 117         if (dsp->ds_dlstate == DL_IDLE) {
 118                 dls_unbind(dsp);
 119                 dsp->ds_dlstate = DL_UNBOUND;
 120         }
 121 
 122         /*
 123          * If the MAC has been set in promiscuous mode then disable it.
 124          * This needs to be done before resetting ds_rx.
 125          */
 126         (void) dls_promisc(dsp, 0);
 127 
 128         /*
 129          * At this point we have cutoff inbound packet flow from the mac
 130          * for this 'dsp'. The dls_link_remove above cut off packets meant
 131          * for us and waited for upcalls to finish. Similarly the dls_promisc
 132          * reset above waited for promisc callbacks to finish. Now we can
 133          * safely reset ds_rx to NULL
 134          */
 135         dsp->ds_rx = NULL;
 136         dsp->ds_rx_arg = NULL;
 137 
 138         dsp->ds_dlp = NULL;
 139 
 140         if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
 141                 mac_stop(dsp->ds_mh);
 142 
 143         /*
 144          * Release our reference to the dls_link_t allowing that to be
 145          * destroyed if there are no more dls_impl_t.
 146          */
 147         dls_link_rele(dlp);
 148 }
 149 
 150 int
 151 dls_bind(dld_str_t *dsp, uint32_t sap)
 152 {
 153         uint32_t        dls_sap;
 154 
 155         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 156 
 157         /*
 158          * Check to see the value is legal for the media type.
 159          */
 160         if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap))
 161                 return (EINVAL);
 162 
 163         if (dsp->ds_promisc & DLS_PROMISC_SAP)
 164                 dls_sap = DLS_SAP_PROMISC;
 165 
 166         /*
 167          * Set up the dld_str_t to mark it as able to receive packets.
 168          */
 169         dsp->ds_sap = sap;
 170 
 171         /*
 172          * The MAC layer does the VLAN demultiplexing and will only pass up
 173          * untagged packets to non-promiscuous primary MAC clients. In order to
 174          * support the binding to the VLAN SAP which is required by DLPI, dls
 175          * needs to get a copy of all tagged packets when the client binds to
 176          * the VLAN SAP. We do this by registering a separate promiscuous
 177          * callback for each dls client binding to that SAP.
 178          *
 179          * Note: even though there are two promiscuous handles in dld_str_t,
 180          * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
 181          * to receive VLAN pkt when promiscuous mode is not on. Only one of
 182          * them can be non-NULL at the same time, to avoid receiving dup copies
 183          * of pkts.
 184          */
 185         if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
 186                 int err;
 187 
 188                 if (dsp->ds_vlan_mph != NULL)
 189                         return (EINVAL);
 190                 err = mac_promisc_add(dsp->ds_mch,
 191                     MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 192                     &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
 193 
 194                 if (err == 0 && dsp->ds_nonip &&
 195                     dsp->ds_dlp->dl_nonip_cnt++ == 0)
 196                         mac_rx_bypass_disable(dsp->ds_mch);
 197 
 198                 return (err);
 199         }
 200 
 201         /*
 202          * Now bind the dld_str_t by adding it into the hash table in the
 203          * dls_link_t.
 204          */
 205         dls_link_add(dsp->ds_dlp, dls_sap, dsp);
 206         if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0)
 207                 mac_rx_bypass_disable(dsp->ds_mch);
 208 
 209         return (0);
 210 }
 211 
 212 void
 213 dls_unbind(dld_str_t *dsp)
 214 {
 215         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 216 
 217         if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0)
 218                 mac_rx_bypass_enable(dsp->ds_mch);
 219 
 220         /*
 221          * For VLAN SAP, there was a promisc handle registered when dls_bind.
 222          * When unbind this dls link, we need to remove the promisc handle.
 223          * See comments in dls_bind().
 224          */
 225         if (dsp->ds_vlan_mph != NULL) {
 226                 mac_promisc_remove(dsp->ds_vlan_mph);
 227                 dsp->ds_vlan_mph = NULL;
 228                 return;
 229         }
 230 
 231         /*
 232          * Unbind the dld_str_t by removing it from the hash table in the
 233          * dls_link_t.
 234          */
 235         dls_link_remove(dsp->ds_dlp, dsp);
 236         dsp->ds_sap = 0;
 237 }
 238 
 239 /*
 240  * In order to prevent promiscuous-mode processing with dsp->ds_promisc
 241  * set to inaccurate values, this function sets dsp->ds_promisc with new
 242  * flags.  For enabling (mac_promisc_add), the flags are set prior to the
 243  * actual enabling.  For disabling (mac_promisc_remove), the flags are set
 244  * after the actual disabling.
 245  */
 246 int
 247 dls_promisc(dld_str_t *dsp, uint32_t new_flags)
 248 {
 249         int err = 0;
 250         uint32_t old_flags = dsp->ds_promisc;
 251         mac_client_promisc_type_t mptype = MAC_CLIENT_PROMISC_ALL;
 252 
 253         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 254         ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
 255             DLS_PROMISC_PHYS)));
 256 
 257         /*
 258          * If the user has only requested DLS_PROMISC_MULTI then we need to make
 259          * sure that they don't see all packets.
 260          */
 261         if (new_flags == DLS_PROMISC_MULTI)
 262                 mptype = MAC_CLIENT_PROMISC_MULTI;
 263 
 264         if (dsp->ds_promisc == 0 && new_flags != 0) {
 265                 /*
 266                  * If only DLS_PROMISC_SAP, we don't turn on the
 267                  * physical promisc mode
 268                  */
 269                 dsp->ds_promisc = new_flags;
 270                 err = mac_promisc_add(dsp->ds_mch, mptype,
 271                     dls_rx_promisc, dsp, &dsp->ds_mph,
 272                     (new_flags != DLS_PROMISC_SAP) ? 0 :
 273                     MAC_PROMISC_FLAGS_NO_PHYS);
 274                 if (err != 0) {
 275                         dsp->ds_promisc = old_flags;
 276                         return (err);
 277                 }
 278 
 279                 /* Remove vlan promisc handle to avoid sending dup copy up */
 280                 if (dsp->ds_vlan_mph != NULL) {
 281                         mac_promisc_remove(dsp->ds_vlan_mph);
 282                         dsp->ds_vlan_mph = NULL;
 283                 }
 284         } else if (dsp->ds_promisc != 0 && new_flags == 0) {
 285                 ASSERT(dsp->ds_mph != NULL);
 286 
 287                 mac_promisc_remove(dsp->ds_mph);
 288                 dsp->ds_promisc = new_flags;
 289                 dsp->ds_mph = NULL;
 290 
 291                 if (dsp->ds_sap == ETHERTYPE_VLAN &&
 292                     dsp->ds_dlstate != DL_UNBOUND) {
 293                         if (dsp->ds_vlan_mph != NULL)
 294                                 return (EINVAL);
 295                         err = mac_promisc_add(dsp->ds_mch,
 296                             MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 297                             &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
 298                 }
 299         } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
 300             new_flags != dsp->ds_promisc) {
 301                 /*
 302                  * If the old flag is PROMISC_SAP, but the current flag has
 303                  * changed to some new non-zero value, we need to turn the
 304                  * physical promiscuous mode.
 305                  */
 306                 ASSERT(dsp->ds_mph != NULL);
 307                 mac_promisc_remove(dsp->ds_mph);
 308                 /* Honors both after-remove and before-add semantics! */
 309                 dsp->ds_promisc = new_flags;
 310                 err = mac_promisc_add(dsp->ds_mch, mptype,
 311                     dls_rx_promisc, dsp, &dsp->ds_mph, 0);
 312                 if (err != 0)
 313                         dsp->ds_promisc = old_flags;
 314         } else {
 315                 /* No adding or removing, but record the new flags anyway. */
 316                 dsp->ds_promisc = new_flags;
 317         }
 318 
 319         return (err);
 320 }
 321 
 322 int
 323 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
 324 {
 325         int                     err;
 326         dls_multicst_addr_t     **pp;
 327         dls_multicst_addr_t     *p;
 328         uint_t                  addr_length;
 329 
 330         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 331 
 332         /*
 333          * Check whether the address is in the list of enabled addresses for
 334          * this dld_str_t.
 335          */
 336         addr_length = dsp->ds_mip->mi_addr_length;
 337 
 338         /*
 339          * Protect against concurrent access of ds_dmap by data threads using
 340          * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
 341          * remove operations. Dropping the ds_rw_lock across mac calls is thus
 342          * ok and is also required by the locking protocol.
 343          */
 344         rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 345         for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
 346                 if (bcmp(addr, p->dma_addr, addr_length) == 0) {
 347                         /*
 348                          * It is there so there's nothing to do.
 349                          */
 350                         err = 0;
 351                         goto done;
 352                 }
 353         }
 354 
 355         /*
 356          * Allocate a new list item and add it to the list.
 357          */
 358         p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
 359         bcopy(addr, p->dma_addr, addr_length);
 360         *pp = p;
 361         rw_exit(&dsp->ds_rw_lock);
 362 
 363         /*
 364          * Enable the address at the MAC.
 365          */
 366         err = mac_multicast_add(dsp->ds_mch, addr);
 367         if (err == 0)
 368                 return (0);
 369 
 370         /* Undo the operation as it has failed */
 371         rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 372         ASSERT(*pp == p && p->dma_nextp == NULL);
 373         *pp = NULL;
 374         kmem_free(p, sizeof (dls_multicst_addr_t));
 375 done:
 376         rw_exit(&dsp->ds_rw_lock);
 377         return (err);
 378 }
 379 
 380 int
 381 dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
 382 {
 383         dls_multicst_addr_t     **pp;
 384         dls_multicst_addr_t     *p;
 385         uint_t                  addr_length;
 386 
 387         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 388 
 389         /*
 390          * Find the address in the list of enabled addresses for this
 391          * dld_str_t.
 392          */
 393         addr_length = dsp->ds_mip->mi_addr_length;
 394 
 395         /*
 396          * Protect against concurrent access to ds_dmap by data threads using
 397          * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
 398          * remove operations. Dropping the ds_rw_lock across mac calls is thus
 399          * ok and is also required by the locking protocol.
 400          */
 401         rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 402         for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
 403                 if (bcmp(addr, p->dma_addr, addr_length) == 0)
 404                         break;
 405         }
 406 
 407         /*
 408          * If we walked to the end of the list then the given address is
 409          * not currently enabled for this dld_str_t.
 410          */
 411         if (p == NULL) {
 412                 rw_exit(&dsp->ds_rw_lock);
 413                 return (ENOENT);
 414         }
 415 
 416         /*
 417          * Remove the address from the list.
 418          */
 419         *pp = p->dma_nextp;
 420         rw_exit(&dsp->ds_rw_lock);
 421 
 422         /*
 423          * Disable the address at the MAC.
 424          */
 425         mac_multicast_remove(dsp->ds_mch, addr);
 426         kmem_free(p, sizeof (dls_multicst_addr_t));
 427         return (0);
 428 }
 429 
 430 mblk_t *
 431 dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
 432     mblk_t **payloadp)
 433 {
 434         uint16_t vid;
 435         size_t extra_len;
 436         uint16_t mac_sap;
 437         mblk_t *mp, *payload;
 438         boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
 439         struct ether_vlan_header *evhp;
 440 
 441         vid = mac_client_vid(dsp->ds_mch);
 442         payload = (payloadp == NULL) ? NULL : (*payloadp);
 443 
 444         /*
 445          * In the case of Ethernet, we need to tell mac_header() if we need
 446          * extra room beyond the Ethernet header for a VLAN header.  We'll
 447          * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
 448          * (because such streams will be handling VLAN headers on their own)
 449          * and one of the following conditions is satisfied:
 450          *
 451          * - This is a VLAN stream
 452          * - This is a physical stream, the priority is not 0, and user
 453          *   priority tagging is allowed.
 454          */
 455         if (is_ethernet && sap != ETHERTYPE_VLAN &&
 456             (vid != VLAN_ID_NONE ||
 457             (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
 458                 extra_len = sizeof (struct ether_vlan_header) -
 459                     sizeof (struct ether_header);
 460                 mac_sap = ETHERTYPE_VLAN;
 461         } else {
 462                 extra_len = 0;
 463                 mac_sap = sap;
 464         }
 465 
 466         mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
 467         if (mp == NULL)
 468                 return (NULL);
 469 
 470         if ((vid == VLAN_ID_NONE && (pri == 0 ||
 471             dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
 472                 return (mp);
 473 
 474         /*
 475          * Fill in the tag information.
 476          */
 477         ASSERT(MBLKL(mp) == sizeof (struct ether_header));
 478         if (extra_len != 0) {
 479                 mp->b_wptr += extra_len;
 480                 evhp = (struct ether_vlan_header *)mp->b_rptr;
 481                 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
 482                 evhp->ether_type = htons(sap);
 483         } else {
 484                 /*
 485                  * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
 486                  * in the payload. Update the priority.
 487                  */
 488                 struct ether_vlan_extinfo *extinfo;
 489                 size_t len = sizeof (struct ether_vlan_extinfo);
 490 
 491                 ASSERT(sap == ETHERTYPE_VLAN);
 492                 ASSERT(payload != NULL);
 493 
 494                 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
 495                         mblk_t *newmp;
 496 
 497                         /*
 498                          * Because some DLS consumers only check the db_ref
 499                          * count of the first mblk, we pullup 'payload' into
 500                          * a single mblk.
 501                          */
 502                         newmp = msgpullup(payload, -1);
 503                         if ((newmp == NULL) || (MBLKL(newmp) < len)) {
 504                                 freemsg(newmp);
 505                                 freemsg(mp);
 506                                 return (NULL);
 507                         } else {
 508                                 freemsg(payload);
 509                                 *payloadp = payload = newmp;
 510                         }
 511                 }
 512 
 513                 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
 514                 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
 515                     VLAN_ID(ntohs(extinfo->ether_tci))));
 516         }
 517         return (mp);
 518 }
 519 
 520 void
 521 dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
 522 {
 523         mutex_enter(&dsp->ds_lock);
 524         dsp->ds_rx = rx;
 525         dsp->ds_rx_arg = arg;
 526         mutex_exit(&dsp->ds_lock);
 527 }
 528 
 529 static boolean_t
 530 dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 531     void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
 532 {
 533         dls_multicst_addr_t     *dmap;
 534         size_t                  addr_length = dsp->ds_mip->mi_addr_length;
 535 
 536         /*
 537          * We must not accept packets if the dld_str_t is not marked as bound
 538          * or is being removed.
 539          */
 540         if (dsp->ds_dlstate != DL_IDLE)
 541                 goto refuse;
 542 
 543         if (dsp->ds_promisc != 0) {
 544                 /*
 545                  * Filter out packets that arrived from the data path
 546                  * (i_dls_link_rx) when promisc mode is on. We need to correlate
 547                  * the ds_promisc flags with the mac header destination type. If
 548                  * only DLS_PROMISC_MULTI is enabled, we need to only reject
 549                  * multicast packets as those are the only ones which filter up
 550                  * the promiscuous path. If we have DLS_PROMISC_PHYS or
 551                  * DLS_PROMISC_SAP set, then we know that we'll be seeing
 552                  * everything, so we should drop it now.
 553                  */
 554                 if (!promisc && !(dsp->ds_promisc == DLS_PROMISC_MULTI &&
 555                     mhip->mhi_dsttype != MAC_ADDRTYPE_MULTICAST))
 556                         goto refuse;
 557                 /*
 558                  * If the dls_impl_t is in 'all physical' mode then
 559                  * always accept.
 560                  */
 561                 if (dsp->ds_promisc & DLS_PROMISC_PHYS)
 562                         goto accept;
 563 
 564                 /*
 565                  * Loopback packets i.e. packets sent out by DLS on a given
 566                  * mac end point, will be accepted back by DLS on loopback
 567                  * from the mac, only in the 'all physical' mode which has been
 568                  * covered by the previous check above
 569                  */
 570                 if (promisc_loopback)
 571                         goto refuse;
 572         }
 573 
 574         switch (mhip->mhi_dsttype) {
 575         case MAC_ADDRTYPE_UNICAST:
 576         case MAC_ADDRTYPE_BROADCAST:
 577                 /*
 578                  * We can accept unicast and broadcast packets because
 579                  * filtering is already done by the mac layer.
 580                  */
 581                 goto accept;
 582         case MAC_ADDRTYPE_MULTICAST:
 583                 /*
 584                  * Additional filtering is needed for multicast addresses
 585                  * because different streams may be interested in different
 586                  * addresses.
 587                  */
 588                 if (dsp->ds_promisc & DLS_PROMISC_MULTI)
 589                         goto accept;
 590 
 591                 rw_enter(&dsp->ds_rw_lock, RW_READER);
 592                 for (dmap = dsp->ds_dmap; dmap != NULL;
 593                     dmap = dmap->dma_nextp) {
 594                         if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
 595                             addr_length) == 0) {
 596                                 rw_exit(&dsp->ds_rw_lock);
 597                                 goto accept;
 598                         }
 599                 }
 600                 rw_exit(&dsp->ds_rw_lock);
 601                 break;
 602         }
 603 
 604 refuse:
 605         return (B_FALSE);
 606 
 607 accept:
 608         /*
 609          * the returned ds_rx and ds_rx_arg will always be in sync.
 610          */
 611         mutex_enter(&dsp->ds_lock);
 612         *ds_rx = dsp->ds_rx;
 613         *ds_rx_arg = dsp->ds_rx_arg;
 614         mutex_exit(&dsp->ds_lock);
 615 
 616         return (B_TRUE);
 617 }
 618 
 619 /* ARGSUSED */
 620 boolean_t
 621 dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 622     void **ds_rx_arg)
 623 {
 624         return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
 625             B_FALSE));
 626 }
 627 
 628 boolean_t
 629 dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 630     void **ds_rx_arg, boolean_t loopback)
 631 {
 632         return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
 633             loopback));
 634 }
 635 
 636 int
 637 dls_mac_active_set(dls_link_t *dlp)
 638 {
 639         int err = 0;
 640 
 641         /*
 642          * First client; add the primary unicast address.
 643          */
 644         if (dlp->dl_nactive == 0) {
 645                 /*
 646                  * First client; add the primary unicast address.
 647                  */
 648                 mac_diag_t diag;
 649 
 650                 /* request the primary MAC address */
 651                 if ((err = mac_unicast_add(dlp->dl_mch, NULL,
 652                     MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
 653                     MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0,
 654                     &diag)) != 0) {
 655                         return (err);
 656                 }
 657 
 658                 /*
 659                  * Set the function to start receiving packets.
 660                  */
 661                 mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
 662         }
 663         dlp->dl_nactive++;
 664         return (0);
 665 }
 666 
 667 void
 668 dls_mac_active_clear(dls_link_t *dlp)
 669 {
 670         if (--dlp->dl_nactive == 0) {
 671                 ASSERT(dlp->dl_mah != NULL);
 672                 (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
 673                 dlp->dl_mah = NULL;
 674                 mac_rx_clear(dlp->dl_mch);
 675         }
 676 }
 677 
 678 int
 679 dls_active_set(dld_str_t *dsp)
 680 {
 681         int err = 0;
 682 
 683         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 684 
 685         if (dsp->ds_passivestate == DLD_PASSIVE)
 686                 return (0);
 687 
 688         /* If we're already active, then there's nothing more to do. */
 689         if ((dsp->ds_nactive == 0) &&
 690             ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
 691                 /* except for ENXIO all other errors are mapped to EBUSY */
 692                 if (err != ENXIO)
 693                         return (EBUSY);
 694                 return (err);
 695         }
 696 
 697         dsp->ds_passivestate = DLD_ACTIVE;
 698         dsp->ds_nactive++;
 699         return (0);
 700 }
 701 
 702 /*
 703  * Note that dls_active_set() is called whenever an active operation
 704  * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
 705  * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
 706  * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
 707  * a stream is closed without every active operation being undone and we
 708  * need to clear all the "active" states by calling
 709  * dls_active_clear(dsp, B_TRUE).
 710  */
 711 void
 712 dls_active_clear(dld_str_t *dsp, boolean_t all)
 713 {
 714         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 715 
 716         if (dsp->ds_passivestate == DLD_PASSIVE)
 717                 return;
 718 
 719         if (all && dsp->ds_nactive == 0)
 720                 return;
 721 
 722         ASSERT(dsp->ds_nactive > 0);
 723 
 724         dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
 725         if (dsp->ds_nactive != 0)
 726                 return;
 727 
 728         ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
 729         dls_mac_active_clear(dsp->ds_dlp);
 730         dsp->ds_passivestate = DLD_UNINITIALIZED;
 731 }