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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Data-Link Driver 31 */ 32 33 #include <sys/types.h> 34 #include <sys/stream.h> 35 #include <sys/stropts.h> 36 #include <sys/strsun.h> 37 #include <sys/strsubr.h> 38 #include <sys/atomic.h> 39 #include <sys/sdt.h> 40 #include <sys/mac.h> 41 #include <sys/dls.h> 42 #include <sys/dld.h> 43 #include <sys/dld_impl.h> 44 #include <sys/taskq.h> 45 #include <sys/vlan.h> 46 47 static int str_constructor(void *, void *, int); 48 static void str_destructor(void *, void *); 49 static void str_m_put(dld_str_t *, mblk_t *); 50 static void str_m_srv(dld_str_t *, mblk_t *); 51 static void str_mdata_fastpath_put(dld_str_t *, mblk_t *); 52 static void str_mdata_raw_put(dld_str_t *, mblk_t *); 53 static void str_mdata_srv(dld_str_t *, mblk_t *); 54 static void str_mproto_put(dld_str_t *, mblk_t *); 55 static void str_mpcproto_put(dld_str_t *, mblk_t *); 56 static void str_mioctl_put(dld_str_t *, mblk_t *); 57 static void str_mflush_put(dld_str_t *, mblk_t *); 58 static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *); 59 static void str_notify_promisc_on_phys(dld_str_t *); 60 static void str_notify_promisc_off_phys(dld_str_t *); 61 static void str_notify_phys_addr(dld_str_t *, const uint8_t *); 62 static void str_notify_link_up(dld_str_t *); 63 static void str_notify_link_down(dld_str_t *); 64 static void str_notify_capab_reneg(dld_str_t *); 65 static void str_notify_speed(dld_str_t *, uint32_t); 66 static void str_notify(void *, mac_notify_type_t); 67 static void str_putbq(queue_t *q, mblk_t *mp); 68 69 static uint32_t str_count; 70 static kmem_cache_t *str_cachep; 71 72 typedef struct str_msg_info { 73 uint8_t smi_type; 74 const char *smi_txt; 75 void (*smi_put)(dld_str_t *, mblk_t *); 76 void (*smi_srv)(dld_str_t *, mblk_t *); 77 } str_msg_info_t; 78 79 /* 80 * Normal priority message jump table. 81 */ 82 str_msg_info_t str_mi[] = { 83 { M_DATA, "M_DATA", str_m_put, str_m_srv }, 84 { M_PROTO, "M_PROTO", str_mproto_put, str_m_srv }, 85 { 0x02, "undefined", str_m_put, str_m_srv }, 86 { 0x03, "undefined", str_m_put, str_m_srv }, 87 { 0x04, "undefined", str_m_put, str_m_srv }, 88 { 0x05, "undefined", str_m_put, str_m_srv }, 89 { 0x06, "undefined", str_m_put, str_m_srv }, 90 { 0x07, "undefined", str_m_put, str_m_srv }, 91 { M_BREAK, "M_BREAK", str_m_put, str_m_srv }, 92 { M_PASSFP, "M_PASSFP", str_m_put, str_m_srv }, 93 { M_EVENT, "M_EVENT", str_m_put, str_m_srv }, 94 { M_SIG, "M_SIG", str_m_put, str_m_srv }, 95 { M_DELAY, "M_DELAY", str_m_put, str_m_srv }, 96 { M_CTL, "M_CTL", str_m_put, str_m_srv }, 97 { M_IOCTL, "M_IOCTL", str_mioctl_put, str_m_srv }, 98 { M_SETOPTS, "M_SETOPTS", str_m_put, str_m_srv }, 99 { M_RSE, "M_RSE", str_m_put, str_m_srv } 100 }; 101 102 #define STR_MI_COUNT (sizeof (str_mi) / sizeof (str_mi[0])) 103 104 /* 105 * High priority message jump table. 106 */ 107 str_msg_info_t str_pmi[] = { 108 { 0x80, "undefined", str_m_put, str_m_srv }, 109 { M_IOCACK, "M_IOCACK", str_m_put, str_m_srv }, 110 { M_IOCNAK, "M_IOCNAK", str_m_put, str_m_srv }, 111 { M_PCPROTO, "M_PCPROTO", str_mpcproto_put, str_m_srv }, 112 { M_PCSIG, "M_PCSIG", str_m_put, str_m_srv }, 113 { M_READ, "M_READ", str_m_put, str_m_srv }, 114 { M_FLUSH, "M_FLUSH", str_mflush_put, str_m_srv }, 115 { M_STOP, "M_STOP", str_m_put, str_m_srv }, 116 { M_START, "M_START", str_m_put, str_m_srv }, 117 { M_HANGUP, "M_HANGUP", str_m_put, str_m_srv }, 118 { M_ERROR, "M_ERROR", str_m_put, str_m_srv }, 119 { M_COPYIN, "M_COPYIN", str_m_put, str_m_srv }, 120 { M_COPYOUT, "M_COPYOUT", str_m_put, str_m_srv }, 121 { M_IOCDATA, "M_IOCDATA", str_m_put, str_m_srv }, 122 { M_PCRSE, "M_PCRSE", str_m_put, str_m_srv }, 123 { M_STOPI, "M_STOPI", str_m_put, str_m_srv }, 124 { M_STARTI, "M_STARTI", str_m_put, str_m_srv }, 125 { M_PCEVENT, "M_PCEVENT", str_m_put, str_m_srv }, 126 { M_UNHANGUP, "M_UNHANGUP", str_m_put, str_m_srv } 127 }; 128 129 #define STR_PMI_COUNT (sizeof (str_pmi) / sizeof (str_pmi[0])) 130 131 /* 132 * Initialize this module's data structures. 133 */ 134 void 135 dld_str_init(void) 136 { 137 /* 138 * Create dld_str_t object cache. 139 */ 140 str_cachep = kmem_cache_create("dld_str_cache", sizeof (dld_str_t), 141 0, str_constructor, str_destructor, NULL, NULL, NULL, 0); 142 ASSERT(str_cachep != NULL); 143 } 144 145 /* 146 * Tear down this module's data structures. 147 */ 148 int 149 dld_str_fini(void) 150 { 151 /* 152 * Make sure that there are no objects in use. 153 */ 154 if (str_count != 0) 155 return (EBUSY); 156 157 /* 158 * Destroy object cache. 159 */ 160 kmem_cache_destroy(str_cachep); 161 162 return (0); 163 } 164 165 /* 166 * Create a new dld_str_t object. 167 */ 168 dld_str_t * 169 dld_str_create(queue_t *rq) 170 { 171 dld_str_t *dsp; 172 173 /* 174 * Allocate an object from the cache. 175 */ 176 dsp = kmem_cache_alloc(str_cachep, KM_SLEEP); 177 atomic_add_32(&str_count, 1); 178 179 /* 180 * Initialize the queue pointers. 181 */ 182 ASSERT(RD(rq) == rq); 183 dsp->ds_rq = rq; 184 dsp->ds_wq = WR(rq); 185 rq->q_ptr = WR(rq)->q_ptr = (void *)dsp; 186 187 return (dsp); 188 } 189 190 /* 191 * Destroy a dld_str_t object. 192 */ 193 void 194 dld_str_destroy(dld_str_t *dsp) 195 { 196 queue_t *rq; 197 queue_t *wq; 198 199 /* 200 * Clear the queue pointers. 201 */ 202 rq = dsp->ds_rq; 203 wq = dsp->ds_wq; 204 ASSERT(wq == WR(rq)); 205 206 rq->q_ptr = wq->q_ptr = NULL; 207 dsp->ds_rq = dsp->ds_wq = NULL; 208 209 /* 210 * Clear down notifications. 211 */ 212 dsp->ds_notifications = 0; 213 214 /* 215 * Free the object back to the cache. 216 */ 217 kmem_cache_free(str_cachep, dsp); 218 atomic_add_32(&str_count, -1); 219 } 220 221 /* 222 * kmem_cache contructor function: see kmem_cache_create(9f). 223 */ 224 /*ARGSUSED*/ 225 static int 226 str_constructor(void *buf, void *cdrarg, int kmflags) 227 { 228 dld_str_t *dsp = buf; 229 230 bzero(buf, sizeof (dld_str_t)); 231 232 /* 233 * Take a copy of the global message handler jump tables. 234 */ 235 ASSERT(dsp->ds_mi == NULL); 236 if ((dsp->ds_mi = kmem_zalloc(sizeof (str_mi), kmflags)) == NULL) 237 return (-1); 238 239 bcopy(str_mi, dsp->ds_mi, sizeof (str_mi)); 240 241 ASSERT(dsp->ds_pmi == NULL); 242 if ((dsp->ds_pmi = kmem_zalloc(sizeof (str_pmi), kmflags)) == NULL) { 243 kmem_free(dsp->ds_mi, sizeof (str_mi)); 244 dsp->ds_mi = NULL; 245 return (-1); 246 } 247 248 bcopy(str_pmi, dsp->ds_pmi, sizeof (str_pmi)); 249 250 /* 251 * Allocate a new minor number. 252 */ 253 if ((dsp->ds_minor = dld_minor_hold(kmflags == KM_SLEEP)) == 0) { 254 kmem_free(dsp->ds_mi, sizeof (str_mi)); 255 dsp->ds_mi = NULL; 256 kmem_free(dsp->ds_pmi, sizeof (str_pmi)); 257 dsp->ds_pmi = NULL; 258 return (-1); 259 } 260 261 /* 262 * Initialize the DLPI state machine. 263 */ 264 dsp->ds_dlstate = DL_UNATTACHED; 265 266 return (0); 267 } 268 269 /* 270 * kmem_cache destructor function. 271 */ 272 /*ARGSUSED*/ 273 static void 274 str_destructor(void *buf, void *cdrarg) 275 { 276 dld_str_t *dsp = buf; 277 278 /* 279 * Make sure the DLPI state machine was reset. 280 */ 281 ASSERT(dsp->ds_dlstate == DL_UNATTACHED); 282 283 /* 284 * Make sure the data-link interface was closed. 285 */ 286 ASSERT(dsp->ds_mh == NULL); 287 ASSERT(dsp->ds_dc == NULL); 288 289 /* 290 * Make sure enabled notifications are cleared. 291 */ 292 ASSERT(dsp->ds_notifications == 0); 293 294 /* 295 * Make sure polling is disabled. 296 */ 297 ASSERT(!dsp->ds_polling); 298 299 /* 300 * Make sure M_DATA message handling is disabled. 301 */ 302 ASSERT(dsp->ds_mi[M_DATA].smi_put == str_m_put); 303 ASSERT(dsp->ds_mi[M_DATA].smi_srv == str_m_srv); 304 305 /* 306 * Release the minor number. 307 */ 308 dld_minor_rele(dsp->ds_minor); 309 310 /* 311 * Clear down the jump tables. 312 */ 313 kmem_free(dsp->ds_mi, sizeof (str_mi)); 314 dsp->ds_mi = NULL; 315 316 kmem_free(dsp->ds_pmi, sizeof (str_pmi)); 317 dsp->ds_pmi = NULL; 318 } 319 320 /* 321 * Called from put(9e) to process a streams message. 322 */ 323 void 324 dld_str_put(dld_str_t *dsp, mblk_t *mp) 325 { 326 uint8_t type; 327 str_msg_info_t *smip; 328 329 /* 330 * Look up the message handler from the appropriate jump table. 331 */ 332 if ((type = DB_TYPE(mp)) & QPCTL) { 333 /* 334 * Clear the priority bit to index into the jump table. 335 */ 336 type &= ~QPCTL; 337 338 /* 339 * Check the message is not out of range for the jump table. 340 */ 341 if (type >= STR_PMI_COUNT) 342 goto unknown; 343 344 /* 345 * Get the handler from the jump table. 346 */ 347 smip = &(dsp->ds_pmi[type]); 348 349 /* 350 * OR the priorty bit back in to restore the original message 351 * type. 352 */ 353 type |= QPCTL; 354 } else { 355 /* 356 * Check the message is not out of range for the jump table. 357 */ 358 if (type >= STR_MI_COUNT) 359 goto unknown; 360 361 /* 362 * Get the handler from the jump table. 363 */ 364 smip = &(dsp->ds_mi[type]); 365 } 366 367 ASSERT(smip->smi_type == type); 368 smip->smi_put(dsp, mp); 369 return; 370 371 unknown: 372 str_m_put(dsp, mp); 373 } 374 375 /* 376 * Called from srv(9e) to process a streams message. 377 */ 378 void 379 dld_str_srv(dld_str_t *dsp, mblk_t *mp) 380 { 381 uint8_t type; 382 str_msg_info_t *smip; 383 384 /* 385 * Look up the message handler from the appropriate jump table. 386 */ 387 if ((type = DB_TYPE(mp)) & QPCTL) { 388 /* 389 * Clear the priority bit to index into the jump table. 390 */ 391 type &= ~QPCTL; 392 393 /* 394 * Check the message is not out of range for the jump table. 395 */ 396 if (type >= STR_PMI_COUNT) 397 goto unknown; 398 399 /* 400 * Get the handler from the jump table. 401 */ 402 smip = &(dsp->ds_pmi[type]); 403 404 /* 405 * OR the priorty bit back in to restore the original message 406 * type. 407 */ 408 type |= QPCTL; 409 } else { 410 /* 411 * Check the message is not out of range for the jump table. 412 */ 413 if (type >= STR_MI_COUNT) 414 goto unknown; 415 416 /* 417 * Get the handler from the jump table. 418 */ 419 ASSERT(type < STR_MI_COUNT); 420 smip = &(dsp->ds_mi[type]); 421 } 422 423 ASSERT(smip->smi_type == type); 424 smip->smi_srv(dsp, mp); 425 return; 426 427 unknown: 428 str_m_srv(dsp, mp); 429 } 430 431 /* 432 * M_DATA put (IP fast-path mode) 433 */ 434 static void 435 str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp) 436 { 437 queue_t *q = dsp->ds_wq; 438 439 /* 440 * If something is already queued then we must queue to avoid 441 * re-ordering. 442 */ 443 if (q->q_first != NULL) { 444 (void) putq(q, mp); 445 return; 446 } 447 448 /* 449 * Attempt to transmit the packet. 450 */ 451 if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) { 452 (void) putbq(q, mp); 453 qenable(q); 454 } 455 } 456 457 /* 458 * M_DATA put (raw mode) 459 */ 460 static void 461 str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) 462 { 463 queue_t *q = dsp->ds_wq; 464 struct ether_header *ehp; 465 mblk_t *bp; 466 size_t size; 467 size_t hdrlen; 468 469 size = MBLKL(mp); 470 if (size < sizeof (struct ether_header)) 471 goto discard; 472 473 hdrlen = sizeof (struct ether_header); 474 475 ehp = (struct ether_header *)mp->b_rptr; 476 if (ntohs(ehp->ether_type) == VLAN_TPID) { 477 struct ether_vlan_header *evhp; 478 479 if (size < sizeof (struct ether_vlan_header)) 480 goto discard; 481 482 /* 483 * Replace vtag with our own 484 */ 485 evhp = (struct ether_vlan_header *)ehp; 486 evhp->ether_tci = htons(VLAN_TCI(dsp->ds_pri, 487 ETHER_CFI, dsp->ds_vid)); 488 hdrlen = sizeof (struct ether_vlan_header); 489 } 490 491 /* 492 * Check the packet is not too big and that any remaining 493 * fragment list is composed entirely of M_DATA messages. (We 494 * know the first fragment was M_DATA otherwise we could not 495 * have got here). 496 */ 497 for (bp = mp->b_next; bp != NULL; bp = bp->b_cont) { 498 if (DB_TYPE(bp) != M_DATA) 499 goto discard; 500 size += MBLKL(bp); 501 } 502 503 if (size > dsp->ds_mip->mi_sdu_max + hdrlen) 504 goto discard; 505 506 /* 507 * If something is already queued then we must queue to avoid 508 * re-ordering. 509 */ 510 if (q->q_first != NULL) { 511 (void) putq(q, bp); 512 return; 513 } 514 515 /* 516 * Attempt to transmit the packet. 517 */ 518 if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) { 519 (void) putbq(q, mp); 520 qenable(q); 521 } 522 return; 523 524 discard: 525 freemsg(mp); 526 } 527 528 /* 529 * M_DATA srv 530 */ 531 static void 532 str_mdata_srv(dld_str_t *dsp, mblk_t *mp) 533 { 534 queue_t *q = dsp->ds_wq; 535 536 /* 537 * Attempt to transmit the packet. 538 */ 539 if ((mp = dls_tx(dsp->ds_dc, mp)) == NULL) 540 return; 541 542 (void) str_putbq(q, mp); 543 qenable(q); 544 } 545 546 /* 547 * M_PROTO put 548 */ 549 static void 550 str_mproto_put(dld_str_t *dsp, mblk_t *mp) 551 { 552 dld_proto(dsp, mp); 553 } 554 555 /* 556 * M_PCPROTO put 557 */ 558 static void 559 str_mpcproto_put(dld_str_t *dsp, mblk_t *mp) 560 { 561 dld_proto(dsp, mp); 562 } 563 564 /* 565 * M_IOCTL put 566 */ 567 static void 568 str_mioctl_put(dld_str_t *dsp, mblk_t *mp) 569 { 570 dld_ioc(dsp, mp); 571 } 572 573 /* 574 * M_FLUSH put 575 */ 576 /*ARGSUSED*/ 577 static void 578 str_mflush_put(dld_str_t *dsp, mblk_t *mp) 579 { 580 queue_t *q = dsp->ds_wq; 581 582 if (*mp->b_rptr & FLUSHW) { 583 flushq(q, FLUSHALL); 584 *mp->b_rptr &= ~FLUSHW; 585 } 586 587 if (*mp->b_rptr & FLUSHR) 588 qreply(q, mp); 589 else 590 freemsg(mp); 591 } 592 593 /* 594 * M_* put. 595 */ 596 /*ARGSUSED*/ 597 static void 598 str_m_put(dld_str_t *dsp, mblk_t *mp) 599 { 600 freemsg(mp); 601 } 602 603 /* 604 * M_* put. 605 */ 606 /*ARGSUSED*/ 607 static void 608 str_m_srv(dld_str_t *dsp, mblk_t *mp) 609 { 610 freemsgchain(mp); 611 } 612 613 /* 614 * Process DL_ATTACH_REQ (style 2) or open(2) (style 1). 615 */ 616 int 617 dld_str_attach(dld_str_t *dsp, dld_ppa_t *dpp) 618 { 619 int err; 620 dls_channel_t dc; 621 uint_t addr_length; 622 623 ASSERT(dsp->ds_dc == NULL); 624 625 /* 626 * Open a channel. 627 */ 628 if ((err = dls_open(dpp->dp_name, &dc)) != 0) 629 return (err); 630 631 /* 632 * Cache the MAC interface handle, a pointer to the immutable MAC 633 * information and the current and 'factory' MAC address. 634 */ 635 dsp->ds_mh = dls_mac(dc); 636 dsp->ds_mip = mac_info(dsp->ds_mh); 637 638 mac_unicst_get(dsp->ds_mh, dsp->ds_curr_addr); 639 640 addr_length = dsp->ds_mip->mi_addr_length; 641 bcopy(dsp->ds_mip->mi_unicst_addr, dsp->ds_fact_addr, addr_length); 642 643 /* 644 * Cache the interface VLAN identifier. (This will be VLAN_ID_NONE for 645 * a non-VLAN interface). 646 */ 647 dsp->ds_vid = dls_vid(dc); 648 649 /* 650 * Set the default packet priority. 651 */ 652 dsp->ds_pri = 0; 653 654 /* 655 * Add a notify function so that the we get updates from the MAC. 656 */ 657 dsp->ds_mnh = mac_notify_add(dsp->ds_mh, str_notify, (void *)dsp); 658 659 dsp->ds_dc = dc; 660 return (0); 661 } 662 663 /* 664 * Process DL_DETACH_REQ (style 2) or close(2) (style 1). Can also be called 665 * from close(2) for style 2. 666 */ 667 void 668 dld_str_detach(dld_str_t *dsp) 669 { 670 /* 671 * Remove the notify function. 672 */ 673 mac_notify_remove(dsp->ds_mh, dsp->ds_mnh); 674 675 /* 676 * Make sure the M_DATA handler is reset. 677 */ 678 dld_str_tx_drop(dsp); 679 680 /* 681 * Clear the polling flag. 682 */ 683 dsp->ds_polling = B_FALSE; 684 685 /* 686 * Close the channel. 687 */ 688 dls_close(dsp->ds_dc); 689 dsp->ds_dc = NULL; 690 dsp->ds_mh = NULL; 691 } 692 693 /* 694 * Enable raw mode for this stream. This mode is mutually exclusive with 695 * fast-path and/or polling. 696 */ 697 void 698 dld_str_tx_raw(dld_str_t *dsp) 699 { 700 /* 701 * Enable M_DATA message handling. 702 */ 703 dsp->ds_mi[M_DATA].smi_put = str_mdata_raw_put; 704 dsp->ds_mi[M_DATA].smi_srv = str_mdata_srv; 705 } 706 707 /* 708 * Enable fast-path for this stream. 709 */ 710 void 711 dld_str_tx_fastpath(dld_str_t *dsp) 712 { 713 /* 714 * Enable M_DATA message handling. 715 */ 716 dsp->ds_mi[M_DATA].smi_put = str_mdata_fastpath_put; 717 dsp->ds_mi[M_DATA].smi_srv = str_mdata_srv; 718 } 719 720 /* 721 * Disable fast-path or raw mode. 722 */ 723 void 724 dld_str_tx_drop(dld_str_t *dsp) 725 { 726 /* 727 * Disable M_DATA message handling. 728 */ 729 dsp->ds_mi[M_DATA].smi_put = str_m_put; 730 dsp->ds_mi[M_DATA].smi_srv = str_m_srv; 731 } 732 733 /* 734 * Raw mode receive function. 735 */ 736 /*ARGSUSED*/ 737 void 738 dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 739 size_t header_length) 740 { 741 dld_str_t *dsp = (dld_str_t *)arg; 742 mblk_t *next; 743 744 ASSERT(mp != NULL); 745 do { 746 /* 747 * Get the pointer to the next packet in the chain and then 748 * clear b_next before the packet gets passed on. 749 */ 750 next = mp->b_next; 751 mp->b_next = NULL; 752 753 /* 754 * Wind back b_rptr to point at the MAC header. 755 */ 756 ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length); 757 mp->b_rptr -= header_length; 758 if (header_length == sizeof (struct ether_vlan_header)) { 759 /* 760 * Strip off the vtag 761 */ 762 ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 763 2 * ETHERADDRL); 764 mp->b_rptr += VLAN_TAGSZ; 765 } 766 767 /* 768 * Pass the packet on. 769 */ 770 putnext(dsp->ds_rq, mp); 771 772 /* 773 * Move on to the next packet in the chain. 774 */ 775 mp = next; 776 } while (mp != NULL); 777 } 778 779 /* 780 * Fast-path receive function. 781 */ 782 /*ARGSUSED*/ 783 void 784 dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 785 size_t header_length) 786 { 787 dld_str_t *dsp = (dld_str_t *)arg; 788 mblk_t *next; 789 790 ASSERT(mp != NULL); 791 do { 792 /* 793 * Get the pointer to the next packet in the chain and then 794 * clear b_next before the packet gets passed on. 795 */ 796 next = mp->b_next; 797 mp->b_next = NULL; 798 799 /* 800 * Pass the packet on. 801 */ 802 putnext(dsp->ds_rq, mp); 803 804 /* 805 * Move on to the next packet in the chain. 806 */ 807 mp = next; 808 } while (mp != NULL); 809 } 810 811 /* 812 * Default receive function (send DL_UNITDATA_IND messages). 813 */ 814 /*ARGSUSED*/ 815 void 816 dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 817 size_t header_length) 818 { 819 dld_str_t *dsp = (dld_str_t *)arg; 820 mblk_t *ud_mp; 821 mblk_t *next; 822 823 ASSERT(mp != NULL); 824 do { 825 /* 826 * Get the pointer to the next packet in the chain and then 827 * clear b_next before the packet gets passed on. 828 */ 829 next = mp->b_next; 830 mp->b_next = NULL; 831 832 /* 833 * Wind back b_rptr to point at the MAC header. 834 */ 835 ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length); 836 mp->b_rptr -= header_length; 837 838 /* 839 * Create the DL_UNITDATA_IND M_PROTO. 840 */ 841 if ((ud_mp = str_unitdata_ind(dsp, mp)) == NULL) { 842 freemsgchain(mp); 843 return; 844 } 845 846 /* 847 * Advance b_rptr to point at the payload again. 848 */ 849 mp->b_rptr += header_length; 850 851 /* 852 * Prepend the DL_UNITDATA_IND. 853 */ 854 ud_mp->b_cont = mp; 855 856 /* 857 * Send the message. 858 */ 859 putnext(dsp->ds_rq, ud_mp); 860 861 /* 862 * Move on to the next packet in the chain. 863 */ 864 mp = next; 865 } while (mp != NULL); 866 } 867 868 /* 869 * Generate DL_NOTIFY_IND messages to notify the DLPI consumer of the 870 * current state of the interface. 871 */ 872 void 873 dld_str_notify_ind(dld_str_t *dsp) 874 { 875 mac_notify_type_t type; 876 877 for (type = 0; type < MAC_NNOTE; type++) 878 str_notify(dsp, type); 879 } 880 881 typedef struct dl_unitdata_ind_wrapper { 882 dl_unitdata_ind_t dl_unitdata; 883 uint8_t dl_dest_addr[MAXADDRLEN + sizeof (uint16_t)]; 884 uint8_t dl_src_addr[MAXADDRLEN + sizeof (uint16_t)]; 885 } dl_unitdata_ind_wrapper_t; 886 887 /* 888 * Create a DL_UNITDATA_IND M_PROTO message. 889 */ 890 static mblk_t * 891 str_unitdata_ind(dld_str_t *dsp, mblk_t *mp) 892 { 893 mblk_t *nmp; 894 dl_unitdata_ind_wrapper_t *dlwp; 895 dl_unitdata_ind_t *dlp; 896 dls_header_info_t dhi; 897 uint_t addr_length; 898 uint8_t *daddr; 899 uint8_t *saddr; 900 901 /* 902 * Get the packet header information. 903 */ 904 dls_header_info(dsp->ds_dc, mp, &dhi); 905 906 /* 907 * Allocate a message large enough to contain the wrapper structure 908 * defined above. 909 */ 910 if ((nmp = mexchange(dsp->ds_wq, NULL, 911 sizeof (dl_unitdata_ind_wrapper_t), M_PROTO, 912 DL_UNITDATA_IND)) == NULL) 913 return (NULL); 914 915 dlwp = (dl_unitdata_ind_wrapper_t *)nmp->b_rptr; 916 917 dlp = &(dlwp->dl_unitdata); 918 ASSERT(dlp == (dl_unitdata_ind_t *)nmp->b_rptr); 919 ASSERT(dlp->dl_primitive == DL_UNITDATA_IND); 920 921 /* 922 * Copy in the destination address. 923 */ 924 addr_length = dsp->ds_mip->mi_addr_length; 925 daddr = dlwp->dl_dest_addr; 926 dlp->dl_dest_addr_offset = (uintptr_t)daddr - (uintptr_t)dlp; 927 bcopy(dhi.dhi_daddr, daddr, addr_length); 928 929 /* 930 * Set the destination DLSAP to our bound DLSAP value. 931 */ 932 *(uint16_t *)(daddr + addr_length) = dsp->ds_sap; 933 dlp->dl_dest_addr_length = addr_length + sizeof (uint16_t); 934 935 /* 936 * If the destination address was a group address then 937 * dl_group_address field should be non-zero. 938 */ 939 dlp->dl_group_address = dhi.dhi_isgroup; 940 941 /* 942 * Copy in the source address. 943 */ 944 saddr = dlwp->dl_src_addr; 945 dlp->dl_src_addr_offset = (uintptr_t)saddr - (uintptr_t)dlp; 946 bcopy(dhi.dhi_saddr, saddr, addr_length); 947 948 /* 949 * Set the source DLSAP to the packet ethertype. 950 */ 951 *(uint16_t *)(saddr + addr_length) = dhi.dhi_ethertype; 952 dlp->dl_src_addr_length = addr_length + sizeof (uint16_t); 953 954 return (nmp); 955 } 956 957 /* 958 * DL_NOTIFY_IND: DL_NOTE_PROMISC_ON_PHYS 959 */ 960 static void 961 str_notify_promisc_on_phys(dld_str_t *dsp) 962 { 963 mblk_t *mp; 964 dl_notify_ind_t *dlip; 965 966 if (!(dsp->ds_notifications & DL_NOTE_PROMISC_ON_PHYS)) 967 return; 968 969 if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), 970 M_PROTO, 0)) == NULL) 971 return; 972 973 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 974 dlip = (dl_notify_ind_t *)mp->b_rptr; 975 dlip->dl_primitive = DL_NOTIFY_IND; 976 dlip->dl_notification = DL_NOTE_PROMISC_ON_PHYS; 977 978 qreply(dsp->ds_wq, mp); 979 } 980 981 /* 982 * DL_NOTIFY_IND: DL_NOTE_PROMISC_OFF_PHYS 983 */ 984 static void 985 str_notify_promisc_off_phys(dld_str_t *dsp) 986 { 987 mblk_t *mp; 988 dl_notify_ind_t *dlip; 989 990 if (!(dsp->ds_notifications & DL_NOTE_PROMISC_OFF_PHYS)) 991 return; 992 993 if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), 994 M_PROTO, 0)) == NULL) 995 return; 996 997 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 998 dlip = (dl_notify_ind_t *)mp->b_rptr; 999 dlip->dl_primitive = DL_NOTIFY_IND; 1000 dlip->dl_notification = DL_NOTE_PROMISC_OFF_PHYS; 1001 1002 qreply(dsp->ds_wq, mp); 1003 } 1004 1005 /* 1006 * DL_NOTIFY_IND: DL_NOTE_PHYS_ADDR 1007 */ 1008 static void 1009 str_notify_phys_addr(dld_str_t *dsp, const uint8_t *addr) 1010 { 1011 mblk_t *mp; 1012 dl_notify_ind_t *dlip; 1013 uint_t addr_length; 1014 uint16_t ethertype; 1015 1016 if (!(dsp->ds_notifications & DL_NOTE_PHYS_ADDR)) 1017 return; 1018 1019 addr_length = dsp->ds_mip->mi_addr_length; 1020 if ((mp = mexchange(dsp->ds_wq, NULL, 1021 sizeof (dl_notify_ind_t) + addr_length + sizeof (uint16_t), 1022 M_PROTO, 0)) == NULL) 1023 return; 1024 1025 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 1026 dlip = (dl_notify_ind_t *)mp->b_rptr; 1027 dlip->dl_primitive = DL_NOTIFY_IND; 1028 dlip->dl_notification = DL_NOTE_PHYS_ADDR; 1029 dlip->dl_data = DL_CURR_PHYS_ADDR; 1030 dlip->dl_addr_offset = sizeof (dl_notify_ind_t); 1031 dlip->dl_addr_length = addr_length + sizeof (uint16_t); 1032 1033 bcopy(addr, &dlip[1], addr_length); 1034 1035 ethertype = (dsp->ds_sap < ETHERTYPE_802_MIN) ? 0 : dsp->ds_sap; 1036 *(uint16_t *)((uchar_t *)(dlip + 1) + addr_length) = 1037 ethertype; 1038 1039 qreply(dsp->ds_wq, mp); 1040 } 1041 1042 /* 1043 * DL_NOTIFY_IND: DL_NOTE_LINK_UP 1044 */ 1045 static void 1046 str_notify_link_up(dld_str_t *dsp) 1047 { 1048 mblk_t *mp; 1049 dl_notify_ind_t *dlip; 1050 1051 if (!(dsp->ds_notifications & DL_NOTE_LINK_UP)) 1052 return; 1053 1054 if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), 1055 M_PROTO, 0)) == NULL) 1056 return; 1057 1058 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 1059 dlip = (dl_notify_ind_t *)mp->b_rptr; 1060 dlip->dl_primitive = DL_NOTIFY_IND; 1061 dlip->dl_notification = DL_NOTE_LINK_UP; 1062 1063 qreply(dsp->ds_wq, mp); 1064 } 1065 1066 /* 1067 * DL_NOTIFY_IND: DL_NOTE_LINK_DOWN 1068 */ 1069 static void 1070 str_notify_link_down(dld_str_t *dsp) 1071 { 1072 mblk_t *mp; 1073 dl_notify_ind_t *dlip; 1074 1075 if (!(dsp->ds_notifications & DL_NOTE_LINK_DOWN)) 1076 return; 1077 1078 if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), 1079 M_PROTO, 0)) == NULL) 1080 return; 1081 1082 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 1083 dlip = (dl_notify_ind_t *)mp->b_rptr; 1084 dlip->dl_primitive = DL_NOTIFY_IND; 1085 dlip->dl_notification = DL_NOTE_LINK_DOWN; 1086 1087 qreply(dsp->ds_wq, mp); 1088 } 1089 1090 /* 1091 * DL_NOTIFY_IND: DL_NOTE_SPEED 1092 */ 1093 static void 1094 str_notify_speed(dld_str_t *dsp, uint32_t speed) 1095 { 1096 mblk_t *mp; 1097 dl_notify_ind_t *dlip; 1098 1099 if (!(dsp->ds_notifications & DL_NOTE_SPEED)) 1100 return; 1101 1102 if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), 1103 M_PROTO, 0)) == NULL) 1104 return; 1105 1106 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 1107 dlip = (dl_notify_ind_t *)mp->b_rptr; 1108 dlip->dl_primitive = DL_NOTIFY_IND; 1109 dlip->dl_notification = DL_NOTE_SPEED; 1110 dlip->dl_data = speed; 1111 1112 qreply(dsp->ds_wq, mp); 1113 } 1114 1115 /* 1116 * DL_NOTIFY_IND: DL_NOTE_CAPAB_RENEG 1117 */ 1118 static void 1119 str_notify_capab_reneg(dld_str_t *dsp) 1120 { 1121 mblk_t *mp; 1122 dl_notify_ind_t *dlip; 1123 1124 if (!(dsp->ds_notifications & DL_NOTE_CAPAB_RENEG)) 1125 return; 1126 1127 if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), 1128 M_PROTO, 0)) == NULL) 1129 return; 1130 1131 bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 1132 dlip = (dl_notify_ind_t *)mp->b_rptr; 1133 dlip->dl_primitive = DL_NOTIFY_IND; 1134 dlip->dl_notification = DL_NOTE_CAPAB_RENEG; 1135 1136 qreply(dsp->ds_wq, mp); 1137 } 1138 1139 /* 1140 * MAC notification callback. 1141 */ 1142 static void 1143 str_notify(void *arg, mac_notify_type_t type) 1144 { 1145 dld_str_t *dsp = (dld_str_t *)arg; 1146 queue_t *q = dsp->ds_wq; 1147 1148 switch (type) { 1149 case MAC_NOTE_TX: 1150 enableok(q); 1151 qenable(q); 1152 break; 1153 1154 case MAC_NOTE_DEVPROMISC: 1155 /* 1156 * Send the appropriate DL_NOTIFY_IND. 1157 */ 1158 if (mac_promisc_get(dsp->ds_mh, MAC_DEVPROMISC)) 1159 str_notify_promisc_on_phys(dsp); 1160 else 1161 str_notify_promisc_off_phys(dsp); 1162 break; 1163 1164 case MAC_NOTE_PROMISC: 1165 break; 1166 1167 case MAC_NOTE_UNICST: 1168 /* 1169 * This notification is sent whenever the MAC unicast address 1170 * changes. We need to re-cache the address. 1171 */ 1172 mac_unicst_get(dsp->ds_mh, dsp->ds_curr_addr); 1173 1174 /* 1175 * Send the appropriate DL_NOTIFY_IND. 1176 */ 1177 str_notify_phys_addr(dsp, dsp->ds_curr_addr); 1178 break; 1179 1180 case MAC_NOTE_LINK: 1181 /* 1182 * This notification is sent every time the MAC driver 1183 * updates the link state. 1184 */ 1185 switch (mac_link_get(dsp->ds_mh)) { 1186 case LINK_STATE_UP: 1187 /* 1188 * The link is up so send the appropriate 1189 * DL_NOTIFY_IND. 1190 */ 1191 str_notify_link_up(dsp); 1192 1193 /* 1194 * If we can find the link speed then send a 1195 * DL_NOTIFY_IND for that too. 1196 */ 1197 if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED]) { 1198 uint64_t val; 1199 1200 val = mac_stat_get(dsp->ds_mh, 1201 MAC_STAT_IFSPEED); 1202 str_notify_speed(dsp, 1203 (uint32_t)(val / 1000ull)); 1204 } 1205 break; 1206 1207 case LINK_STATE_DOWN: 1208 /* 1209 * The link is down so send the appropriate 1210 * DL_NOTIFY_IND. 1211 */ 1212 str_notify_link_down(dsp); 1213 break; 1214 1215 default: 1216 break; 1217 } 1218 break; 1219 1220 case MAC_NOTE_RESOURCE: 1221 /* 1222 * This notification is sent whenever the MAC resources 1223 * change. We need to renegotiate the capabilities. 1224 * Send the appropriate DL_NOTIFY_IND. 1225 */ 1226 str_notify_capab_reneg(dsp); 1227 break; 1228 1229 default: 1230 ASSERT(B_FALSE); 1231 break; 1232 } 1233 } 1234 1235 /* 1236 * Put a chain of packets back on the queue. 1237 */ 1238 static void 1239 str_putbq(queue_t *q, mblk_t *mp) 1240 { 1241 mblk_t *bp = NULL; 1242 mblk_t *nextp; 1243 1244 /* 1245 * Reverse the order of the chain. 1246 */ 1247 while (mp != NULL) { 1248 nextp = mp->b_next; 1249 1250 mp->b_next = bp; 1251 bp = mp; 1252 1253 mp = nextp; 1254 } 1255 1256 /* 1257 * Walk the reversed chain and put each message back on the 1258 * queue. 1259 */ 1260 while (bp != NULL) { 1261 nextp = bp->b_next; 1262 bp->b_next = NULL; 1263 1264 (void) putbq(q, bp); 1265 1266 bp = nextp; 1267 } 1268 } 1269