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