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/systm.h> 29 #include <sys/cred.h> 30 #include <sys/user.h> 31 #include <sys/file.h> 32 #include <sys/stream.h> 33 #include <sys/strsubr.h> 34 #include <sys/stropts.h> 35 #include <sys/strsun.h> 36 #include <sys/debug.h> 37 #include <sys/tiuser.h> 38 #include <sys/sockio.h> 39 #include <sys/socket.h> 40 #include <sys/t_kuser.h> 41 #include <sys/utsname.h> 42 #include <sys/systeminfo.h> 43 #include <sys/netconfig.h> 44 #include <sys/ethernet.h> 45 #include <sys/dlpi.h> 46 #include <sys/vfs.h> 47 #include <sys/sysmacros.h> 48 #include <sys/bootconf.h> 49 #include <sys/bootprops.h> 50 #include <sys/cmn_err.h> 51 #include <sys/promif.h> 52 #include <sys/mount.h> 53 54 #include <net/if.h> 55 #include <net/route.h> 56 57 #include <netinet/in.h> 58 #include <netinet/arp.h> 59 #include <netinet/dhcp.h> 60 #include <netinet/inetutil.h> 61 #include <dhcp_impl.h> 62 #include <sys/sunos_dhcp_class.h> 63 64 #include <rpc/types.h> 65 #include <rpc/rpc.h> 66 #include <rpc/xdr.h> 67 #include <rpc/auth.h> 68 #include <rpc/clnt.h> 69 #include <rpc/pmap_clnt.h> 70 #include <rpc/pmap_rmt.h> 71 #include <rpc/pmap_prot.h> 72 #include <rpc/bootparam.h> 73 #include <rpc/rpcb_prot.h> 74 75 #include <nfs/nfs.h> 76 #include <nfs/nfs4.h> 77 #include <nfs/nfs_clnt.h> 78 #include <nfs/mount.h> 79 #include <sys/mntent.h> 80 81 #include <sys/kstr.h> 82 #include <sys/sunddi.h> 83 #include <sys/sunldi.h> 84 #include <sys/esunddi.h> 85 86 #include <sys/errno.h> 87 #include <sys/modctl.h> 88 89 /* 90 * RPC timers and retries 91 */ 92 #define PMAP_RETRIES 5 93 #define DEFAULT_RETRIES 3 94 #define GETFILE_RETRIES 2 95 96 #define DEFAULT_TIMEO 3 97 #define WHOAMI_TIMEO 20 98 #define REVARP_TIMEO 5 99 #define GETFILE_TIMEO 1 100 101 /* 102 * These are from the rpcgen'd version of mount.h XXX 103 */ 104 #define MOUNTPROG 100005 105 #define MOUNTPROC_MNT 1 106 #define MOUNTVERS 1 107 #define MOUNTVERS_POSIX 2 108 #define MOUNTVERS3 3 109 110 struct fhstatus { 111 int fhs_status; 112 fhandle_t fhs_fh; 113 }; 114 115 #define FHSIZE3 64 116 117 struct fhandle3 { 118 uint_t fhandle3_len; 119 char *fhandle3_val; 120 }; 121 122 enum mountstat3 { 123 MNT_OK = 0, 124 MNT3ERR_PERM = 1, 125 MNT3ERR_NOENT = 2, 126 MNT3ERR_IO = 5, 127 MNT3ERR_ACCES = 13, 128 MNT3ERR_NOTDIR = 20, 129 MNT3ERR_INVAL = 22, 130 MNT3ERR_NAMETOOLONG = 63, 131 MNT3ERR_NOTSUPP = 10004, 132 MNT3ERR_SERVERFAULT = 10006 133 }; 134 135 struct mountres3_ok { 136 struct fhandle3 fhandle; 137 struct { 138 uint_t auth_flavors_len; 139 int *auth_flavors_val; 140 } auth_flavors; 141 }; 142 143 struct mountres3 { 144 enum mountstat3 fhs_status; 145 union { 146 struct mountres3_ok mountinfo; 147 } mountres3_u; 148 }; 149 150 /* 151 * DLPI address format. 152 */ 153 struct dladdr { 154 uchar_t dl_phys[6]; 155 ushort_t dl_sap; 156 }; 157 158 static struct modlmisc modlmisc = { 159 &mod_miscops, "Boot diskless" 160 }; 161 162 static struct modlinkage modlinkage = { 163 MODREV_1, (void *)&modlmisc, NULL 164 }; 165 166 static int dldebug; 167 168 int 169 _init(void) 170 { 171 return (mod_install(&modlinkage)); 172 } 173 174 int 175 _fini(void) 176 { 177 return (mod_remove(&modlinkage)); 178 } 179 180 int 181 _info(struct modinfo *modinfop) 182 { 183 return (mod_info(&modlinkage, modinfop)); 184 } 185 186 187 static enum clnt_stat pmap_rmt_call(struct knetconfig *, struct netbuf *, 188 bool_t, rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t, 189 caddr_t, xdrproc_t, caddr_t, struct timeval, 190 struct netbuf *); 191 static bool_t myxdr_rmtcall_args(XDR *, struct rmtcallargs *); 192 static bool_t myxdr_rmtcallres(XDR *, struct rmtcallres *); 193 static bool_t myxdr_pmap(XDR *, struct pmap *); 194 static bool_t myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp); 195 static bool_t myxdr_fhandle(XDR *xdrs, fhandle_t *fh); 196 static bool_t myxdr_mountres3(XDR *xdrs, struct mountres3 *objp); 197 static bool_t myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp); 198 static bool_t myxdr_mountres3_ok(XDR *xdrs, 199 struct mountres3_ok *objp); 200 static bool_t myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp); 201 static enum clnt_stat pmap_kgetport(struct knetconfig *, struct netbuf *, 202 rpcprog_t, rpcvers_t, rpcprot_t); 203 static enum clnt_stat mycallrpc(struct knetconfig *, struct netbuf *, 204 rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t, 205 char *, xdrproc_t, char *, int, int); 206 static int ifioctl(TIUSER *, int, struct netbuf *); 207 static int getfile(char *, char *, struct netbuf *, char *); 208 static int ping_prog(struct netbuf *, uint_t prog, uint_t vers, 209 int proto, enum clnt_stat *); 210 static int mountnfs(struct netbuf *, char *, char *, 211 fhandle_t *, int *); 212 static int mountnfs3(struct netbuf *, char *, char *, 213 nfs_fh3 *, int *); 214 static int init_mountopts(struct nfs_args *, int, 215 struct knetconfig **, int *); 216 static int revarp_myaddr(TIUSER *); 217 static void revarp_start(ldi_handle_t, struct netbuf *); 218 static void revarpinput(ldi_handle_t, struct netbuf *); 219 static void init_netbuf(struct netbuf *); 220 static void free_netbuf(struct netbuf *); 221 static int rtioctl(TIUSER *, int, struct rtentry *); 222 static void init_config(void); 223 224 static void cacheinit(void); 225 static int cacheinfo(char *, int, struct netbuf *, char *, int); 226 static int dlifconfig(TIUSER *, struct in_addr *, struct in_addr *, 227 struct in_addr *, uint_t); 228 static int setifflags(TIUSER *, uint_t); 229 230 static char *inet_ntoa(struct in_addr); 231 static int inet_aton(char *, uchar_t *); 232 static int isdigit(int); 233 234 /* 235 * Should be in some common 236 * ethernet source file. 237 */ 238 static struct ether_addr etherbroadcastaddr = { 239 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 240 }; 241 242 static struct ether_addr myether; 243 244 /* 245 * "ifname" is the interface name/unit as read from the boot 246 * arguments. 247 * "ndev" is the major device number of the network interface 248 * used to boot from. 249 * "ifunit" it the physical point of attachment for the network 250 * interface used to boot from. 251 * 252 * Both of these are initialized in "init_config()". 253 */ 254 255 static char ifname[IFNAMSIZ]; 256 static char ndev_path[MAXPATHLEN]; 257 static int ifunit; 258 259 /* 260 * XXX these should be shared 261 */ 262 static struct knetconfig dl_udp_netconf = { 263 NC_TPI_CLTS, /* semantics */ 264 NC_INET, /* family */ 265 NC_UDP, /* protocol */ 266 0, /* device */ 267 }; 268 269 static struct knetconfig dl_tcp_netconf = { 270 NC_TPI_COTS, /* semantics */ 271 NC_INET, /* family */ 272 NC_TCP, /* protocol */ 273 0, /* device */ 274 }; 275 276 /* parameters from DHCP or bootparamd */ 277 static PKT_LIST *pl = NULL; 278 static uchar_t server_ip[4]; 279 static uchar_t dhcp_server_ip[4]; 280 static char *server_name_c, *server_path_c; 281 static char rootopts[256]; 282 283 /* 284 * XXX Until we get the nfsmapid deadlocks all fixed, don't allow 285 * XXX a v4 root mount. 286 */ 287 int nfs4_no_diskless_root_support = 1; 288 289 int 290 mount_root(char *name, char *path, int version, struct nfs_args *args, 291 int *vfsflags) 292 { 293 int rc; 294 int proto; 295 struct knetconfig *dl_cf; 296 static int init_done = 0; 297 enum clnt_stat stat; 298 299 if (dldebug) 300 printf("mount_root: name=%s\n", name); 301 302 if (init_done == 0) { 303 init_config(); 304 init_done = 1; 305 } 306 307 init_netbuf(args->addr); 308 309 do { 310 rc = getfile(name, args->hostname, args->addr, path); 311 } while (rc == ETIMEDOUT); 312 313 if (rc) { 314 free_netbuf(args->addr); 315 return (rc); 316 } 317 318 ASSERT(args->knconf->knc_protofmly != NULL); 319 ASSERT(args->knconf->knc_proto != NULL); 320 321 switch (version) { 322 case NFS_VERSION: 323 rc = mountnfs(args->addr, args->hostname, path, 324 (fhandle_t *)args->fh, &proto); 325 break; 326 case NFS_V3: 327 rc = mountnfs3(args->addr, args->hostname, path, 328 (nfs_fh3 *)args->fh, &proto); 329 break; 330 case NFS_V4: 331 ((struct sockaddr_in *)args->addr->buf)->sin_port = 332 htons(NFS_PORT); 333 if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP, 334 &stat)) { 335 proto = IPPROTO_TCP; 336 rc = 0; 337 } else { 338 switch (stat) { 339 case RPC_PROGVERSMISMATCH: 340 case RPC_XPRTFAILED: 341 /* 342 * Common failures if v4 unsupported or no TCP 343 */ 344 rc = EPROTONOSUPPORT; 345 break; 346 default: 347 rc = ENXIO; 348 } 349 } 350 if (nfs4_no_diskless_root_support) 351 rc = EPROTONOSUPPORT; 352 break; 353 default: 354 rc = EPROTONOSUPPORT; 355 break; 356 } 357 358 if (rc) 359 goto errout; 360 361 switch (proto) { 362 case IPPROTO_TCP: 363 dl_cf = &dl_tcp_netconf; 364 break; 365 case IPPROTO_UDP: 366 default: 367 dl_cf = &dl_udp_netconf; 368 break; 369 } 370 371 rc = init_mountopts(args, version, &dl_cf, vfsflags); 372 373 /* 374 * Copy knetconfig information from the template, note that the 375 * rdev field has been set by init_config above. 376 */ 377 args->knconf->knc_semantics = dl_cf->knc_semantics; 378 args->knconf->knc_rdev = dl_cf->knc_rdev; 379 (void) strcpy(args->knconf->knc_protofmly, dl_cf->knc_protofmly); 380 (void) strcpy(args->knconf->knc_proto, dl_cf->knc_proto); 381 382 errout: 383 if (dldebug) { 384 if (rc) 385 nfs_perror(rc, "mount_root: mount %s:%s failed: %m\n", 386 args->hostname, path); 387 else 388 printf("mount_root: leaving\n"); 389 } 390 391 return (rc); 392 } 393 394 /* 395 * Call mount daemon on server `sa' to mount path. 396 * `port' is set to nfs port and fh is the fhandle 397 * returned from the server. 398 */ 399 static int 400 mountnfs(struct netbuf *sa, char *server, 401 char *path, fhandle_t *fh, int *proto) 402 { 403 struct fhstatus fhs; 404 enum clnt_stat stat; 405 406 if (dldebug) 407 printf("mountnfs: entered\n"); 408 409 /* 410 * Get the port number for the mount program. 411 * pmap_kgetport first tries a SunOS portmapper 412 * and, if no reply is received, will try a 413 * SVR4 rpcbind. Either way, `sa' is set to 414 * the correct address. 415 */ 416 do { 417 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG, 418 (rpcvers_t)MOUNTVERS, (rpcprot_t)IPPROTO_UDP); 419 420 if (stat == RPC_TIMEDOUT) { 421 cmn_err(CE_WARN, 422 "mountnfs: %s:%s portmap not responding", 423 server, path); 424 } else if (stat != RPC_SUCCESS) { 425 cmn_err(CE_WARN, 426 "mountnfs: pmap_kgetport RPC error %d (%s).", 427 stat, clnt_sperrno(stat)); 428 return (ENXIO); /* XXX */ 429 } 430 } while (stat == RPC_TIMEDOUT); 431 432 /* 433 * The correct port number has been 434 * put into `sa' by pmap_kgetport(). 435 */ 436 do { 437 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG, 438 (rpcvers_t)MOUNTVERS, (rpcproc_t)MOUNTPROC_MNT, 439 xdr_bp_path_t, (char *)&path, 440 myxdr_fhstatus, (char *)&fhs, 441 DEFAULT_TIMEO, DEFAULT_RETRIES); 442 if (stat == RPC_TIMEDOUT) { 443 cmn_err(CE_WARN, 444 "mountnfs: %s:%s mount server not responding", 445 server, path); 446 } 447 } while (stat == RPC_TIMEDOUT); 448 449 if (stat != RPC_SUCCESS) { 450 cmn_err(CE_WARN, "mountnfs: RPC failed: error %d (%s).", 451 stat, clnt_sperrno(stat)); 452 return (ENXIO); /* XXX */ 453 } 454 455 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT); 456 457 *fh = fhs.fhs_fh; 458 if (fhs.fhs_status != 0) { 459 if (dldebug) 460 printf("mountnfs: fhs_status %d\n", fhs.fhs_status); 461 return (ENXIO); /* XXX */ 462 } 463 464 *proto = IPPROTO_UDP; 465 466 if (ping_prog(sa, NFS_PROGRAM, NFS_VERSION, IPPROTO_TCP, NULL)) 467 *proto = IPPROTO_TCP; 468 469 if (dldebug) 470 printf("mountnfs: leaving\n"); 471 return (0); 472 } 473 474 /* 475 * Call mount daemon on server `sa' to mount path. 476 * `port' is set to nfs port and fh is the fhandle 477 * returned from the server. 478 */ 479 static int 480 mountnfs3(struct netbuf *sa, char *server, 481 char *path, nfs_fh3 *fh, int *proto) 482 { 483 struct mountres3 mountres3; 484 enum clnt_stat stat; 485 int ret = 0; 486 487 if (dldebug) 488 printf("mountnfs3: entered\n"); 489 490 /* 491 * Get the port number for the mount program. 492 * pmap_kgetport first tries a SunOS portmapper 493 * and, if no reply is received, will try a 494 * SVR4 rpcbind. Either way, `sa' is set to 495 * the correct address. 496 */ 497 do { 498 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG, 499 (rpcvers_t)MOUNTVERS3, (rpcprot_t)IPPROTO_UDP); 500 501 if (stat == RPC_PROGVERSMISMATCH) { 502 if (dldebug) 503 printf("mountnfs3: program/version mismatch\n"); 504 return (EPROTONOSUPPORT); /* XXX */ 505 } else if (stat == RPC_TIMEDOUT) { 506 cmn_err(CE_WARN, 507 "mountnfs3: %s:%s portmap not responding", 508 server, path); 509 } else if (stat != RPC_SUCCESS) { 510 cmn_err(CE_WARN, 511 "mountnfs3: pmap_kgetport RPC error %d (%s).", 512 stat, clnt_sperrno(stat)); 513 return (ENXIO); /* XXX */ 514 } 515 } while (stat == RPC_TIMEDOUT); 516 517 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = NULL; 518 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = NULL; 519 520 /* 521 * The correct port number has been 522 * put into `sa' by pmap_kgetport(). 523 */ 524 do { 525 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG, 526 (rpcvers_t)MOUNTVERS3, (rpcproc_t)MOUNTPROC_MNT, 527 xdr_bp_path_t, (char *)&path, 528 myxdr_mountres3, (char *)&mountres3, 529 DEFAULT_TIMEO, DEFAULT_RETRIES); 530 if (stat == RPC_TIMEDOUT) { 531 cmn_err(CE_WARN, 532 "mountnfs3: %s:%s mount server not responding", 533 server, path); 534 } 535 } while (stat == RPC_TIMEDOUT); 536 537 if (stat == RPC_PROGVERSMISMATCH) { 538 if (dldebug) 539 printf("mountnfs3: program/version mismatch\n"); 540 ret = EPROTONOSUPPORT; 541 goto out; 542 } 543 if (stat != RPC_SUCCESS) { 544 cmn_err(CE_WARN, "mountnfs3: RPC failed: error %d (%s).", 545 stat, clnt_sperrno(stat)); 546 ret = ENXIO; /* XXX */ 547 goto out; 548 } 549 550 if (mountres3.fhs_status != MNT_OK) { 551 if (dldebug) 552 printf("mountnfs3: fhs_status %d\n", 553 mountres3.fhs_status); 554 ret = ENXIO; /* XXX */ 555 goto out; 556 } 557 558 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT); 559 560 *proto = IPPROTO_UDP; 561 562 if (ping_prog(sa, NFS_PROGRAM, NFS_V3, IPPROTO_TCP, NULL)) { 563 *proto = IPPROTO_TCP; 564 } 565 566 fh->fh3_length = mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; 567 bcopy(mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, 568 fh->fh3_u.data, fh->fh3_length); 569 570 out: 571 xdr_free(myxdr_mountres3, (caddr_t)&mountres3); 572 573 if (dldebug) 574 printf("mountnfs3: leaving\n"); 575 return (ret); 576 } 577 578 static int 579 ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto, 580 enum clnt_stat *statp) 581 { 582 struct knetconfig *knconf; 583 enum clnt_stat stat; 584 int retries = DEFAULT_RETRIES; 585 586 switch (proto) { 587 case IPPROTO_TCP: 588 knconf = &dl_tcp_netconf; 589 break; 590 case IPPROTO_UDP: 591 knconf = &dl_udp_netconf; 592 break; 593 default: 594 return (0); 595 } 596 597 do { 598 stat = mycallrpc(knconf, call_addr, prog, vers, NULLPROC, 599 xdr_void, NULL, xdr_void, NULL, 600 DEFAULT_TIMEO, DEFAULT_RETRIES); 601 602 if (dldebug) 603 printf("ping_prog: %d return %d (%s)\n", proto, stat, 604 clnt_sperrno(stat)); 605 /* 606 * Special case for TCP, it may "timeout" because it failed 607 * to establish an initial connection but it doesn't 608 * actually retry, so we do the retry. 609 * Persistence pays in diskless. 610 */ 611 } while (stat == RPC_TIMEDOUT && proto == IPPROTO_TCP && retries--); 612 613 if (statp != NULL) 614 *statp = stat; 615 616 if (stat != RPC_SUCCESS) 617 return (0); 618 return (1); 619 } 620 621 static struct netbuf bootparam_addr; 622 623 /* 624 * Returns after filling in the following global variables: 625 * bootparam_addr, 626 * utsname.nodename, 627 * srpc_domain. 628 */ 629 static int 630 whoami(void) 631 { 632 TIUSER *tiptr; 633 struct netbuf sa; 634 struct netbuf req; 635 struct bp_whoami_arg arg; 636 struct bp_whoami_res res; 637 struct timeval tv; 638 enum clnt_stat stat; 639 int rc; 640 size_t namelen; 641 int printed_waiting_msg; 642 643 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev, 644 FREAD|FWRITE, &tiptr, CRED())) != 0) { 645 nfs_perror(rc, "whoami: t_kopen udp failed: %m.\n"); 646 } 647 648 /* 649 * Find out our local (IP) address. 650 */ 651 if (rc = revarp_myaddr(tiptr)) { 652 nfs_perror(rc, "whoami: revarp_myaddr failed: %m.\n"); 653 (void) t_kclose(tiptr, 0); 654 return (rc); 655 } 656 657 /* explicitly use the limited broadcast address */ 658 init_netbuf(&sa); 659 ((struct sockaddr_in *)sa.buf)->sin_family = AF_INET; 660 ((struct sockaddr_in *)sa.buf)->sin_addr.s_addr = 661 htonl(INADDR_BROADCAST); 662 sa.len = sizeof (struct sockaddr_in); 663 664 /* 665 * Pick up our local (IP) address. 666 */ 667 init_netbuf(&req); 668 if (rc = ifioctl(tiptr, SIOCGIFADDR, &req)) { 669 nfs_perror(rc, 670 "whoami: couldn't get my IP address: %m.\n"); 671 free_netbuf(&sa); 672 free_netbuf(&req); 673 (void) t_kclose(tiptr, 0); 674 return (rc); 675 } 676 677 /* 678 * Set up the arguments expected by bootparamd. 679 */ 680 arg.client_address.address_type = IP_ADDR_TYPE; 681 bcopy(&((struct sockaddr_in *)req.buf)->sin_addr, 682 &arg.client_address.bp_address.ip_addr, sizeof (struct in_addr)); 683 684 free_netbuf(&req); 685 686 init_netbuf(&bootparam_addr); 687 688 /* 689 * Initial retransmission interval 690 */ 691 tv.tv_sec = DEFAULT_TIMEO; 692 tv.tv_usec = 0; 693 res.client_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP); 694 res.domain_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP); 695 696 /* 697 * Do a broadcast call to find a bootparam daemon that 698 * will tell us our hostname, domainname and any 699 * router that we have to use to talk to our NFS server. 700 */ 701 printed_waiting_msg = 0; 702 do { 703 /* 704 * pmap_rmt_call will first try the SunOS portmapper 705 * and if no reply is received will then try the SVR4 706 * rpcbind. 707 * Either way, `bootparam_addr' will be set to the 708 * correct address for the bootparamd that responds. 709 */ 710 stat = pmap_rmt_call(&dl_udp_netconf, &sa, TRUE, BOOTPARAMPROG, 711 BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI, 712 xdr_bp_whoami_arg, (caddr_t)&arg, 713 xdr_bp_whoami_res, (caddr_t)&res, 714 tv, &bootparam_addr); 715 if (stat == RPC_TIMEDOUT && !printed_waiting_msg) { 716 cmn_err(CE_WARN, 717 "No bootparam server responding; still trying"); 718 printed_waiting_msg = 1; 719 } 720 /* 721 * Retransmission interval for second and subsequent tries. 722 * We expect first pmap_rmt_call to retransmit and backoff to 723 * at least this value. 724 */ 725 tv.tv_sec = WHOAMI_TIMEO; 726 tv.tv_usec = 0; 727 } while (stat == RPC_TIMEDOUT); 728 729 if (printed_waiting_msg) 730 printf("Bootparam response received\n"); 731 732 if (stat != RPC_SUCCESS) { 733 /* XXX should get real error here */ 734 rc = ENXIO; 735 cmn_err(CE_WARN, 736 "whoami: bootparam RPC failed: error %d (%s).", 737 stat, clnt_sperrno(stat)); 738 goto done; 739 } 740 741 namelen = strlen(res.client_name); 742 if (namelen > sizeof (utsname.nodename)) { 743 printf("whoami: hostname too long"); 744 rc = ENAMETOOLONG; 745 goto done; 746 } 747 if (namelen != 0) { 748 bcopy(res.client_name, &utsname.nodename, namelen); 749 cmn_err(CE_CONT, "?hostname: %s\n", utsname.nodename); 750 } else { 751 printf("whoami: no host name\n"); 752 rc = ENXIO; 753 goto done; 754 } 755 756 namelen = strlen(res.domain_name); 757 if (namelen != 0) { 758 if (namelen > SYS_NMLN) { 759 printf("whoami: domainname too long"); 760 rc = ENAMETOOLONG; 761 goto done; 762 } 763 bcopy(res.domain_name, &srpc_domain, namelen); 764 cmn_err(CE_CONT, "?domainname: %s\n", srpc_domain); 765 } else { 766 printf("whoami: no domain name\n"); 767 } 768 769 if (res.router_address.address_type == IP_ADDR_TYPE) { 770 struct rtentry rtentry; 771 struct sockaddr_in *sin; 772 struct in_addr ipaddr; 773 774 bcopy(&res.router_address.bp_address.ip_addr, &ipaddr, 775 sizeof (struct in_addr)); 776 777 if (ipaddr.s_addr != (uint32_t)0) { 778 sin = (struct sockaddr_in *)&rtentry.rt_dst; 779 bzero(sin, sizeof (*sin)); 780 sin->sin_family = AF_INET; 781 782 sin = (struct sockaddr_in *)&rtentry.rt_gateway; 783 bzero(sin, sizeof (*sin)); 784 sin->sin_family = AF_INET; 785 sin->sin_addr.s_addr = ipaddr.s_addr; 786 787 rtentry.rt_flags = RTF_GATEWAY | RTF_UP; 788 789 if (rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) { 790 nfs_perror(rc, 791 "whoami: couldn't add route: %m.\n"); 792 goto done; 793 } 794 } 795 } else { 796 printf("whoami: unknown gateway addr family %d\n", 797 res.router_address.address_type); 798 } 799 done: 800 kmem_free(res.client_name, MAX_MACHINE_NAME + 1); 801 kmem_free(res.domain_name, MAX_MACHINE_NAME + 1); 802 free_netbuf(&sa); 803 (void) t_kclose(tiptr, 0); 804 return (rc); 805 } 806 807 /* 808 * Returns: 809 * 1) The ascii form of our root servers name in `server_name'. 810 * 2) Actual network address of our root server in `server_address'. 811 * 3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in 812 * `server_path'. If fileid is "root", it is the pathname of our 813 * root on the server. 814 */ 815 static int 816 getfile(char *fileid, 817 char *server_name, struct netbuf *server_address, char *server_path) 818 { 819 struct bp_getfile_arg arg; 820 struct bp_getfile_res res; 821 enum clnt_stat stat; 822 int root = FALSE; 823 static int using_cache = FALSE; 824 struct in_addr ipaddr; 825 int timeo = DEFAULT_TIMEO; 826 int retries = DEFAULT_RETRIES; 827 828 if (dldebug) 829 printf("getfile: entered\n"); 830 831 /* 832 * Call cacheinfo() to see whether we can satisfy this request by using 833 * the information cached in memory by the boot program's DHCP 834 * implementation or boot properties rather than consult BOOTPARAMS, 835 * but while preserving the semantics of getfile(). We know that 836 * the server name is SYS_NMLN in length, and server_path is 837 * MAXPATHLEN (pn_alloc). 838 */ 839 if (strcmp(fileid, "root") == 0) { 840 if (cacheinfo(server_name, SYS_NMLN, server_address, 841 server_path, MAXPATHLEN) == 0) { 842 using_cache = TRUE; 843 return (0); 844 } 845 root = TRUE; 846 } 847 848 /* 849 * If using cache, rootopts is already available. 850 */ 851 if (strcmp(fileid, "rootopts") == 0 && using_cache == TRUE) { 852 return (rootopts[0] != 0 ? 0 : ENXIO); 853 } 854 855 if (bootparam_addr.len == 0) { 856 return (ENXIO); 857 } 858 arg.client_name = (caddr_t)&utsname.nodename; 859 arg.file_id = fileid; 860 861 bzero(&res, sizeof (res)); 862 res.server_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP); 863 res.server_path = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP); 864 865 /* 866 * If we are not looking up the root file, we are looking 867 * up a non-critical option that should timeout quickly. 868 */ 869 if (!root) { 870 timeo = GETFILE_TIMEO; 871 retries = GETFILE_RETRIES; 872 } 873 874 /* 875 * bootparam_addr was filled in by the call to 876 * whoami(), so now send an rpc message to the 877 * bootparam daemon requesting our server information. 878 * Use UDP to talk to bootparms. 879 */ 880 stat = mycallrpc(&dl_udp_netconf, &bootparam_addr, 881 (rpcprog_t)BOOTPARAMPROG, (rpcvers_t)BOOTPARAMVERS, 882 (rpcproc_t)BOOTPARAMPROC_GETFILE, 883 xdr_bp_getfile_arg, (caddr_t)&arg, 884 xdr_bp_getfile_res, (caddr_t)&res, 885 timeo, retries); 886 887 if (stat == RPC_SUCCESS) { 888 (void) strcpy(server_name, res.server_name); 889 (void) strcpy(server_path, res.server_path); 890 } 891 892 kmem_free(res.server_name, MAX_MACHINE_NAME + 1); 893 kmem_free(res.server_path, MAX_MACHINE_NAME + 1); 894 895 if (stat != RPC_SUCCESS) { 896 if (root) 897 cmn_err(CE_WARN, "getfile: RPC failed: error %d (%s).", 898 stat, clnt_sperrno(stat)); 899 return ((stat == RPC_TIMEDOUT) ? ETIMEDOUT : ENXIO); /* XXX */ 900 } 901 902 if (*server_path == '\0') 903 return (EINVAL); 904 905 /* 906 * If the fileid is "root", we must get back a server name, for 907 * other parameters a server name is not required 908 */ 909 if (!root) { 910 if (dldebug) 911 printf("getfile: leaving: non-root\n"); 912 return (0); 913 } 914 915 if (*server_name == '\0') 916 return (EINVAL); 917 918 switch (res.server_address.address_type) { 919 case IP_ADDR_TYPE: 920 /* 921 * server_address is where we will get our root 922 * from. 923 */ 924 ((struct sockaddr_in *)server_address->buf)->sin_family = 925 AF_INET; 926 bcopy(&res.server_address.bp_address.ip_addr, 927 &ipaddr, sizeof (ipaddr)); 928 if (ipaddr.s_addr == 0) 929 return (EINVAL); 930 931 ((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr = 932 ipaddr.s_addr; 933 server_address->len = sizeof (struct sockaddr_in); 934 break; 935 936 default: 937 printf("getfile: unknown address type %d\n", 938 res.server_address.address_type); 939 return (EPROTONOSUPPORT); 940 } 941 if (dldebug) 942 printf("getfile: leaving\n"); 943 return (0); 944 } 945 946 /* 947 * If the boot property "bootp-response" exists, then OBP performed a 948 * successful DHCP lease acquisition for us and left the resultant ACK packet 949 * encoded at that location. 950 * 951 * If no such property exists (or the information is incomplete or garbled), 952 * the function returns -1. 953 */ 954 int 955 dhcpinit(void) 956 { 957 int rc, i; 958 char *p; 959 struct in_addr braddr; 960 struct in_addr subnet; 961 DHCP_OPT *doptp; 962 TIUSER *tiptr; 963 struct sockaddr_in *sin; 964 static int once_only = 0; 965 966 if (once_only == 1) { 967 return (0); 968 } 969 once_only = 1; 970 971 if (dhcack == NULL) { 972 return (-1); 973 } 974 975 if (dldebug) { 976 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack, 977 dhcacklen); 978 } 979 980 pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP); 981 pl->len = dhcacklen; 982 pl->pkt = kmem_alloc(pl->len, KM_SLEEP); 983 bcopy(dhcack, pl->pkt, dhcacklen); 984 985 /* 986 * For x86, ifname is not initialized 987 * in the netinstall case and dhcack interface name is 988 * set in strplumb(). So we only copy the name if ifname 989 * is set properly. 990 */ 991 if (ifname[0]) 992 (void) strlcpy(dhcifname, ifname, sizeof (dhcifname)); 993 994 /* remember the server_ip in dhcack */ 995 bcopy((uchar_t *)pl->pkt + 20, dhcp_server_ip, 4); 996 bzero(pl->opts, (DHCP_LAST_OPT + 1) * sizeof (DHCP_OPT *)); 997 bzero(pl->vs, (VS_OPTION_END - VS_OPTION_START + 1) * 998 sizeof (DHCP_OPT *)); 999 1000 if (dhcp_options_scan(pl, B_TRUE) != 0) { 1001 /* garbled packet */ 1002 cmn_err(CE_WARN, "dhcp: DHCP packet parsing failed"); 1003 kmem_free(pl->pkt, pl->len); 1004 kmem_free(pl, sizeof (PKT_LIST)); 1005 pl = NULL; 1006 return (-1); 1007 } 1008 1009 /* set node name */ 1010 if (pl->opts[CD_HOSTNAME] != NULL) { 1011 doptp = pl->opts[CD_HOSTNAME]; 1012 i = doptp->len; 1013 if (i >= SYS_NMLN) { 1014 cmn_err(CE_WARN, "dhcp: Hostname is too long"); 1015 } else { 1016 bcopy(doptp->value, utsname.nodename, i); 1017 utsname.nodename[i] = '\0'; 1018 if (dldebug) { 1019 printf("hostname is %s\n", 1020 utsname.nodename); 1021 } 1022 } 1023 } 1024 1025 /* Set NIS domain name. */ 1026 p = NULL; 1027 if (pl->opts[CD_NIS_DOMAIN] != NULL) { 1028 doptp = pl->opts[CD_NIS_DOMAIN]; 1029 i = doptp->len; 1030 p = (caddr_t)doptp->value; 1031 } 1032 if (p != NULL) { 1033 if (i > SYS_NMLN) { 1034 cmn_err(CE_WARN, 1035 "dhcp: NIS domainname too long."); 1036 } else { 1037 bcopy(p, srpc_domain, i); 1038 srpc_domain[i] = '\0'; 1039 if (dldebug) 1040 printf("dhcp: NIS domain name is %s\n", 1041 srpc_domain); 1042 } 1043 } 1044 1045 /* fetch netmask */ 1046 if (pl->opts[CD_SUBNETMASK] != NULL) { 1047 doptp = pl->opts[CD_SUBNETMASK]; 1048 if (doptp->len != sizeof (struct in_addr)) { 1049 pl->opts[CD_SUBNETMASK] = NULL; 1050 cmn_err(CE_WARN, "dhcp: netmask option malformed"); 1051 } else { 1052 bcopy(doptp->value, &subnet, sizeof (struct in_addr)); 1053 if (dldebug) 1054 printf("dhcp: setting netmask to: %s\n", 1055 inet_ntoa(subnet)); 1056 } 1057 } else { 1058 struct in_addr myIPaddr; 1059 1060 myIPaddr.s_addr = pl->pkt->yiaddr.s_addr; 1061 cmn_err(CE_WARN, "dhcp: no subnet mask supplied - inferring"); 1062 if (IN_CLASSA(ntohl(myIPaddr.s_addr))) 1063 subnet.s_addr = htonl(IN_CLASSA_NET); 1064 else if (IN_CLASSB(ntohl(myIPaddr.s_addr))) 1065 subnet.s_addr = htonl(IN_CLASSB_NET); 1066 else if (IN_CLASSC(ntohl(myIPaddr.s_addr))) 1067 subnet.s_addr = htonl(IN_CLASSC_NET); 1068 else if (IN_CLASSD(ntohl(myIPaddr.s_addr))) 1069 cmn_err(CE_WARN, "dhcp: bad IP address (%s)", 1070 inet_ntoa(myIPaddr)); 1071 else 1072 subnet.s_addr = htonl(IN_CLASSE_NET); 1073 } 1074 /* and broadcast address */ 1075 if (pl->opts[CD_BROADCASTADDR] != NULL) { 1076 doptp = pl->opts[CD_BROADCASTADDR]; 1077 if (doptp->len != sizeof (struct in_addr)) { 1078 pl->opts[CD_BROADCASTADDR] = NULL; 1079 if (dldebug) 1080 printf("dhcp: broadcast address len %d\n", 1081 doptp->len); 1082 } else { 1083 bcopy(doptp->value, &braddr, sizeof (struct in_addr)); 1084 if (dldebug) 1085 printf("dhcp: setting broadcast addr to: %s\n", 1086 inet_ntoa(braddr)); 1087 } 1088 } else { 1089 if (dldebug) 1090 printf("dhcp: no broadcast address supplied\n"); 1091 braddr.s_addr = htonl(INADDR_BROADCAST); 1092 } 1093 /* and plumb and initialize interface */ 1094 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev, 1095 FREAD|FWRITE, &tiptr, CRED())) == 0) { 1096 if (rc = dlifconfig(tiptr, &pl->pkt->yiaddr, &subnet, 1097 &braddr, IFF_DHCPRUNNING)) { 1098 nfs_perror(rc, "dhcp: dlifconfig failed: %m\n"); 1099 kmem_free(pl->pkt, pl->len); 1100 kmem_free(pl, sizeof (PKT_LIST)); 1101 pl = NULL; 1102 (void) t_kclose(tiptr, 0); 1103 return (-1); 1104 } 1105 1106 /* add routes */ 1107 if (pl->opts[CD_ROUTER] != NULL) { 1108 doptp = pl->opts[CD_ROUTER]; 1109 if ((doptp->len % sizeof (struct in_addr)) != 0) { 1110 pl->opts[CD_ROUTER] = NULL; 1111 } else { 1112 int nrouters; 1113 uchar_t *tp; 1114 1115 nrouters = doptp->len / sizeof (struct in_addr); 1116 for (tp = doptp->value, i = 0; i < nrouters; 1117 i++) { 1118 struct in_addr defr; 1119 struct rtentry rtentry; 1120 1121 bcopy(tp, &defr, 1122 sizeof (struct in_addr)); 1123 if (defr.s_addr == 0) 1124 continue; 1125 1126 sin = (struct 1127 sockaddr_in *)&rtentry.rt_dst; 1128 1129 bzero(sin, sizeof (*sin)); 1130 sin->sin_family = AF_INET; 1131 1132 sin = (struct 1133 sockaddr_in *)&rtentry.rt_gateway; 1134 bzero(sin, sizeof (*sin)); 1135 sin->sin_family = AF_INET; 1136 sin->sin_addr = defr; 1137 1138 rtentry.rt_flags = RTF_GATEWAY | RTF_UP; 1139 1140 if (rc = rtioctl(tiptr, SIOCADDRT, 1141 &rtentry)) { 1142 nfs_perror(rc, 1143 "dhcp: couldn't add route " 1144 "to %s: %m.\n", 1145 inet_ntoa(defr)); 1146 continue; 1147 } 1148 if (dldebug) { 1149 printf("dhcp: added route %s\n", 1150 inet_ntoa(defr)); 1151 } 1152 tp += sizeof (struct in_addr); 1153 } 1154 } 1155 } 1156 1157 (void) t_kclose(tiptr, 0); 1158 } 1159 1160 if (dldebug) 1161 printf("dhcpinit: leaving\n"); 1162 1163 return (0); 1164 } 1165 1166 /* 1167 * Initialize nfs mount info from properties and dhcp response. 1168 */ 1169 static void 1170 cacheinit(void) 1171 { 1172 char *str; 1173 DHCP_OPT *doptp; 1174 1175 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1176 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c); 1177 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1178 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c); 1179 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1180 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) { 1181 (void) strncpy(rootopts, str, 255); 1182 ddi_prop_free(str); 1183 } 1184 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1185 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) { 1186 if (inet_aton(str, server_ip) != 0) 1187 cmn_err(CE_NOTE, "server_ipaddr %s is invalid", 1188 str); 1189 ddi_prop_free(str); 1190 if (dldebug) 1191 printf("server ip is %s\n", 1192 inet_ntoa(*(struct in_addr *)server_ip)); 1193 } 1194 1195 if (pl == NULL) 1196 return; 1197 1198 /* extract root path in server_path */ 1199 if (server_path_c == NULL) { 1200 doptp = pl->vs[VS_NFSMNT_ROOTPATH]; 1201 if (doptp == NULL) 1202 doptp = pl->opts[CD_ROOT_PATH]; 1203 if (doptp != NULL) { 1204 int len, size; 1205 uint8_t c, *source; 1206 1207 str = NULL; 1208 source = doptp->value; 1209 size = doptp->len; 1210 c = ':'; 1211 1212 /* 1213 * We have to consider three cases for root path: 1214 * "nfs://server_ip/path" 1215 * "server_ip:/path" 1216 * "/path" 1217 */ 1218 if (bcmp(source, "nfs://", 6) == 0) { 1219 source += 6; 1220 size -= 6; 1221 c = '/'; 1222 } 1223 /* 1224 * Search for next char after ':' or first '/'. 1225 * Note, the '/' is part of the path, but we do 1226 * not need to preserve the ':'. 1227 */ 1228 for (len = 0; len < size; len++) { 1229 if (source[len] == c) { 1230 if (c == ':') { 1231 str = (char *)(&source[++len]); 1232 } else { 1233 str = (char *)(&source[len++]); 1234 size++; 1235 } 1236 break; 1237 } 1238 } 1239 if (str != NULL) { 1240 /* Do not override server_ip from property. */ 1241 if ((*(uint_t *)server_ip) == 0) { 1242 char *ip = kmem_alloc(len, KM_SLEEP); 1243 bcopy(source, ip, len); 1244 ip[len - 1] = '\0'; 1245 if (inet_aton((ip), server_ip) != 0) { 1246 cmn_err(CE_NOTE, 1247 "server_ipaddr %s is " 1248 "invalid", ip); 1249 } 1250 kmem_free(ip, len); 1251 if (dldebug) { 1252 printf("server ip is %s\n", 1253 inet_ntoa( 1254 *(struct in_addr *) 1255 server_ip)); 1256 } 1257 } 1258 len = size - len; 1259 } else { 1260 str = (char *)doptp->value; 1261 len = doptp->len; 1262 } 1263 server_path_c = kmem_alloc(len + 1, KM_SLEEP); 1264 bcopy(str, server_path_c, len); 1265 server_path_c[len] = '\0'; 1266 if (dldebug) 1267 printf("dhcp: root path %s\n", server_path_c); 1268 } else { 1269 cmn_err(CE_WARN, "dhcp: root server path missing"); 1270 } 1271 } 1272 1273 /* set server_name */ 1274 if (server_name_c == NULL) { 1275 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_NAME]; 1276 if (doptp != NULL) { 1277 server_name_c = kmem_alloc(doptp->len + 1, KM_SLEEP); 1278 bcopy(doptp->value, server_name_c, doptp->len); 1279 server_name_c[doptp->len] = '\0'; 1280 if (dldebug) 1281 printf("dhcp: root server name %s\n", 1282 server_name_c); 1283 } else { 1284 cmn_err(CE_WARN, "dhcp: root server name missing"); 1285 } 1286 } 1287 1288 /* set root server_address */ 1289 if ((*(uint_t *)server_ip) == 0) { 1290 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_IP]; 1291 if (doptp) { 1292 bcopy(doptp->value, server_ip, sizeof (server_ip)); 1293 if (dldebug) { 1294 printf("dhcp: root server IP address %s\n", 1295 inet_ntoa(*(struct in_addr *)server_ip)); 1296 } 1297 } else { 1298 if (dldebug) 1299 cmn_err(CE_CONT, 1300 "dhcp: file server ip address missing," 1301 " fallback to dhcp server as file server"); 1302 bcopy(dhcp_server_ip, server_ip, sizeof (server_ip)); 1303 } 1304 } 1305 1306 /* set root file system mount options */ 1307 if (rootopts[0] == 0) { 1308 doptp = pl->vs[VS_NFSMNT_ROOTOPTS]; 1309 if (doptp != NULL && doptp->len < 255) { 1310 bcopy(doptp->value, rootopts, doptp->len); 1311 rootopts[doptp->len] = '\0'; 1312 if (dldebug) 1313 printf("dhcp: rootopts %s\n", rootopts); 1314 } else if (dldebug) { 1315 printf("dhcp: no rootopts or too long\n"); 1316 /* not an error */ 1317 } 1318 } 1319 1320 /* now we are done with pl, just free it */ 1321 kmem_free(pl->pkt, pl->len); 1322 kmem_free(pl, sizeof (PKT_LIST)); 1323 pl = NULL; 1324 } 1325 1326 static int 1327 cacheinfo(char *name, int namelen, 1328 struct netbuf *server_address, char *rootpath, int pathlen) 1329 { 1330 static int init_done = 0; 1331 struct sockaddr_in *sin; 1332 1333 if (init_done == 0) { 1334 cacheinit(); 1335 init_done = 1; 1336 } 1337 1338 /* server_path is a reliable indicator of cache availability */ 1339 if (server_path_c == NULL) 1340 return (-1); 1341 1342 (void) strncpy(rootpath, server_path_c, pathlen); 1343 if (server_name_c) { 1344 (void) strncpy(name, server_name_c, namelen); 1345 } else { 1346 (void) strncpy(name, "unknown", namelen); 1347 } 1348 1349 sin = (struct sockaddr_in *)server_address->buf; 1350 sin->sin_family = AF_INET; 1351 server_address->len = sizeof (struct sockaddr_in); 1352 bcopy(server_ip, &sin->sin_addr, sizeof (struct in_addr)); 1353 return (0); 1354 } 1355 1356 /* 1357 * Set this interface's IP address and netmask, and bring it up. 1358 */ 1359 static int 1360 dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask, 1361 struct in_addr *mybraddr, uint_t flags) 1362 { 1363 int rc; 1364 struct netbuf sbuf; 1365 struct sockaddr_in sin; 1366 1367 if (dldebug) { 1368 printf("dlifconfig: entered\n"); 1369 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr)); 1370 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask)); 1371 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr)); 1372 } 1373 1374 bcopy(myIPaddr, &sin.sin_addr, sizeof (struct in_addr)); 1375 sin.sin_family = AF_INET; 1376 sbuf.buf = (caddr_t)&sin; 1377 sbuf.maxlen = sbuf.len = sizeof (sin); 1378 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) { 1379 nfs_perror(rc, 1380 "dlifconfig: couldn't set interface net address: %m\n"); 1381 return (rc); 1382 } 1383 1384 if (mybraddr->s_addr != INADDR_BROADCAST) { 1385 bcopy(mybraddr, &sin.sin_addr, sizeof (struct in_addr)); 1386 sin.sin_family = AF_INET; 1387 sbuf.buf = (caddr_t)&sin; 1388 sbuf.maxlen = sbuf.len = sizeof (sin); 1389 if (rc = ifioctl(tiptr, SIOCSIFBRDADDR, &sbuf)) { 1390 nfs_perror(rc, 1391 "dlifconfig: couldn't set interface broadcast addr: %m\n"); 1392 return (rc); 1393 } 1394 } 1395 1396 bcopy(mymask, &sin.sin_addr, sizeof (struct in_addr)); 1397 sin.sin_family = AF_INET; 1398 sbuf.buf = (caddr_t)&sin; 1399 sbuf.maxlen = sbuf.len = sizeof (sin); 1400 if (rc = ifioctl(tiptr, SIOCSIFNETMASK, &sbuf)) { 1401 nfs_perror(rc, 1402 "dlifconfig: couldn't set interface net address: %m\n"); 1403 return (rc); 1404 } 1405 1406 /* 1407 * Now turn on the interface. 1408 */ 1409 if (rc = setifflags(tiptr, IFF_UP | flags)) { 1410 nfs_perror(rc, 1411 "dlifconfig: couldn't enable network interface: %m\n"); 1412 return (rc); 1413 } 1414 1415 if (dldebug) 1416 printf("dlifconfig: returned\n"); 1417 return (0); 1418 } 1419 1420 static char * 1421 inet_ntoa(struct in_addr in) 1422 { 1423 static char b[18]; 1424 unsigned char *p; 1425 1426 p = (unsigned char *)∈ 1427 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 1428 return (b); 1429 } 1430 1431 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */ 1432 static int 1433 inet_aton(char *ipstr, uchar_t *ip) 1434 { 1435 int i = 0; 1436 uchar_t val[4] = {0}; 1437 char c = *ipstr; 1438 1439 for (;;) { 1440 if (!isdigit(c)) 1441 return (-1); 1442 for (;;) { 1443 if (!isdigit(c)) 1444 break; 1445 val[i] = val[i] * 10 + (c - '0'); 1446 c = *++ipstr; 1447 } 1448 i++; 1449 if (i == 4) 1450 break; 1451 if (c != '.') 1452 return (-1); 1453 c = *++ipstr; 1454 } 1455 if (c != 0) 1456 return (-1); 1457 bcopy(val, ip, 4); 1458 return (0); 1459 } 1460 1461 #define MAX_ADDR_SIZE 128 1462 1463 /* 1464 * Initialize a netbuf suitable for 1465 * describing an address for the 1466 * transport defined by `tiptr'. 1467 */ 1468 static void 1469 init_netbuf(struct netbuf *nbuf) 1470 { 1471 nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP); 1472 nbuf->maxlen = MAX_ADDR_SIZE; 1473 nbuf->len = 0; 1474 } 1475 1476 static void 1477 free_netbuf(struct netbuf *nbuf) 1478 { 1479 kmem_free(nbuf->buf, nbuf->maxlen); 1480 nbuf->buf = NULL; 1481 nbuf->maxlen = 0; 1482 nbuf->len = 0; 1483 } 1484 1485 static int 1486 rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry) 1487 { 1488 struct strioctl iocb; 1489 int rc; 1490 vnode_t *vp; 1491 1492 iocb.ic_cmd = cmd; 1493 iocb.ic_timout = 0; 1494 iocb.ic_len = sizeof (struct rtentry); 1495 iocb.ic_dp = (caddr_t)rtentry; 1496 1497 vp = tiptr->fp->f_vnode; 1498 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb); 1499 if (rc) 1500 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n"); 1501 return (rc); 1502 } 1503 1504 /* 1505 * Send an ioctl down the stream defined 1506 * by `tiptr'. 1507 * 1508 * We isolate the ifreq dependencies in here. The 1509 * ioctl really ought to take a netbuf and be of 1510 * type TRANSPARENT - one day. 1511 */ 1512 static int 1513 ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf) 1514 { 1515 struct strioctl iocb; 1516 int rc; 1517 vnode_t *vp; 1518 struct ifreq ifr; 1519 1520 /* 1521 * Now do the one requested. 1522 */ 1523 if (nbuf->len) 1524 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf; 1525 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1526 iocb.ic_cmd = cmd; 1527 iocb.ic_timout = 0; 1528 iocb.ic_len = sizeof (ifr); 1529 iocb.ic_dp = (caddr_t)𝔦 1530 1531 vp = tiptr->fp->f_vnode; 1532 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb); 1533 if (rc) { 1534 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n"); 1535 return (rc); 1536 } 1537 1538 /* 1539 * Set reply length. 1540 */ 1541 if (nbuf->len == 0) { 1542 /* 1543 * GET type. 1544 */ 1545 nbuf->len = sizeof (struct sockaddr); 1546 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr; 1547 } 1548 1549 return (0); 1550 } 1551 1552 static int 1553 setifflags(TIUSER *tiptr, uint_t value) 1554 { 1555 struct ifreq ifr; 1556 int rc; 1557 struct strioctl iocb; 1558 1559 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1560 iocb.ic_cmd = SIOCGIFFLAGS; 1561 iocb.ic_timout = 0; 1562 iocb.ic_len = sizeof (ifr); 1563 iocb.ic_dp = (caddr_t)𝔦 1564 if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb)) 1565 return (rc); 1566 1567 ifr.ifr_flags |= value; 1568 iocb.ic_cmd = SIOCSIFFLAGS; 1569 return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb)); 1570 } 1571 1572 /* 1573 * REVerse Address Resolution Protocol (revarp) 1574 * is used by a diskless client to find out its 1575 * IP address when all it knows is its Ethernet address. 1576 * 1577 * Open the ethernet driver, attach and bind 1578 * (DL_BIND_REQ) it, and then format a broadcast RARP 1579 * message for it to send. We pick up the reply and 1580 * let the caller set the interface address using SIOCSIFADDR. 1581 */ 1582 static int 1583 revarp_myaddr(TIUSER *tiptr) 1584 { 1585 int rc; 1586 dl_info_ack_t info; 1587 struct sockaddr_in sin; 1588 struct netbuf sbuf; 1589 ldi_handle_t lh; 1590 ldi_ident_t li; 1591 struct netbuf myaddr = {0, 0, NULL}; 1592 1593 if (dldebug) 1594 printf("revarp_myaddr: entered\n"); 1595 1596 if (rc = ldi_ident_from_mod(&modlinkage, &li)) { 1597 nfs_perror(rc, 1598 "revarp_myaddr: ldi_ident_from_mod failed: %m\n"); 1599 return (rc); 1600 } 1601 1602 rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li); 1603 ldi_ident_release(li); 1604 if (rc) { 1605 nfs_perror(rc, 1606 "revarp_myaddr: ldi_open_by_name failed: %m\n"); 1607 return (rc); 1608 } 1609 1610 if (rc = dl_attach(lh, ifunit, NULL)) { 1611 nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n"); 1612 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 1613 return (rc); 1614 } 1615 1616 if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) { 1617 nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n"); 1618 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 1619 return (rc); 1620 } 1621 1622 if (rc = dl_info(lh, &info, NULL, NULL, NULL)) { 1623 nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n"); 1624 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 1625 return (rc); 1626 } 1627 1628 /* Initialize myaddr */ 1629 myaddr.maxlen = info.dl_addr_length; 1630 myaddr.buf = kmem_alloc(myaddr.maxlen, KM_SLEEP); 1631 1632 revarp_start(lh, &myaddr); 1633 1634 bcopy(myaddr.buf, &sin.sin_addr, myaddr.len); 1635 sin.sin_family = AF_INET; 1636 1637 sbuf.buf = (caddr_t)&sin; 1638 sbuf.maxlen = sbuf.len = sizeof (sin); 1639 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) { 1640 nfs_perror(rc, 1641 "revarp_myaddr: couldn't set interface net address: %m\n"); 1642 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 1643 kmem_free(myaddr.buf, myaddr.maxlen); 1644 return (rc); 1645 } 1646 1647 /* Now turn on the interface */ 1648 if (rc = setifflags(tiptr, IFF_UP)) { 1649 nfs_perror(rc, 1650 "revarp_myaddr: couldn't enable network interface: %m\n"); 1651 } 1652 1653 (void) ldi_close(lh, FREAD|FWRITE, CRED()); 1654 kmem_free(myaddr.buf, myaddr.maxlen); 1655 return (rc); 1656 } 1657 1658 static void 1659 revarp_start(ldi_handle_t lh, struct netbuf *myaddr) 1660 { 1661 struct ether_arp *ea; 1662 int rc; 1663 dl_unitdata_req_t *dl_udata; 1664 mblk_t *bp; 1665 mblk_t *mp; 1666 struct dladdr *dlsap; 1667 static int done = 0; 1668 size_t addrlen = ETHERADDRL; 1669 1670 if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 || 1671 addrlen != ETHERADDRL) { 1672 /* Fallback using per-node address */ 1673 (void) localetheraddr((struct ether_addr *)NULL, &myether); 1674 cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using " 1675 "system wide Ethernet address %s\n", 1676 ether_sprintf(&myether)); 1677 } 1678 1679 getreply: 1680 if (myaddr->len != 0) { 1681 cmn_err(CE_CONT, "?Found my IP address: %x (%d.%d.%d.%d)\n", 1682 *(int *)myaddr->buf, 1683 (uchar_t)myaddr->buf[0], (uchar_t)myaddr->buf[1], 1684 (uchar_t)myaddr->buf[2], (uchar_t)myaddr->buf[3]); 1685 return; 1686 } 1687 1688 if (done++ == 0) 1689 cmn_err(CE_CONT, "?Requesting Internet address for %s\n", 1690 ether_sprintf(&myether)); 1691 1692 /* 1693 * Send another RARP request. 1694 */ 1695 if ((mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap), 1696 BPRI_HI)) == NULL) { 1697 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory"); 1698 return; 1699 } 1700 if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) { 1701 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory"); 1702 return; 1703 } 1704 1705 /* 1706 * Format the transmit request part. 1707 */ 1708 mp->b_datap->db_type = M_PROTO; 1709 dl_udata = (dl_unitdata_req_t *)mp->b_wptr; 1710 mp->b_wptr += sizeof (dl_unitdata_req_t) + sizeof (*dlsap); 1711 dl_udata->dl_primitive = DL_UNITDATA_REQ; 1712 dl_udata->dl_dest_addr_length = sizeof (*dlsap); 1713 dl_udata->dl_dest_addr_offset = sizeof (*dl_udata); 1714 dl_udata->dl_priority.dl_min = 0; 1715 dl_udata->dl_priority.dl_max = 0; 1716 1717 dlsap = (struct dladdr *)(mp->b_rptr + sizeof (*dl_udata)); 1718 bcopy(ðerbroadcastaddr, &dlsap->dl_phys, 1719 sizeof (etherbroadcastaddr)); 1720 dlsap->dl_sap = ETHERTYPE_REVARP; 1721 1722 /* 1723 * Format the actual REVARP request. 1724 */ 1725 bzero(bp->b_wptr, sizeof (struct ether_arp)); 1726 ea = (struct ether_arp *)bp->b_wptr; 1727 bp->b_wptr += sizeof (struct ether_arp); 1728 ea->arp_hrd = htons(ARPHRD_ETHER); 1729 ea->arp_pro = htons(ETHERTYPE_IP); 1730 ea->arp_hln = sizeof (ea->arp_sha); /* hardware address length */ 1731 ea->arp_pln = sizeof (ea->arp_spa); /* protocol address length */ 1732 ea->arp_op = htons(REVARP_REQUEST); 1733 ether_copy(&myether, &ea->arp_sha); 1734 ether_copy(&myether, &ea->arp_tha); 1735 1736 mp->b_cont = bp; 1737 1738 if ((rc = ldi_putmsg(lh, mp)) != 0) { 1739 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n"); 1740 return; 1741 } 1742 revarpinput(lh, myaddr); 1743 1744 goto getreply; 1745 } 1746 1747 /* 1748 * Client side Reverse-ARP input 1749 * Server side is handled by user level server 1750 */ 1751 static void 1752 revarpinput(ldi_handle_t lh, struct netbuf *myaddr) 1753 { 1754 struct ether_arp *ea; 1755 mblk_t *bp; 1756 mblk_t *mp; 1757 int rc; 1758 timestruc_t tv, give_up, now; 1759 1760 /* 1761 * Choose the time at which we will give up, and resend our 1762 * request. 1763 */ 1764 gethrestime(&give_up); 1765 give_up.tv_sec += REVARP_TIMEO; 1766 wait: 1767 /* 1768 * Compute new timeout value. 1769 */ 1770 tv = give_up; 1771 gethrestime(&now); 1772 timespecsub(&tv, &now); 1773 /* 1774 * If we don't have at least one full second remaining, give up. 1775 * This means we might wait only just over 4.0 seconds, but that's 1776 * okay. 1777 */ 1778 if (tv.tv_sec <= 0) 1779 return; 1780 rc = ldi_getmsg(lh, &mp, &tv); 1781 if (rc == ETIME) { 1782 goto out; 1783 } else if (rc != 0) { 1784 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n"); 1785 return; 1786 } 1787 1788 if (mp->b_cont == NULL) { 1789 printf("revarpinput: b_cont == NULL\n"); 1790 goto out; 1791 } 1792 1793 if (mp->b_datap->db_type != M_PROTO) { 1794 printf("revarpinput: bad header type %d\n", 1795 mp->b_datap->db_type); 1796 goto out; 1797 } 1798 1799 bp = mp->b_cont; 1800 1801 if (bp->b_wptr - bp->b_rptr < sizeof (*ea)) { 1802 printf("revarpinput: bad data len %d, expect %d\n", 1803 (int)(bp->b_wptr - bp->b_rptr), (int)sizeof (*ea)); 1804 goto out; 1805 } 1806 1807 ea = (struct ether_arp *)bp->b_rptr; 1808 1809 if ((ushort_t)ntohs(ea->arp_pro) != ETHERTYPE_IP) { 1810 /* We could have received another broadcast arp packet. */ 1811 if (dldebug) 1812 printf("revarpinput: bad type %x\n", 1813 (ushort_t)ntohs(ea->arp_pro)); 1814 freemsg(mp); 1815 goto wait; 1816 } 1817 if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) { 1818 /* We could have received a broadcast arp request. */ 1819 if (dldebug) 1820 printf("revarpinput: bad op %x\n", 1821 (ushort_t)ntohs(ea->arp_op)); 1822 freemsg(mp); 1823 goto wait; 1824 } 1825 1826 if (!ether_cmp(&ea->arp_tha, &myether)) { 1827 bcopy(&ea->arp_tpa, myaddr->buf, sizeof (ea->arp_tpa)); 1828 myaddr->len = sizeof (ea->arp_tpa); 1829 } else { 1830 /* We could have gotten a broadcast arp response. */ 1831 if (dldebug) 1832 printf("revarpinput: got reply, but not my address\n"); 1833 freemsg(mp); 1834 goto wait; 1835 } 1836 out: 1837 freemsg(mp); 1838 } 1839 1840 /* 1841 * From rpcsvc/mountxdr.c in SunOS. We can't 1842 * put this into the rpc directory because 1843 * it calls xdr_fhandle() which is in a 1844 * loadable module. 1845 */ 1846 static bool_t 1847 myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp) 1848 { 1849 1850 if (!xdr_int(xdrs, &fhsp->fhs_status)) 1851 return (FALSE); 1852 if (fhsp->fhs_status == 0) { 1853 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh)) 1854 return (FALSE); 1855 } 1856 return (TRUE); 1857 } 1858 1859 /* 1860 * From nfs_xdr.c. 1861 * 1862 * File access handle 1863 * The fhandle struct is treated a opaque data on the wire 1864 */ 1865 static bool_t 1866 myxdr_fhandle(XDR *xdrs, fhandle_t *fh) 1867 { 1868 return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE)); 1869 } 1870 1871 static bool_t 1872 myxdr_mountres3(XDR *xdrs, struct mountres3 *objp) 1873 { 1874 if (!myxdr_mountstat3(xdrs, &objp->fhs_status)) 1875 return (FALSE); 1876 switch (objp->fhs_status) { 1877 case MNT_OK: 1878 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)) 1879 return (FALSE); 1880 break; 1881 default: 1882 break; 1883 } 1884 return (TRUE); 1885 } 1886 1887 static bool_t 1888 myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp) 1889 { 1890 return (xdr_enum(xdrs, (enum_t *)objp)); 1891 } 1892 1893 static bool_t 1894 myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp) 1895 { 1896 if (!myxdr_fhandle3(xdrs, &objp->fhandle)) 1897 return (FALSE); 1898 if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val, 1899 (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0, 1900 sizeof (int), (xdrproc_t)xdr_int)) 1901 return (FALSE); 1902 return (TRUE); 1903 } 1904 1905 static bool_t 1906 myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp) 1907 { 1908 return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val, 1909 (uint_t *)&objp->fhandle3_len, FHSIZE3)); 1910 } 1911 1912 /* 1913 * From SunOS pmap_clnt.c 1914 * 1915 * Port mapper routines: 1916 * pmap_kgetport() - get port number. 1917 * pmap_rmt_call() - indirect call via port mapper. 1918 * 1919 */ 1920 static enum clnt_stat 1921 pmap_kgetport(struct knetconfig *knconf, struct netbuf *call_addr, 1922 rpcprog_t prog, rpcvers_t vers, rpcprot_t prot) 1923 { 1924 ushort_t port; 1925 int tries; 1926 enum clnt_stat stat; 1927 struct pmap pmap_parms; 1928 RPCB rpcb_parms; 1929 char *ua = NULL; 1930 1931 port = 0; 1932 1933 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT); 1934 1935 pmap_parms.pm_prog = prog; 1936 pmap_parms.pm_vers = vers; 1937 pmap_parms.pm_prot = prot; 1938 pmap_parms.pm_port = 0; 1939 for (tries = 0; tries < 5; tries++) { 1940 stat = mycallrpc(knconf, call_addr, 1941 PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 1942 myxdr_pmap, (char *)&pmap_parms, 1943 xdr_u_short, (char *)&port, 1944 DEFAULT_TIMEO, DEFAULT_RETRIES); 1945 1946 if (stat != RPC_TIMEDOUT) 1947 break; 1948 cmn_err(CE_WARN, 1949 "pmap_kgetport: Portmapper not responding; still trying"); 1950 } 1951 1952 if (stat == RPC_PROGUNAVAIL) { 1953 cmn_err(CE_WARN, 1954 "pmap_kgetport: Portmapper failed - trying rpcbind"); 1955 1956 rpcb_parms.r_prog = prog; 1957 rpcb_parms.r_vers = vers; 1958 rpcb_parms.r_netid = knconf->knc_proto; 1959 rpcb_parms.r_addr = rpcb_parms.r_owner = ""; 1960 1961 for (tries = 0; tries < 5; tries++) { 1962 stat = mycallrpc(knconf, call_addr, 1963 RPCBPROG, RPCBVERS, RPCBPROC_GETADDR, 1964 xdr_rpcb, (char *)&rpcb_parms, 1965 xdr_wrapstring, (char *)&ua, 1966 DEFAULT_TIMEO, DEFAULT_RETRIES); 1967 1968 if (stat != RPC_TIMEDOUT) 1969 break; 1970 cmn_err(CE_WARN, 1971 "pmap_kgetport: rpcbind not responding; still trying"); 1972 } 1973 1974 if (stat == RPC_SUCCESS) { 1975 if ((ua != NULL) && (ua[0] != NULL)) { 1976 port = rpc_uaddr2port(AF_INET, ua); 1977 } else { 1978 /* Address unknown */ 1979 stat = RPC_PROGUNAVAIL; 1980 } 1981 } 1982 } 1983 1984 if (stat == RPC_SUCCESS) 1985 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port); 1986 1987 return (stat); 1988 } 1989 1990 /* 1991 * pmapper remote-call-service interface. 1992 * This routine is used to call the pmapper remote call service 1993 * which will look up a service program in the port maps, and then 1994 * remotely call that routine with the given parameters. This allows 1995 * programs to do a lookup and call in one step. In addition to the call_addr, 1996 * the caller provides a boolean hint about the destination address (TRUE if 1997 * address is a broadcast address, FALSE otherwise). 1998 * 1999 * On return, `call addr' contains the port number for the 2000 * service requested, and `resp_addr' contains its IP address. 2001 */ 2002 static enum clnt_stat 2003 pmap_rmt_call(struct knetconfig *knconf, struct netbuf *call_addr, 2004 bool_t bcast, rpcprog_t progn, rpcvers_t versn, rpcproc_t procn, 2005 xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp, 2006 struct timeval tout, struct netbuf *resp_addr) 2007 { 2008 CLIENT *cl; 2009 enum clnt_stat stat; 2010 rpcport_t port; 2011 int rc; 2012 struct rmtcallargs pmap_args; 2013 struct rmtcallres pmap_res; 2014 struct rpcb_rmtcallargs rpcb_args; 2015 struct rpcb_rmtcallres rpcb_res; 2016 char ua[100]; /* XXX */ 2017 2018 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT); 2019 2020 rc = clnt_tli_kcreate(knconf, call_addr, PMAPPROG, PMAPVERS, 2021 0, PMAP_RETRIES, CRED(), &cl); 2022 if (rc != 0) { 2023 nfs_perror(rc, 2024 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n"); 2025 return (RPC_SYSTEMERROR); /* XXX */ 2026 } 2027 if (cl == (CLIENT *)NULL) { 2028 panic("pmap_rmt_call: clnt_tli_kcreate failed"); 2029 /* NOTREACHED */ 2030 } 2031 2032 (void) CLNT_CONTROL(cl, CLSET_BCAST, (char *)&bcast); 2033 2034 pmap_args.prog = progn; 2035 pmap_args.vers = versn; 2036 pmap_args.proc = procn; 2037 pmap_args.args_ptr = argsp; 2038 pmap_args.xdr_args = xdrargs; 2039 pmap_res.port_ptr = &port; 2040 pmap_res.results_ptr = resp; 2041 pmap_res.xdr_results = xdrres; 2042 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT, 2043 myxdr_rmtcall_args, (caddr_t)&pmap_args, 2044 myxdr_rmtcallres, (caddr_t)&pmap_res, 2045 tout, resp_addr); 2046 2047 if (stat == RPC_SUCCESS) { 2048 ((struct sockaddr_in *)resp_addr->buf)->sin_port = 2049 htons((ushort_t)port); 2050 } 2051 CLNT_DESTROY(cl); 2052 2053 if (stat != RPC_PROGUNAVAIL) 2054 return (stat); 2055 2056 cmn_err(CE_WARN, "pmap_rmt_call: Portmapper failed - trying rpcbind"); 2057 2058 rc = clnt_tli_kcreate(knconf, call_addr, RPCBPROG, RPCBVERS, 2059 0, PMAP_RETRIES, CRED(), &cl); 2060 if (rc != 0) { 2061 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n"); 2062 return (RPC_SYSTEMERROR); /* XXX */ 2063 } 2064 2065 if (cl == NULL) { 2066 panic("pmap_rmt_call: clnt_tli_kcreate failed"); 2067 /* NOTREACHED */ 2068 } 2069 2070 rpcb_args.prog = progn; 2071 rpcb_args.vers = versn; 2072 rpcb_args.proc = procn; 2073 rpcb_args.args_ptr = argsp; 2074 rpcb_args.xdr_args = xdrargs; 2075 rpcb_res.addr_ptr = ua; 2076 rpcb_res.results_ptr = resp; 2077 rpcb_res.xdr_results = xdrres; 2078 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT, 2079 xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_args, 2080 xdr_rpcb_rmtcallres, (caddr_t)&rpcb_res, 2081 tout, resp_addr); 2082 2083 if (stat == RPC_SUCCESS) 2084 ((struct sockaddr_in *)resp_addr->buf)->sin_port = 2085 rpc_uaddr2port(AF_INET, ua); 2086 CLNT_DESTROY(cl); 2087 2088 return (stat); 2089 } 2090 2091 /* 2092 * XDR remote call arguments 2093 * written for XDR_ENCODE direction only 2094 */ 2095 static bool_t 2096 myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap) 2097 { 2098 uint_t lenposition; 2099 uint_t argposition; 2100 uint_t position; 2101 2102 if (xdr_rpcprog(xdrs, &(cap->prog)) && 2103 xdr_rpcvers(xdrs, &(cap->vers)) && 2104 xdr_rpcproc(xdrs, &(cap->proc))) { 2105 lenposition = XDR_GETPOS(xdrs); 2106 if (!xdr_u_int(xdrs, &cap->arglen)) 2107 return (FALSE); 2108 argposition = XDR_GETPOS(xdrs); 2109 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr)) 2110 return (FALSE); 2111 position = XDR_GETPOS(xdrs); 2112 cap->arglen = (uint_t)position - (uint_t)argposition; 2113 XDR_SETPOS(xdrs, lenposition); 2114 if (!xdr_u_int(xdrs, &cap->arglen)) 2115 return (FALSE); 2116 XDR_SETPOS(xdrs, position); 2117 return (TRUE); 2118 } 2119 return (FALSE); 2120 } 2121 2122 /* 2123 * XDR remote call results 2124 * written for XDR_DECODE direction only 2125 */ 2126 static bool_t 2127 myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp) 2128 { 2129 caddr_t port_ptr; 2130 2131 port_ptr = (caddr_t)crp->port_ptr; 2132 if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) && 2133 xdr_u_int(xdrs, &crp->resultslen)) { 2134 crp->port_ptr = (rpcport_t *)port_ptr; 2135 return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); 2136 } 2137 return (FALSE); 2138 } 2139 2140 static bool_t 2141 myxdr_pmap(XDR *xdrs, struct pmap *regs) 2142 { 2143 if (xdr_rpcprog(xdrs, ®s->pm_prog) && 2144 xdr_rpcvers(xdrs, ®s->pm_vers) && 2145 xdr_rpcprot(xdrs, ®s->pm_prot)) 2146 return (xdr_rpcport(xdrs, ®s->pm_port)); 2147 2148 return (FALSE); 2149 } 2150 2151 /* 2152 * From SunOS callrpc.c 2153 */ 2154 static enum clnt_stat 2155 mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr, 2156 rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum, 2157 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out, 2158 int timeo, int retries) 2159 { 2160 CLIENT *cl; 2161 struct timeval tv; 2162 enum clnt_stat cl_stat; 2163 int rc; 2164 2165 rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum, 2166 0, retries, CRED(), &cl); 2167 if (rc) { 2168 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n"); 2169 return (RPC_SYSTEMERROR); /* XXX */ 2170 } 2171 tv.tv_sec = timeo; 2172 tv.tv_usec = 0; 2173 cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv); 2174 AUTH_DESTROY(cl->cl_auth); 2175 CLNT_DESTROY(cl); 2176 return (cl_stat); 2177 } 2178 2179 /* 2180 * Configure the 'default' interface based on existing boot properties. 2181 */ 2182 static int 2183 bp_netconfig(void) 2184 { 2185 char *str; 2186 struct in_addr my_ip, my_netmask, my_router, my_broadcast; 2187 struct sockaddr_in *sin; 2188 TIUSER *tiptr; 2189 int rc; 2190 struct rtentry rtentry; 2191 2192 my_ip.s_addr = my_netmask.s_addr = my_router.s_addr = 0; 2193 2194 /* 2195 * No way of getting this right now. Collude with dlifconfig() 2196 * to let the protocol stack choose. 2197 */ 2198 my_broadcast.s_addr = INADDR_BROADCAST; 2199 2200 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2201 DDI_PROP_DONTPASS, BP_HOST_IP, &str) == DDI_SUCCESS) { 2202 if (inet_aton(str, (uchar_t *)&my_ip) != 0) 2203 cmn_err(CE_NOTE, "host-ip %s is invalid\n", 2204 str); 2205 ddi_prop_free(str); 2206 if (dldebug) 2207 printf("host ip is %s\n", 2208 inet_ntoa(my_ip)); 2209 } 2210 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2211 DDI_PROP_DONTPASS, BP_SUBNET_MASK, &str) == DDI_SUCCESS) { 2212 if (inet_aton(str, (uchar_t *)&my_netmask) != 0) 2213 cmn_err(CE_NOTE, "subnet-mask %s is invalid\n", 2214 str); 2215 ddi_prop_free(str); 2216 if (dldebug) 2217 printf("subnet mask is %s\n", 2218 inet_ntoa(my_netmask)); 2219 } 2220 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2221 DDI_PROP_DONTPASS, BP_ROUTER_IP, &str) == DDI_SUCCESS) { 2222 if (inet_aton(str, (uchar_t *)&my_router) != 0) 2223 cmn_err(CE_NOTE, "router-ip %s is invalid\n", 2224 str); 2225 ddi_prop_free(str); 2226 if (dldebug) 2227 printf("router ip is %s\n", 2228 inet_ntoa(my_router)); 2229 } 2230 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2231 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c); 2232 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2233 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c); 2234 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2235 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) { 2236 (void) strlcpy(rootopts, str, sizeof (rootopts)); 2237 ddi_prop_free(str); 2238 } 2239 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2240 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) { 2241 if (inet_aton(str, server_ip) != 0) 2242 cmn_err(CE_NOTE, "server-ip %s is invalid\n", 2243 str); 2244 ddi_prop_free(str); 2245 if (dldebug) 2246 printf("server ip is %s\n", 2247 inet_ntoa(*(struct in_addr *)server_ip)); 2248 } 2249 2250 /* 2251 * We need all of these to configure based on properties. 2252 */ 2253 if ((my_ip.s_addr == 0) || 2254 (my_netmask.s_addr == 0) || 2255 (server_path_c == NULL) || 2256 (server_name_c == NULL) || 2257 (*(uint_t *)server_ip == 0)) 2258 return (-1); 2259 2260 cmn_err(CE_CONT, "?IP address: %s\n", inet_ntoa(my_ip)); 2261 cmn_err(CE_CONT, "?IP netmask: %s\n", inet_ntoa(my_netmask)); 2262 if (my_router.s_addr != 0) 2263 cmn_err(CE_CONT, "?IP router: %s\n", inet_ntoa(my_router)); 2264 cmn_err(CE_CONT, "?NFS server: %s (%s)\n", server_name_c, 2265 inet_ntoa(*(struct in_addr *)server_ip)); 2266 cmn_err(CE_CONT, "?NFS path: %s\n", server_path_c); 2267 2268 /* 2269 * Configure the interface. 2270 */ 2271 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev, 2272 FREAD|FWRITE, &tiptr, CRED())) != 0) { 2273 nfs_perror(rc, "bp_netconfig: t_kopen udp failed: %m.\n"); 2274 return (rc); 2275 } 2276 2277 if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast, 2278 0)) < 0) { 2279 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n"); 2280 (void) t_kclose(tiptr, 0); 2281 return (rc); 2282 } 2283 2284 if (my_router.s_addr != 0) { 2285 /* 2286 * Add a default route. 2287 */ 2288 sin = (struct sockaddr_in *)&rtentry.rt_dst; 2289 bzero(sin, sizeof (*sin)); 2290 sin->sin_family = AF_INET; 2291 2292 sin = (struct sockaddr_in *)&rtentry.rt_gateway; 2293 bzero(sin, sizeof (*sin)); 2294 sin->sin_family = AF_INET; 2295 sin->sin_addr = my_router; 2296 2297 rtentry.rt_flags = RTF_GATEWAY | RTF_UP; 2298 2299 if ((rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) != 0) { 2300 nfs_perror(rc, 2301 "bp_netconfig: couldn't add route: %m.\n"); 2302 (void) t_kclose(tiptr, 0); 2303 return (rc); 2304 } 2305 } 2306 2307 (void) t_kclose(tiptr, 0); 2308 2309 return (0); 2310 } 2311 2312 /* 2313 * The network device we will use to boot from is plumbed. Extract the details 2314 * from rootfs. 2315 */ 2316 static void 2317 init_config(void) 2318 { 2319 (void) strlcpy(ndev_path, rootfs.bo_devname, sizeof (ndev_path)); 2320 (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname)); 2321 ifunit = rootfs.bo_ppa; 2322 2323 /* 2324 * Assumes only one linkage array element. 2325 */ 2326 dl_udp_netconf.knc_rdev = 2327 makedevice(clone_major, ddi_name_to_major("udp")); 2328 dl_tcp_netconf.knc_rdev = 2329 makedevice(clone_major, ddi_name_to_major("tcp")); 2330 2331 /* 2332 * Now we bringup the interface. 2333 * Try cached dhcp response first. If it fails, do rarp. 2334 */ 2335 if ((bp_netconfig() != 0) && 2336 (dhcpinit() != 0) && 2337 (whoami() != 0)) 2338 cmn_err(CE_WARN, 2339 "%s: no response from interface", ifname); 2340 else if (dldebug) 2341 printf("init_config: ifname %s is up\n", ifname); 2342 } 2343 2344 /* 2345 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c 2346 * Changes must be made to both lists. 2347 */ 2348 static char *optlist[] = { 2349 #define OPT_RO 0 2350 MNTOPT_RO, 2351 #define OPT_RW 1 2352 MNTOPT_RW, 2353 #define OPT_QUOTA 2 2354 MNTOPT_QUOTA, 2355 #define OPT_NOQUOTA 3 2356 MNTOPT_NOQUOTA, 2357 #define OPT_SOFT 4 2358 MNTOPT_SOFT, 2359 #define OPT_HARD 5 2360 MNTOPT_HARD, 2361 #define OPT_SUID 6 2362 MNTOPT_SUID, 2363 #define OPT_NOSUID 7 2364 MNTOPT_NOSUID, 2365 #define OPT_GRPID 8 2366 MNTOPT_GRPID, 2367 #define OPT_REMOUNT 9 2368 MNTOPT_REMOUNT, 2369 #define OPT_NOSUB 10 2370 MNTOPT_NOSUB, 2371 #define OPT_INTR 11 2372 MNTOPT_INTR, 2373 #define OPT_NOINTR 12 2374 MNTOPT_NOINTR, 2375 #define OPT_PORT 13 2376 MNTOPT_PORT, 2377 #define OPT_SECURE 14 2378 MNTOPT_SECURE, 2379 #define OPT_RSIZE 15 2380 MNTOPT_RSIZE, 2381 #define OPT_WSIZE 16 2382 MNTOPT_WSIZE, 2383 #define OPT_TIMEO 17 2384 MNTOPT_TIMEO, 2385 #define OPT_RETRANS 18 2386 MNTOPT_RETRANS, 2387 #define OPT_ACTIMEO 19 2388 MNTOPT_ACTIMEO, 2389 #define OPT_ACREGMIN 20 2390 MNTOPT_ACREGMIN, 2391 #define OPT_ACREGMAX 21 2392 MNTOPT_ACREGMAX, 2393 #define OPT_ACDIRMIN 22 2394 MNTOPT_ACDIRMIN, 2395 #define OPT_ACDIRMAX 23 2396 MNTOPT_ACDIRMAX, 2397 #define OPT_BG 24 2398 MNTOPT_BG, 2399 #define OPT_FG 25 2400 MNTOPT_FG, 2401 #define OPT_RETRY 26 2402 MNTOPT_RETRY, 2403 #define OPT_NOAC 27 2404 MNTOPT_NOAC, 2405 #define OPT_NOCTO 28 2406 MNTOPT_NOCTO, 2407 #define OPT_LLOCK 29 2408 MNTOPT_LLOCK, 2409 #define OPT_POSIX 30 2410 MNTOPT_POSIX, 2411 #define OPT_VERS 31 2412 MNTOPT_VERS, 2413 #define OPT_PROTO 32 2414 MNTOPT_PROTO, 2415 #define OPT_SEMISOFT 33 2416 MNTOPT_SEMISOFT, 2417 #define OPT_NOPRINT 34 2418 MNTOPT_NOPRINT, 2419 #define OPT_SEC 35 2420 MNTOPT_SEC, 2421 #define OPT_LARGEFILES 36 2422 MNTOPT_LARGEFILES, 2423 #define OPT_NOLARGEFILES 37 2424 MNTOPT_NOLARGEFILES, 2425 #define OPT_PUBLIC 38 2426 MNTOPT_PUBLIC, 2427 #define OPT_DIRECTIO 39 2428 MNTOPT_FORCEDIRECTIO, 2429 #define OPT_NODIRECTIO 40 2430 MNTOPT_NOFORCEDIRECTIO, 2431 #define OPT_XATTR 41 2432 MNTOPT_XATTR, 2433 #define OPT_NOXATTR 42 2434 MNTOPT_NOXATTR, 2435 #define OPT_DEVICES 43 2436 MNTOPT_DEVICES, 2437 #define OPT_NODEVICES 44 2438 MNTOPT_NODEVICES, 2439 #define OPT_SETUID 45 2440 MNTOPT_SETUID, 2441 #define OPT_NOSETUID 46 2442 MNTOPT_NOSETUID, 2443 #define OPT_EXEC 47 2444 MNTOPT_EXEC, 2445 #define OPT_NOEXEC 48 2446 MNTOPT_NOEXEC, 2447 NULL 2448 }; 2449 2450 static int 2451 isdigit(int ch) 2452 { 2453 return (ch >= '0' && ch <= '9'); 2454 } 2455 2456 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') 2457 #define bad(val) (val == NULL || !isdigit(*val)) 2458 2459 static int 2460 atoi(const char *p) 2461 { 2462 int n; 2463 int c, neg = 0; 2464 2465 if (!isdigit(c = *p)) { 2466 while (isspace(c)) 2467 c = *++p; 2468 switch (c) { 2469 case '-': 2470 neg++; 2471 /* FALLTHROUGH */ 2472 case '+': 2473 c = *++p; 2474 } 2475 if (!isdigit(c)) 2476 return (0); 2477 } 2478 for (n = '0' - c; isdigit(c = *++p); ) { 2479 n *= 10; /* two steps to avoid unnecessary overflow */ 2480 n += '0' - c; /* accum neg to avoid surprises at MAX */ 2481 } 2482 return (neg ? n : -n); 2483 } 2484 2485 /* 2486 * Default root read tsize XXX 2487 */ 2488 int nfs_root_rsize = 8 * 1024; /* conservative for dumb NICs */ 2489 int nfs4_root_rsize = 32 * 1024; /* only runs on TCP be aggressive */ 2490 2491 /* 2492 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT 2493 */ 2494 int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT; 2495 2496 static int 2497 init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf, 2498 int *vfsflags) 2499 { 2500 char servername[SYS_NMLN]; 2501 static int first = 0; 2502 struct netbuf server_address; 2503 char *opts, *val; 2504 int vers; 2505 struct knetconfig *cf = *dl_cf; 2506 char rootoptsbuf[256]; 2507 2508 /* 2509 * Set default mount options 2510 */ 2511 args->flags = nfs_rootopts; 2512 args->rsize = 0; 2513 args->flags |= NFSMNT_ACREGMIN; 2514 args->acregmin = ACMINMAX; 2515 args->flags |= NFSMNT_ACREGMAX; 2516 args->acregmax = ACMAXMAX; 2517 args->flags |= NFSMNT_ACDIRMIN; 2518 args->acdirmin = ACMINMAX; 2519 args->flags |= NFSMNT_ACDIRMAX; 2520 args->acdirmax = ACMAXMAX; 2521 2522 *vfsflags = 0; 2523 2524 /* 2525 * Only look up the rootopts the first time, we store this in 2526 * a static buffer but we are guaranteed to be single threaded 2527 * and not reentrant. 2528 */ 2529 if (first == 0) { 2530 first++; 2531 2532 init_netbuf(&server_address); 2533 2534 if (getfile("rootopts", servername, &server_address, 2535 rootopts)) { 2536 rootopts[0] = '\0'; 2537 free_netbuf(&server_address); 2538 goto sanity; 2539 } 2540 free_netbuf(&server_address); 2541 } 2542 2543 if (dldebug) 2544 printf("rootopts = %s\n", rootopts); 2545 2546 /* 2547 * We have to preserve rootopts for second time. 2548 */ 2549 (void) strncpy(rootoptsbuf, rootopts, sizeof (rootoptsbuf)); 2550 rootoptsbuf[sizeof (rootoptsbuf) - 1] = '\0'; 2551 opts = rootoptsbuf; 2552 while (*opts) { 2553 int opt; 2554 2555 switch (opt = getsubopt(&opts, optlist, &val)) { 2556 /* 2557 * Options that are defaults or meaningless so ignored 2558 */ 2559 case OPT_QUOTA: 2560 case OPT_NOQUOTA: 2561 case OPT_SUID: 2562 case OPT_DEVICES: 2563 case OPT_SETUID: 2564 case OPT_BG: 2565 case OPT_FG: 2566 case OPT_RETRY: 2567 case OPT_POSIX: 2568 case OPT_LARGEFILES: 2569 case OPT_XATTR: 2570 case OPT_NOXATTR: 2571 case OPT_EXEC: 2572 break; 2573 case OPT_RO: 2574 *vfsflags |= MS_RDONLY; 2575 break; 2576 case OPT_RW: 2577 *vfsflags &= ~(MS_RDONLY); 2578 break; 2579 case OPT_SOFT: 2580 args->flags |= NFSMNT_SOFT; 2581 args->flags &= ~(NFSMNT_SEMISOFT); 2582 break; 2583 case OPT_SEMISOFT: 2584 args->flags |= NFSMNT_SOFT; 2585 args->flags |= NFSMNT_SEMISOFT; 2586 break; 2587 case OPT_HARD: 2588 args->flags &= ~(NFSMNT_SOFT); 2589 args->flags &= ~(NFSMNT_SEMISOFT); 2590 break; 2591 case OPT_NOSUID: 2592 case OPT_NODEVICES: 2593 case OPT_NOSETUID: 2594 case OPT_NOEXEC: 2595 cmn_err(CE_WARN, 2596 "nfs_dlboot: may not set root partition %s", 2597 optlist[opt]); 2598 break; 2599 case OPT_GRPID: 2600 args->flags |= NFSMNT_GRPID; 2601 break; 2602 case OPT_REMOUNT: 2603 cmn_err(CE_WARN, 2604 "nfs_dlboot: may not remount root partition"); 2605 break; 2606 case OPT_INTR: 2607 args->flags |= NFSMNT_INT; 2608 break; 2609 case OPT_NOINTR: 2610 args->flags &= ~(NFSMNT_INT); 2611 break; 2612 case OPT_NOAC: 2613 args->flags |= NFSMNT_NOAC; 2614 break; 2615 case OPT_PORT: 2616 cmn_err(CE_WARN, 2617 "nfs_dlboot: may not change root port number"); 2618 break; 2619 case OPT_SECURE: 2620 cmn_err(CE_WARN, 2621 "nfs_dlboot: root mounted auth_unix, secure ignored"); 2622 break; 2623 case OPT_NOCTO: 2624 args->flags |= NFSMNT_NOCTO; 2625 break; 2626 case OPT_RSIZE: 2627 if (bad(val)) { 2628 cmn_err(CE_WARN, 2629 "nfs_dlboot: invalid option: rsize"); 2630 break; 2631 } 2632 args->flags |= NFSMNT_RSIZE; 2633 args->rsize = atoi(val); 2634 break; 2635 case OPT_WSIZE: 2636 if (bad(val)) { 2637 cmn_err(CE_WARN, 2638 "nfs_dlboot: invalid option: wsize"); 2639 break; 2640 } 2641 args->flags |= NFSMNT_WSIZE; 2642 args->wsize = atoi(val); 2643 break; 2644 case OPT_TIMEO: 2645 if (bad(val)) { 2646 cmn_err(CE_WARN, 2647 "nfs_dlboot: invalid option: timeo"); 2648 break; 2649 } 2650 args->flags |= NFSMNT_TIMEO; 2651 args->timeo = atoi(val); 2652 break; 2653 case OPT_RETRANS: 2654 if (bad(val)) { 2655 cmn_err(CE_WARN, 2656 "nfs_dlboot: invalid option: retrans"); 2657 break; 2658 } 2659 args->flags |= NFSMNT_RETRANS; 2660 args->retrans = atoi(val); 2661 break; 2662 case OPT_ACTIMEO: 2663 if (bad(val)) { 2664 cmn_err(CE_WARN, 2665 "nfs_dlboot: invalid option: actimeo"); 2666 break; 2667 } 2668 args->flags |= NFSMNT_ACDIRMAX; 2669 args->flags |= NFSMNT_ACREGMAX; 2670 args->flags |= NFSMNT_ACDIRMIN; 2671 args->flags |= NFSMNT_ACREGMIN; 2672 args->acdirmin = args->acregmin = args->acdirmax = 2673 args->acregmax = atoi(val); 2674 break; 2675 case OPT_ACREGMIN: 2676 if (bad(val)) { 2677 cmn_err(CE_WARN, 2678 "nfs_dlboot: invalid option: acregmin"); 2679 break; 2680 } 2681 args->flags |= NFSMNT_ACREGMIN; 2682 args->acregmin = atoi(val); 2683 break; 2684 case OPT_ACREGMAX: 2685 if (bad(val)) { 2686 cmn_err(CE_WARN, 2687 "nfs_dlboot: invalid option: acregmax"); 2688 break; 2689 } 2690 args->flags |= NFSMNT_ACREGMAX; 2691 args->acregmax = atoi(val); 2692 break; 2693 case OPT_ACDIRMIN: 2694 if (bad(val)) { 2695 cmn_err(CE_WARN, 2696 "nfs_dlboot: invalid option: acdirmin"); 2697 break; 2698 } 2699 args->flags |= NFSMNT_ACDIRMIN; 2700 args->acdirmin = atoi(val); 2701 break; 2702 case OPT_ACDIRMAX: 2703 if (bad(val)) { 2704 cmn_err(CE_WARN, 2705 "nfs_dlboot: invalid option: acdirmax"); 2706 break; 2707 } 2708 args->flags |= NFSMNT_ACDIRMAX; 2709 args->acdirmax = atoi(val); 2710 break; 2711 case OPT_LLOCK: 2712 args->flags |= NFSMNT_LLOCK; 2713 break; 2714 case OPT_VERS: 2715 if (bad(val)) { 2716 cmn_err(CE_WARN, 2717 "nfs_dlboot: invalid option: vers"); 2718 break; 2719 } 2720 vers = atoi(val); 2721 /* 2722 * If the requested version is less than what we 2723 * chose, pretend the chosen version doesn't exist 2724 */ 2725 if (vers < version) { 2726 return (EPROTONOSUPPORT); 2727 } 2728 if (vers > version) { 2729 cmn_err(CE_WARN, 2730 "nfs_dlboot: version %d unavailable", 2731 vers); 2732 return (EINVAL); 2733 } 2734 break; 2735 case OPT_PROTO: 2736 /* 2737 * NFSv4 can only run over TCP, if they requested 2738 * UDP pretend v4 doesn't exist, they might not have 2739 * specified a version allowing a fallback to v2 or v3. 2740 */ 2741 if (version == NFS_V4 && strcmp(val, NC_UDP) == 0) 2742 return (EPROTONOSUPPORT); 2743 /* 2744 * TCP is always chosen over UDP, so if the 2745 * requested is the same as the chosen either 2746 * they chose TCP when available or UDP on a UDP 2747 * only server. 2748 */ 2749 if (strcmp(cf->knc_proto, val) == 0) 2750 break; 2751 /* 2752 * If we chose UDP, they must have requested TCP 2753 */ 2754 if (strcmp(cf->knc_proto, NC_TCP) != 0) { 2755 cmn_err(CE_WARN, 2756 "nfs_dlboot: TCP protocol unavailable"); 2757 return (EINVAL); 2758 } 2759 /* 2760 * They can only have requested UDP 2761 */ 2762 if (strcmp(val, NC_UDP) != 0) { 2763 cmn_err(CE_WARN, 2764 "nfs_dlboot: unknown protocol"); 2765 return (EINVAL); 2766 } 2767 *dl_cf = &dl_udp_netconf; 2768 break; 2769 case OPT_NOPRINT: 2770 args->flags |= NFSMNT_NOPRINT; 2771 break; 2772 case OPT_NOLARGEFILES: 2773 cmn_err(CE_WARN, 2774 "nfs_dlboot: NFS can't support nolargefiles"); 2775 break; 2776 case OPT_SEC: 2777 cmn_err(CE_WARN, 2778 "nfs_dlboot: root mounted auth_unix, sec ignored"); 2779 break; 2780 2781 case OPT_DIRECTIO: 2782 args->flags |= NFSMNT_DIRECTIO; 2783 break; 2784 2785 case OPT_NODIRECTIO: 2786 args->flags &= ~(NFSMNT_DIRECTIO); 2787 break; 2788 2789 default: 2790 cmn_err(CE_WARN, 2791 "nfs_dlboot: ignoring invalid option \"%s\"", val); 2792 break; 2793 } 2794 } 2795 sanity: 2796 /* 2797 * Set some sane limits on read size 2798 */ 2799 if (!(args->flags & NFSMNT_RSIZE) || args->rsize == 0) { 2800 /* 2801 * Establish defaults 2802 */ 2803 args->flags |= NFSMNT_RSIZE; 2804 if (version == NFS_V4) 2805 args->rsize = nfs4_root_rsize; 2806 else 2807 args->rsize = nfs_root_rsize; 2808 return (0); 2809 } 2810 /* 2811 * No less than 512 bytes, otherwise it will take forever to boot 2812 */ 2813 if (args->rsize < 512) 2814 args->rsize = 512; 2815 /* 2816 * If we are running over UDP, we cannot exceed 64KB, trim 2817 * to 56KB to allow room for headers. 2818 */ 2819 if (*dl_cf == &dl_udp_netconf && args->rsize > (56 * 1024)) 2820 args->rsize = 56 * 1024; 2821 return (0); 2822 } 2823