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 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/user.h> 32 #include <sys/vfs.h> 33 #include <sys/vnode.h> 34 #include <sys/file.h> 35 #include <sys/stream.h> 36 #include <sys/stropts.h> 37 #include <sys/strsubr.h> 38 #include <sys/dlpi.h> 39 #include <sys/vnode.h> 40 #include <sys/socket.h> 41 #include <sys/sockio.h> 42 #include <net/if.h> 43 44 #include <sys/cred.h> 45 #include <sys/sysmacros.h> 46 47 #include <sys/sad.h> 48 #include <sys/kstr.h> 49 #include <sys/bootconf.h> 50 #include <sys/bootprops.h> 51 52 #include <sys/errno.h> 53 #include <sys/modctl.h> 54 #include <sys/sunddi.h> 55 #include <sys/sunldi.h> 56 #include <sys/esunddi.h> 57 #include <sys/promif.h> 58 59 #include <netinet/in.h> 60 #include <netinet/ip6.h> 61 #include <netinet/icmp6.h> 62 #include <netinet/sctp.h> 63 #include <inet/common.h> 64 #include <inet/ip.h> 65 #include <inet/ip6.h> 66 #include <inet/tcp.h> 67 #include <inet/sctp_ip.h> 68 69 #include <sys/strlog.h> 70 #include <sys/log.h> 71 #include <sys/ethernet.h> 72 #include <sys/ddi_implfuncs.h> 73 74 #include <sys/dld.h> 75 76 /* 77 * Debug Macros 78 */ 79 int strplumbdebug = 0; 80 81 #define DBG0(_f) \ 82 if (strplumbdebug != 0) \ 83 printf("strplumb: " _f) 84 85 #define DBG1(_f, _a) \ 86 if (strplumbdebug != 0) \ 87 printf("strplumb: " _f, (_a)) 88 89 #define DBG2(_f, _a, _b) \ 90 if (strplumbdebug != 0) \ 91 printf("strplumb: " _f, (_a), (_b)) 92 93 #define DBG3(_f, _a, _b, _c) \ 94 if (strplumbdebug != 0) \ 95 printf("strplumb: " _f, (_a), (_b), (_c)) 96 97 /* 98 * Module linkage information for the kernel. 99 */ 100 #define STRPLUMB_IDENT "STREAMS Plumbing Module v%I%" 101 102 static struct modlmisc modlmisc = { 103 &mod_miscops, 104 STRPLUMB_IDENT 105 }; 106 107 static struct modlinkage modlinkage = { 108 MODREV_1, 109 &modlmisc, 110 NULL 111 }; 112 113 int 114 _init(void) 115 { 116 return (mod_install(&modlinkage)); 117 } 118 119 int 120 _fini(void) 121 { 122 return (mod_remove(&modlinkage)); 123 } 124 125 int 126 _info(struct modinfo *modinfop) 127 { 128 return (mod_info(&modlinkage, modinfop)); 129 } 130 131 #define ARP "arp" 132 #define TCP "tcp" 133 #define TCP6 "tcp6" 134 #define UDP "udp" 135 #define UDP6 "udp6" 136 #define SCTP "sctp" 137 #define SCTP6 "sctp6" 138 #define ICMP "icmp" 139 #define ICMP6 "icmp6" 140 #define IP "ip" 141 #define IP6 "ip6" 142 #define TIMOD "timod" 143 144 #define UDPDEV "/devices/pseudo/udp@0:udp" 145 #define TCP6DEV "/devices/pseudo/tcp6@0:tcp6" 146 #define SCTP6DEV "/devices/pseudo/sctp6@0:sctp6" 147 #define IP6DEV "/devices/pseudo/ip6@0:ip6" 148 149 typedef struct strplumb_modspec { 150 char *sm_type; 151 char *sm_name; 152 } strplumb_modspec_t; 153 154 static strplumb_modspec_t strplumb_modlist[] = { 155 { "drv", DLD_DRIVER_NAME }, 156 { "drv", IP }, 157 { "drv", IP6 }, 158 { "drv", TCP }, 159 { "drv", TCP6 }, 160 { "drv", UDP }, 161 { "drv", UDP6 }, 162 { "drv", SCTP }, 163 { "drv", SCTP6 }, 164 { "drv", ICMP }, 165 { "drv", ICMP6 }, 166 { "drv", ARP }, 167 { "strmod", TIMOD } 168 }; 169 170 /* 171 * Called from swapgeneric.c:loadrootmodules() in the network boot case. 172 */ 173 int 174 strplumb_load(void) 175 { 176 uint_t i; 177 strplumb_modspec_t *p; 178 179 DBG0("loading modules\n"); 180 181 for (i = 0, p = strplumb_modlist; 182 i < sizeof (strplumb_modlist) / sizeof (strplumb_modlist[0]); 183 i++, p++) { 184 if (modloadonly(p->sm_type, p->sm_name) < 0) { 185 printf("strplumb: failed to load %s/%s\n", 186 p->sm_type, p->sm_name); 187 return (EFAULT); 188 } 189 } 190 191 return (0); 192 } 193 194 static int 195 strplumb_init(void) 196 { 197 uint_t i; 198 strplumb_modspec_t *p; 199 int err; 200 201 DBG0("initializing modules\n"); 202 203 for (i = 0, p = strplumb_modlist; 204 i < sizeof (strplumb_modlist) / sizeof (strplumb_modlist[0]); 205 i++, p++) { 206 if (strcmp(p->sm_type, "drv") == 0) 207 err = (i_ddi_attach_pseudo_node(p->sm_name) != NULL) ? 208 0 : EFAULT; 209 else 210 err = (modload(p->sm_type, p->sm_name) < 0) ? 211 EFAULT : 0; 212 213 if (err != 0) { 214 printf("strplumb: failed to initialize %s/%s\n", 215 p->sm_type, p->sm_name); 216 return (err); 217 } 218 } 219 220 return (0); 221 } 222 223 static int 224 strplumb_autopush(void) 225 { 226 major_t maj; 227 minor_t min; 228 char *mods[5]; 229 uint_t anchor = 1; 230 int err; 231 232 min = (minor_t)-1; 233 mods[1] = NULL; 234 235 /* 236 * UDP 237 */ 238 DBG0("setting up udp autopush\n"); 239 240 mods[0] = UDP; 241 242 maj = ddi_name_to_major(UDP); 243 if ((err = kstr_autopush(SET_AUTOPUSH, &maj, &min, NULL, &anchor, 244 mods)) != 0) { 245 printf("strplumb: kstr_autopush(SET/UDP) failed: %d\n", err); 246 return (err); 247 } 248 249 maj = ddi_name_to_major(UDP6); 250 if ((err = kstr_autopush(SET_AUTOPUSH, &maj, &min, NULL, &anchor, 251 mods)) != 0) { 252 printf("strplumb: kstr_autopush(SET/UDP6) failed: %d\n", err); 253 return (err); 254 } 255 256 /* 257 * ICMP 258 */ 259 DBG0("setting up icmp autopush\n"); 260 261 mods[0] = ICMP; 262 263 maj = ddi_name_to_major(ICMP); 264 if ((err = kstr_autopush(SET_AUTOPUSH, &maj, &min, NULL, NULL, 265 mods)) != 0) { 266 printf("strplumb: kstr_autopush(SET/ICMP) failed: %d\n", err); 267 return (err); 268 } 269 270 maj = ddi_name_to_major(ICMP6); 271 if ((err = kstr_autopush(SET_AUTOPUSH, &maj, &min, NULL, NULL, 272 mods)) != 0) { 273 printf("strplumb: kstr_autopush(SET/ICMP6) failed: %d\n", err); 274 return (err); 275 } 276 277 /* 278 * ARP 279 */ 280 DBG0("setting up arp autopush\n"); 281 282 mods[0] = ARP; 283 284 maj = ddi_name_to_major(ARP); 285 if ((err = kstr_autopush(SET_AUTOPUSH, &maj, &min, NULL, &anchor, 286 mods)) != 0) { 287 printf("strplumb: kstr_autopush(SET/ARP) failed: %d\n", err); 288 return (err); 289 } 290 291 return (0); 292 } 293 294 static int 295 strplumb_sctpq(ldi_ident_t li) 296 { 297 ldi_handle_t lh = NULL; 298 int err; 299 int rval; 300 301 DBG0("configuring SCTP default queue\n"); 302 303 if ((err = ldi_open_by_name(SCTP6DEV, FREAD|FWRITE, CRED(), &lh, 304 li)) != 0) { 305 printf("strplumb: open of SCTP6DEV failed: %d\n", err); 306 return (err); 307 } 308 309 if ((err = ldi_ioctl(lh, SCTP_IOC_DEFAULT_Q, (intptr_t)0, FKIOCTL, 310 CRED(), &rval)) != 0) { 311 printf("strplumb: failed to set SCTP default queue: %d\n", 312 err); 313 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 314 return (err); 315 } 316 317 return (0); 318 } 319 320 static int 321 strplumb_tcpq(ldi_ident_t li) 322 { 323 ldi_handle_t lh = NULL; 324 ldi_handle_t ip_lh = NULL; 325 int err; 326 int rval; 327 328 DBG0("configuring TCP default queue\n"); 329 330 /* 331 * We open IP6DEV here because we need to have it open to in 332 * order to open TCP6DEV successfully. 333 */ 334 if ((err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, CRED(), &ip_lh, 335 li)) != 0) { 336 printf("strplumb: open of IP6DEV failed: %d\n", err); 337 return (err); 338 } 339 340 /* 341 * We set the tcp default queue to IPv6 because IPv4 falls back to 342 * IPv6 when it can't find a client, but IPv6 does not fall back to 343 * IPv4. 344 */ 345 if ((err = ldi_open_by_name(TCP6DEV, FREAD|FWRITE, CRED(), &lh, 346 li)) != 0) { 347 printf("strplumb: open of TCP6DEV failed: %d\n", err); 348 goto done; 349 } 350 351 if ((err = ldi_ioctl(lh, TCP_IOC_DEFAULT_Q, (intptr_t)0, FKIOCTL, 352 CRED(), &rval)) != 0) { 353 printf("strplumb: failed to set TCP default queue: %d\n", 354 err); 355 goto done; 356 } 357 358 done: 359 (void) ldi_close(ip_lh, FREAD|FWRITE, CRED()); 360 return (err); 361 } 362 363 /* 364 * Can be set in /etc/system in the case of local booting. See comment below. 365 */ 366 char *ndev_name = 0; 367 int ndev_unit = 0; 368 369 /* 370 * If we booted diskless then strplumb() will have been called from 371 * swapgeneric.c:rootconf(). All we can do in that case is plumb the 372 * network device that we booted from. 373 * 374 * If we booted from a local disk, we will have been called from main(), 375 * and normally we defer the plumbing of interfaces until network/physical. 376 * This can be overridden by setting "ndev_name" in /etc/system. 377 */ 378 static int 379 resolve_boot_path(void) 380 { 381 char *devpath = NULL; 382 dev_info_t *dip; 383 const char *driver; 384 int instance; 385 386 if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) 387 devpath = rootfs.bo_name; 388 #ifndef __sparc 389 else 390 devpath = strplumb_get_netdev_path(); 391 #endif 392 393 if (devpath != NULL) { 394 DBG1("resolving boot-path: %s\n", devpath); 395 396 /* 397 * Hold the devi since this is the root device. 398 */ 399 if ((dip = e_ddi_hold_devi_by_path(devpath, 0)) == NULL) { 400 printf("strplumb: unable to hold root device: %s\n", 401 devpath); 402 return (ENXIO); 403 } 404 405 driver = ddi_driver_name(dip); 406 instance = ddi_get_instance(dip); 407 } else { 408 if (ndev_name == NULL) 409 return (ENODEV); 410 411 DBG2("using ndev_name (%s) ndev_unit (%d)\n", ndev_name, 412 ndev_unit); 413 414 if (i_ddi_attach_hw_nodes(ndev_name) != DDI_SUCCESS) { 415 printf("strplumb: cannot load ndev_name '%s'\n", 416 ndev_name); 417 return (ENXIO); 418 } 419 420 driver = ndev_name; 421 instance = ndev_unit; 422 } 423 424 (void) snprintf(rootfs.bo_devname, BO_MAXOBJNAME, 425 "/devices/pseudo/clone@0:%s", driver); 426 (void) snprintf(rootfs.bo_ifname, BO_MAXOBJNAME, "%s%d", 427 driver, instance); 428 rootfs.bo_ppa = instance; 429 return (0); 430 } 431 432 static int 433 getifflags(ldi_handle_t lh, struct lifreq *lifrp) 434 { 435 struct strioctl iocb; 436 int rval; 437 438 iocb.ic_cmd = SIOCGLIFFLAGS; 439 iocb.ic_timout = 15; 440 iocb.ic_len = sizeof (struct lifreq); 441 iocb.ic_dp = (char *)lifrp; 442 443 return (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, CRED(), &rval)); 444 445 } 446 447 static int 448 setifname(ldi_handle_t lh, struct lifreq *lifrp) 449 { 450 struct strioctl iocb; 451 int rval; 452 453 iocb.ic_cmd = SIOCSLIFNAME; 454 iocb.ic_timout = 15; 455 iocb.ic_len = sizeof (struct lifreq); 456 iocb.ic_dp = (char *)lifrp; 457 458 return (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, CRED(), &rval)); 459 } 460 461 static int 462 strplumb_dev(ldi_ident_t li) 463 { 464 ldi_handle_t lh = NULL; 465 ldi_handle_t mux_lh = NULL; 466 int err; 467 struct lifreq lifr; 468 struct ifreq ifr; 469 int rval; 470 471 bzero(&lifr, sizeof (struct lifreq)); 472 bzero(&ifr, sizeof (ifr)); 473 474 /* 475 * Now set up the links. Ultimately, we should have two streams 476 * permanently linked underneath UDP (which is actually IP with UDP 477 * autopushed). One stream consists of the ARP-[ifname] combination, 478 * while the other consists of ARP-IP-[ifname]. The second combination 479 * seems a little weird, but is linked underneath UDP just to keep it 480 * around. 481 * 482 * We pin underneath UDP here to match what is done in ifconfig(1m); 483 * otherwise, ifconfig will be unable to unplumb the stream (the major 484 * number and mux id must both match for a successful I_PUNLINK). 485 * 486 * There are subtleties in the plumbing which make it essential to 487 * follow the logic used in ifconfig(1m) very closely. 488 */ 489 490 /* 491 * Plumb UDP-ARP-IP-<dev> 492 */ 493 494 if ((err = ldi_open_by_name(rootfs.bo_devname, FREAD|FWRITE, CRED(), 495 &lh, li)) != 0) { 496 printf("strplumb: open %s failed: %d\n", rootfs.bo_devname, 497 err); 498 goto done; 499 } 500 501 502 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)IP, FKIOCTL, CRED(), 503 &rval)) != 0) { 504 printf("strplumb: push IP failed: %d\n", err); 505 goto done; 506 } 507 508 if ((err = getifflags(lh, &lifr)) != 0) 509 goto done; 510 511 lifr.lifr_flags |= IFF_IPV4; 512 lifr.lifr_flags &= ~IFF_IPV6; 513 514 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)ARP, FKIOCTL, CRED(), 515 &rval)) != 0) { 516 printf("strplumb: push ARP failed: %d\n", err); 517 goto done; 518 } 519 520 (void) strlcpy(lifr.lifr_name, rootfs.bo_ifname, 521 sizeof (lifr.lifr_name)); 522 lifr.lifr_ppa = rootfs.bo_ppa; 523 524 if ((err = setifname(lh, &lifr)) != 0) 525 goto done; 526 527 /* Get the flags and check if ARP is needed */ 528 if ((err = getifflags(lh, &lifr)) != 0) { 529 printf("strplumb: getifflags %s IP failed, error %d\n", 530 lifr.lifr_name, err); 531 goto done; 532 } 533 534 /* Pop out ARP if not needed */ 535 if (lifr.lifr_flags & IFF_NOARP) { 536 err = ldi_ioctl(lh, I_POP, (intptr_t)0, FKIOCTL, CRED(), 537 &rval); 538 if (err != 0) { 539 printf("strplumb: pop ARP failed, error %d\n", err); 540 goto done; 541 } 542 } 543 544 if ((err = ldi_open_by_name(UDPDEV, FREAD|FWRITE, CRED(), &mux_lh, 545 li)) != 0) { 546 printf("strplumb: open of UDPDEV failed: %d\n", err); 547 goto done; 548 } 549 550 if ((err = ldi_ioctl(mux_lh, I_PLINK, (intptr_t)lh, 551 FREAD|FWRITE|FNOCTTY|FKIOCTL, CRED(), 552 &(ifr.ifr_ip_muxid))) != 0) { 553 printf("strplumb: plink UDP-ARP-IP-%s failed: %d\n", 554 rootfs.bo_ifname, err); 555 goto done; 556 } 557 558 DBG2("UDP-ARP-IP-%s muxid: %d\n", rootfs.bo_ifname, ifr.ifr_ip_muxid); 559 560 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 561 lh = NULL; 562 563 /* 564 * Plumb UDP-ARP-<dev> 565 */ 566 567 if ((err = ldi_open_by_name(rootfs.bo_devname, FREAD|FWRITE, CRED(), 568 &lh, li)) != 0) { 569 printf("strplumb: open %s failed: %d\n", rootfs.bo_devname, 570 err); 571 goto done; 572 } 573 574 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)ARP, FKIOCTL, CRED(), 575 &rval)) != 0) { 576 printf("strplumb: push ARP failed: %d\n", err); 577 goto done; 578 } 579 580 if ((err = setifname(lh, &lifr)) != 0) 581 goto done; 582 583 if ((err = ldi_ioctl(mux_lh, I_PLINK, (intptr_t)lh, 584 FREAD|FWRITE|FNOCTTY|FKIOCTL, CRED(), 585 &(ifr.ifr_arp_muxid))) != 0) { 586 printf("strplumb: plink UDP-ARP-%s failed: %d\n", 587 rootfs.bo_ifname, err); 588 goto done; 589 } 590 591 DBG2("UDP-ARP-%s muxid: %d\n", rootfs.bo_ifname, ifr.ifr_arp_muxid); 592 593 /* 594 * Cache the mux ids. 595 */ 596 (void) strlcpy(ifr.ifr_name, rootfs.bo_ifname, sizeof (ifr.ifr_name)); 597 598 if ((err = ldi_ioctl(mux_lh, SIOCSIFMUXID, (intptr_t)&ifr, FKIOCTL, 599 CRED(), &rval)) != 0) { 600 printf("strplumb: SIOCSIFMUXID failed: %d\n", err); 601 goto done; 602 } 603 604 done: 605 if (lh != NULL) 606 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 607 608 if (mux_lh != NULL) 609 (void) ldi_close(mux_lh, FREAD|FWRITE, CRED()); 610 611 return (err); 612 } 613 614 /* 615 * Do streams plumbing for internet protocols. 616 */ 617 int 618 strplumb(void) 619 { 620 ldi_ident_t li; 621 int err; 622 623 if ((err = strplumb_init()) != 0) 624 return (err); 625 626 if ((err = strplumb_autopush()) != 0) 627 return (err); 628 629 if ((err = ldi_ident_from_mod(&modlinkage, &li)) != 0) 630 return (err); 631 632 if ((err = strplumb_sctpq(li)) != 0) 633 goto done; 634 635 if ((err = strplumb_tcpq(li)) != 0) 636 goto done; 637 638 if ((err = resolve_boot_path()) != 0) 639 goto done; 640 641 DBG1("rootfs.bo_devname: %s\n", rootfs.bo_devname); 642 DBG1("rootfs.bo_ifname: %s\n", rootfs.bo_ifname); 643 DBG1("rootfs.bo_ppa: %d\n", rootfs.bo_ppa); 644 645 if ((err = strplumb_dev(li)) != 0) 646 goto done; 647 648 done: 649 ldi_ident_release(li); 650 651 return (err); 652 } 653 654 /* multiboot: diskless boot interface discovery */ 655 656 #ifndef __sparc 657 658 static uchar_t boot_macaddr[16]; 659 static int boot_maclen; 660 static uchar_t *getmacaddr(dev_info_t *dip, int *maclen); 661 static int matchmac(dev_info_t *dip, void *arg); 662 int dl_attach(ldi_handle_t lh, int unit); 663 int dl_bind(ldi_handle_t lh, uint_t sap, uint_t max_conn, 664 uint_t service, uint_t conn_mgmt); 665 int dl_phys_addr(ldi_handle_t lh, struct ether_addr *eaddr); 666 667 char * 668 strplumb_get_netdev_path(void) 669 { 670 char *macstr, *devpath = NULL; 671 uchar_t *bootp; 672 uint_t bootp_len, len; 673 674 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 675 DDI_PROP_DONTPASS, BP_BOOT_MAC, &macstr) == DDI_SUCCESS) { 676 /* 677 * hard coded ether mac len for booting floppy on 678 * machines with old cards 679 */ 680 boot_maclen = ether_aton(macstr, boot_macaddr); 681 if (boot_maclen != 6) { 682 cmn_err(CE_WARN, 683 "malformed boot_mac property, %d bytes", 684 boot_maclen); 685 } 686 ddi_prop_free(macstr); 687 } else if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 688 DDI_PROP_DONTPASS, BP_BOOTP_RESPONSE, &bootp, &bootp_len) 689 == DDI_SUCCESS) { 690 691 /* 692 * These offsets are defined by dhcp standard 693 * Should use structure offsets 694 */ 695 boot_maclen = *(bootp + 2); 696 ASSERT(boot_maclen <= 16); 697 (void) bcopy(bootp + 28, boot_macaddr, boot_maclen); 698 699 /* encode to ascii string to match what sparc OBP exports */ 700 dhcack = kmem_zalloc(bootp_len * 2 + IFNAMSIZ + 2, KM_SLEEP); 701 (void) octet_to_hexascii(bootp, bootp_len, dhcack + IFNAMSIZ, 702 &len); 703 ASSERT(len < bootp_len * 2 + 2); 704 ddi_prop_free(bootp); 705 } else 706 return (NULL); 707 708 ddi_walk_devs(ddi_root_node(), matchmac, (void *)&devpath); 709 return (devpath); 710 } 711 712 /* 713 * Get boot path from the boot_mac address 714 */ 715 /*ARGSUSED*/ 716 static int 717 matchmac(dev_info_t *dip, void *arg) 718 { 719 char **devpathp = (char **)arg; 720 char *model_str; 721 uchar_t *macaddr; 722 int maclen; 723 724 /* XXX Should use "device-type" per IEEE 1275 */ 725 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 726 "model", &model_str) != DDI_SUCCESS) 727 return (DDI_WALK_CONTINUE); 728 729 if (strcmp(model_str, "Ethernet controller") != 0) { 730 ddi_prop_free(model_str); 731 return (DDI_WALK_CONTINUE); 732 } 733 ddi_prop_free(model_str); 734 735 /* We have a network device now */ 736 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) { 737 return (DDI_WALK_CONTINUE); 738 } 739 740 ASSERT(boot_maclen != 0); 741 macaddr = getmacaddr(dip, &maclen); 742 if (macaddr == NULL) 743 return (DDI_WALK_CONTINUE); 744 745 if (maclen != boot_maclen || 746 bcmp(macaddr, boot_macaddr, maclen) != 0) { 747 kmem_free(macaddr, maclen); 748 return (DDI_WALK_CONTINUE); 749 } 750 751 /* found hardware with the mac address */ 752 (void) localetheraddr((struct ether_addr *)macaddr, NULL); 753 kmem_free(macaddr, maclen); 754 755 *devpathp = kmem_alloc(MAXPATHLEN, KM_SLEEP); 756 (void) ddi_pathname(dip, *devpathp); 757 758 /* fill in the name portion of dhcack */ 759 if (dhcack) 760 (void) snprintf(dhcack, IFNAMSIZ, "%s%d", 761 ddi_driver_name(dip), i_ddi_devi_get_ppa(dip)); 762 return (DDI_WALK_TERMINATE); 763 } 764 765 static uchar_t * 766 getmacaddr_gldv3(char *drv, int inst, int *maclenp) 767 { 768 char ifname[16]; 769 mac_handle_t mh; 770 uchar_t *macaddr; 771 772 (void) snprintf(ifname, sizeof (ifname), "%s%d", drv, inst); 773 if (mac_open(ifname, 0, &mh) < 0) { 774 return (NULL); 775 } 776 *maclenp = sizeof (struct ether_addr); 777 macaddr = kmem_alloc(*maclenp, KM_SLEEP); 778 mac_unicst_get(mh, macaddr); 779 mac_close(mh); 780 781 return (macaddr); 782 } 783 784 static uchar_t * 785 getmacaddr(dev_info_t *dip, int *maclenp) 786 { 787 int rc, ppa; 788 ldi_ident_t li; 789 ldi_handle_t lh; 790 char *drv_name = (char *)ddi_driver_name(dip); 791 char *clonepath; 792 uchar_t *macaddr = NULL; 793 794 /* a simpler way to get mac address for GLDv3 drivers */ 795 if (GLDV3_DRV(ddi_name_to_major(drv_name))) { 796 return (getmacaddr_gldv3(drv_name, ddi_get_instance(dip), 797 maclenp)); 798 } 799 800 if (rc = ldi_ident_from_mod(&modlinkage, &li)) { 801 cmn_err(CE_WARN, 802 "getmacaddr: ldi_ident_from_mod failed: %d\n", rc); 803 return (NULL); 804 } 805 806 clonepath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 807 (void) snprintf(clonepath, MAXPATHLEN, 808 "/devices/pseudo/clone@0:%s", drv_name); 809 810 rc = ldi_open_by_name(clonepath, FREAD|FWRITE, CRED(), &lh, li); 811 ldi_ident_release(li); 812 if (rc) { 813 cmn_err(CE_WARN, 814 "getmacaddr: ldi_open_by_name(%s) failed: %d\n", 815 clonepath, rc); 816 kmem_free(clonepath, MAXPATHLEN); 817 return (NULL); 818 } 819 kmem_free(clonepath, MAXPATHLEN); 820 821 ppa = i_ddi_devi_get_ppa(dip); 822 if ((dl_attach(lh, ppa) != 0) || 823 (dl_bind(lh, ETHERTYPE_IP, 0, DL_CLDLS, 0) != 0)) { 824 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 825 cmn_err(CE_WARN, 826 "getmacaddr: dl_attach/bind(%s%d) failed: %d\n", 827 drv_name, ppa, rc); 828 return (NULL); 829 } 830 *maclenp = sizeof (struct ether_addr); 831 macaddr = kmem_alloc(*maclenp, KM_SLEEP); 832 if (dl_phys_addr(lh, (struct ether_addr *)macaddr) != 0) { 833 kmem_free(macaddr, *maclenp); 834 macaddr = NULL; 835 *maclenp = 0; 836 cmn_err(CE_WARN, 837 "getmacaddr: dl_macaddr(%s%d) failed: %d\n", 838 drv_name, ppa, rc); 839 } 840 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 841 return (macaddr); 842 } 843 844 #endif /* !__sparc */ 845 846 int 847 dl_attach(ldi_handle_t lh, int unit) 848 { 849 dl_attach_req_t *attach_req; 850 dl_error_ack_t *error_ack; 851 union DL_primitives *dl_prim; 852 mblk_t *mp; 853 int error; 854 855 if ((mp = allocb(sizeof (dl_attach_req_t), BPRI_MED)) == NULL) { 856 cmn_err(CE_WARN, "dl_attach: allocb failed"); 857 return (ENOSR); 858 } 859 mp->b_datap->db_type = M_PROTO; 860 mp->b_wptr += sizeof (dl_attach_req_t); 861 862 attach_req = (dl_attach_req_t *)mp->b_rptr; 863 attach_req->dl_primitive = DL_ATTACH_REQ; 864 attach_req->dl_ppa = unit; 865 866 (void) ldi_putmsg(lh, mp); 867 if ((error = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) { 868 printf("dl_attach: ldi_getmsg failed: %d\n", error); 869 return (error); 870 } 871 872 dl_prim = (union DL_primitives *)mp->b_rptr; 873 switch (dl_prim->dl_primitive) { 874 case DL_OK_ACK: 875 if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_ok_ack_t)) { 876 printf("dl_attach: DL_OK_ACK protocol error\n"); 877 break; 878 } 879 if (((dl_ok_ack_t *)dl_prim)->dl_correct_primitive != 880 DL_ATTACH_REQ) { 881 printf("dl_attach: DL_OK_ACK rtnd prim %u\n", 882 ((dl_ok_ack_t *)dl_prim)->dl_correct_primitive); 883 break; 884 } 885 freemsg(mp); 886 return (0); 887 888 case DL_ERROR_ACK: 889 if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { 890 printf("dl_attach: DL_ERROR_ACK protocol error\n"); 891 break; 892 } 893 894 error_ack = (dl_error_ack_t *)dl_prim; 895 switch (error_ack->dl_errno) { 896 case DL_BADPPA: 897 printf("dl_attach: DL_ERROR_ACK bad PPA\n"); 898 break; 899 900 case DL_ACCESS: 901 printf("dl_attach: DL_ERROR_ACK access error\n"); 902 break; 903 904 default: 905 printf("dl_attach: DLPI error %u\n", 906 error_ack->dl_errno); 907 break; 908 } 909 break; 910 911 default: 912 printf("dl_attach: bad ACK header %u\n", dl_prim->dl_primitive); 913 break; 914 } 915 916 /* 917 * Error return only. 918 */ 919 freemsg(mp); 920 return (-1); 921 } 922 923 int 924 dl_bind(ldi_handle_t lh, uint_t sap, uint_t max_conn, uint_t service, 925 uint_t conn_mgmt) 926 { 927 dl_bind_req_t *bind_req; 928 dl_error_ack_t *error_ack; 929 union DL_primitives *dl_prim; 930 mblk_t *mp; 931 int error; 932 933 if ((mp = allocb(sizeof (dl_bind_req_t), BPRI_MED)) == NULL) { 934 cmn_err(CE_WARN, "dl_bind: allocb failed"); 935 return (ENOSR); 936 } 937 mp->b_datap->db_type = M_PROTO; 938 939 bind_req = (dl_bind_req_t *)mp->b_wptr; 940 mp->b_wptr += sizeof (dl_bind_req_t); 941 bind_req->dl_primitive = DL_BIND_REQ; 942 bind_req->dl_sap = sap; 943 bind_req->dl_max_conind = max_conn; 944 bind_req->dl_service_mode = service; 945 bind_req->dl_conn_mgmt = conn_mgmt; 946 bind_req->dl_xidtest_flg = 0; 947 948 (void) ldi_putmsg(lh, mp); 949 if ((error = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) { 950 printf("dl_bind: ldi_getmsg failed: %d\n", error); 951 return (error); 952 } 953 954 dl_prim = (union DL_primitives *)mp->b_rptr; 955 switch (dl_prim->dl_primitive) { 956 case DL_BIND_ACK: 957 if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_bind_ack_t)) { 958 printf("dl_bind: DL_BIND_ACK protocol error\n"); 959 break; 960 } 961 if (((dl_bind_ack_t *)dl_prim)->dl_sap != sap) { 962 printf("dl_bind: DL_BIND_ACK bad sap %u\n", 963 ((dl_bind_ack_t *)dl_prim)->dl_sap); 964 break; 965 } 966 freemsg(mp); 967 return (0); 968 969 case DL_ERROR_ACK: 970 if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { 971 printf("dl_bind: DL_ERROR_ACK protocol error\n"); 972 break; 973 } 974 975 error_ack = (dl_error_ack_t *)dl_prim; 976 printf("dl_bind: DLPI error %u\n", error_ack->dl_errno); 977 break; 978 979 default: 980 printf("dl_bind: bad ACK header %u\n", dl_prim->dl_primitive); 981 break; 982 } 983 984 /* 985 * Error return only. 986 */ 987 freemsg(mp); 988 return (-1); 989 } 990 991 int 992 dl_phys_addr(ldi_handle_t lh, struct ether_addr *eaddr) 993 { 994 dl_phys_addr_req_t *phys_addr_req; 995 dl_phys_addr_ack_t *phys_addr_ack; 996 dl_error_ack_t *error_ack; 997 union DL_primitives *dl_prim; 998 mblk_t *mp; 999 int error; 1000 uchar_t *addrp; 1001 timestruc_t tv; 1002 1003 if ((mp = allocb(sizeof (dl_phys_addr_req_t), BPRI_MED)) == 1004 (mblk_t *)NULL) { 1005 cmn_err(CE_WARN, "dl_phys_addr: allocb failed"); 1006 return (ENOSR); 1007 } 1008 mp->b_datap->db_type = M_PROTO; 1009 mp->b_wptr += sizeof (dl_phys_addr_req_t); 1010 1011 phys_addr_req = (dl_phys_addr_req_t *)mp->b_rptr; 1012 phys_addr_req->dl_primitive = DL_PHYS_ADDR_REQ; 1013 phys_addr_req->dl_addr_type = DL_CURR_PHYS_ADDR; 1014 1015 /* 1016 * In case some provider doesn't implement or nack the 1017 * request just wait for 15 seconds. 1018 */ 1019 tv.tv_sec = 15; 1020 tv.tv_nsec = 0; 1021 1022 (void) ldi_putmsg(lh, mp); 1023 error = ldi_getmsg(lh, &mp, &tv); 1024 if (error == ETIME) { 1025 printf("dl_phys_addr: timed out\n"); 1026 return (-1); 1027 } else if (error != 0) { 1028 printf("dl_phys_addr: ldi_getmsg failed: %d\n", error); 1029 return (error); 1030 } 1031 1032 dl_prim = (union DL_primitives *)mp->b_rptr; 1033 switch (dl_prim->dl_primitive) { 1034 case DL_PHYS_ADDR_ACK: 1035 if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_phys_addr_ack_t)) { 1036 printf("dl_phys_addr: " 1037 "DL_PHYS_ADDR_ACK protocol error\n"); 1038 break; 1039 } 1040 phys_addr_ack = &dl_prim->physaddr_ack; 1041 if (phys_addr_ack->dl_addr_length != sizeof (*eaddr)) { 1042 printf("dl_phys_addr: DL_PHYS_ADDR_ACK bad len %u\n", 1043 phys_addr_ack->dl_addr_length); 1044 break; 1045 } 1046 if (phys_addr_ack->dl_addr_length + 1047 phys_addr_ack->dl_addr_offset > (mp->b_wptr-mp->b_rptr)) { 1048 printf("dl_phys_addr: DL_PHYS_ADDR_ACK bad len %u\n", 1049 phys_addr_ack->dl_addr_length); 1050 break; 1051 } 1052 addrp = mp->b_rptr + phys_addr_ack->dl_addr_offset; 1053 bcopy(addrp, eaddr, sizeof (*eaddr)); 1054 freemsg(mp); 1055 return (0); 1056 1057 case DL_ERROR_ACK: 1058 if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { 1059 printf("dl_phys_addr: DL_ERROR_ACK protocol error\n"); 1060 break; 1061 } 1062 1063 error_ack = (dl_error_ack_t *)dl_prim; 1064 printf("dl_phys_addr: DLPI error %u\n", 1065 error_ack->dl_errno); 1066 break; 1067 1068 default: 1069 printf("dl_phys_addr: bad ACK header %u\n", 1070 dl_prim->dl_primitive); 1071 break; 1072 } 1073 1074 /* 1075 * Error return only. 1076 */ 1077 freemsg(mp); 1078 return (-1); 1079 } 1080