Home | History | Annotate | Download | only in nfs
      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 }
   2764