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