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