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\n",
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                         server_path_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1203                         bcopy(doptp->value, server_path_c, doptp->len);
1204                         server_path_c[doptp->len] = '\0';
1205                         if (dldebug)
1206                                 printf("dhcp:  root path %s\n", server_path_c);
1207                 } else {
1208                         cmn_err(CE_WARN, "dhcp: root server path missing");
1209                 }
1210         }
1211 
1212         /* set server_name */
1213         if (server_name_c == NULL) {
1214                 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_NAME];
1215                 if (doptp != NULL) {
1216                         server_name_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1217                         bcopy(doptp->value, server_name_c, doptp->len);
1218                         server_name_c[doptp->len] = '\0';
1219                         if (dldebug)
1220                                 printf("dhcp: root server name %s\n",
1221                                     server_name_c);
1222                 } else {
1223                         cmn_err(CE_WARN, "dhcp: root server name missing");
1224                 }
1225         }
1226 
1227         /* set root server_address */
1228         if ((*(uint_t *)server_ip) == 0) {
1229                 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_IP];
1230                 if (doptp) {
1231                         bcopy(doptp->value, server_ip, sizeof (server_ip));
1232                         if (dldebug) {
1233                                 printf("dhcp:  root server IP address %s\n",
1234                                     inet_ntoa(*(struct in_addr *)server_ip));
1235                         }
1236                 } else {
1237                         if (dldebug)
1238                                 cmn_err(CE_CONT,
1239                                     "dhcp: file server ip address missing,"
1240                                     " fallback to dhcp server as file server");
1241                         bcopy(dhcp_server_ip, server_ip, sizeof (server_ip));
1242                 }
1243         }
1244 
1245         /* set root file system mount options */
1246         if (rootopts[0] == 0) {
1247                 doptp = pl->vs[VS_NFSMNT_ROOTOPTS];
1248                 if (doptp != NULL && doptp->len < 255) {
1249                         bcopy(doptp->value, rootopts, doptp->len);
1250                         rootopts[doptp->len] = '\0';
1251                         if (dldebug)
1252                                 printf("dhcp:  rootopts %s\n", rootopts);
1253                 } else if (dldebug) {
1254                         printf("dhcp:  no rootopts or too long\n");
1255                         /* not an error */
1256                 }
1257         }
1258 
1259         /* now we are done with pl, just free it */
1260         kmem_free(pl->pkt, pl->len);
1261         kmem_free(pl, sizeof (PKT_LIST));
1262         pl = NULL;
1263 }
1264 
1265 static int
1266 cacheinfo(char *name, int namelen,
1267     struct netbuf *server_address, char *rootpath, int pathlen)
1268 {
1269         static int init_done = 0;
1270         struct sockaddr_in *sin;
1271 
1272         if (init_done == 0) {
1273                 cacheinit();
1274                 init_done = 1;
1275         }
1276 
1277         /* server_path is a reliable indicator of cache availability */
1278         if (server_path_c == NULL)
1279                 return (-1);
1280 
1281         (void) strncpy(rootpath, server_path_c, pathlen);
1282         if (server_name_c) {
1283                 (void) strncpy(name, server_name_c, namelen);
1284         } else {
1285                 (void) strncpy(name, "unknown", namelen);
1286         }
1287 
1288         sin = (struct sockaddr_in *)server_address->buf;
1289         sin->sin_family = AF_INET;
1290         server_address->len = sizeof (struct sockaddr_in);
1291         bcopy(server_ip, &sin->sin_addr, sizeof (struct in_addr));
1292         return (0);
1293 }
1294 
1295 /*
1296  *      Set this interface's IP address and netmask, and bring it up.
1297  */
1298 static int
1299 dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask,
1300     struct in_addr *mybraddr, uint_t flags)
1301 {
1302         int rc;
1303         struct netbuf sbuf;
1304         struct sockaddr_in sin;
1305 
1306         if (dldebug) {
1307                 printf("dlifconfig:  entered\n");
1308                 printf("dlifconfig:  addr %s\n", inet_ntoa(*myIPaddr));
1309                 printf("dlifconfig:  mask %s\n", inet_ntoa(*mymask));
1310                 printf("dlifconfig:  broadcast %s\n", inet_ntoa(*mybraddr));
1311         }
1312 
1313         bcopy(myIPaddr, &sin.sin_addr, sizeof (struct in_addr));
1314         sin.sin_family = AF_INET;
1315         sbuf.buf = (caddr_t)&sin;
1316         sbuf.maxlen = sbuf.len = sizeof (sin);
1317         if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1318                 nfs_perror(rc,
1319                     "dlifconfig: couldn't set interface net address: %m\n");
1320                 return (rc);
1321         }
1322 
1323         if (mybraddr->s_addr != INADDR_BROADCAST) {
1324                 bcopy(mybraddr, &sin.sin_addr, sizeof (struct in_addr));
1325                 sin.sin_family = AF_INET;
1326                 sbuf.buf = (caddr_t)&sin;
1327                 sbuf.maxlen = sbuf.len = sizeof (sin);
1328                 if (rc = ifioctl(tiptr, SIOCSIFBRDADDR, &sbuf)) {
1329                         nfs_perror(rc,
1330                     "dlifconfig: couldn't set interface broadcast addr: %m\n");
1331                         return (rc);
1332                 }
1333         }
1334 
1335         bcopy(mymask, &sin.sin_addr, sizeof (struct in_addr));
1336         sin.sin_family = AF_INET;
1337         sbuf.buf = (caddr_t)&sin;
1338         sbuf.maxlen = sbuf.len = sizeof (sin);
1339         if (rc = ifioctl(tiptr, SIOCSIFNETMASK, &sbuf)) {
1340                 nfs_perror(rc,
1341                     "dlifconfig: couldn't set interface net address: %m\n");
1342                 return (rc);
1343         }
1344 
1345         /*
1346          * Now turn on the interface.
1347          */
1348         if (rc = setifflags(tiptr, IFF_UP | flags)) {
1349                 nfs_perror(rc,
1350                     "dlifconfig: couldn't enable network interface: %m\n");
1351                 return (rc);
1352         }
1353 
1354         if (dldebug)
1355                 printf("dlifconfig:  returned\n");
1356         return (0);
1357 }
1358 
1359 static char *
1360 inet_ntoa(struct in_addr in)
1361 {
1362         static char b[18];
1363         unsigned char *p;
1364 
1365         p = (unsigned char *)&in;
1366         (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1367         return (b);
1368 }
1369 
1370 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1371 static int
1372 inet_aton(char *ipstr, uchar_t *ip)
1373 {
1374         int i = 0;
1375         uchar_t val[4] = {0};
1376         char c = *ipstr;
1377 
1378         for (;;) {
1379                 if (!isdigit(c))
1380                         return (-1);
1381                 for (;;) {
1382                         if (!isdigit(c))
1383                                 break;
1384                         val[i] = val[i] * 10 + (c - '0');
1385                         c = *++ipstr;
1386                 }
1387                 i++;
1388                 if (i == 4)
1389                         break;
1390                 if (c != '.')
1391                         return (-1);
1392                 c = *++ipstr;
1393         }
1394         if (c != 0)
1395                 return (-1);
1396         bcopy(val, ip, 4);
1397         return (0);
1398 }
1399 
1400 #define MAX_ADDR_SIZE   128
1401 
1402 /*
1403  * Initialize a netbuf suitable for
1404  * describing an address for the
1405  * transport defined by `tiptr'.
1406  */
1407 static void
1408 init_netbuf(struct netbuf *nbuf)
1409 {
1410         nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP);
1411         nbuf->maxlen = MAX_ADDR_SIZE;
1412         nbuf->len = 0;
1413 }
1414 
1415 static void
1416 free_netbuf(struct netbuf *nbuf)
1417 {
1418         kmem_free(nbuf->buf, nbuf->maxlen);
1419         nbuf->buf = NULL;
1420         nbuf->maxlen = 0;
1421         nbuf->len = 0;
1422 }
1423 
1424 static int
1425 rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry)
1426 {
1427         struct strioctl iocb;
1428         int rc;
1429         vnode_t *vp;
1430 
1431         iocb.ic_cmd = cmd;
1432         iocb.ic_timout = 0;
1433         iocb.ic_len = sizeof (struct rtentry);
1434         iocb.ic_dp = (caddr_t)rtentry;
1435 
1436         vp = tiptr->fp->f_vnode;
1437         rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1438         if (rc)
1439                 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n");
1440         return (rc);
1441 }
1442 
1443 /*
1444  * Send an ioctl down the stream defined
1445  * by `tiptr'.
1446  *
1447  * We isolate the ifreq dependencies in here. The
1448  * ioctl really ought to take a netbuf and be of
1449  * type TRANSPARENT - one day.
1450  */
1451 static int
1452 ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf)
1453 {
1454         struct strioctl iocb;
1455         int rc;
1456         vnode_t *vp;
1457         struct ifreq ifr;
1458 
1459         /*
1460          * Now do the one requested.
1461          */
1462         if (nbuf->len)
1463                 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf;
1464         (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1465         iocb.ic_cmd = cmd;
1466         iocb.ic_timout = 0;
1467         iocb.ic_len = sizeof (ifr);
1468         iocb.ic_dp = (caddr_t)&ifr;
1469 
1470         vp = tiptr->fp->f_vnode;
1471         rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1472         if (rc) {
1473                 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n");
1474                 return (rc);
1475         }
1476 
1477         /*
1478          * Set reply length.
1479          */
1480         if (nbuf->len == 0) {
1481                 /*
1482                  * GET type.
1483                  */
1484                 nbuf->len = sizeof (struct sockaddr);
1485                 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr;
1486         }
1487 
1488         return (0);
1489 }
1490 
1491 static int
1492 setifflags(TIUSER *tiptr, uint_t value)
1493 {
1494         struct ifreq ifr;
1495         int rc;
1496         struct strioctl iocb;
1497 
1498         (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1499         iocb.ic_cmd = SIOCGIFFLAGS;
1500         iocb.ic_timout = 0;
1501         iocb.ic_len = sizeof (ifr);
1502         iocb.ic_dp = (caddr_t)&ifr;
1503         if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb))
1504                 return (rc);
1505 
1506         ifr.ifr_flags |= value;
1507         iocb.ic_cmd = SIOCSIFFLAGS;
1508         return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb));
1509 }
1510 
1511 /*
1512  * REVerse Address Resolution Protocol (revarp)
1513  * is used by a diskless client to find out its
1514  * IP address when all it knows is its Ethernet address.
1515  *
1516  * Open the ethernet driver, attach and bind
1517  * (DL_BIND_REQ) it, and then format a broadcast RARP
1518  * message for it to send. We pick up the reply and
1519  * let the caller set the interface address using SIOCSIFADDR.
1520  */
1521 static int
1522 revarp_myaddr(TIUSER *tiptr)
1523 {
1524         int                     rc;
1525         dl_info_ack_t           info;
1526         struct sockaddr_in      sin;
1527         struct netbuf           sbuf;
1528         ldi_handle_t            lh;
1529         ldi_ident_t             li;
1530         struct netbuf           myaddr = {0, 0, NULL};
1531 
1532         if (dldebug)
1533                 printf("revarp_myaddr: entered\n");
1534 
1535         if (rc = ldi_ident_from_mod(&modlinkage, &li)) {
1536                 nfs_perror(rc,
1537                     "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1538                 return (rc);
1539         }
1540 
1541         rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li);
1542         ldi_ident_release(li);
1543         if (rc) {
1544                 nfs_perror(rc,
1545                     "revarp_myaddr: ldi_open_by_name failed: %m\n");
1546                 return (rc);
1547         }
1548 
1549         if (rc = dl_attach(lh, ifunit, NULL)) {
1550                 nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n");
1551                 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1552                 return (rc);
1553         }
1554 
1555         if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) {
1556                 nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n");
1557                 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1558                 return (rc);
1559         }
1560 
1561         if (rc = dl_info(lh, &info, NULL, NULL, NULL)) {
1562                 nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n");
1563                 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1564                 return (rc);
1565         }
1566 
1567         /* Initialize myaddr */
1568         myaddr.maxlen = info.dl_addr_length;
1569         myaddr.buf = kmem_alloc(myaddr.maxlen, KM_SLEEP);
1570 
1571         revarp_start(lh, &myaddr);
1572 
1573         bcopy(myaddr.buf, &sin.sin_addr, myaddr.len);
1574         sin.sin_family = AF_INET;
1575 
1576         sbuf.buf = (caddr_t)&sin;
1577         sbuf.maxlen = sbuf.len = sizeof (sin);
1578         if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1579                 nfs_perror(rc,
1580                     "revarp_myaddr: couldn't set interface net address: %m\n");
1581                 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1582                 kmem_free(myaddr.buf, myaddr.maxlen);
1583                 return (rc);
1584         }
1585 
1586         /* Now turn on the interface */
1587         if (rc = setifflags(tiptr, IFF_UP)) {
1588                 nfs_perror(rc,
1589                     "revarp_myaddr: couldn't enable network interface: %m\n");
1590         }
1591 
1592         (void) ldi_close(lh, FREAD|FWRITE, CRED());
1593         kmem_free(myaddr.buf, myaddr.maxlen);
1594         return (rc);
1595 }
1596 
1597 static void
1598 revarp_start(ldi_handle_t lh, struct netbuf *myaddr)
1599 {
1600         struct ether_arp *ea;
1601         int rc;
1602         dl_unitdata_req_t *dl_udata;
1603         mblk_t *bp;
1604         mblk_t *mp;
1605         struct dladdr *dlsap;
1606         static int done = 0;
1607         size_t addrlen = ETHERADDRL;
1608 
1609         if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 ||
1610             addrlen != ETHERADDRL) {
1611                 /* Fallback using per-node address */
1612                 (void) localetheraddr((struct ether_addr *)NULL, &myether);
1613                 cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using "
1614                     "system wide Ethernet address %s\n",
1615                     ether_sprintf(&myether));
1616         }
1617 
1618 getreply:
1619         if (myaddr->len != 0) {
1620                 cmn_err(CE_CONT, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1621                     *(int *)myaddr->buf,
1622                     (uchar_t)myaddr->buf[0], (uchar_t)myaddr->buf[1],
1623                     (uchar_t)myaddr->buf[2], (uchar_t)myaddr->buf[3]);
1624                 return;
1625         }
1626 
1627         if (done++ == 0)
1628                 cmn_err(CE_CONT, "?Requesting Internet address for %s\n",
1629                     ether_sprintf(&myether));
1630 
1631         /*
1632          * Send another RARP request.
1633          */
1634         if ((mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap),
1635             BPRI_HI)) == NULL) {
1636                 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1637                 return;
1638         }
1639         if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) {
1640                 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1641                 return;
1642         }
1643 
1644         /*
1645          * Format the transmit request part.
1646          */
1647         mp->b_datap->db_type = M_PROTO;
1648         dl_udata = (dl_unitdata_req_t *)mp->b_wptr;
1649         mp->b_wptr += sizeof (dl_unitdata_req_t) + sizeof (*dlsap);
1650         dl_udata->dl_primitive = DL_UNITDATA_REQ;
1651         dl_udata->dl_dest_addr_length = sizeof (*dlsap);
1652         dl_udata->dl_dest_addr_offset = sizeof (*dl_udata);
1653         dl_udata->dl_priority.dl_min = 0;
1654         dl_udata->dl_priority.dl_max = 0;
1655 
1656         dlsap = (struct dladdr *)(mp->b_rptr + sizeof (*dl_udata));
1657         bcopy(&etherbroadcastaddr, &dlsap->dl_phys,
1658             sizeof (etherbroadcastaddr));
1659         dlsap->dl_sap = ETHERTYPE_REVARP;
1660 
1661         /*
1662          * Format the actual REVARP request.
1663          */
1664         bzero(bp->b_wptr, sizeof (struct ether_arp));
1665         ea = (struct ether_arp *)bp->b_wptr;
1666         bp->b_wptr += sizeof (struct ether_arp);
1667         ea->arp_hrd = htons(ARPHRD_ETHER);
1668         ea->arp_pro = htons(ETHERTYPE_IP);
1669         ea->arp_hln = sizeof (ea->arp_sha);       /* hardware address length */
1670         ea->arp_pln = sizeof (ea->arp_spa);       /* protocol address length */
1671         ea->arp_op = htons(REVARP_REQUEST);
1672         ether_copy(&myether, &ea->arp_sha);
1673         ether_copy(&myether, &ea->arp_tha);
1674 
1675         mp->b_cont = bp;
1676 
1677         if ((rc = ldi_putmsg(lh, mp)) != 0) {
1678                 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n");
1679                 return;
1680         }
1681         revarpinput(lh, myaddr);
1682 
1683         goto getreply;
1684 }
1685 
1686 /*
1687  * Client side Reverse-ARP input
1688  * Server side is handled by user level server
1689  */
1690 static void
1691 revarpinput(ldi_handle_t lh, struct netbuf *myaddr)
1692 {
1693         struct ether_arp *ea;
1694         mblk_t *bp;
1695         mblk_t *mp;
1696         int rc;
1697         timestruc_t tv, give_up, now;
1698 
1699         /*
1700          * Choose the time at which we will give up, and resend our
1701          * request.
1702          */
1703         gethrestime(&give_up);
1704         give_up.tv_sec += REVARP_TIMEO;
1705 wait:
1706         /*
1707          * Compute new timeout value.
1708          */
1709         tv = give_up;
1710         gethrestime(&now);
1711         timespecsub(&tv, &now);
1712         /*
1713          * If we don't have at least one full second remaining, give up.
1714          * This means we might wait only just over 4.0 seconds, but that's
1715          * okay.
1716          */
1717         if (tv.tv_sec <= 0)
1718                 return;
1719         rc = ldi_getmsg(lh, &mp, &tv);
1720         if (rc == ETIME) {
1721                 goto out;
1722         } else if (rc != 0) {
1723                 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n");
1724                 return;
1725         }
1726 
1727         if (mp->b_cont == NULL) {
1728                 printf("revarpinput: b_cont == NULL\n");
1729                 goto out;
1730         }
1731 
1732         if (mp->b_datap->db_type != M_PROTO) {
1733                 printf("revarpinput: bad header type %d\n",
1734                     mp->b_datap->db_type);
1735                 goto out;
1736         }
1737 
1738         bp = mp->b_cont;
1739 
1740         if (bp->b_wptr - bp->b_rptr < sizeof (*ea)) {
1741                 printf("revarpinput: bad data len %d, expect %d\n",
1742                     (int)(bp->b_wptr - bp->b_rptr),  (int)sizeof (*ea));
1743                 goto out;
1744         }
1745 
1746         ea = (struct ether_arp *)bp->b_rptr;
1747 
1748         if ((ushort_t)ntohs(ea->arp_pro) != ETHERTYPE_IP) {
1749                 /* We could have received another broadcast arp packet. */
1750                 if (dldebug)
1751                         printf("revarpinput: bad type %x\n",
1752                             (ushort_t)ntohs(ea->arp_pro));
1753                 freemsg(mp);
1754                 goto wait;
1755         }
1756         if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) {
1757                 /* We could have received a broadcast arp request. */
1758                 if (dldebug)
1759                         printf("revarpinput: bad op %x\n",
1760                             (ushort_t)ntohs(ea->arp_op));
1761                 freemsg(mp);
1762                 goto wait;
1763         }
1764 
1765         if (!ether_cmp(&ea->arp_tha, &myether)) {
1766                 bcopy(&ea->arp_tpa, myaddr->buf, sizeof (ea->arp_tpa));
1767                 myaddr->len = sizeof (ea->arp_tpa);
1768         } else {
1769                 /* We could have gotten a broadcast arp response. */
1770                 if (dldebug)
1771                         printf("revarpinput: got reply, but not my address\n");
1772                 freemsg(mp);
1773                 goto wait;
1774         }
1775 out:
1776         freemsg(mp);
1777 }
1778 
1779 /*
1780  * From rpcsvc/mountxdr.c in SunOS. We can't
1781  * put this into the rpc directory because
1782  * it calls xdr_fhandle() which is in a
1783  * loadable module.
1784  */
1785 static bool_t
1786 myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp)
1787 {
1788 
1789         if (!xdr_int(xdrs, &fhsp->fhs_status))
1790                 return (FALSE);
1791         if (fhsp->fhs_status == 0) {
1792                 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh))
1793                         return (FALSE);
1794         }
1795         return (TRUE);
1796 }
1797 
1798 /*
1799  * From nfs_xdr.c.
1800  *
1801  * File access handle
1802  * The fhandle struct is treated a opaque data on the wire
1803  */
1804 static bool_t
1805 myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1806 {
1807         return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1808 }
1809 
1810 static bool_t
1811 myxdr_mountres3(XDR *xdrs, struct mountres3 *objp)
1812 {
1813         if (!myxdr_mountstat3(xdrs, &objp->fhs_status))
1814                 return (FALSE);
1815         switch (objp->fhs_status) {
1816         case MNT_OK:
1817                 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
1818                         return (FALSE);
1819                 break;
1820         default:
1821                 break;
1822         }
1823         return (TRUE);
1824 }
1825 
1826 static bool_t
1827 myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1828 {
1829         return (xdr_enum(xdrs, (enum_t *)objp));
1830 }
1831 
1832 static bool_t
1833 myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp)
1834 {
1835         if (!myxdr_fhandle3(xdrs, &objp->fhandle))
1836                 return (FALSE);
1837         if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val,
1838             (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0,
1839             sizeof (int), (xdrproc_t)xdr_int))
1840                 return (FALSE);
1841         return (TRUE);
1842 }
1843 
1844 static bool_t
1845 myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp)
1846 {
1847         return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
1848             (uint_t *)&objp->fhandle3_len, FHSIZE3));
1849 }
1850 
1851 /*
1852  * From SunOS pmap_clnt.c
1853  *
1854  * Port mapper routines:
1855  *      pmap_kgetport() - get port number.
1856  *      pmap_rmt_call()  - indirect call via port mapper.
1857  *
1858  */
1859 static enum clnt_stat
1860 pmap_kgetport(struct knetconfig *knconf, struct netbuf *call_addr,
1861         rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
1862 {
1863         ushort_t port;
1864         int tries;
1865         enum clnt_stat stat;
1866         struct pmap     pmap_parms;
1867         RPCB            rpcb_parms;
1868         char            *ua = NULL;
1869 
1870         port = 0;
1871 
1872         ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1873 
1874         pmap_parms.pm_prog = prog;
1875         pmap_parms.pm_vers = vers;
1876         pmap_parms.pm_prot = prot;
1877         pmap_parms.pm_port = 0;
1878         for (tries = 0; tries < 5; tries++) {
1879                 stat = mycallrpc(knconf, call_addr,
1880                     PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
1881                     myxdr_pmap, (char *)&pmap_parms,
1882                     xdr_u_short, (char *)&port,
1883                     DEFAULT_TIMEO, DEFAULT_RETRIES);
1884 
1885                 if (stat != RPC_TIMEDOUT)
1886                         break;
1887                 cmn_err(CE_WARN,
1888                     "pmap_kgetport: Portmapper not responding; still trying");
1889         }
1890 
1891         if (stat == RPC_PROGUNAVAIL) {
1892                 cmn_err(CE_WARN,
1893                     "pmap_kgetport: Portmapper failed - trying rpcbind");
1894 
1895                 rpcb_parms.r_prog = prog;
1896                 rpcb_parms.r_vers = vers;
1897                 rpcb_parms.r_netid = knconf->knc_proto;
1898                 rpcb_parms.r_addr = rpcb_parms.r_owner = "";
1899 
1900                 for (tries = 0; tries < 5; tries++) {
1901                         stat = mycallrpc(knconf, call_addr,
1902                             RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
1903                             xdr_rpcb, (char *)&rpcb_parms,
1904                             xdr_wrapstring, (char *)&ua,
1905                             DEFAULT_TIMEO, DEFAULT_RETRIES);
1906 
1907                         if (stat != RPC_TIMEDOUT)
1908                                 break;
1909                         cmn_err(CE_WARN,
1910                         "pmap_kgetport: rpcbind not responding; still trying");
1911                 }
1912 
1913                 if (stat == RPC_SUCCESS) {
1914                         if ((ua != NULL) && (ua[0] != NULL)) {
1915                                 port = rpc_uaddr2port(AF_INET, ua);
1916                         } else {
1917                                 /* Address unknown */
1918                                 stat = RPC_PROGUNAVAIL;
1919                         }
1920                 }
1921         }
1922 
1923         if (stat == RPC_SUCCESS)
1924                 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port);
1925 
1926         return (stat);
1927 }
1928 
1929 /*
1930  * pmapper remote-call-service interface.
1931  * This routine is used to call the pmapper remote call service
1932  * which will look up a service program in the port maps, and then
1933  * remotely call that routine with the given parameters.  This allows
1934  * programs to do a lookup and call in one step. In addition to the call_addr,
1935  * the caller provides a boolean hint about the destination address (TRUE if
1936  * address is a broadcast address, FALSE otherwise).
1937  *
1938  * On return, `call addr' contains the port number for the
1939  * service requested, and `resp_addr' contains its IP address.
1940  */
1941 static enum clnt_stat
1942 pmap_rmt_call(struct knetconfig *knconf, struct netbuf *call_addr,
1943         bool_t bcast, rpcprog_t progn, rpcvers_t versn, rpcproc_t procn,
1944         xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
1945         struct timeval tout, struct netbuf *resp_addr)
1946 {
1947         CLIENT *cl;
1948         enum clnt_stat stat;
1949         rpcport_t port;
1950         int rc;
1951         struct rmtcallargs      pmap_args;
1952         struct rmtcallres       pmap_res;
1953         struct rpcb_rmtcallargs rpcb_args;
1954         struct rpcb_rmtcallres  rpcb_res;
1955         char                    ua[100];        /* XXX */
1956 
1957         ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1958 
1959         rc = clnt_tli_kcreate(knconf, call_addr, PMAPPROG, PMAPVERS,
1960             0, PMAP_RETRIES, CRED(), &cl);
1961         if (rc != 0) {
1962                 nfs_perror(rc,
1963                     "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
1964                 return (RPC_SYSTEMERROR);       /* XXX */
1965         }
1966         if (cl == (CLIENT *)NULL) {
1967                 panic("pmap_rmt_call: clnt_tli_kcreate failed");
1968                 /* NOTREACHED */
1969         }
1970 
1971         (void) CLNT_CONTROL(cl, CLSET_BCAST, (char *)&bcast);
1972 
1973         pmap_args.prog = progn;
1974         pmap_args.vers = versn;
1975         pmap_args.proc = procn;
1976         pmap_args.args_ptr = argsp;
1977         pmap_args.xdr_args = xdrargs;
1978         pmap_res.port_ptr = &port;
1979         pmap_res.results_ptr = resp;
1980         pmap_res.xdr_results = xdrres;
1981         stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
1982             myxdr_rmtcall_args, (caddr_t)&pmap_args,
1983             myxdr_rmtcallres, (caddr_t)&pmap_res,
1984             tout, resp_addr);
1985 
1986         if (stat == RPC_SUCCESS) {
1987                 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
1988                     htons((ushort_t)port);
1989         }
1990         CLNT_DESTROY(cl);
1991 
1992         if (stat != RPC_PROGUNAVAIL)
1993                 return (stat);
1994 
1995         cmn_err(CE_WARN, "pmap_rmt_call: Portmapper failed - trying rpcbind");
1996 
1997         rc = clnt_tli_kcreate(knconf, call_addr, RPCBPROG, RPCBVERS,
1998             0, PMAP_RETRIES, CRED(), &cl);
1999         if (rc != 0) {
2000                 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2001                 return (RPC_SYSTEMERROR);       /* XXX */
2002         }
2003 
2004         if (cl == NULL) {
2005                 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2006                 /* NOTREACHED */
2007         }
2008 
2009         rpcb_args.prog = progn;
2010         rpcb_args.vers = versn;
2011         rpcb_args.proc = procn;
2012         rpcb_args.args_ptr = argsp;
2013         rpcb_args.xdr_args = xdrargs;
2014         rpcb_res.addr_ptr = ua;
2015         rpcb_res.results_ptr = resp;
2016         rpcb_res.xdr_results = xdrres;
2017         stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2018             xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_args,
2019             xdr_rpcb_rmtcallres, (caddr_t)&rpcb_res,
2020             tout, resp_addr);
2021 
2022         if (stat == RPC_SUCCESS)
2023                 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2024                     rpc_uaddr2port(AF_INET, ua);
2025         CLNT_DESTROY(cl);
2026 
2027         return (stat);
2028 }
2029 
2030 /*
2031  * XDR remote call arguments
2032  * written for XDR_ENCODE direction only
2033  */
2034 static bool_t
2035 myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2036 {
2037         uint_t lenposition;
2038         uint_t argposition;
2039         uint_t position;
2040 
2041         if (xdr_rpcprog(xdrs, &(cap->prog)) &&
2042             xdr_rpcvers(xdrs, &(cap->vers)) &&
2043             xdr_rpcproc(xdrs, &(cap->proc))) {
2044                 lenposition = XDR_GETPOS(xdrs);
2045                 if (!xdr_u_int(xdrs, &cap->arglen))
2046                         return (FALSE);
2047                 argposition = XDR_GETPOS(xdrs);
2048                 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2049                         return (FALSE);
2050                 position = XDR_GETPOS(xdrs);
2051                 cap->arglen = (uint_t)position - (uint_t)argposition;
2052                 XDR_SETPOS(xdrs, lenposition);
2053                 if (!xdr_u_int(xdrs, &cap->arglen))
2054                         return (FALSE);
2055                 XDR_SETPOS(xdrs, position);
2056                 return (TRUE);
2057         }
2058         return (FALSE);
2059 }
2060 
2061 /*
2062  * XDR remote call results
2063  * written for XDR_DECODE direction only
2064  */
2065 static bool_t
2066 myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2067 {
2068         caddr_t port_ptr;
2069 
2070         port_ptr = (caddr_t)crp->port_ptr;
2071         if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
2072             xdr_u_int(xdrs, &crp->resultslen)) {
2073                 crp->port_ptr = (rpcport_t *)port_ptr;
2074                 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
2075         }
2076         return (FALSE);
2077 }
2078 
2079 static bool_t
2080 myxdr_pmap(XDR *xdrs, struct pmap *regs)
2081 {
2082         if (xdr_rpcprog(xdrs, &regs->pm_prog) &&
2083             xdr_rpcvers(xdrs, &regs->pm_vers) &&
2084             xdr_rpcprot(xdrs, &regs->pm_prot))
2085                 return (xdr_rpcport(xdrs, &regs->pm_port));
2086 
2087         return (FALSE);
2088 }
2089 
2090 /*
2091  * From SunOS callrpc.c
2092  */
2093 static enum clnt_stat
2094 mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr,
2095         rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
2096         xdrproc_t inproc, char *in, xdrproc_t outproc, char *out,
2097         int timeo, int retries)
2098 {
2099         CLIENT *cl;
2100         struct timeval tv;
2101         enum clnt_stat cl_stat;
2102         int rc;
2103 
2104         rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum,
2105             0, retries, CRED(), &cl);
2106         if (rc) {
2107                 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2108                 return (RPC_SYSTEMERROR);       /* XXX */
2109         }
2110         tv.tv_sec = timeo;
2111         tv.tv_usec = 0;
2112         cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv);
2113         AUTH_DESTROY(cl->cl_auth);
2114         CLNT_DESTROY(cl);
2115         return (cl_stat);
2116 }
2117 
2118 /*
2119  * Configure the 'default' interface based on existing boot properties.
2120  */
2121 static int
2122 bp_netconfig(void)
2123 {
2124         char *str;
2125         struct in_addr my_ip, my_netmask, my_router, my_broadcast;
2126         struct sockaddr_in *sin;
2127         TIUSER *tiptr;
2128         int rc;
2129         struct rtentry rtentry;
2130 
2131         my_ip.s_addr = my_netmask.s_addr = my_router.s_addr = 0;
2132 
2133         /*
2134          * No way of getting this right now.  Collude with dlifconfig()
2135          * to let the protocol stack choose.
2136          */
2137         my_broadcast.s_addr = INADDR_BROADCAST;
2138 
2139         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2140             DDI_PROP_DONTPASS, BP_HOST_IP, &str) == DDI_SUCCESS) {
2141                 if (inet_aton(str, (uchar_t *)&my_ip) != 0)
2142                         cmn_err(CE_NOTE, "host-ip %s is invalid\n",
2143                             str);
2144                 ddi_prop_free(str);
2145                 if (dldebug)
2146                         printf("host ip is %s\n",
2147                             inet_ntoa(my_ip));
2148         }
2149         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2150             DDI_PROP_DONTPASS, BP_SUBNET_MASK, &str) == DDI_SUCCESS) {
2151                 if (inet_aton(str, (uchar_t *)&my_netmask) != 0)
2152                         cmn_err(CE_NOTE, "subnet-mask %s is invalid\n",
2153                             str);
2154                 ddi_prop_free(str);
2155                 if (dldebug)
2156                         printf("subnet mask is %s\n",
2157                             inet_ntoa(my_netmask));
2158         }
2159         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2160             DDI_PROP_DONTPASS, BP_ROUTER_IP, &str) == DDI_SUCCESS) {
2161                 if (inet_aton(str, (uchar_t *)&my_router) != 0)
2162                         cmn_err(CE_NOTE, "router-ip %s is invalid\n",
2163                             str);
2164                 ddi_prop_free(str);
2165                 if (dldebug)
2166                         printf("router ip is %s\n",
2167                             inet_ntoa(my_router));
2168         }
2169         (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2170             DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
2171         (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2172             DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
2173         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2174             DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
2175                 (void) strlcpy(rootopts, str, sizeof (rootopts));
2176                 ddi_prop_free(str);
2177         }
2178         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2179             DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
2180                 if (inet_aton(str, server_ip) != 0)
2181                         cmn_err(CE_NOTE, "server-ip %s is invalid\n",
2182                             str);
2183                 ddi_prop_free(str);
2184                 if (dldebug)
2185                         printf("server ip is %s\n",
2186                             inet_ntoa(*(struct in_addr *)server_ip));
2187         }
2188 
2189         /*
2190          * We need all of these to configure based on properties.
2191          */
2192         if ((my_ip.s_addr == 0) ||
2193             (my_netmask.s_addr == 0) ||
2194             (server_path_c == NULL) ||
2195             (server_name_c == NULL) ||
2196             (*(uint_t *)server_ip == 0))
2197                 return (-1);
2198 
2199         cmn_err(CE_CONT, "?IP address: %s\n", inet_ntoa(my_ip));
2200         cmn_err(CE_CONT, "?IP netmask: %s\n", inet_ntoa(my_netmask));
2201         if (my_router.s_addr != 0)
2202                 cmn_err(CE_CONT, "?IP router: %s\n", inet_ntoa(my_router));
2203         cmn_err(CE_CONT, "?NFS server: %s (%s)\n", server_name_c,
2204             inet_ntoa(*(struct in_addr *)server_ip));
2205         cmn_err(CE_CONT, "?NFS path: %s\n", server_path_c);
2206 
2207         /*
2208          * Configure the interface.
2209          */
2210         if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
2211             FREAD|FWRITE, &tiptr, CRED())) != 0) {
2212                 nfs_perror(rc, "bp_netconfig: t_kopen udp failed: %m.\n");
2213                 return (rc);
2214         }
2215 
2216         if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast,
2217             0)) < 0) {
2218                 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n");
2219                 (void) t_kclose(tiptr, 0);
2220                 return (rc);
2221         }
2222 
2223         if (my_router.s_addr != 0) {
2224                 /*
2225                  * Add a default route.
2226                  */
2227                 sin = (struct sockaddr_in *)&rtentry.rt_dst;
2228                 bzero(sin, sizeof (*sin));
2229                 sin->sin_family = AF_INET;
2230 
2231                 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
2232                 bzero(sin, sizeof (*sin));
2233                 sin->sin_family = AF_INET;
2234                 sin->sin_addr = my_router;
2235 
2236                 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
2237 
2238                 if ((rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) != 0) {
2239                         nfs_perror(rc,
2240                             "bp_netconfig: couldn't add route: %m.\n");
2241                         (void) t_kclose(tiptr, 0);
2242                         return (rc);
2243                 }
2244         }
2245 
2246         (void) t_kclose(tiptr, 0);
2247 
2248         return (0);
2249 }
2250 
2251 /*
2252  * The network device we will use to boot from is plumbed. Extract the details
2253  * from rootfs.
2254  */
2255 static void
2256 init_config(void)
2257 {
2258         (void) strlcpy(ndev_path, rootfs.bo_devname, sizeof (ndev_path));
2259         (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
2260         ifunit = rootfs.bo_ppa;
2261 
2262         /*
2263          * Assumes only one linkage array element.
2264          */
2265         dl_udp_netconf.knc_rdev =
2266             makedevice(clone_major, ddi_name_to_major("udp"));
2267         dl_tcp_netconf.knc_rdev =
2268             makedevice(clone_major, ddi_name_to_major("tcp"));
2269 
2270         /*
2271          * Now we bringup the interface.
2272          * Try cached dhcp response first. If it fails, do rarp.
2273          */
2274         if ((bp_netconfig() != 0) &&
2275             (dhcpinit() != 0) &&
2276             (whoami() != 0))
2277                 cmn_err(CE_WARN,
2278                     "%s: no response from interface", ifname);
2279         else if (dldebug)
2280                 printf("init_config: ifname %s is up\n", ifname);
2281 }
2282 
2283 /*
2284  * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2285  * Changes must be made to both lists.
2286  */
2287 static char *optlist[] = {
2288 #define OPT_RO          0
2289         MNTOPT_RO,
2290 #define OPT_RW          1
2291         MNTOPT_RW,
2292 #define OPT_QUOTA       2
2293         MNTOPT_QUOTA,
2294 #define OPT_NOQUOTA     3
2295         MNTOPT_NOQUOTA,
2296 #define OPT_SOFT        4
2297         MNTOPT_SOFT,
2298 #define OPT_HARD        5
2299         MNTOPT_HARD,
2300 #define OPT_SUID        6
2301         MNTOPT_SUID,
2302 #define OPT_NOSUID      7
2303         MNTOPT_NOSUID,
2304 #define OPT_GRPID       8
2305         MNTOPT_GRPID,
2306 #define OPT_REMOUNT     9
2307         MNTOPT_REMOUNT,
2308 #define OPT_NOSUB       10
2309         MNTOPT_NOSUB,
2310 #define OPT_INTR        11
2311         MNTOPT_INTR,
2312 #define OPT_NOINTR      12
2313         MNTOPT_NOINTR,
2314 #define OPT_PORT        13
2315         MNTOPT_PORT,
2316 #define OPT_SECURE      14
2317         MNTOPT_SECURE,
2318 #define OPT_RSIZE       15
2319         MNTOPT_RSIZE,
2320 #define OPT_WSIZE       16
2321         MNTOPT_WSIZE,
2322 #define OPT_TIMEO       17
2323         MNTOPT_TIMEO,
2324 #define OPT_RETRANS     18
2325         MNTOPT_RETRANS,
2326 #define OPT_ACTIMEO     19
2327         MNTOPT_ACTIMEO,
2328 #define OPT_ACREGMIN    20
2329         MNTOPT_ACREGMIN,
2330 #define OPT_ACREGMAX    21
2331         MNTOPT_ACREGMAX,
2332 #define OPT_ACDIRMIN    22
2333         MNTOPT_ACDIRMIN,
2334 #define OPT_ACDIRMAX    23
2335         MNTOPT_ACDIRMAX,
2336 #define OPT_BG          24
2337         MNTOPT_BG,
2338 #define OPT_FG          25
2339         MNTOPT_FG,
2340 #define OPT_RETRY       26
2341         MNTOPT_RETRY,
2342 #define OPT_NOAC        27
2343         MNTOPT_NOAC,
2344 #define OPT_NOCTO       28
2345         MNTOPT_NOCTO,
2346 #define OPT_LLOCK       29
2347         MNTOPT_LLOCK,
2348 #define OPT_POSIX       30
2349         MNTOPT_POSIX,
2350 #define OPT_VERS        31
2351         MNTOPT_VERS,
2352 #define OPT_PROTO       32
2353         MNTOPT_PROTO,
2354 #define OPT_SEMISOFT    33
2355         MNTOPT_SEMISOFT,
2356 #define OPT_NOPRINT     34
2357         MNTOPT_NOPRINT,
2358 #define OPT_SEC         35
2359         MNTOPT_SEC,
2360 #define OPT_LARGEFILES  36
2361         MNTOPT_LARGEFILES,
2362 #define OPT_NOLARGEFILES        37
2363         MNTOPT_NOLARGEFILES,
2364 #define OPT_PUBLIC      38
2365         MNTOPT_PUBLIC,
2366 #define OPT_DIRECTIO    39
2367         MNTOPT_FORCEDIRECTIO,
2368 #define OPT_NODIRECTIO  40
2369         MNTOPT_NOFORCEDIRECTIO,
2370 #define OPT_XATTR       41
2371         MNTOPT_XATTR,
2372 #define OPT_NOXATTR     42
2373         MNTOPT_NOXATTR,
2374 #define OPT_DEVICES     43
2375         MNTOPT_DEVICES,
2376 #define OPT_NODEVICES   44
2377         MNTOPT_NODEVICES,
2378 #define OPT_SETUID      45
2379         MNTOPT_SETUID,
2380 #define OPT_NOSETUID    46
2381         MNTOPT_NOSETUID,
2382 #define OPT_EXEC        47
2383         MNTOPT_EXEC,
2384 #define OPT_NOEXEC      48
2385         MNTOPT_NOEXEC,
2386         NULL
2387 };
2388 
2389 static int
2390 isdigit(int ch)
2391 {
2392         return (ch >= '0' && ch <= '9');
2393 }
2394 
2395 #define isspace(c)      ((c) == ' ' || (c) == '\t' || (c) == '\n')
2396 #define bad(val)        (val == NULL || !isdigit(*val))
2397 
2398 static int
2399 atoi(const char *p)
2400 {
2401         int n;
2402         int c, neg = 0;
2403 
2404         if (!isdigit(c = *p)) {
2405                 while (isspace(c))
2406                         c = *++p;
2407                 switch (c) {
2408                 case '-':
2409                         neg++;
2410                         /* FALLTHROUGH */
2411                 case '+':
2412                         c = *++p;
2413                 }
2414                 if (!isdigit(c))
2415                         return (0);
2416         }
2417         for (n = '0' - c; isdigit(c = *++p); ) {
2418                 n *= 10; /* two steps to avoid unnecessary overflow */
2419                 n += '0' - c; /* accum neg to avoid surprises at MAX */
2420         }
2421         return (neg ? n : -n);
2422 }
2423 
2424 /*
2425  * Default root read tsize XXX
2426  */
2427 int nfs_root_rsize = 8 * 1024;          /* conservative for dumb NICs */
2428 int nfs4_root_rsize = 32 * 1024;        /* only runs on TCP be aggressive */
2429 
2430 /*
2431  * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2432  */
2433 int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT;
2434 
2435 static int
2436 init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf,
2437                                                 int *vfsflags)
2438 {
2439         char servername[SYS_NMLN];
2440         static int first = 0;
2441         struct netbuf server_address;
2442         char *opts, *val;
2443         int vers;
2444         struct knetconfig *cf = *dl_cf;
2445         char rootoptsbuf[256];
2446 
2447         /*
2448          * Set default mount options
2449          */
2450         args->flags = nfs_rootopts;
2451         args->rsize = 0;
2452         args->flags |= NFSMNT_ACREGMIN;
2453         args->acregmin = ACMINMAX;
2454         args->flags |= NFSMNT_ACREGMAX;
2455         args->acregmax = ACMAXMAX;
2456         args->flags |= NFSMNT_ACDIRMIN;
2457         args->acdirmin = ACMINMAX;
2458         args->flags |= NFSMNT_ACDIRMAX;
2459         args->acdirmax = ACMAXMAX;
2460 
2461         *vfsflags = 0;
2462 
2463         /*
2464          * Only look up the rootopts the first time, we store this in
2465          * a static buffer but we are guaranteed to be single threaded
2466          * and not reentrant.
2467          */
2468         if (first == 0) {
2469                 first++;
2470 
2471                 init_netbuf(&server_address);
2472 
2473                 if (getfile("rootopts", servername, &server_address,
2474                     rootopts)) {
2475                         rootopts[0] = '\0';
2476                         free_netbuf(&server_address);
2477                         goto sanity;
2478                 }
2479                 free_netbuf(&server_address);
2480         }
2481 
2482         if (dldebug)
2483                 printf("rootopts = %s\n", rootopts);
2484 
2485         /*
2486          * We have to preserve rootopts for second time.
2487          */
2488         (void) strncpy(rootoptsbuf, rootopts, sizeof (rootoptsbuf));
2489         rootoptsbuf[sizeof (rootoptsbuf) - 1] = '\0';
2490         opts = rootoptsbuf;
2491         while (*opts) {
2492                 int opt;
2493 
2494                 switch (opt = getsubopt(&opts, optlist, &val)) {
2495                 /*
2496                  * Options that are defaults or meaningless so ignored
2497                  */
2498                 case OPT_QUOTA:
2499                 case OPT_NOQUOTA:
2500                 case OPT_SUID:
2501                 case OPT_DEVICES:
2502                 case OPT_SETUID:
2503                 case OPT_BG:
2504                 case OPT_FG:
2505                 case OPT_RETRY:
2506                 case OPT_POSIX:
2507                 case OPT_LARGEFILES:
2508                 case OPT_XATTR:
2509                 case OPT_NOXATTR:
2510                 case OPT_EXEC:
2511                         break;
2512                 case OPT_RO:
2513                         *vfsflags |= MS_RDONLY;
2514                         break;
2515                 case OPT_RW:
2516                         *vfsflags &= ~(MS_RDONLY);
2517                         break;
2518                 case OPT_SOFT:
2519                         args->flags |= NFSMNT_SOFT;
2520                         args->flags &= ~(NFSMNT_SEMISOFT);
2521                         break;
2522                 case OPT_SEMISOFT:
2523                         args->flags |= NFSMNT_SOFT;
2524                         args->flags |= NFSMNT_SEMISOFT;
2525                         break;
2526                 case OPT_HARD:
2527                         args->flags &= ~(NFSMNT_SOFT);
2528                         args->flags &= ~(NFSMNT_SEMISOFT);
2529                         break;
2530                 case OPT_NOSUID:
2531                 case OPT_NODEVICES:
2532                 case OPT_NOSETUID:
2533                 case OPT_NOEXEC:
2534                         cmn_err(CE_WARN,
2535                             "nfs_dlboot: may not set root partition %s",
2536                             optlist[opt]);
2537                         break;
2538                 case OPT_GRPID:
2539                         args->flags |= NFSMNT_GRPID;
2540                         break;
2541                 case OPT_REMOUNT:
2542                         cmn_err(CE_WARN,
2543                             "nfs_dlboot: may not remount root partition");
2544                         break;
2545                 case OPT_INTR:
2546                         args->flags |= NFSMNT_INT;
2547                         break;
2548                 case OPT_NOINTR:
2549                         args->flags &= ~(NFSMNT_INT);
2550                         break;
2551                 case OPT_NOAC:
2552                         args->flags |= NFSMNT_NOAC;
2553                         break;
2554                 case OPT_PORT:
2555                         cmn_err(CE_WARN,
2556                             "nfs_dlboot: may not change root port number");
2557                         break;
2558                 case OPT_SECURE:
2559                         cmn_err(CE_WARN,
2560                         "nfs_dlboot: root mounted auth_unix, secure ignored");
2561                         break;
2562                 case OPT_NOCTO:
2563                         args->flags |= NFSMNT_NOCTO;
2564                         break;
2565                 case OPT_RSIZE:
2566                         if (bad(val)) {
2567                                 cmn_err(CE_WARN,
2568                                     "nfs_dlboot: invalid option: rsize");
2569                                 break;
2570                         }
2571                         args->flags |= NFSMNT_RSIZE;
2572                         args->rsize = atoi(val);
2573                         break;
2574                 case OPT_WSIZE:
2575                         if (bad(val)) {
2576                                 cmn_err(CE_WARN,
2577                                     "nfs_dlboot: invalid option: wsize");
2578                                 break;
2579                         }
2580                         args->flags |= NFSMNT_WSIZE;
2581                         args->wsize = atoi(val);
2582                         break;
2583                 case OPT_TIMEO:
2584                         if (bad(val)) {
2585                                 cmn_err(CE_WARN,
2586                                     "nfs_dlboot: invalid option: timeo");
2587                                 break;
2588                         }
2589                         args->flags |= NFSMNT_TIMEO;
2590                         args->timeo = atoi(val);
2591                         break;
2592                 case OPT_RETRANS:
2593                         if (bad(val)) {
2594                                 cmn_err(CE_WARN,
2595                                     "nfs_dlboot: invalid option: retrans");
2596                                 break;
2597                         }
2598                         args->flags |= NFSMNT_RETRANS;
2599                         args->retrans = atoi(val);
2600                         break;
2601                 case OPT_ACTIMEO:
2602                         if (bad(val)) {
2603                                 cmn_err(CE_WARN,
2604                                     "nfs_dlboot: invalid option: actimeo");
2605                                 break;
2606                         }
2607                         args->flags |= NFSMNT_ACDIRMAX;
2608                         args->flags |= NFSMNT_ACREGMAX;
2609                         args->flags |= NFSMNT_ACDIRMIN;
2610                         args->flags |= NFSMNT_ACREGMIN;
2611                         args->acdirmin = args->acregmin = args->acdirmax =
2612                             args->acregmax = atoi(val);
2613                         break;
2614                 case OPT_ACREGMIN:
2615                         if (bad(val)) {
2616                                 cmn_err(CE_WARN,
2617                                     "nfs_dlboot: invalid option: acregmin");
2618                                 break;
2619                         }
2620                         args->flags |= NFSMNT_ACREGMIN;
2621                         args->acregmin = atoi(val);
2622                         break;
2623                 case OPT_ACREGMAX:
2624                         if (bad(val)) {
2625                                 cmn_err(CE_WARN,
2626                                     "nfs_dlboot: invalid option: acregmax");
2627                                 break;
2628                         }
2629                         args->flags |= NFSMNT_ACREGMAX;
2630                         args->acregmax = atoi(val);
2631                         break;
2632                 case OPT_ACDIRMIN:
2633                         if (bad(val)) {
2634                                 cmn_err(CE_WARN,
2635                                     "nfs_dlboot: invalid option: acdirmin");
2636                                 break;
2637                         }
2638                         args->flags |= NFSMNT_ACDIRMIN;
2639                         args->acdirmin = atoi(val);
2640                         break;
2641                 case OPT_ACDIRMAX:
2642                         if (bad(val)) {
2643                                 cmn_err(CE_WARN,
2644                                     "nfs_dlboot: invalid option: acdirmax");
2645                                 break;
2646                         }
2647                         args->flags |= NFSMNT_ACDIRMAX;
2648                         args->acdirmax = atoi(val);
2649                         break;
2650                 case OPT_LLOCK:
2651                         args->flags |= NFSMNT_LLOCK;
2652                         break;
2653                 case OPT_VERS:
2654                         if (bad(val)) {
2655                                 cmn_err(CE_WARN,
2656                                     "nfs_dlboot: invalid option: vers");
2657                                 break;
2658                         }
2659                         vers = atoi(val);
2660                         /*
2661                          * If the requested version is less than what we
2662                          * chose, pretend the chosen version doesn't exist
2663                          */
2664                         if (vers < version) {
2665                                 return (EPROTONOSUPPORT);
2666                         }
2667                         if (vers > version) {
2668                                 cmn_err(CE_WARN,
2669                                     "nfs_dlboot: version %d unavailable",
2670                                     vers);
2671                                 return (EINVAL);
2672                         }
2673                         break;
2674                 case OPT_PROTO:
2675                         /*
2676                          * NFSv4 can only run over TCP, if they requested
2677                          * UDP pretend v4 doesn't exist, they might not have
2678                          * specified a version allowing a fallback to v2 or v3.
2679                          */
2680                         if (version == NFS_V4 && strcmp(val, NC_UDP) == 0)
2681                                 return (EPROTONOSUPPORT);
2682                         /*
2683                          * TCP is always chosen over UDP, so if the
2684                          * requested is the same as the chosen either
2685                          * they chose TCP when available or UDP on a UDP
2686                          * only server.
2687                          */
2688                         if (strcmp(cf->knc_proto, val) == 0)
2689                                 break;
2690                         /*
2691                          * If we chose UDP, they must have requested TCP
2692                          */
2693                         if (strcmp(cf->knc_proto, NC_TCP) != 0) {
2694                                 cmn_err(CE_WARN,
2695                                     "nfs_dlboot: TCP protocol unavailable");
2696                                 return (EINVAL);
2697                         }
2698                         /*
2699                          * They can only have requested UDP
2700                          */
2701                         if (strcmp(val, NC_UDP) != 0) {
2702                                 cmn_err(CE_WARN,
2703                                     "nfs_dlboot: unknown protocol");
2704                                 return (EINVAL);
2705                         }
2706                         *dl_cf = &dl_udp_netconf;
2707                         break;
2708                 case OPT_NOPRINT:
2709                         args->flags |= NFSMNT_NOPRINT;
2710                         break;
2711                 case OPT_NOLARGEFILES:
2712                         cmn_err(CE_WARN,
2713                             "nfs_dlboot: NFS can't support nolargefiles");
2714                         break;
2715                 case OPT_SEC:
2716                         cmn_err(CE_WARN,
2717                             "nfs_dlboot: root mounted auth_unix, sec ignored");
2718                         break;
2719 
2720                 case OPT_DIRECTIO:
2721                         args->flags |= NFSMNT_DIRECTIO;
2722                         break;
2723 
2724                 case OPT_NODIRECTIO:
2725                         args->flags &= ~(NFSMNT_DIRECTIO);
2726                         break;
2727 
2728                 default:
2729                         cmn_err(CE_WARN,
2730                             "nfs_dlboot: ignoring invalid option \"%s\"", val);
2731                         break;
2732                 }
2733         }
2734 sanity:
2735         /*
2736          * Set some sane limits on read size
2737          */
2738         if (!(args->flags & NFSMNT_RSIZE) || args->rsize == 0) {
2739                 /*
2740                  * Establish defaults
2741                  */
2742                 args->flags |= NFSMNT_RSIZE;
2743                 if (version == NFS_V4)
2744                         args->rsize = nfs4_root_rsize;
2745                 else
2746                         args->rsize = nfs_root_rsize;
2747                 return (0);
2748         }
2749         /*
2750          * No less than 512 bytes, otherwise it will take forever to boot
2751          */
2752         if (args->rsize < 512)
2753                 args->rsize = 512;
2754         /*
2755          * If we are running over UDP, we cannot exceed 64KB, trim
2756          * to 56KB to allow room for headers.
2757          */
2758         if (*dl_cf == &dl_udp_netconf && args->rsize > (56 * 1024))
2759                 args->rsize = 56 * 1024;
2760         return (0);
2761 }