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