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
114struct fhstatus {
115	int fhs_status;
116	fhandle_t fhs_fh;
117};
118
119#define	FHSIZE3 64
120
121struct fhandle3 {
122	uint_t fhandle3_len;
123	char *fhandle3_val;
124};
125
126enum 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
139struct mountres3_ok {
140	struct fhandle3 fhandle;
141	struct {
142		uint_t auth_flavors_len;
143		int *auth_flavors_val;
144	} auth_flavors;
145};
146
147struct mountres3 {
148	enum mountstat3 fhs_status;
149	union {
150		struct mountres3_ok mountinfo;
151	} mountres3_u;
152};
153
154/*
155 * DLPI address format.
156 */
157struct	dladdr {
158	uchar_t		dl_phys[6];
159	ushort_t	dl_sap;
160};
161
162static struct modlmisc modlmisc = {
163	&mod_miscops, "Boot diskless"
164};
165
166static struct modlinkage modlinkage = {
167	MODREV_1, (void *)&modlmisc, NULL
168};
169
170static int	dldebug;
171
172int
173_init(void)
174{
175	return (mod_install(&modlinkage));
176}
177
178int
179_fini(void)
180{
181	return (mod_remove(&modlinkage));
182}
183
184int
185_info(struct modinfo *modinfop)
186{
187	return (mod_info(&modlinkage, modinfop));
188}
189
190
191static 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 *);
195static bool_t		myxdr_rmtcall_args(XDR *, struct rmtcallargs *);
196static bool_t		myxdr_rmtcallres(XDR *, struct rmtcallres *);
197static bool_t		myxdr_pmap(XDR *, struct pmap *);
198static bool_t		myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp);
199static bool_t		myxdr_fhandle(XDR *xdrs, fhandle_t *fh);
200static bool_t		myxdr_mountres3(XDR *xdrs, struct mountres3 *objp);
201static bool_t		myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp);
202static bool_t		myxdr_mountres3_ok(XDR *xdrs,
203			    struct mountres3_ok *objp);
204static bool_t		myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp);
205static enum clnt_stat	pmap_kgetport(struct knetconfig *, struct netbuf *,
206			    rpcprog_t, rpcvers_t, rpcprot_t);
207static enum clnt_stat	mycallrpc(struct knetconfig *, struct netbuf *,
208			    rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
209			    char *, xdrproc_t, char *, int, int);
210static int		ifioctl(TIUSER *, int, struct netbuf *);
211static int		getfile(char *, char *, struct netbuf *, char *);
212static int		ping_prog(struct netbuf *, uint_t prog, uint_t vers,
213			    int proto, enum clnt_stat *);
214static int		mountnfs(struct netbuf *, char *, char *,
215			    fhandle_t *, int *);
216static int		mountnfs3(struct netbuf *, char *, char *,
217			    nfs_fh3 *, int *);
218static int		init_mountopts(struct nfs_args *, int,
219			    struct knetconfig **, int *);
220static int		revarp_myaddr(TIUSER *);
221static void		revarp_start(ldi_handle_t, struct netbuf *);
222static void		revarpinput(ldi_handle_t, struct netbuf *);
223static void		init_netbuf(struct netbuf *);
224static void		free_netbuf(struct netbuf *);
225static int		rtioctl(TIUSER *, int, struct rtentry *);
226static void		init_config(void);
227
228static void		cacheinit(void);
229static int		cacheinfo(char *, int, struct netbuf *, char *, int);
230static int		dlifconfig(TIUSER *, struct in_addr *, struct in_addr *,
231			    struct in_addr *, uint_t);
232static int		setifflags(TIUSER *, uint_t);
233
234static char		*inet_ntoa(struct in_addr);
235static int		inet_aton(char *, uchar_t *);
236static int		isdigit(int);
237
238/*
239 * Should be in some common
240 * ethernet source file.
241 */
242static struct ether_addr etherbroadcastaddr = {
243	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
244};
245
246static 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
259static char	ifname[IFNAMSIZ];
260static char	ndev_path[MAXPATHLEN];
261static int	ifunit;
262
263/*
264 * XXX these should be shared
265 */
266static struct knetconfig dl_udp_netconf = {
267	NC_TPI_CLTS,			/* semantics */
268	NC_INET,			/* family */
269	NC_UDP,				/* protocol */
270	0,				/* device */
271};
272
273static 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 */
281static PKT_LIST	*pl = NULL;
282static uchar_t server_ip[4];
283static uchar_t dhcp_server_ip[4];
284static char *server_name_c, *server_path_c;
285static 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 */
291int nfs4_no_diskless_root_support = 1;
292
293int
294mount_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
386errout:
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 */
403static int
404mountnfs(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 */
483static int
484mountnfs3(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
574out:
575	xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
576
577	if (dldebug)
578		printf("mountnfs3: leaving\n");
579	return (ret);
580}
581
582static int
583ping_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
625static 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 */
633static int
634whoami(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	}
803done:
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 */
819static int
820getfile(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 */
958int
959dhcpinit(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 */
1173static void
1174cacheinit(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
1330static int
1331cacheinfo(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 */
1363static int
1364dlifconfig(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
1424static char *
1425inet_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 */
1436static int
1437inet_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 */
1472static void
1473init_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
1480static void
1481free_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
1489static int
1490rtioctl(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 */
1516static int
1517ifioctl(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
1556static int
1557setifflags(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 */
1586static int
1587revarp_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
1662static void
1663revarp_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
1683getreply:
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 */
1755static void
1756revarpinput(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;
1770wait:
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	}
1840out:
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 */
1850static bool_t
1851myxdr_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 */
1869static bool_t
1870myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1871{
1872	return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1873}
1874
1875static bool_t
1876myxdr_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
1891static bool_t
1892myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1893{
1894	return (xdr_enum(xdrs, (enum_t *)objp));
1895}
1896
1897static bool_t
1898myxdr_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
1909static bool_t
1910myxdr_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 */
1924static enum clnt_stat
1925pmap_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] != '\0')) {
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 */
2006static enum clnt_stat
2007pmap_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 */
2099static bool_t
2100myxdr_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 */
2130static bool_t
2131myxdr_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
2144static bool_t
2145myxdr_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 */
2158static enum clnt_stat
2159mycallrpc(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 */
2186static int
2187bp_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 */
2320static void
2321init_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 */
2352static 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
2454static int
2455isdigit(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
2463static int
2464atoi(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 */
2492int nfs_root_rsize = 8 * 1024;		/* conservative for dumb NICs */
2493int nfs4_root_rsize = 32 * 1024;	/* only runs on TCP be aggressive */
2494
2495/*
2496 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2497 */
2498int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT;
2499
2500static int
2501init_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	}
2799sanity:
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