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