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