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 #include <sys/param.h> 27 #include <sys/types.h> 28 #include <sys/user.h> 29 #include <sys/vfs.h> 30 #include <sys/vnode.h> 31 #include <sys/file.h> 32 #include <sys/stream.h> 33 #include <sys/stropts.h> 34 #include <sys/strsubr.h> 35 #include <sys/dlpi.h> 36 #include <sys/vnode.h> 37 #include <sys/socket.h> 38 #include <sys/sockio.h> 39 #include <net/if.h> 40 41 #include <sys/cred.h> 42 #include <sys/sysmacros.h> 43 44 #include <sys/sad.h> 45 #include <sys/kstr.h> 46 #include <sys/bootconf.h> 47 #include <sys/bootprops.h> 48 49 #include <sys/errno.h> 50 #include <sys/modctl.h> 51 #include <sys/sunddi.h> 52 #include <sys/sunldi.h> 53 #include <sys/esunddi.h> 54 #include <sys/promif.h> 55 56 #include <netinet/in.h> 57 #include <netinet/ip6.h> 58 #include <netinet/icmp6.h> 59 #include <netinet/sctp.h> 60 #include <inet/common.h> 61 #include <inet/ip.h> 62 #include <inet/ip6.h> 63 #include <inet/tcp.h> 64 #include <inet/sctp_ip.h> 65 66 #include <sys/strlog.h> 67 #include <sys/log.h> 68 #include <sys/ethernet.h> 69 #include <sys/ddi_implfuncs.h> 70 71 #include <sys/dld.h> 72 #include <sys/mac.h> 73 74 /* 75 * Debug Macros 76 */ 77 int strplumbdebug = 0; 78 79 extern ib_boot_prop_t *iscsiboot_prop; 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" 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 UDP6DEV "/devices/pseudo/udp6@0:udp6" 147 #define SCTP6DEV "/devices/pseudo/sctp6@0:sctp6" 148 #define IP6DEV "/devices/pseudo/ip6@0:ip6" 149 150 typedef struct strplumb_modspec { 151 char *sm_type; 152 char *sm_name; 153 } strplumb_modspec_t; 154 155 static strplumb_modspec_t strplumb_modlist[] = { 156 { "drv", DLD_DRIVER_NAME }, 157 { "drv", IP }, 158 { "drv", IP6 }, 159 { "drv", TCP }, 160 { "drv", TCP6 }, 161 { "drv", UDP }, 162 { "drv", UDP6 }, 163 { "drv", SCTP }, 164 { "drv", SCTP6 }, 165 { "drv", ICMP }, 166 { "drv", ICMP6 }, 167 { "drv", ARP }, 168 { "strmod", TIMOD } 169 }; 170 171 /* 172 * Called from swapgeneric.c:loadrootmodules() in the network boot case. 173 */ 174 int 175 strplumb_load(void) 176 { 177 uint_t i; 178 strplumb_modspec_t *p; 179 180 DBG0("loading modules\n"); 181 182 for (i = 0, p = strplumb_modlist; 183 i < sizeof (strplumb_modlist) / sizeof (strplumb_modlist[0]); 184 i++, p++) { 185 if (modloadonly(p->sm_type, p->sm_name) < 0) { 186 printf("strplumb: failed to load %s/%s\n", 187 p->sm_type, p->sm_name); 188 return (EFAULT); 189 } 190 } 191 192 return (0); 193 } 194 195 static int 196 strplumb_init(void) 197 { 198 uint_t i; 199 strplumb_modspec_t *p; 200 int err; 201 202 DBG0("initializing modules\n"); 203 204 for (i = 0, p = strplumb_modlist; 205 i < sizeof (strplumb_modlist) / sizeof (strplumb_modlist[0]); 206 i++, p++) { 207 if (strcmp(p->sm_type, "drv") == 0) 208 err = (i_ddi_attach_pseudo_node(p->sm_name) != NULL) ? 209 0 : EFAULT; 210 else 211 err = (modload(p->sm_type, p->sm_name) < 0) ? 212 EFAULT : 0; 213 214 if (err != 0) { 215 printf("strplumb: failed to initialize %s/%s\n", 216 p->sm_type, p->sm_name); 217 return (err); 218 } 219 } 220 221 return (0); 222 } 223 224 static int 225 strplumb_autopush(void) 226 { 227 major_t maj; 228 minor_t min; 229 char *mods[5]; 230 uint_t anchor = 1; 231 int err; 232 233 min = (minor_t)-1; 234 mods[1] = NULL; 235 236 /* 237 * ARP 238 */ 239 DBG0("setting up arp autopush\n"); 240 241 mods[0] = ARP; 242 243 maj = ddi_name_to_major(ARP); 244 if ((err = kstr_autopush(SET_AUTOPUSH, &maj, &min, NULL, &anchor, 245 mods)) != 0) { 246 printf("strplumb: kstr_autopush(SET/ARP) failed: %d\n", err); 247 return (err); 248 } 249 250 return (0); 251 } 252 253 static int 254 strplumb_sctpq(ldi_ident_t li) 255 { 256 ldi_handle_t lh = NULL; 257 int err; 258 int rval; 259 260 DBG0("configuring SCTP default queue\n"); 261 262 if ((err = ldi_open_by_name(SCTP6DEV, FREAD|FWRITE, CRED(), &lh, 263 li)) != 0) { 264 printf("strplumb: open of SCTP6DEV failed: %d\n", err); 265 return (err); 266 } 267 268 if ((err = ldi_ioctl(lh, SCTP_IOC_DEFAULT_Q, (intptr_t)0, FKIOCTL, 269 CRED(), &rval)) != 0) { 270 printf("strplumb: failed to set SCTP default queue: %d\n", 271 err); 272 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 273 return (err); 274 } 275 276 return (0); 277 } 278 279 static int 280 strplumb_tcpq(ldi_ident_t li) 281 { 282 ldi_handle_t lh = NULL; 283 ldi_handle_t ip_lh = NULL; 284 int err; 285 int rval; 286 287 DBG0("configuring TCP default queue\n"); 288 289 /* 290 * We open IP6DEV here because we need to have it open to in 291 * order to open TCP6DEV successfully. 292 */ 293 if ((err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, CRED(), &ip_lh, 294 li)) != 0) { 295 printf("strplumb: open of IP6DEV failed: %d\n", err); 296 return (err); 297 } 298 299 /* 300 * We set the tcp default queue to IPv6 because IPv4 falls back to 301 * IPv6 when it can't find a client, but IPv6 does not fall back to 302 * IPv4. 303 */ 304 if ((err = ldi_open_by_name(TCP6DEV, FREAD|FWRITE, CRED(), &lh, 305 li)) != 0) { 306 printf("strplumb: open of TCP6DEV failed: %d\n", err); 307 goto done; 308 } 309 310 if ((err = ldi_ioctl(lh, TCP_IOC_DEFAULT_Q, (intptr_t)0, FKIOCTL, 311 CRED(), &rval)) != 0) { 312 printf("strplumb: failed to set TCP default queue: %d\n", 313 err); 314 goto done; 315 } 316 317 done: 318 (void) ldi_close(ip_lh, FREAD|FWRITE, CRED()); 319 return (err); 320 } 321 322 /* 323 * Can be set in /etc/system in the case of local booting. See comment below. 324 */ 325 char *ndev_name = 0; 326 int ndev_unit = 0; 327 328 /* 329 * If we booted diskless then strplumb() will have been called from 330 * swapgeneric.c:rootconf(). All we can do in that case is plumb the 331 * network device that we booted from. 332 * 333 * If we booted from a local disk, we will have been called from main(), 334 * and normally we defer the plumbing of interfaces until network/physical. 335 * This can be overridden by setting "ndev_name" in /etc/system. 336 */ 337 static int 338 resolve_boot_path(void) 339 { 340 char *devpath; 341 dev_info_t *dip; 342 const char *driver; 343 int instance; 344 #ifdef _OBP 345 char stripped_path[OBP_MAXPATHLEN]; 346 #endif 347 348 if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) 349 devpath = rootfs.bo_name; 350 else 351 devpath = strplumb_get_netdev_path(); 352 353 if (devpath != NULL) { 354 DBG1("resolving boot-path: %s\n", devpath); 355 #ifdef _OBP 356 /* 357 * OBP passes options e.g, "net:dhcp" 358 * remove them here 359 */ 360 prom_strip_options(devpath, stripped_path); 361 devpath = stripped_path; 362 #endif 363 /* 364 * Hold the devi since this is the root device. 365 */ 366 if ((dip = e_ddi_hold_devi_by_path(devpath, 0)) == NULL) { 367 printf("strplumb: unable to hold root device: %s\n", 368 devpath); 369 return (ENXIO); 370 } 371 372 driver = ddi_driver_name(dip); 373 instance = ddi_get_instance(dip); 374 } else { 375 if (ndev_name == NULL) 376 return (ENODEV); 377 378 DBG2("using ndev_name (%s) ndev_unit (%d)\n", ndev_name, 379 ndev_unit); 380 381 if (i_ddi_attach_hw_nodes(ndev_name) != DDI_SUCCESS) { 382 printf("strplumb: cannot load ndev_name '%s'\n", 383 ndev_name); 384 return (ENXIO); 385 } 386 387 driver = ndev_name; 388 instance = ndev_unit; 389 } 390 391 (void) snprintf(rootfs.bo_devname, BO_MAXOBJNAME, 392 "/devices/pseudo/clone@0:%s", driver); 393 (void) snprintf(rootfs.bo_ifname, BO_MAXOBJNAME, "%s%d", 394 driver, instance); 395 rootfs.bo_ppa = instance; 396 return (0); 397 } 398 399 static int 400 getifflags(ldi_handle_t lh, struct lifreq *lifrp) 401 { 402 struct strioctl iocb; 403 int rval; 404 405 iocb.ic_cmd = SIOCGLIFFLAGS; 406 iocb.ic_timout = 15; 407 iocb.ic_len = sizeof (struct lifreq); 408 iocb.ic_dp = (char *)lifrp; 409 410 return (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, CRED(), &rval)); 411 412 } 413 414 static int 415 setifname(ldi_handle_t lh, struct lifreq *lifrp) 416 { 417 struct strioctl iocb; 418 int rval; 419 420 iocb.ic_cmd = SIOCSLIFNAME; 421 iocb.ic_timout = 15; 422 iocb.ic_len = sizeof (struct lifreq); 423 iocb.ic_dp = (char *)lifrp; 424 425 return (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, CRED(), &rval)); 426 } 427 428 extern ib_boot_prop_t *iscsiboot_prop; 429 430 static int 431 strplumb_dev(ldi_ident_t li) 432 { 433 ldi_handle_t lh = NULL; 434 ldi_handle_t mux_lh = NULL; 435 int err; 436 struct lifreq lifr; 437 struct ifreq ifr; 438 int rval; 439 int af = 0; 440 char *name = NULL; 441 442 bzero(&lifr, sizeof (struct lifreq)); 443 bzero(&ifr, sizeof (ifr)); 444 445 if (iscsiboot_prop != NULL) { 446 af = iscsiboot_prop->boot_nic.sin_family; 447 } 448 449 /* 450 * Now set up the links. Ultimately, we should have two streams 451 * permanently linked underneath UDP (which is actually IP with UDP 452 * autopushed). One stream consists of the ARP-[ifname] combination, 453 * while the other consists of ARP-IP-[ifname]. The second combination 454 * seems a little weird, but is linked underneath UDP just to keep it 455 * around. 456 * 457 * We pin underneath UDP here to match what is done in ifconfig(1m); 458 * otherwise, ifconfig will be unable to unplumb the stream (the major 459 * number and mux id must both match for a successful I_PUNLINK). 460 * 461 * There are subtleties in the plumbing which make it essential to 462 * follow the logic used in ifconfig(1m) very closely. 463 */ 464 465 /* 466 * Plumb UDP-ARP-IP-<dev> 467 */ 468 469 if ((err = ldi_open_by_name(rootfs.bo_devname, FREAD|FWRITE, CRED(), 470 &lh, li)) != 0) { 471 printf("strplumb: open %s failed: %d\n", rootfs.bo_devname, 472 err); 473 goto done; 474 } 475 476 477 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)IP, FKIOCTL, CRED(), 478 &rval)) != 0) { 479 printf("strplumb: push IP failed: %d\n", err); 480 goto done; 481 } 482 483 if ((err = getifflags(lh, &lifr)) != 0) 484 goto done; 485 486 if (af == 0 || af == AF_INET) { 487 lifr.lifr_flags |= IFF_IPV4; 488 lifr.lifr_flags &= ~IFF_IPV6; 489 name = UDPDEV; 490 } else { 491 /* 492 * iscsi boot is used with ipv6 enabled 493 */ 494 lifr.lifr_flags |= IFF_IPV6; 495 lifr.lifr_flags &= ~IFF_IPV4; 496 name = UDP6DEV; 497 } 498 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)ARP, FKIOCTL, CRED(), 499 &rval)) != 0) { 500 printf("strplumb: push ARP failed: %d\n", err); 501 goto done; 502 } 503 504 (void) strlcpy(lifr.lifr_name, rootfs.bo_ifname, 505 sizeof (lifr.lifr_name)); 506 lifr.lifr_ppa = rootfs.bo_ppa; 507 508 if ((err = setifname(lh, &lifr)) != 0) 509 goto done; 510 511 /* Get the flags and check if ARP is needed */ 512 if ((err = getifflags(lh, &lifr)) != 0) { 513 printf("strplumb: getifflags %s IP failed, error %d\n", 514 lifr.lifr_name, err); 515 goto done; 516 } 517 518 /* Pop out ARP if not needed */ 519 if (lifr.lifr_flags & (IFF_NOARP | IFF_IPV6)) { 520 err = ldi_ioctl(lh, I_POP, (intptr_t)0, FKIOCTL, CRED(), 521 &rval); 522 if (err != 0) { 523 printf("strplumb: pop ARP failed, error %d\n", err); 524 goto done; 525 } 526 } 527 528 if ((err = ldi_open_by_name(name, FREAD|FWRITE, CRED(), &mux_lh, 529 li)) != 0) { 530 printf("strplumb: open of %s failed: %d\n", name, err); 531 goto done; 532 } 533 534 if ((err = ldi_ioctl(mux_lh, I_PLINK, (intptr_t)lh, 535 FREAD|FWRITE|FNOCTTY|FKIOCTL, CRED(), 536 &(ifr.ifr_ip_muxid))) != 0) { 537 printf("strplumb: plink UDP-ARP-IP-%s failed: %d\n", 538 rootfs.bo_ifname, err); 539 goto done; 540 } 541 542 if (af == AF_INET6) { 543 goto done; 544 } 545 546 DBG2("UDP-ARP-IP-%s muxid: %d\n", rootfs.bo_ifname, ifr.ifr_ip_muxid); 547 548 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 549 lh = NULL; 550 551 /* 552 * Plumb UDP-ARP-<dev> 553 */ 554 555 if ((err = ldi_open_by_name(rootfs.bo_devname, FREAD|FWRITE, CRED(), 556 &lh, li)) != 0) { 557 printf("strplumb: open %s failed: %d\n", rootfs.bo_devname, 558 err); 559 goto done; 560 } 561 562 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)ARP, FKIOCTL, CRED(), 563 &rval)) != 0) { 564 printf("strplumb: push ARP failed: %d\n", err); 565 goto done; 566 } 567 568 if ((err = setifname(lh, &lifr)) != 0) 569 goto done; 570 571 if ((err = ldi_ioctl(mux_lh, I_PLINK, (intptr_t)lh, 572 FREAD|FWRITE|FNOCTTY|FKIOCTL, CRED(), 573 &(ifr.ifr_arp_muxid))) != 0) { 574 printf("strplumb: plink UDP-ARP-%s failed: %d\n", 575 rootfs.bo_ifname, err); 576 goto done; 577 } 578 579 DBG2("UDP-ARP-%s muxid: %d\n", rootfs.bo_ifname, ifr.ifr_arp_muxid); 580 581 /* 582 * Cache the mux ids. 583 */ 584 (void) strlcpy(ifr.ifr_name, rootfs.bo_ifname, sizeof (ifr.ifr_name)); 585 586 if ((err = ldi_ioctl(mux_lh, SIOCSIFMUXID, (intptr_t)&ifr, FKIOCTL, 587 CRED(), &rval)) != 0) { 588 printf("strplumb: SIOCSIFMUXID failed: %d\n", err); 589 goto done; 590 } 591 592 done: 593 if (lh != NULL) 594 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 595 596 if (mux_lh != NULL) 597 (void) ldi_close(mux_lh, FREAD|FWRITE, CRED()); 598 599 return (err); 600 } 601 602 /* 603 * Do streams plumbing for internet protocols. 604 */ 605 int 606 strplumb(void) 607 { 608 ldi_ident_t li; 609 int err; 610 611 if ((err = strplumb_init()) != 0) 612 return (err); 613 614 if ((err = strplumb_autopush()) != 0) 615 return (err); 616 617 if ((err = ldi_ident_from_mod(&modlinkage, &li)) != 0) 618 return (err); 619 620 /* 621 * Setup the TCP and SCTP default queues for the global stack. 622 * tcp/sctp_stack_init will do this for additional stack instances. 623 */ 624 if ((err = strplumb_sctpq(li)) != 0) 625 goto done; 626 627 if ((err = strplumb_tcpq(li)) != 0) 628 goto done; 629 630 if ((err = resolve_boot_path()) != 0) 631 goto done; 632 633 DBG1("rootfs.bo_devname: %s\n", rootfs.bo_devname); 634 DBG1("rootfs.bo_ifname: %s\n", rootfs.bo_ifname); 635 DBG1("rootfs.bo_ppa: %d\n", rootfs.bo_ppa); 636 637 if ((err = strplumb_dev(li)) != 0) 638 goto done; 639 640 done: 641 ldi_ident_release(li); 642 643 return (err); 644 } 645 646 /* multiboot: diskless boot interface discovery */ 647 648 #ifndef _OBP 649 650 static uchar_t boot_macaddr[16]; 651 static int boot_maclen; 652 static uchar_t *getmacaddr(dev_info_t *dip, size_t *maclenp); 653 static int matchmac(dev_info_t *dip, void *arg); 654 655 #endif /* !_OBP */ 656 657 char * 658 strplumb_get_netdev_path(void) 659 { 660 #ifdef _OBP 661 char fstype[OBP_MAXPROPNAME]; 662 663 if (bop_getprop("fstype", fstype) == -1) 664 return (NULL); 665 666 if (strncmp(fstype, "nfs", 3) == 0) 667 return (prom_bootpath()); 668 else 669 return (NULL); 670 #else 671 672 char *macstr, *devpath = NULL; 673 uchar_t *bootp; 674 uint_t bootp_len; 675 676 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 677 DDI_PROP_DONTPASS, BP_BOOT_MAC, &macstr) == DDI_SUCCESS) { 678 /* 679 * hard coded ether mac len for booting floppy on 680 * machines with old cards 681 */ 682 boot_maclen = ether_aton(macstr, boot_macaddr); 683 if (boot_maclen != 6) { 684 cmn_err(CE_WARN, 685 "malformed boot_mac property, %d bytes", 686 boot_maclen); 687 } 688 ddi_prop_free(macstr); 689 } else if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 690 DDI_PROP_DONTPASS, BP_BOOTP_RESPONSE, &bootp, &bootp_len) 691 == DDI_SUCCESS) { 692 693 /* 694 * These offsets are defined by dhcp standard 695 * Should use structure offsets 696 */ 697 boot_maclen = *(bootp + 2); 698 ASSERT(boot_maclen <= 16); 699 bcopy(bootp + 28, boot_macaddr, boot_maclen); 700 701 dhcack = kmem_alloc(bootp_len, KM_SLEEP); 702 bcopy(bootp, dhcack, bootp_len); 703 dhcacklen = bootp_len; 704 705 ddi_prop_free(bootp); 706 } else if (iscsiboot_prop != NULL) { 707 bcopy(iscsiboot_prop->boot_nic.nic_mac, 708 boot_macaddr, IB_BOOT_MACLEN); 709 boot_maclen = IB_BOOT_MACLEN; 710 } else { 711 return (NULL); 712 } 713 714 ddi_walk_devs(ddi_root_node(), matchmac, (void *)&devpath); 715 return (devpath); 716 717 #endif /* _OBP */ 718 } 719 720 #ifndef _OBP 721 722 /* 723 * Get boot path from the boot_mac address 724 */ 725 /*ARGSUSED*/ 726 static int 727 matchmac(dev_info_t *dip, void *arg) 728 { 729 char **devpathp = (char **)arg; 730 char *model_str; 731 uchar_t *macaddr; 732 size_t maclen; 733 734 /* XXX Should use "device-type" per IEEE 1275 */ 735 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 736 "model", &model_str) != DDI_SUCCESS) 737 return (DDI_WALK_CONTINUE); 738 739 if (strcmp(model_str, "Ethernet controller") != 0) { 740 ddi_prop_free(model_str); 741 return (DDI_WALK_CONTINUE); 742 } 743 ddi_prop_free(model_str); 744 745 /* We have a network device now */ 746 if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) { 747 return (DDI_WALK_CONTINUE); 748 } 749 750 ASSERT(boot_maclen != 0); 751 macaddr = getmacaddr(dip, &maclen); 752 if (macaddr == NULL) 753 return (DDI_WALK_CONTINUE); 754 755 if (maclen != boot_maclen || 756 bcmp(macaddr, boot_macaddr, maclen) != 0) { 757 kmem_free(macaddr, maclen); 758 return (DDI_WALK_CONTINUE); 759 } 760 761 /* found hardware with the mac address */ 762 (void) localetheraddr((struct ether_addr *)macaddr, NULL); 763 kmem_free(macaddr, maclen); 764 765 *devpathp = kmem_alloc(MAXPATHLEN, KM_SLEEP); 766 (void) ddi_pathname(dip, *devpathp); 767 768 /* fill in dhcifname */ 769 if (dhcack) { 770 (void) snprintf(dhcifname, IFNAMSIZ, "%s%d", 771 ddi_driver_name(dip), i_ddi_devi_get_ppa(dip)); 772 } 773 return (DDI_WALK_TERMINATE); 774 } 775 776 static uchar_t * 777 getmacaddr(dev_info_t *dip, size_t *maclenp) 778 { 779 int rc, ppa; 780 ldi_ident_t li; 781 ldi_handle_t lh; 782 const char *drv_name = ddi_driver_name(dip); 783 char *clonepath; 784 uchar_t *macaddr = NULL; 785 786 if (rc = ldi_ident_from_mod(&modlinkage, &li)) { 787 cmn_err(CE_WARN, 788 "getmacaddr: ldi_ident_from_mod failed: %d\n", rc); 789 return (NULL); 790 } 791 792 clonepath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 793 (void) snprintf(clonepath, MAXPATHLEN, 794 "/devices/pseudo/clone@0:%s", drv_name); 795 796 rc = ldi_open_by_name(clonepath, FREAD|FWRITE, CRED(), &lh, li); 797 ldi_ident_release(li); 798 if (rc) { 799 cmn_err(CE_WARN, 800 "getmacaddr: ldi_open_by_name(%s) failed: %d\n", 801 clonepath, rc); 802 kmem_free(clonepath, MAXPATHLEN); 803 return (NULL); 804 } 805 kmem_free(clonepath, MAXPATHLEN); 806 807 ppa = i_ddi_devi_get_ppa(dip); 808 if ((dl_attach(lh, ppa, NULL) != 0) || 809 (dl_bind(lh, ETHERTYPE_IP, NULL) != 0)) { 810 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 811 cmn_err(CE_WARN, 812 "getmacaddr: dl_attach/bind(%s%d) failed: %d\n", 813 drv_name, ppa, rc); 814 return (NULL); 815 } 816 817 *maclenp = ETHERADDRL; 818 macaddr = kmem_alloc(ETHERADDRL, KM_SLEEP); 819 if (dl_phys_addr(lh, macaddr, maclenp, NULL) != 0 || 820 *maclenp != ETHERADDRL) { 821 kmem_free(macaddr, ETHERADDRL); 822 macaddr = NULL; 823 *maclenp = 0; 824 cmn_err(CE_WARN, 825 "getmacaddr: dl_phys_addr(%s%d) failed: %d\n", 826 drv_name, ppa, rc); 827 } 828 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 829 return (macaddr); 830 } 831 #endif /* !_OBP */ 832