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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Data-Link Services Module 30 */ 31 32 #include <sys/types.h> 33 #include <sys/stream.h> 34 #include <sys/strsun.h> 35 #include <sys/sysmacros.h> 36 #include <sys/atomic.h> 37 #include <sys/dlpi.h> 38 #include <sys/vlan.h> 39 #include <sys/ethernet.h> 40 #include <sys/byteorder.h> 41 #include <sys/mac.h> 42 43 #include <sys/dls.h> 44 #include <sys/dls_impl.h> 45 #include <sys/dls_soft_ring.h> 46 47 static kmem_cache_t *i_dls_impl_cachep; 48 static uint32_t i_dls_impl_count; 49 50 static kstat_t *dls_ksp = (kstat_t *)NULL; 51 struct dls_kstats dls_kstat = 52 { 53 { "soft_ring_pkt_drop", KSTAT_DATA_UINT32 }, 54 }; 55 56 57 /* 58 * Private functions. 59 */ 60 61 /*ARGSUSED*/ 62 static int 63 i_dls_constructor(void *buf, void *arg, int kmflag) 64 { 65 dls_impl_t *dip = buf; 66 67 bzero(buf, sizeof (dls_impl_t)); 68 69 rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL); 70 return (0); 71 } 72 73 /*ARGSUSED*/ 74 static void 75 i_dls_destructor(void *buf, void *arg) 76 { 77 dls_impl_t *dip = buf; 78 79 ASSERT(dip->di_dvp == NULL); 80 ASSERT(dip->di_mnh == NULL); 81 ASSERT(dip->di_dmap == NULL); 82 ASSERT(!dip->di_bound); 83 ASSERT(dip->di_rx == NULL); 84 ASSERT(dip->di_txinfo == NULL); 85 86 rw_destroy(&(dip->di_lock)); 87 } 88 89 static void 90 i_dls_notify(void *arg, mac_notify_type_t type) 91 { 92 dls_impl_t *dip = arg; 93 94 switch (type) { 95 case MAC_NOTE_UNICST: 96 mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 97 break; 98 99 case MAC_NOTE_PROMISC: 100 /* 101 * Every time the MAC interface changes promiscuity we 102 * need to reset our transmit information. 103 */ 104 dip->di_txinfo = mac_tx_get(dip->di_mh); 105 break; 106 } 107 } 108 109 static void 110 dls_stat_init() 111 { 112 if ((dls_ksp = kstat_create("dls", 0, "dls_stat", 113 "net", KSTAT_TYPE_NAMED, 114 sizeof (dls_kstat) / sizeof (kstat_named_t), 115 KSTAT_FLAG_VIRTUAL)) == NULL) { 116 cmn_err(CE_WARN, 117 "DLS: failed to create kstat structure for dls stats"); 118 return; 119 } 120 dls_ksp->ks_data = (void *)&dls_kstat; 121 kstat_install(dls_ksp); 122 } 123 124 static void 125 dls_stat_destroy() 126 { 127 kstat_delete(dls_ksp); 128 } 129 130 /* 131 * Module initialization functions. 132 */ 133 134 void 135 dls_init(void) 136 { 137 /* 138 * Create a kmem_cache of dls_impl_t. 139 */ 140 i_dls_impl_cachep = kmem_cache_create("dls_cache", 141 sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL, 142 NULL, NULL, 0); 143 ASSERT(i_dls_impl_cachep != NULL); 144 soft_ring_init(); 145 dls_stat_init(); 146 } 147 148 int 149 dls_fini(void) 150 { 151 /* 152 * If there are any dls_impl_t in use then return EBUSY. 153 */ 154 if (i_dls_impl_count != 0) 155 return (EBUSY); 156 157 /* 158 * Destroy the kmem_cache. 159 */ 160 kmem_cache_destroy(i_dls_impl_cachep); 161 dls_stat_destroy(); 162 return (0); 163 } 164 165 /* 166 * Client function. 167 */ 168 169 int 170 dls_create(const char *linkname, const char *macname, uint_t ddi_instance) 171 { 172 return (dls_vlan_create(linkname, macname, ddi_instance, 0)); 173 } 174 175 int 176 dls_destroy(const char *name) 177 { 178 return (dls_vlan_destroy(name)); 179 } 180 181 int 182 dls_open(const char *name, dls_channel_t *dcp) 183 { 184 dls_impl_t *dip; 185 dls_vlan_t *dvp; 186 dls_link_t *dlp; 187 int err; 188 189 /* 190 * Get a reference to the named dls_vlan_t. 191 * Tagged vlans get created automatically. 192 */ 193 if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) 194 return (err); 195 196 /* 197 * Allocate a new dls_impl_t. 198 */ 199 dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP); 200 dip->di_dvp = dvp; 201 202 /* 203 * Cache a copy of the MAC interface handle, a pointer to the 204 * immutable MAC info and a copy of the current MAC address. 205 */ 206 dlp = dvp->dv_dlp; 207 dip->di_mh = dlp->dl_mh; 208 dip->di_mip = dlp->dl_mip; 209 210 mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 211 212 /* 213 * Set the MAC transmit information. 214 */ 215 dip->di_txinfo = mac_tx_get(dip->di_mh); 216 217 /* 218 * Add a notification function so that we get updates from the MAC. 219 */ 220 dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip); 221 222 /* 223 * Bump the kmem_cache count to make sure it is not prematurely 224 * destroyed. 225 */ 226 atomic_add_32(&i_dls_impl_count, 1); 227 228 /* 229 * Hand back a reference to the dls_impl_t. 230 */ 231 *dcp = (dls_channel_t)dip; 232 return (0); 233 } 234 235 void 236 dls_close(dls_channel_t dc) 237 { 238 dls_impl_t *dip = (dls_impl_t *)dc; 239 dls_vlan_t *dvp; 240 dls_link_t *dlp; 241 dls_multicst_addr_t *p; 242 dls_multicst_addr_t *nextp; 243 244 dls_active_clear(dc); 245 246 rw_enter(&(dip->di_lock), RW_WRITER); 247 248 /* 249 * Remove the notify function. 250 */ 251 mac_notify_remove(dip->di_mh, dip->di_mnh); 252 dip->di_mnh = NULL; 253 254 /* 255 * If the dls_impl_t is bound then unbind it. 256 */ 257 dvp = dip->di_dvp; 258 dlp = dvp->dv_dlp; 259 260 if (dip->di_bound) { 261 rw_exit(&(dip->di_lock)); 262 dls_link_remove(dlp, dip); 263 rw_enter(&(dip->di_lock), RW_WRITER); 264 dip->di_bound = B_FALSE; 265 } 266 267 dip->di_rx = NULL; 268 dip->di_rx_arg = NULL; 269 270 /* 271 * Walk the list of multicast addresses, disabling each at the MAC. 272 */ 273 for (p = dip->di_dmap; p != NULL; p = nextp) { 274 (void) mac_multicst_remove(dip->di_mh, p->dma_addr); 275 nextp = p->dma_nextp; 276 kmem_free(p, sizeof (dls_multicst_addr_t)); 277 } 278 dip->di_dmap = NULL; 279 280 rw_exit(&(dip->di_lock)); 281 282 /* 283 * If the MAC has been set in promiscuous mode then disable it. 284 */ 285 (void) dls_promisc(dc, 0); 286 287 /* 288 * Free the dls_impl_t back to the cache. 289 */ 290 dip->di_dvp = NULL; 291 dip->di_txinfo = NULL; 292 293 if (dip->di_soft_ring_list != NULL) { 294 soft_ring_set_destroy(dip->di_soft_ring_list, 295 dip->di_soft_ring_size); 296 dip->di_soft_ring_list = NULL; 297 } 298 dip->di_soft_ring_size = 0; 299 300 kmem_cache_free(i_dls_impl_cachep, dip); 301 302 /* 303 * Decrement the reference count to allow the cache to be destroyed 304 * if there are no more dls_impl_t. 305 */ 306 atomic_add_32(&i_dls_impl_count, -1); 307 308 /* 309 * Release our reference to the dls_vlan_t allowing that to be 310 * destroyed if there are no more dls_impl_t. An unreferenced tagged 311 * vlan gets destroyed automatically. 312 */ 313 dls_vlan_rele(dvp); 314 } 315 316 mac_handle_t 317 dls_mac(dls_channel_t dc) 318 { 319 return (((dls_impl_t *)dc)->di_mh); 320 } 321 322 uint16_t 323 dls_vid(dls_channel_t dc) 324 { 325 return (((dls_impl_t *)dc)->di_dvp->dv_id); 326 } 327 328 int 329 dls_bind(dls_channel_t dc, uint32_t sap) 330 { 331 dls_impl_t *dip = (dls_impl_t *)dc; 332 dls_link_t *dlp; 333 uint32_t dls_sap; 334 335 /* 336 * Check to see the value is legal for the media type. 337 */ 338 if (!mac_sap_verify(dip->di_mh, sap, &dls_sap)) 339 return (EINVAL); 340 if (dip->di_promisc & DLS_PROMISC_SAP) 341 dls_sap = DLS_SAP_PROMISC; 342 343 /* 344 * Set up the dls_impl_t to mark it as able to receive packets. 345 */ 346 rw_enter(&(dip->di_lock), RW_WRITER); 347 ASSERT(!dip->di_bound); 348 dip->di_sap = sap; 349 dip->di_bound = B_TRUE; 350 rw_exit(&(dip->di_lock)); 351 352 /* 353 * Now bind the dls_impl_t by adding it into the hash table in the 354 * dls_link_t. 355 * 356 * NOTE: This must be done without the dls_impl_t lock being held 357 * otherwise deadlock may ensue. 358 */ 359 dlp = dip->di_dvp->dv_dlp; 360 dls_link_add(dlp, dls_sap, dip); 361 362 return (0); 363 } 364 365 void 366 dls_unbind(dls_channel_t dc) 367 { 368 dls_impl_t *dip = (dls_impl_t *)dc; 369 dls_link_t *dlp; 370 371 /* 372 * Unbind the dls_impl_t by removing it from the hash table in the 373 * dls_link_t. 374 * 375 * NOTE: This must be done without the dls_impl_t lock being held 376 * otherise deadlock may enuse. 377 */ 378 dlp = dip->di_dvp->dv_dlp; 379 dls_link_remove(dlp, dip); 380 381 /* 382 * Mark the dls_impl_t as unable to receive packets This will make 383 * sure that 'receives in flight' will not come our way. 384 */ 385 dip->di_bound = B_FALSE; 386 } 387 388 int 389 dls_promisc(dls_channel_t dc, uint32_t flags) 390 { 391 dls_impl_t *dip = (dls_impl_t *)dc; 392 dls_link_t *dlp; 393 int err = 0; 394 395 ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 396 DLS_PROMISC_PHYS))); 397 398 /* 399 * Check if we need to turn on 'all sap' mode. 400 */ 401 rw_enter(&(dip->di_lock), RW_WRITER); 402 dlp = dip->di_dvp->dv_dlp; 403 if ((flags & DLS_PROMISC_SAP) && 404 !(dip->di_promisc & DLS_PROMISC_SAP)) { 405 dip->di_promisc |= DLS_PROMISC_SAP; 406 if (!dip->di_bound) 407 goto multi; 408 409 rw_exit(&(dip->di_lock)); 410 dls_link_remove(dlp, dip); 411 dls_link_add(dlp, DLS_SAP_PROMISC, dip); 412 rw_enter(&(dip->di_lock), RW_WRITER); 413 goto multi; 414 } 415 416 /* 417 * Check if we need to turn off 'all sap' mode. 418 */ 419 if (!(flags & DLS_PROMISC_SAP) && 420 (dip->di_promisc & DLS_PROMISC_SAP)) { 421 uint32_t dls_sap; 422 423 dip->di_promisc &= ~DLS_PROMISC_SAP; 424 if (!dip->di_bound) 425 goto multi; 426 427 rw_exit(&(dip->di_lock)); 428 dls_link_remove(dlp, dip); 429 (void) mac_sap_verify(dip->di_mh, dip->di_sap, &dls_sap); 430 dls_link_add(dlp, dls_sap, dip); 431 rw_enter(&(dip->di_lock), RW_WRITER); 432 } 433 434 multi: 435 /* 436 * It's easiest to add the txloop handler up-front; if promiscuous 437 * mode cannot be enabled, then we'll remove it before returning. 438 * Use dl_promisc_lock to prevent racing with another thread also 439 * manipulating the promiscuous state on another dls_impl_t associated 440 * with the same dls_link_t. 441 */ 442 mutex_enter(&dlp->dl_promisc_lock); 443 if (dlp->dl_npromisc == 0 && 444 (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) { 445 ASSERT(dlp->dl_mth == NULL); 446 dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_txloop, dlp); 447 } 448 449 /* 450 * Turn on or off 'all multicast' mode, if necessary. 451 */ 452 if (flags & DLS_PROMISC_MULTI) { 453 if (!(dip->di_promisc & DLS_PROMISC_MULTI)) { 454 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 455 if (err != 0) 456 goto done; 457 dip->di_promisc |= DLS_PROMISC_MULTI; 458 dlp->dl_npromisc++; 459 } 460 } else { 461 if (dip->di_promisc & DLS_PROMISC_MULTI) { 462 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 463 if (err != 0) 464 goto done; 465 dip->di_promisc &= ~DLS_PROMISC_MULTI; 466 dlp->dl_npromisc--; 467 } 468 } 469 470 /* 471 * Turn on or off 'all physical' mode, if necessary. 472 */ 473 if (flags & DLS_PROMISC_PHYS) { 474 if (!(dip->di_promisc & DLS_PROMISC_PHYS)) { 475 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 476 if (err != 0) 477 goto done; 478 dip->di_promisc |= DLS_PROMISC_PHYS; 479 dlp->dl_npromisc++; 480 } 481 } else { 482 if (dip->di_promisc & DLS_PROMISC_PHYS) { 483 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 484 if (err != 0) 485 goto done; 486 dip->di_promisc &= ~DLS_PROMISC_PHYS; 487 dlp->dl_npromisc--; 488 } 489 } 490 491 done: 492 if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 493 mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 494 dlp->dl_mth = NULL; 495 } 496 497 ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 498 mutex_exit(&dlp->dl_promisc_lock); 499 500 rw_exit(&(dip->di_lock)); 501 return (err); 502 } 503 504 int 505 dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 506 { 507 dls_impl_t *dip = (dls_impl_t *)dc; 508 int err; 509 dls_multicst_addr_t **pp; 510 dls_multicst_addr_t *p; 511 uint_t addr_length; 512 513 /* 514 * Check whether the address is in the list of enabled addresses for 515 * this dls_impl_t. 516 */ 517 rw_enter(&(dip->di_lock), RW_WRITER); 518 addr_length = dip->di_mip->mi_addr_length; 519 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 520 if (bcmp(addr, p->dma_addr, addr_length) == 0) { 521 /* 522 * It is there so there's nothing to do. 523 */ 524 err = 0; 525 goto done; 526 } 527 } 528 529 /* 530 * Allocate a new list item. 531 */ 532 if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 533 KM_NOSLEEP)) == NULL) { 534 err = ENOMEM; 535 goto done; 536 } 537 538 /* 539 * Enable the address at the MAC. 540 */ 541 if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 542 kmem_free(p, sizeof (dls_multicst_addr_t)); 543 goto done; 544 } 545 546 /* 547 * The address is now enabled at the MAC so add it to the list. 548 */ 549 bcopy(addr, p->dma_addr, addr_length); 550 *pp = p; 551 552 done: 553 rw_exit(&(dip->di_lock)); 554 return (err); 555 } 556 557 int 558 dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 559 { 560 dls_impl_t *dip = (dls_impl_t *)dc; 561 int err; 562 dls_multicst_addr_t **pp; 563 dls_multicst_addr_t *p; 564 uint_t addr_length; 565 566 /* 567 * Find the address in the list of enabled addresses for this 568 * dls_impl_t. 569 */ 570 rw_enter(&(dip->di_lock), RW_WRITER); 571 addr_length = dip->di_mip->mi_addr_length; 572 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 573 if (bcmp(addr, p->dma_addr, addr_length) == 0) 574 break; 575 } 576 577 /* 578 * If we walked to the end of the list then the given address is 579 * not currently enabled for this dls_impl_t. 580 */ 581 if (p == NULL) { 582 err = ENOENT; 583 goto done; 584 } 585 586 /* 587 * Disable the address at the MAC. 588 */ 589 if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 590 goto done; 591 592 /* 593 * Remove the address from the list. 594 */ 595 *pp = p->dma_nextp; 596 kmem_free(p, sizeof (dls_multicst_addr_t)); 597 598 done: 599 rw_exit(&(dip->di_lock)); 600 return (err); 601 } 602 603 mblk_t * 604 dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri, 605 mblk_t *payload) 606 { 607 dls_impl_t *dip = (dls_impl_t *)dc; 608 uint16_t vid; 609 size_t extra_len; 610 uint16_t mac_sap; 611 mblk_t *mp; 612 struct ether_vlan_header *evhp; 613 614 vid = dip->di_dvp->dv_id; 615 if (vid != VLAN_ID_NONE) { 616 /* 617 * We know ahead of time that we'll need to fill in 618 * additional VLAN information in the link-layer header. 619 * We will tell the MAC layer to pre-allocate some space at 620 * the end of the Ethernet header for us. 621 */ 622 ASSERT(dip->di_mip->mi_media == DL_ETHER); 623 extra_len = sizeof (struct ether_vlan_header) - 624 sizeof (struct ether_header); 625 mac_sap = VLAN_TPID; 626 } else { 627 extra_len = 0; 628 mac_sap = sap; 629 } 630 631 mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len); 632 if (vid == VLAN_ID_NONE || mp == NULL) 633 return (mp); 634 635 /* This is an Ethernet VLAN link. Fill in the VLAN information */ 636 ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 637 mp->b_wptr += extra_len; 638 evhp = (struct ether_vlan_header *)mp->b_rptr; 639 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 640 evhp->ether_type = htons(sap); 641 return (mp); 642 } 643 644 int 645 dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip) 646 { 647 return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp, 648 mp, mhip, NULL)); 649 } 650 651 void 652 dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 653 { 654 dls_impl_t *dip = (dls_impl_t *)dc; 655 656 rw_enter(&(dip->di_lock), RW_WRITER); 657 dip->di_rx = rx; 658 dip->di_rx_arg = arg; 659 rw_exit(&(dip->di_lock)); 660 } 661 662 mblk_t * 663 dls_tx(dls_channel_t dc, mblk_t *mp) 664 { 665 const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo; 666 667 return (mtp->mt_fn(mtp->mt_arg, mp)); 668 } 669 670 boolean_t 671 dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 672 void **di_rx_arg) 673 { 674 dls_multicst_addr_t *dmap; 675 size_t addr_length = dip->di_mip->mi_addr_length; 676 677 /* 678 * We must not accept packets if the dls_impl_t is not marked as bound 679 * or is being removed. 680 */ 681 rw_enter(&(dip->di_lock), RW_READER); 682 if (!dip->di_bound || dip->di_removing) 683 goto refuse; 684 685 /* 686 * If the dls_impl_t is in 'all physical' mode then always accept. 687 */ 688 if (dip->di_promisc & DLS_PROMISC_PHYS) 689 goto accept; 690 691 switch (mhip->mhi_dsttype) { 692 case MAC_ADDRTYPE_UNICAST: 693 /* 694 * Check to see if the destination address matches the 695 * dls_impl_t unicast address. 696 */ 697 if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) == 698 0) { 699 goto accept; 700 } 701 break; 702 case MAC_ADDRTYPE_MULTICAST: 703 /* 704 * Check the address against the list of addresses enabled 705 * for this dls_impl_t or accept it unconditionally if the 706 * dls_impl_t is in 'all multicast' mode. 707 */ 708 if (dip->di_promisc & DLS_PROMISC_MULTI) 709 goto accept; 710 for (dmap = dip->di_dmap; dmap != NULL; 711 dmap = dmap->dma_nextp) { 712 if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 713 addr_length) == 0) { 714 goto accept; 715 } 716 } 717 break; 718 case MAC_ADDRTYPE_BROADCAST: 719 /* 720 * If the address is broadcast then the dls_impl_t will 721 * always accept it. 722 */ 723 goto accept; 724 } 725 726 refuse: 727 rw_exit(&(dip->di_lock)); 728 return (B_FALSE); 729 730 accept: 731 /* 732 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 733 * always be in sync. 734 */ 735 *di_rx = dip->di_rx; 736 *di_rx_arg = dip->di_rx_arg; 737 rw_exit(&(dip->di_lock)); 738 return (B_TRUE); 739 } 740 741 boolean_t 742 dls_accept_loopback(dls_impl_t *dip, dls_rx_t *di_rx, void **di_rx_arg) 743 { 744 /* 745 * We must not accept packets if the dls_impl_t is not marked as bound 746 * or is being removed. 747 */ 748 rw_enter(&(dip->di_lock), RW_READER); 749 if (!dip->di_bound || dip->di_removing) 750 goto refuse; 751 752 /* 753 * A dls_impl_t should only accept loopback packets if it is in 754 * 'all physical' mode. 755 */ 756 if (dip->di_promisc & DLS_PROMISC_PHYS) 757 goto accept; 758 759 refuse: 760 rw_exit(&(dip->di_lock)); 761 return (B_FALSE); 762 763 accept: 764 /* 765 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 766 * always be in sync. 767 */ 768 *di_rx = dip->di_rx; 769 *di_rx_arg = dip->di_rx_arg; 770 rw_exit(&(dip->di_lock)); 771 return (B_TRUE); 772 } 773 774 boolean_t 775 dls_active_set(dls_channel_t dc) 776 { 777 dls_impl_t *dip = (dls_impl_t *)dc; 778 dls_link_t *dlp = dip->di_dvp->dv_dlp; 779 780 rw_enter(&dip->di_lock, RW_WRITER); 781 782 /* If we're already active, then there's nothing more to do. */ 783 if (dip->di_active) { 784 rw_exit(&dip->di_lock); 785 return (B_TRUE); 786 } 787 788 /* 789 * If this is the first active client on this link, notify 790 * the mac that we're becoming an active client. 791 */ 792 if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) { 793 rw_exit(&dip->di_lock); 794 return (B_FALSE); 795 } 796 dip->di_active = B_TRUE; 797 mutex_enter(&dlp->dl_lock); 798 dlp->dl_nactive++; 799 mutex_exit(&dlp->dl_lock); 800 rw_exit(&dip->di_lock); 801 return (B_TRUE); 802 } 803 804 void 805 dls_active_clear(dls_channel_t dc) 806 { 807 dls_impl_t *dip = (dls_impl_t *)dc; 808 dls_link_t *dlp = dip->di_dvp->dv_dlp; 809 810 rw_enter(&dip->di_lock, RW_WRITER); 811 812 if (!dip->di_active) 813 goto out; 814 dip->di_active = B_FALSE; 815 816 mutex_enter(&dlp->dl_lock); 817 if (--dlp->dl_nactive == 0) 818 mac_active_clear(dip->di_mh); 819 mutex_exit(&dlp->dl_lock); 820 out: 821 rw_exit(&dip->di_lock); 822 } 823