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 2019 Joyent, Inc.
  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          * A VLAN SAP does not actually add itself to the STREAM head today.
 222          * While we initially set up a VLAN handle below, it's possible that
 223          * something else will have come in and clobbered it.
 224          */
 225         if (dsp->ds_sap == ETHERTYPE_VLAN) {
 226                 if (dsp->ds_vlan_mph != NULL) {
 227                         mac_promisc_remove(dsp->ds_vlan_mph);
 228                         dsp->ds_vlan_mph = NULL;
 229                 }
 230                 return;
 231         }
 232 
 233         /*
 234          * Unbind the dld_str_t by removing it from the hash table in the
 235          * dls_link_t.
 236          */
 237         dls_link_remove(dsp->ds_dlp, dsp);
 238         dsp->ds_sap = 0;
 239 }
 240 
 241 /*
 242  * In order to prevent promiscuous-mode processing with dsp->ds_promisc
 243  * set to inaccurate values, this function sets dsp->ds_promisc with new
 244  * flags.  For enabling (mac_promisc_add), the flags are set prior to the
 245  * actual enabling.  For disabling (mac_promisc_remove), the flags are set
 246  * after the actual disabling.
 247  */
 248 int
 249 dls_promisc(dld_str_t *dsp, uint32_t new_flags)
 250 {
 251         int err = 0;
 252         uint32_t old_flags = dsp->ds_promisc;
 253         mac_client_promisc_type_t mptype = MAC_CLIENT_PROMISC_ALL;
 254 
 255         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 256         ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
 257             DLS_PROMISC_PHYS)));
 258 
 259         /*
 260          * If the user has only requested DLS_PROMISC_MULTI then we need to make
 261          * sure that they don't see all packets.
 262          */
 263         if (new_flags == DLS_PROMISC_MULTI)
 264                 mptype = MAC_CLIENT_PROMISC_MULTI;
 265 
 266         if (dsp->ds_promisc == 0 && new_flags != 0) {
 267                 /*
 268                  * If only DLS_PROMISC_SAP, we don't turn on the
 269                  * physical promisc mode
 270                  */
 271                 dsp->ds_promisc = new_flags;
 272                 err = mac_promisc_add(dsp->ds_mch, mptype,
 273                     dls_rx_promisc, dsp, &dsp->ds_mph,
 274                     (new_flags != DLS_PROMISC_SAP) ? 0 :
 275                     MAC_PROMISC_FLAGS_NO_PHYS);
 276                 if (err != 0) {
 277                         dsp->ds_promisc = old_flags;
 278                         return (err);
 279                 }
 280 
 281                 /* Remove vlan promisc handle to avoid sending dup copy up */
 282                 if (dsp->ds_vlan_mph != NULL) {
 283                         mac_promisc_remove(dsp->ds_vlan_mph);
 284                         dsp->ds_vlan_mph = NULL;
 285                 }
 286         } else if (dsp->ds_promisc != 0 && new_flags == 0) {
 287                 ASSERT(dsp->ds_mph != NULL);
 288 
 289                 mac_promisc_remove(dsp->ds_mph);
 290                 dsp->ds_promisc = new_flags;
 291                 dsp->ds_mph = NULL;
 292 
 293                 if (dsp->ds_sap == ETHERTYPE_VLAN &&
 294                     dsp->ds_dlstate != DL_UNBOUND) {
 295                         if (dsp->ds_vlan_mph != NULL)
 296                                 return (EINVAL);
 297                         err = mac_promisc_add(dsp->ds_mch,
 298                             MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
 299                             &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
 300                 }
 301         } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
 302             new_flags != dsp->ds_promisc) {
 303                 /*
 304                  * If the old flag is PROMISC_SAP, but the current flag has
 305                  * changed to some new non-zero value, we need to turn the
 306                  * physical promiscuous mode.
 307                  */
 308                 ASSERT(dsp->ds_mph != NULL);
 309                 mac_promisc_remove(dsp->ds_mph);
 310                 /* Honors both after-remove and before-add semantics! */
 311                 dsp->ds_promisc = new_flags;
 312                 err = mac_promisc_add(dsp->ds_mch, mptype,
 313                     dls_rx_promisc, dsp, &dsp->ds_mph, 0);
 314                 if (err != 0)
 315                         dsp->ds_promisc = old_flags;
 316         } else {
 317                 /* No adding or removing, but record the new flags anyway. */
 318                 dsp->ds_promisc = new_flags;
 319         }
 320 
 321         return (err);
 322 }
 323 
 324 int
 325 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
 326 {
 327         int                     err;
 328         dls_multicst_addr_t     **pp;
 329         dls_multicst_addr_t     *p;
 330         uint_t                  addr_length;
 331 
 332         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 333 
 334         /*
 335          * Check whether the address is in the list of enabled addresses for
 336          * this dld_str_t.
 337          */
 338         addr_length = dsp->ds_mip->mi_addr_length;
 339 
 340         /*
 341          * Protect against concurrent access of ds_dmap by data threads using
 342          * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
 343          * remove operations. Dropping the ds_rw_lock across mac calls is thus
 344          * ok and is also required by the locking protocol.
 345          */
 346         rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 347         for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
 348                 if (bcmp(addr, p->dma_addr, addr_length) == 0) {
 349                         /*
 350                          * It is there so there's nothing to do.
 351                          */
 352                         err = 0;
 353                         goto done;
 354                 }
 355         }
 356 
 357         /*
 358          * Allocate a new list item and add it to the list.
 359          */
 360         p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
 361         bcopy(addr, p->dma_addr, addr_length);
 362         *pp = p;
 363         rw_exit(&dsp->ds_rw_lock);
 364 
 365         /*
 366          * Enable the address at the MAC.
 367          */
 368         err = mac_multicast_add(dsp->ds_mch, addr);
 369         if (err == 0)
 370                 return (0);
 371 
 372         /* Undo the operation as it has failed */
 373         rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 374         ASSERT(*pp == p && p->dma_nextp == NULL);
 375         *pp = NULL;
 376         kmem_free(p, sizeof (dls_multicst_addr_t));
 377 done:
 378         rw_exit(&dsp->ds_rw_lock);
 379         return (err);
 380 }
 381 
 382 int
 383 dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
 384 {
 385         dls_multicst_addr_t     **pp;
 386         dls_multicst_addr_t     *p;
 387         uint_t                  addr_length;
 388 
 389         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 390 
 391         /*
 392          * Find the address in the list of enabled addresses for this
 393          * dld_str_t.
 394          */
 395         addr_length = dsp->ds_mip->mi_addr_length;
 396 
 397         /*
 398          * Protect against concurrent access to ds_dmap by data threads using
 399          * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
 400          * remove operations. Dropping the ds_rw_lock across mac calls is thus
 401          * ok and is also required by the locking protocol.
 402          */
 403         rw_enter(&dsp->ds_rw_lock, RW_WRITER);
 404         for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
 405                 if (bcmp(addr, p->dma_addr, addr_length) == 0)
 406                         break;
 407         }
 408 
 409         /*
 410          * If we walked to the end of the list then the given address is
 411          * not currently enabled for this dld_str_t.
 412          */
 413         if (p == NULL) {
 414                 rw_exit(&dsp->ds_rw_lock);
 415                 return (ENOENT);
 416         }
 417 
 418         /*
 419          * Remove the address from the list.
 420          */
 421         *pp = p->dma_nextp;
 422         rw_exit(&dsp->ds_rw_lock);
 423 
 424         /*
 425          * Disable the address at the MAC.
 426          */
 427         mac_multicast_remove(dsp->ds_mch, addr);
 428         kmem_free(p, sizeof (dls_multicst_addr_t));
 429         return (0);
 430 }
 431 
 432 mblk_t *
 433 dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
 434     mblk_t **payloadp)
 435 {
 436         uint16_t vid;
 437         size_t extra_len;
 438         uint16_t mac_sap;
 439         mblk_t *mp, *payload;
 440         boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
 441         struct ether_vlan_header *evhp;
 442 
 443         vid = mac_client_vid(dsp->ds_mch);
 444         payload = (payloadp == NULL) ? NULL : (*payloadp);
 445 
 446         /*
 447          * In the case of Ethernet, we need to tell mac_header() if we need
 448          * extra room beyond the Ethernet header for a VLAN header.  We'll
 449          * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
 450          * (because such streams will be handling VLAN headers on their own)
 451          * and one of the following conditions is satisfied:
 452          *
 453          * - This is a VLAN stream
 454          * - This is a physical stream, the priority is not 0, and user
 455          *   priority tagging is allowed.
 456          */
 457         if (is_ethernet && sap != ETHERTYPE_VLAN &&
 458             (vid != VLAN_ID_NONE ||
 459             (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
 460                 extra_len = sizeof (struct ether_vlan_header) -
 461                     sizeof (struct ether_header);
 462                 mac_sap = ETHERTYPE_VLAN;
 463         } else {
 464                 extra_len = 0;
 465                 mac_sap = sap;
 466         }
 467 
 468         mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
 469         if (mp == NULL)
 470                 return (NULL);
 471 
 472         if ((vid == VLAN_ID_NONE && (pri == 0 ||
 473             dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
 474                 return (mp);
 475 
 476         /*
 477          * Fill in the tag information.
 478          */
 479         ASSERT(MBLKL(mp) == sizeof (struct ether_header));
 480         if (extra_len != 0) {
 481                 mp->b_wptr += extra_len;
 482                 evhp = (struct ether_vlan_header *)mp->b_rptr;
 483                 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
 484                 evhp->ether_type = htons(sap);
 485         } else {
 486                 /*
 487                  * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
 488                  * in the payload. Update the priority.
 489                  */
 490                 struct ether_vlan_extinfo *extinfo;
 491                 size_t len = sizeof (struct ether_vlan_extinfo);
 492 
 493                 ASSERT(sap == ETHERTYPE_VLAN);
 494                 ASSERT(payload != NULL);
 495 
 496                 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
 497                         mblk_t *newmp;
 498 
 499                         /*
 500                          * Because some DLS consumers only check the db_ref
 501                          * count of the first mblk, we pullup 'payload' into
 502                          * a single mblk.
 503                          */
 504                         newmp = msgpullup(payload, -1);
 505                         if ((newmp == NULL) || (MBLKL(newmp) < len)) {
 506                                 freemsg(newmp);
 507                                 freemsg(mp);
 508                                 return (NULL);
 509                         } else {
 510                                 freemsg(payload);
 511                                 *payloadp = payload = newmp;
 512                         }
 513                 }
 514 
 515                 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
 516                 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
 517                     VLAN_ID(ntohs(extinfo->ether_tci))));
 518         }
 519         return (mp);
 520 }
 521 
 522 void
 523 dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
 524 {
 525         mutex_enter(&dsp->ds_lock);
 526         dsp->ds_rx = rx;
 527         dsp->ds_rx_arg = arg;
 528         mutex_exit(&dsp->ds_lock);
 529 }
 530 
 531 static boolean_t
 532 dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 533     void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
 534 {
 535         dls_multicst_addr_t     *dmap;
 536         size_t                  addr_length = dsp->ds_mip->mi_addr_length;
 537 
 538         /*
 539          * We must not accept packets if the dld_str_t is not marked as bound
 540          * or is being removed.
 541          */
 542         if (dsp->ds_dlstate != DL_IDLE)
 543                 goto refuse;
 544 
 545         if (dsp->ds_promisc != 0) {
 546                 /*
 547                  * Filter out packets that arrived from the data path
 548                  * (i_dls_link_rx) when promisc mode is on. We need to correlate
 549                  * the ds_promisc flags with the mac header destination type. If
 550                  * only DLS_PROMISC_MULTI is enabled, we need to only reject
 551                  * multicast packets as those are the only ones which filter up
 552                  * the promiscuous path. If we have DLS_PROMISC_PHYS or
 553                  * DLS_PROMISC_SAP set, then we know that we'll be seeing
 554                  * everything, so we should drop it now.
 555                  */
 556                 if (!promisc && !(dsp->ds_promisc == DLS_PROMISC_MULTI &&
 557                     mhip->mhi_dsttype != MAC_ADDRTYPE_MULTICAST))
 558                         goto refuse;
 559                 /*
 560                  * If the dls_impl_t is in 'all physical' mode then
 561                  * always accept.
 562                  */
 563                 if (dsp->ds_promisc & DLS_PROMISC_PHYS)
 564                         goto accept;
 565 
 566                 /*
 567                  * Loopback packets i.e. packets sent out by DLS on a given
 568                  * mac end point, will be accepted back by DLS on loopback
 569                  * from the mac, only in the 'all physical' mode which has been
 570                  * covered by the previous check above
 571                  */
 572                 if (promisc_loopback)
 573                         goto refuse;
 574         }
 575 
 576         switch (mhip->mhi_dsttype) {
 577         case MAC_ADDRTYPE_UNICAST:
 578         case MAC_ADDRTYPE_BROADCAST:
 579                 /*
 580                  * We can accept unicast and broadcast packets because
 581                  * filtering is already done by the mac layer.
 582                  */
 583                 goto accept;
 584         case MAC_ADDRTYPE_MULTICAST:
 585                 /*
 586                  * Additional filtering is needed for multicast addresses
 587                  * because different streams may be interested in different
 588                  * addresses.
 589                  */
 590                 if (dsp->ds_promisc & DLS_PROMISC_MULTI)
 591                         goto accept;
 592 
 593                 rw_enter(&dsp->ds_rw_lock, RW_READER);
 594                 for (dmap = dsp->ds_dmap; dmap != NULL;
 595                     dmap = dmap->dma_nextp) {
 596                         if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
 597                             addr_length) == 0) {
 598                                 rw_exit(&dsp->ds_rw_lock);
 599                                 goto accept;
 600                         }
 601                 }
 602                 rw_exit(&dsp->ds_rw_lock);
 603                 break;
 604         }
 605 
 606 refuse:
 607         return (B_FALSE);
 608 
 609 accept:
 610         /*
 611          * the returned ds_rx and ds_rx_arg will always be in sync.
 612          */
 613         mutex_enter(&dsp->ds_lock);
 614         *ds_rx = dsp->ds_rx;
 615         *ds_rx_arg = dsp->ds_rx_arg;
 616         mutex_exit(&dsp->ds_lock);
 617 
 618         return (B_TRUE);
 619 }
 620 
 621 /* ARGSUSED */
 622 boolean_t
 623 dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 624     void **ds_rx_arg)
 625 {
 626         return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
 627             B_FALSE));
 628 }
 629 
 630 boolean_t
 631 dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
 632     void **ds_rx_arg, boolean_t loopback)
 633 {
 634         return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
 635             loopback));
 636 }
 637 
 638 int
 639 dls_mac_active_set(dls_link_t *dlp)
 640 {
 641         int err = 0;
 642 
 643         /*
 644          * First client; add the primary unicast address.
 645          */
 646         if (dlp->dl_nactive == 0) {
 647                 /*
 648                  * First client; add the primary unicast address.
 649                  */
 650                 mac_diag_t diag;
 651 
 652                 /* request the primary MAC address */
 653                 if ((err = mac_unicast_add(dlp->dl_mch, NULL,
 654                     MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
 655                     MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0,
 656                     &diag)) != 0) {
 657                         return (err);
 658                 }
 659 
 660                 /*
 661                  * Set the function to start receiving packets.
 662                  */
 663                 mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
 664         }
 665         dlp->dl_nactive++;
 666         return (0);
 667 }
 668 
 669 void
 670 dls_mac_active_clear(dls_link_t *dlp)
 671 {
 672         if (--dlp->dl_nactive == 0) {
 673                 ASSERT(dlp->dl_mah != NULL);
 674                 (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
 675                 dlp->dl_mah = NULL;
 676                 mac_rx_clear(dlp->dl_mch);
 677         }
 678 }
 679 
 680 int
 681 dls_active_set(dld_str_t *dsp)
 682 {
 683         int err = 0;
 684 
 685         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 686 
 687         if (dsp->ds_passivestate == DLD_PASSIVE)
 688                 return (0);
 689 
 690         /* If we're already active, then there's nothing more to do. */
 691         if ((dsp->ds_nactive == 0) &&
 692             ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
 693                 /* except for ENXIO all other errors are mapped to EBUSY */
 694                 if (err != ENXIO)
 695                         return (EBUSY);
 696                 return (err);
 697         }
 698 
 699         dsp->ds_passivestate = DLD_ACTIVE;
 700         dsp->ds_nactive++;
 701         return (0);
 702 }
 703 
 704 /*
 705  * Note that dls_active_set() is called whenever an active operation
 706  * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
 707  * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
 708  * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
 709  * a stream is closed without every active operation being undone and we
 710  * need to clear all the "active" states by calling
 711  * dls_active_clear(dsp, B_TRUE).
 712  */
 713 void
 714 dls_active_clear(dld_str_t *dsp, boolean_t all)
 715 {
 716         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
 717 
 718         if (dsp->ds_passivestate == DLD_PASSIVE)
 719                 return;
 720 
 721         if (all && dsp->ds_nactive == 0)
 722                 return;
 723 
 724         ASSERT(dsp->ds_nactive > 0);
 725 
 726         dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
 727         if (dsp->ds_nactive != 0)
 728                 return;
 729 
 730         ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
 731         dls_mac_active_clear(dsp->ds_dlp);
 732         dsp->ds_passivestate = DLD_UNINITIALIZED;
 733 }