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