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