xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_dlinet.c (revision ad256857)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d62bc4baSyz  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
2615c07adcSJohn Levon /*
2715c07adcSJohn Levon  * Copyright (c) 2018, Joyent, Inc.
2815c07adcSJohn Levon  */
2915c07adcSJohn Levon 
307c478bd9Sstevel@tonic-gate #include <sys/param.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/cred.h>
347c478bd9Sstevel@tonic-gate #include <sys/user.h>
357c478bd9Sstevel@tonic-gate #include <sys/file.h>
367c478bd9Sstevel@tonic-gate #include <sys/stream.h>
377c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include <sys/debug.h>
417c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
427c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
437c478bd9Sstevel@tonic-gate #include <sys/socket.h>
447c478bd9Sstevel@tonic-gate #include <sys/t_kuser.h>
457c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
467c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
477c478bd9Sstevel@tonic-gate #include <sys/netconfig.h>
487c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
497c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
507c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
527c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
537c478bd9Sstevel@tonic-gate #include <sys/bootprops.h>
547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
557c478bd9Sstevel@tonic-gate #include <sys/promif.h>
567c478bd9Sstevel@tonic-gate #include <sys/mount.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <net/if.h>
597c478bd9Sstevel@tonic-gate #include <net/route.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <netinet/in.h>
627c478bd9Sstevel@tonic-gate #include <netinet/arp.h>
637c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h>
647c478bd9Sstevel@tonic-gate #include <netinet/inetutil.h>
657c478bd9Sstevel@tonic-gate #include <dhcp_impl.h>
667c478bd9Sstevel@tonic-gate #include <sys/sunos_dhcp_class.h>
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #include <rpc/types.h>
697c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
707c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
717c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
727c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
737c478bd9Sstevel@tonic-gate #include <rpc/pmap_clnt.h>
747c478bd9Sstevel@tonic-gate #include <rpc/pmap_rmt.h>
757c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h>
767c478bd9Sstevel@tonic-gate #include <rpc/bootparam.h>
777c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h>
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
807c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
817c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
827c478bd9Sstevel@tonic-gate #include <nfs/mount.h>
837c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #include <sys/kstr.h>
867c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
877c478bd9Sstevel@tonic-gate #include <sys/sunldi.h>
887c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #include <sys/errno.h>
917c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * RPC timers and retries
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate #define	PMAP_RETRIES	5
977c478bd9Sstevel@tonic-gate #define	DEFAULT_RETRIES	3
987c478bd9Sstevel@tonic-gate #define	GETFILE_RETRIES	2
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #define	DEFAULT_TIMEO	3
1017c478bd9Sstevel@tonic-gate #define	WHOAMI_TIMEO	20
1027c478bd9Sstevel@tonic-gate #define	REVARP_TIMEO	5
1037c478bd9Sstevel@tonic-gate #define	GETFILE_TIMEO	1
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * These are from the rpcgen'd version of mount.h XXX
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate #define	MOUNTPROG 100005
1097c478bd9Sstevel@tonic-gate #define	MOUNTPROC_MNT		1
1107c478bd9Sstevel@tonic-gate #define	MOUNTVERS		1
1117c478bd9Sstevel@tonic-gate #define	MOUNTVERS_POSIX		2
1127c478bd9Sstevel@tonic-gate #define	MOUNTVERS3		3
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate struct fhstatus {
1157c478bd9Sstevel@tonic-gate 	int fhs_status;
1167c478bd9Sstevel@tonic-gate 	fhandle_t fhs_fh;
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate #define	FHSIZE3 64
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate struct fhandle3 {
1227c478bd9Sstevel@tonic-gate 	uint_t fhandle3_len;
1237c478bd9Sstevel@tonic-gate 	char *fhandle3_val;
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate enum mountstat3 {
1277c478bd9Sstevel@tonic-gate 	MNT_OK = 0,
1287c478bd9Sstevel@tonic-gate 	MNT3ERR_PERM = 1,
1297c478bd9Sstevel@tonic-gate 	MNT3ERR_NOENT = 2,
1307c478bd9Sstevel@tonic-gate 	MNT3ERR_IO = 5,
1317c478bd9Sstevel@tonic-gate 	MNT3ERR_ACCES = 13,
1327c478bd9Sstevel@tonic-gate 	MNT3ERR_NOTDIR = 20,
1337c478bd9Sstevel@tonic-gate 	MNT3ERR_INVAL = 22,
1347c478bd9Sstevel@tonic-gate 	MNT3ERR_NAMETOOLONG = 63,
1357c478bd9Sstevel@tonic-gate 	MNT3ERR_NOTSUPP = 10004,
1367c478bd9Sstevel@tonic-gate 	MNT3ERR_SERVERFAULT = 10006
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate struct mountres3_ok {
1407c478bd9Sstevel@tonic-gate 	struct fhandle3 fhandle;
1417c478bd9Sstevel@tonic-gate 	struct {
1427c478bd9Sstevel@tonic-gate 		uint_t auth_flavors_len;
1437c478bd9Sstevel@tonic-gate 		int *auth_flavors_val;
1447c478bd9Sstevel@tonic-gate 	} auth_flavors;
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate struct mountres3 {
1487c478bd9Sstevel@tonic-gate 	enum mountstat3 fhs_status;
1497c478bd9Sstevel@tonic-gate 	union {
1507c478bd9Sstevel@tonic-gate 		struct mountres3_ok mountinfo;
1517c478bd9Sstevel@tonic-gate 	} mountres3_u;
1527c478bd9Sstevel@tonic-gate };
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * DLPI address format.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate struct	dladdr {
1587c478bd9Sstevel@tonic-gate 	uchar_t		dl_phys[6];
1597c478bd9Sstevel@tonic-gate 	ushort_t	dl_sap;
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
1637c478bd9Sstevel@tonic-gate 	&mod_miscops, "Boot diskless"
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1677c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
1687c478bd9Sstevel@tonic-gate };
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate static int	dldebug;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate int
_init(void)1737c478bd9Sstevel@tonic-gate _init(void)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate int
_fini(void)1797c478bd9Sstevel@tonic-gate _fini(void)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1857c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
190cc2b7f04Sdduvall 
1917c478bd9Sstevel@tonic-gate static enum clnt_stat	pmap_rmt_call(struct knetconfig *, struct netbuf *,
1927c478bd9Sstevel@tonic-gate 			    bool_t, rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
1937c478bd9Sstevel@tonic-gate 			    caddr_t, xdrproc_t, caddr_t, struct timeval,
1947c478bd9Sstevel@tonic-gate 			    struct netbuf *);
1957c478bd9Sstevel@tonic-gate static bool_t		myxdr_rmtcall_args(XDR *, struct rmtcallargs *);
1967c478bd9Sstevel@tonic-gate static bool_t		myxdr_rmtcallres(XDR *, struct rmtcallres *);
1977c478bd9Sstevel@tonic-gate static bool_t		myxdr_pmap(XDR *, struct pmap *);
1987c478bd9Sstevel@tonic-gate static bool_t		myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp);
1997c478bd9Sstevel@tonic-gate static bool_t		myxdr_fhandle(XDR *xdrs, fhandle_t *fh);
2007c478bd9Sstevel@tonic-gate static bool_t		myxdr_mountres3(XDR *xdrs, struct mountres3 *objp);
2017c478bd9Sstevel@tonic-gate static bool_t		myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp);
2027c478bd9Sstevel@tonic-gate static bool_t		myxdr_mountres3_ok(XDR *xdrs,
2037c478bd9Sstevel@tonic-gate 			    struct mountres3_ok *objp);
2047c478bd9Sstevel@tonic-gate static bool_t		myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp);
2057c478bd9Sstevel@tonic-gate static enum clnt_stat	pmap_kgetport(struct knetconfig *, struct netbuf *,
2067c478bd9Sstevel@tonic-gate 			    rpcprog_t, rpcvers_t, rpcprot_t);
2077c478bd9Sstevel@tonic-gate static enum clnt_stat	mycallrpc(struct knetconfig *, struct netbuf *,
2087c478bd9Sstevel@tonic-gate 			    rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
2097c478bd9Sstevel@tonic-gate 			    char *, xdrproc_t, char *, int, int);
2107c478bd9Sstevel@tonic-gate static int		ifioctl(TIUSER *, int, struct netbuf *);
2117c478bd9Sstevel@tonic-gate static int		getfile(char *, char *, struct netbuf *, char *);
2127c478bd9Sstevel@tonic-gate static int		ping_prog(struct netbuf *, uint_t prog, uint_t vers,
2137c478bd9Sstevel@tonic-gate 			    int proto, enum clnt_stat *);
2147c478bd9Sstevel@tonic-gate static int		mountnfs(struct netbuf *, char *, char *,
2157c478bd9Sstevel@tonic-gate 			    fhandle_t *, int *);
2167c478bd9Sstevel@tonic-gate static int		mountnfs3(struct netbuf *, char *, char *,
2177c478bd9Sstevel@tonic-gate 			    nfs_fh3 *, int *);
2187c478bd9Sstevel@tonic-gate static int		init_mountopts(struct nfs_args *, int,
2197c478bd9Sstevel@tonic-gate 			    struct knetconfig **, int *);
2207c478bd9Sstevel@tonic-gate static int		revarp_myaddr(TIUSER *);
2217c478bd9Sstevel@tonic-gate static void		revarp_start(ldi_handle_t, struct netbuf *);
2227c478bd9Sstevel@tonic-gate static void		revarpinput(ldi_handle_t, struct netbuf *);
2237c478bd9Sstevel@tonic-gate static void		init_netbuf(struct netbuf *);
2247c478bd9Sstevel@tonic-gate static void		free_netbuf(struct netbuf *);
2257c478bd9Sstevel@tonic-gate static int		rtioctl(TIUSER *, int, struct rtentry *);
2267c478bd9Sstevel@tonic-gate static void		init_config(void);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate static void		cacheinit(void);
2297c478bd9Sstevel@tonic-gate static int		cacheinfo(char *, int, struct netbuf *, char *, int);
2307c478bd9Sstevel@tonic-gate static int		dlifconfig(TIUSER *, struct in_addr *, struct in_addr *,
231843e1988Sjohnlev 			    struct in_addr *, uint_t);
2327c478bd9Sstevel@tonic-gate static int		setifflags(TIUSER *, uint_t);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static char		*inet_ntoa(struct in_addr);
2357c478bd9Sstevel@tonic-gate static int		inet_aton(char *, uchar_t *);
2367c478bd9Sstevel@tonic-gate static int		isdigit(int);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * Should be in some common
2407c478bd9Sstevel@tonic-gate  * ethernet source file.
2417c478bd9Sstevel@tonic-gate  */
2427c478bd9Sstevel@tonic-gate static struct ether_addr etherbroadcastaddr = {
2437c478bd9Sstevel@tonic-gate 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2447c478bd9Sstevel@tonic-gate };
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate static struct ether_addr myether;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * "ifname" is the interface name/unit as read from the boot
2507c478bd9Sstevel@tonic-gate  * arguments.
2517c478bd9Sstevel@tonic-gate  * "ndev" is the major device number of the network interface
2527c478bd9Sstevel@tonic-gate  * used to boot from.
2537c478bd9Sstevel@tonic-gate  * "ifunit" it the physical point of attachment for the network
2547c478bd9Sstevel@tonic-gate  * interface used to boot from.
2557c478bd9Sstevel@tonic-gate  *
2567c478bd9Sstevel@tonic-gate  * Both of these are initialized in "init_config()".
2577c478bd9Sstevel@tonic-gate  */
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate static char	ifname[IFNAMSIZ];
2607c478bd9Sstevel@tonic-gate static char	ndev_path[MAXPATHLEN];
2617c478bd9Sstevel@tonic-gate static int	ifunit;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate  * XXX these should be shared
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate static struct knetconfig dl_udp_netconf = {
2677c478bd9Sstevel@tonic-gate 	NC_TPI_CLTS,			/* semantics */
2687c478bd9Sstevel@tonic-gate 	NC_INET,			/* family */
2697c478bd9Sstevel@tonic-gate 	NC_UDP,				/* protocol */
2707c478bd9Sstevel@tonic-gate 	0,				/* device */
2717c478bd9Sstevel@tonic-gate };
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate static struct knetconfig dl_tcp_netconf = {
2747c478bd9Sstevel@tonic-gate 	NC_TPI_COTS,			/* semantics */
2757c478bd9Sstevel@tonic-gate 	NC_INET,			/* family */
2767c478bd9Sstevel@tonic-gate 	NC_TCP,				/* protocol */
2777c478bd9Sstevel@tonic-gate 	0,				/* device */
2787c478bd9Sstevel@tonic-gate };
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /* parameters from DHCP or bootparamd */
2817c478bd9Sstevel@tonic-gate static PKT_LIST	*pl = NULL;
2827c478bd9Sstevel@tonic-gate static uchar_t server_ip[4];
2837c478bd9Sstevel@tonic-gate static uchar_t dhcp_server_ip[4];
2847c478bd9Sstevel@tonic-gate static char *server_name_c, *server_path_c;
2857c478bd9Sstevel@tonic-gate static char rootopts[256];
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate /*
2887c478bd9Sstevel@tonic-gate  * XXX Until we get the nfsmapid deadlocks all fixed, don't allow
2897c478bd9Sstevel@tonic-gate  * XXX a v4 root mount.
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate int nfs4_no_diskless_root_support = 1;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate int
mount_root(char * name,char * path,int version,struct nfs_args * args,int * vfsflags)2947c478bd9Sstevel@tonic-gate mount_root(char *name, char *path, int version, struct nfs_args *args,
295f3de0dd9SToomas Soome     int *vfsflags)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	int rc;
2987c478bd9Sstevel@tonic-gate 	int proto;
2997c478bd9Sstevel@tonic-gate 	struct knetconfig *dl_cf;
3007c478bd9Sstevel@tonic-gate 	static int init_done = 0;
3017c478bd9Sstevel@tonic-gate 	enum clnt_stat stat;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if (dldebug)
3047c478bd9Sstevel@tonic-gate 		printf("mount_root: name=%s\n", name);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (init_done == 0) {
3077c478bd9Sstevel@tonic-gate 		init_config();
3087c478bd9Sstevel@tonic-gate 		init_done = 1;
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	init_netbuf(args->addr);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	do {
3147c478bd9Sstevel@tonic-gate 		rc = getfile(name, args->hostname, args->addr, path);
3157c478bd9Sstevel@tonic-gate 	} while (rc == ETIMEDOUT);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (rc) {
3187c478bd9Sstevel@tonic-gate 		free_netbuf(args->addr);
3197c478bd9Sstevel@tonic-gate 		return (rc);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	ASSERT(args->knconf->knc_protofmly != NULL);
3237c478bd9Sstevel@tonic-gate 	ASSERT(args->knconf->knc_proto != NULL);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	switch (version) {
3267c478bd9Sstevel@tonic-gate 	case NFS_VERSION:
3277c478bd9Sstevel@tonic-gate 		rc = mountnfs(args->addr, args->hostname, path,
3287c478bd9Sstevel@tonic-gate 		    (fhandle_t *)args->fh, &proto);
3297c478bd9Sstevel@tonic-gate 		break;
3307c478bd9Sstevel@tonic-gate 	case NFS_V3:
3317c478bd9Sstevel@tonic-gate 		rc = mountnfs3(args->addr, args->hostname, path,
3327c478bd9Sstevel@tonic-gate 		    (nfs_fh3 *)args->fh, &proto);
3337c478bd9Sstevel@tonic-gate 		break;
3347c478bd9Sstevel@tonic-gate 	case NFS_V4:
3357c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)args->addr->buf)->sin_port =
336843e1988Sjohnlev 		    htons(NFS_PORT);
3377c478bd9Sstevel@tonic-gate 		if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP,
338843e1988Sjohnlev 		    &stat)) {
3397c478bd9Sstevel@tonic-gate 			proto = IPPROTO_TCP;
3407c478bd9Sstevel@tonic-gate 			rc = 0;
3417c478bd9Sstevel@tonic-gate 		} else {
3427c478bd9Sstevel@tonic-gate 			switch (stat) {
3437c478bd9Sstevel@tonic-gate 			case RPC_PROGVERSMISMATCH:
3447c478bd9Sstevel@tonic-gate 			case RPC_XPRTFAILED:
3457c478bd9Sstevel@tonic-gate 				/*
3467c478bd9Sstevel@tonic-gate 				 * Common failures if v4 unsupported or no TCP
3477c478bd9Sstevel@tonic-gate 				 */
3487c478bd9Sstevel@tonic-gate 				rc = EPROTONOSUPPORT;
3497c478bd9Sstevel@tonic-gate 				break;
3507c478bd9Sstevel@tonic-gate 			default:
3517c478bd9Sstevel@tonic-gate 				rc = ENXIO;
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 		}
3547c478bd9Sstevel@tonic-gate 		if (nfs4_no_diskless_root_support)
3557c478bd9Sstevel@tonic-gate 			rc = EPROTONOSUPPORT;
3567c478bd9Sstevel@tonic-gate 		break;
3577c478bd9Sstevel@tonic-gate 	default:
3587c478bd9Sstevel@tonic-gate 		rc = EPROTONOSUPPORT;
3597c478bd9Sstevel@tonic-gate 		break;
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (rc)
3637c478bd9Sstevel@tonic-gate 		goto errout;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	switch (proto) {
3667c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
3677c478bd9Sstevel@tonic-gate 		dl_cf = &dl_tcp_netconf;
3687c478bd9Sstevel@tonic-gate 		break;
3697c478bd9Sstevel@tonic-gate 	case IPPROTO_UDP:
3707c478bd9Sstevel@tonic-gate 	default:
3717c478bd9Sstevel@tonic-gate 		dl_cf = &dl_udp_netconf;
3727c478bd9Sstevel@tonic-gate 		break;
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	rc = init_mountopts(args, version, &dl_cf, vfsflags);
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/*
3787c478bd9Sstevel@tonic-gate 	 * Copy knetconfig information from the template, note that the
3797c478bd9Sstevel@tonic-gate 	 * rdev field has been set by init_config above.
3807c478bd9Sstevel@tonic-gate 	 */
3817c478bd9Sstevel@tonic-gate 	args->knconf->knc_semantics = dl_cf->knc_semantics;
3827c478bd9Sstevel@tonic-gate 	args->knconf->knc_rdev = dl_cf->knc_rdev;
3837c478bd9Sstevel@tonic-gate 	(void) strcpy(args->knconf->knc_protofmly, dl_cf->knc_protofmly);
3847c478bd9Sstevel@tonic-gate 	(void) strcpy(args->knconf->knc_proto, dl_cf->knc_proto);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate errout:
3877c478bd9Sstevel@tonic-gate 	if (dldebug) {
3887c478bd9Sstevel@tonic-gate 		if (rc)
3897c478bd9Sstevel@tonic-gate 			nfs_perror(rc, "mount_root: mount %s:%s failed: %m\n",
3907c478bd9Sstevel@tonic-gate 			    args->hostname, path);
3917c478bd9Sstevel@tonic-gate 		else
3927c478bd9Sstevel@tonic-gate 			printf("mount_root: leaving\n");
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	return (rc);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate  * Call mount daemon on server `sa' to mount path.
4007c478bd9Sstevel@tonic-gate  * `port' is set to nfs port and fh is the fhandle
4017c478bd9Sstevel@tonic-gate  * returned from the server.
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate static int
mountnfs(struct netbuf * sa,char * server,char * path,fhandle_t * fh,int * proto)4047c478bd9Sstevel@tonic-gate mountnfs(struct netbuf *sa, char *server,
405f3de0dd9SToomas Soome     char *path, fhandle_t *fh, int *proto)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	struct fhstatus fhs;
4087c478bd9Sstevel@tonic-gate 	enum clnt_stat stat;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if (dldebug)
4117c478bd9Sstevel@tonic-gate 		printf("mountnfs: entered\n");
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * Get the port number for the mount program.
4157c478bd9Sstevel@tonic-gate 	 * pmap_kgetport first tries a SunOS portmapper
4167c478bd9Sstevel@tonic-gate 	 * and, if no reply is received, will try a
4177c478bd9Sstevel@tonic-gate 	 * SVR4 rpcbind. Either way, `sa' is set to
4187c478bd9Sstevel@tonic-gate 	 * the correct address.
4197c478bd9Sstevel@tonic-gate 	 */
4207c478bd9Sstevel@tonic-gate 	do {
4217c478bd9Sstevel@tonic-gate 		stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
4227c478bd9Sstevel@tonic-gate 		    (rpcvers_t)MOUNTVERS, (rpcprot_t)IPPROTO_UDP);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 		if (stat == RPC_TIMEDOUT) {
4257c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4267c478bd9Sstevel@tonic-gate 			    "mountnfs: %s:%s portmap not responding",
4277c478bd9Sstevel@tonic-gate 			    server, path);
4287c478bd9Sstevel@tonic-gate 		} else if (stat != RPC_SUCCESS) {
4297c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4307c478bd9Sstevel@tonic-gate 			    "mountnfs: pmap_kgetport RPC error %d (%s).",
4317c478bd9Sstevel@tonic-gate 			    stat, clnt_sperrno(stat));
4327c478bd9Sstevel@tonic-gate 			return (ENXIO);	/* XXX */
4337c478bd9Sstevel@tonic-gate 		}
4347c478bd9Sstevel@tonic-gate 	} while (stat == RPC_TIMEDOUT);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/*
4377c478bd9Sstevel@tonic-gate 	 * The correct port number has been
4387c478bd9Sstevel@tonic-gate 	 * put into `sa' by pmap_kgetport().
4397c478bd9Sstevel@tonic-gate 	 */
4407c478bd9Sstevel@tonic-gate 	do {
4417c478bd9Sstevel@tonic-gate 		stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
4427c478bd9Sstevel@tonic-gate 		    (rpcvers_t)MOUNTVERS, (rpcproc_t)MOUNTPROC_MNT,
4437c478bd9Sstevel@tonic-gate 		    xdr_bp_path_t, (char *)&path,
4447c478bd9Sstevel@tonic-gate 		    myxdr_fhstatus, (char *)&fhs,
4457c478bd9Sstevel@tonic-gate 		    DEFAULT_TIMEO, DEFAULT_RETRIES);
4467c478bd9Sstevel@tonic-gate 		if (stat == RPC_TIMEDOUT) {
4477c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4487c478bd9Sstevel@tonic-gate 			    "mountnfs: %s:%s mount server not responding",
4497c478bd9Sstevel@tonic-gate 			    server, path);
4507c478bd9Sstevel@tonic-gate 		}
4517c478bd9Sstevel@tonic-gate 	} while (stat == RPC_TIMEDOUT);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if (stat != RPC_SUCCESS) {
4547c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "mountnfs: RPC failed: error %d (%s).",
4557c478bd9Sstevel@tonic-gate 		    stat, clnt_sperrno(stat));
4567c478bd9Sstevel@tonic-gate 		return (ENXIO);	/* XXX */
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	*fh = fhs.fhs_fh;
4627c478bd9Sstevel@tonic-gate 	if (fhs.fhs_status != 0) {
4637c478bd9Sstevel@tonic-gate 		if (dldebug)
4647c478bd9Sstevel@tonic-gate 			printf("mountnfs: fhs_status %d\n", fhs.fhs_status);
4657c478bd9Sstevel@tonic-gate 		return (ENXIO);		/* XXX */
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	*proto = IPPROTO_UDP;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (ping_prog(sa, NFS_PROGRAM, NFS_VERSION, IPPROTO_TCP, NULL))
4717c478bd9Sstevel@tonic-gate 		*proto = IPPROTO_TCP;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	if (dldebug)
4747c478bd9Sstevel@tonic-gate 		printf("mountnfs: leaving\n");
4757c478bd9Sstevel@tonic-gate 	return (0);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * Call mount daemon on server `sa' to mount path.
4807c478bd9Sstevel@tonic-gate  * `port' is set to nfs port and fh is the fhandle
4817c478bd9Sstevel@tonic-gate  * returned from the server.
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate static int
mountnfs3(struct netbuf * sa,char * server,char * path,nfs_fh3 * fh,int * proto)4847c478bd9Sstevel@tonic-gate mountnfs3(struct netbuf *sa, char *server,
485f3de0dd9SToomas Soome     char *path, nfs_fh3 *fh, int *proto)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	struct mountres3 mountres3;
4887c478bd9Sstevel@tonic-gate 	enum clnt_stat stat;
4897c478bd9Sstevel@tonic-gate 	int ret = 0;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (dldebug)
4927c478bd9Sstevel@tonic-gate 		printf("mountnfs3: entered\n");
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	/*
4957c478bd9Sstevel@tonic-gate 	 * Get the port number for the mount program.
4967c478bd9Sstevel@tonic-gate 	 * pmap_kgetport first tries a SunOS portmapper
4977c478bd9Sstevel@tonic-gate 	 * and, if no reply is received, will try a
4987c478bd9Sstevel@tonic-gate 	 * SVR4 rpcbind. Either way, `sa' is set to
4997c478bd9Sstevel@tonic-gate 	 * the correct address.
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 	do {
5027c478bd9Sstevel@tonic-gate 		stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
5037c478bd9Sstevel@tonic-gate 		    (rpcvers_t)MOUNTVERS3, (rpcprot_t)IPPROTO_UDP);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 		if (stat == RPC_PROGVERSMISMATCH) {
5067c478bd9Sstevel@tonic-gate 			if (dldebug)
5077c478bd9Sstevel@tonic-gate 				printf("mountnfs3: program/version mismatch\n");
5087c478bd9Sstevel@tonic-gate 			return (EPROTONOSUPPORT); /* XXX */
5097c478bd9Sstevel@tonic-gate 		} else if (stat == RPC_TIMEDOUT) {
5107c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
5117c478bd9Sstevel@tonic-gate 			    "mountnfs3: %s:%s portmap not responding",
5127c478bd9Sstevel@tonic-gate 			    server, path);
5137c478bd9Sstevel@tonic-gate 		} else if (stat != RPC_SUCCESS) {
5147c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
5157c478bd9Sstevel@tonic-gate 			    "mountnfs3: pmap_kgetport RPC error %d (%s).",
5167c478bd9Sstevel@tonic-gate 			    stat, clnt_sperrno(stat));
5177c478bd9Sstevel@tonic-gate 			return (ENXIO);	/* XXX */
5187c478bd9Sstevel@tonic-gate 		}
5197c478bd9Sstevel@tonic-gate 	} while (stat == RPC_TIMEDOUT);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = NULL;
5227c478bd9Sstevel@tonic-gate 	mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = NULL;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/*
5257c478bd9Sstevel@tonic-gate 	 * The correct port number has been
5267c478bd9Sstevel@tonic-gate 	 * put into `sa' by pmap_kgetport().
5277c478bd9Sstevel@tonic-gate 	 */
5287c478bd9Sstevel@tonic-gate 	do {
5297c478bd9Sstevel@tonic-gate 		stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
5307c478bd9Sstevel@tonic-gate 		    (rpcvers_t)MOUNTVERS3, (rpcproc_t)MOUNTPROC_MNT,
5317c478bd9Sstevel@tonic-gate 		    xdr_bp_path_t, (char *)&path,
5327c478bd9Sstevel@tonic-gate 		    myxdr_mountres3, (char *)&mountres3,
5337c478bd9Sstevel@tonic-gate 		    DEFAULT_TIMEO, DEFAULT_RETRIES);
5347c478bd9Sstevel@tonic-gate 		if (stat == RPC_TIMEDOUT) {
5357c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
5367c478bd9Sstevel@tonic-gate 			    "mountnfs3: %s:%s mount server not responding",
5377c478bd9Sstevel@tonic-gate 			    server, path);
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 	} while (stat == RPC_TIMEDOUT);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if (stat == RPC_PROGVERSMISMATCH) {
5427c478bd9Sstevel@tonic-gate 		if (dldebug)
5437c478bd9Sstevel@tonic-gate 			printf("mountnfs3: program/version mismatch\n");
5447c478bd9Sstevel@tonic-gate 		ret = EPROTONOSUPPORT;
5457c478bd9Sstevel@tonic-gate 		goto out;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	if (stat != RPC_SUCCESS) {
5487c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "mountnfs3: RPC failed: error %d (%s).",
5497c478bd9Sstevel@tonic-gate 		    stat, clnt_sperrno(stat));
5507c478bd9Sstevel@tonic-gate 		ret = ENXIO;	/* XXX */
5517c478bd9Sstevel@tonic-gate 		goto out;
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if (mountres3.fhs_status != MNT_OK) {
5557c478bd9Sstevel@tonic-gate 		if (dldebug)
5567c478bd9Sstevel@tonic-gate 			printf("mountnfs3: fhs_status %d\n",
557843e1988Sjohnlev 			    mountres3.fhs_status);
5587c478bd9Sstevel@tonic-gate 		ret = ENXIO;	/* XXX */
5597c478bd9Sstevel@tonic-gate 		goto out;
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	*proto = IPPROTO_UDP;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if (ping_prog(sa, NFS_PROGRAM, NFS_V3, IPPROTO_TCP, NULL)) {
5677c478bd9Sstevel@tonic-gate 		*proto = IPPROTO_TCP;
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	fh->fh3_length = mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
5717c478bd9Sstevel@tonic-gate 	bcopy(mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
5727c478bd9Sstevel@tonic-gate 	    fh->fh3_u.data, fh->fh3_length);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate out:
5757c478bd9Sstevel@tonic-gate 	xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (dldebug)
5787c478bd9Sstevel@tonic-gate 		printf("mountnfs3: leaving\n");
5797c478bd9Sstevel@tonic-gate 	return (ret);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate static int
ping_prog(struct netbuf * call_addr,uint_t prog,uint_t vers,int proto,enum clnt_stat * statp)5837c478bd9Sstevel@tonic-gate ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto,
584f3de0dd9SToomas Soome     enum clnt_stat *statp)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate 	struct knetconfig *knconf;
5877c478bd9Sstevel@tonic-gate 	enum clnt_stat stat;
5887c478bd9Sstevel@tonic-gate 	int retries = DEFAULT_RETRIES;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	switch (proto) {
5917c478bd9Sstevel@tonic-gate 	case IPPROTO_TCP:
5927c478bd9Sstevel@tonic-gate 		knconf = &dl_tcp_netconf;
5937c478bd9Sstevel@tonic-gate 		break;
5947c478bd9Sstevel@tonic-gate 	case IPPROTO_UDP:
5957c478bd9Sstevel@tonic-gate 		knconf = &dl_udp_netconf;
5967c478bd9Sstevel@tonic-gate 		break;
5977c478bd9Sstevel@tonic-gate 	default:
5987c478bd9Sstevel@tonic-gate 		return (0);
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	do {
6027c478bd9Sstevel@tonic-gate 		stat = mycallrpc(knconf, call_addr, prog, vers, NULLPROC,
6037c478bd9Sstevel@tonic-gate 		    xdr_void, NULL, xdr_void, NULL,
6047c478bd9Sstevel@tonic-gate 		    DEFAULT_TIMEO, DEFAULT_RETRIES);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 		if (dldebug)
6077c478bd9Sstevel@tonic-gate 			printf("ping_prog: %d return %d (%s)\n", proto, stat,
6087c478bd9Sstevel@tonic-gate 			    clnt_sperrno(stat));
6097c478bd9Sstevel@tonic-gate 		/*
6107c478bd9Sstevel@tonic-gate 		 * Special case for TCP, it may "timeout" because it failed
6117c478bd9Sstevel@tonic-gate 		 * to establish an initial connection but it doesn't
6127c478bd9Sstevel@tonic-gate 		 * actually retry, so we do the retry.
6137c478bd9Sstevel@tonic-gate 		 * Persistence pays in diskless.
6147c478bd9Sstevel@tonic-gate 		 */
6157c478bd9Sstevel@tonic-gate 	} while (stat == RPC_TIMEDOUT && proto == IPPROTO_TCP && retries--);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	if (statp != NULL)
6187c478bd9Sstevel@tonic-gate 		*statp = stat;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (stat != RPC_SUCCESS)
6217c478bd9Sstevel@tonic-gate 		return (0);
6227c478bd9Sstevel@tonic-gate 	return (1);
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate static struct netbuf bootparam_addr;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate  * Returns after filling in the following global variables:
6297c478bd9Sstevel@tonic-gate  *	bootparam_addr,
6307c478bd9Sstevel@tonic-gate  *	utsname.nodename,
6317c478bd9Sstevel@tonic-gate  *	srpc_domain.
6327c478bd9Sstevel@tonic-gate  */
6337c478bd9Sstevel@tonic-gate static int
whoami(void)6347c478bd9Sstevel@tonic-gate whoami(void)
6357c478bd9Sstevel@tonic-gate {
636cc2b7f04Sdduvall 	TIUSER *tiptr;
637cc2b7f04Sdduvall 	struct netbuf sa;
638cc2b7f04Sdduvall 	struct netbuf req;
639cc2b7f04Sdduvall 	struct bp_whoami_arg arg;
640cc2b7f04Sdduvall 	struct bp_whoami_res res;
641cc2b7f04Sdduvall 	struct timeval tv;
642cc2b7f04Sdduvall 	enum clnt_stat stat;
643cc2b7f04Sdduvall 	int rc;
644cc2b7f04Sdduvall 	size_t namelen;
645cc2b7f04Sdduvall 	int printed_waiting_msg;
646cc2b7f04Sdduvall 
647cc2b7f04Sdduvall 	if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
648cc2b7f04Sdduvall 	    FREAD|FWRITE, &tiptr, CRED())) != 0) {
6497c478bd9Sstevel@tonic-gate 		nfs_perror(rc, "whoami: t_kopen udp failed: %m.\n");
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/*
6537c478bd9Sstevel@tonic-gate 	 * Find out our local (IP) address.
6547c478bd9Sstevel@tonic-gate 	 */
6557c478bd9Sstevel@tonic-gate 	if (rc = revarp_myaddr(tiptr)) {
6567c478bd9Sstevel@tonic-gate 		nfs_perror(rc, "whoami: revarp_myaddr failed: %m.\n");
6577c478bd9Sstevel@tonic-gate 		(void) t_kclose(tiptr, 0);
6587c478bd9Sstevel@tonic-gate 		return (rc);
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	/* explicitly use the limited broadcast address */
6627c478bd9Sstevel@tonic-gate 	init_netbuf(&sa);
6637c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)sa.buf)->sin_family = AF_INET;
6647c478bd9Sstevel@tonic-gate 	((struct sockaddr_in *)sa.buf)->sin_addr.s_addr =
6657c478bd9Sstevel@tonic-gate 	    htonl(INADDR_BROADCAST);
6667c478bd9Sstevel@tonic-gate 	sa.len = sizeof (struct sockaddr_in);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * Pick up our local (IP) address.
6707c478bd9Sstevel@tonic-gate 	 */
6717c478bd9Sstevel@tonic-gate 	init_netbuf(&req);
6727c478bd9Sstevel@tonic-gate 	if (rc = ifioctl(tiptr, SIOCGIFADDR, &req)) {
6737c478bd9Sstevel@tonic-gate 		nfs_perror(rc,
6747c478bd9Sstevel@tonic-gate 		    "whoami: couldn't get my IP address: %m.\n");
6757c478bd9Sstevel@tonic-gate 		free_netbuf(&sa);
6767c478bd9Sstevel@tonic-gate 		free_netbuf(&req);
6777c478bd9Sstevel@tonic-gate 		(void) t_kclose(tiptr, 0);
6787c478bd9Sstevel@tonic-gate 		return (rc);
6797c478bd9Sstevel@tonic-gate 	}
680cc2b7f04Sdduvall 
6817c478bd9Sstevel@tonic-gate 	/*
6827c478bd9Sstevel@tonic-gate 	 * Set up the arguments expected by bootparamd.
6837c478bd9Sstevel@tonic-gate 	 */
6847c478bd9Sstevel@tonic-gate 	arg.client_address.address_type = IP_ADDR_TYPE;
6857c478bd9Sstevel@tonic-gate 	bcopy(&((struct sockaddr_in *)req.buf)->sin_addr,
6867c478bd9Sstevel@tonic-gate 	    &arg.client_address.bp_address.ip_addr, sizeof (struct in_addr));
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	free_netbuf(&req);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	init_netbuf(&bootparam_addr);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	/*
6937c478bd9Sstevel@tonic-gate 	 * Initial retransmission interval
6947c478bd9Sstevel@tonic-gate 	 */
6957c478bd9Sstevel@tonic-gate 	tv.tv_sec = DEFAULT_TIMEO;
6967c478bd9Sstevel@tonic-gate 	tv.tv_usec = 0;
6977c478bd9Sstevel@tonic-gate 	res.client_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
6987c478bd9Sstevel@tonic-gate 	res.domain_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/*
7017c478bd9Sstevel@tonic-gate 	 * Do a broadcast call to find a bootparam daemon that
7027c478bd9Sstevel@tonic-gate 	 * will tell us our hostname, domainname and any
7037c478bd9Sstevel@tonic-gate 	 * router that we have to use to talk to our NFS server.
7047c478bd9Sstevel@tonic-gate 	 */
7057c478bd9Sstevel@tonic-gate 	printed_waiting_msg = 0;
7067c478bd9Sstevel@tonic-gate 	do {
7077c478bd9Sstevel@tonic-gate 		/*
7087c478bd9Sstevel@tonic-gate 		 * pmap_rmt_call will first try the SunOS portmapper
7097c478bd9Sstevel@tonic-gate 		 * and if no reply is received will then try the SVR4
7107c478bd9Sstevel@tonic-gate 		 * rpcbind.
7117c478bd9Sstevel@tonic-gate 		 * Either way, `bootparam_addr' will be set to the
7127c478bd9Sstevel@tonic-gate 		 * correct address for the bootparamd that responds.
7137c478bd9Sstevel@tonic-gate 		 */
7147c478bd9Sstevel@tonic-gate 		stat = pmap_rmt_call(&dl_udp_netconf, &sa, TRUE, BOOTPARAMPROG,
7157c478bd9Sstevel@tonic-gate 		    BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI,
7167c478bd9Sstevel@tonic-gate 		    xdr_bp_whoami_arg, (caddr_t)&arg,
7177c478bd9Sstevel@tonic-gate 		    xdr_bp_whoami_res, (caddr_t)&res,
7187c478bd9Sstevel@tonic-gate 		    tv, &bootparam_addr);
7197c478bd9Sstevel@tonic-gate 		if (stat == RPC_TIMEDOUT && !printed_waiting_msg) {
7207c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
7217c478bd9Sstevel@tonic-gate 			    "No bootparam server responding; still trying");
7227c478bd9Sstevel@tonic-gate 			printed_waiting_msg = 1;
7237c478bd9Sstevel@tonic-gate 		}
7247c478bd9Sstevel@tonic-gate 		/*
7257c478bd9Sstevel@tonic-gate 		 * Retransmission interval for second and subsequent tries.
7267c478bd9Sstevel@tonic-gate 		 * We expect first pmap_rmt_call to retransmit and backoff to
7277c478bd9Sstevel@tonic-gate 		 * at least this value.
7287c478bd9Sstevel@tonic-gate 		 */
7297c478bd9Sstevel@tonic-gate 		tv.tv_sec = WHOAMI_TIMEO;
7307c478bd9Sstevel@tonic-gate 		tv.tv_usec = 0;
7317c478bd9Sstevel@tonic-gate 	} while (stat == RPC_TIMEDOUT);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	if (printed_waiting_msg)
7347c478bd9Sstevel@tonic-gate 		printf("Bootparam response received\n");
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	if (stat != RPC_SUCCESS) {
7377c478bd9Sstevel@tonic-gate 		/* XXX should get real error here */
7387c478bd9Sstevel@tonic-gate 		rc = ENXIO;
7397c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
7407c478bd9Sstevel@tonic-gate 		    "whoami: bootparam RPC failed: error %d (%s).",
7417c478bd9Sstevel@tonic-gate 		    stat, clnt_sperrno(stat));
7427c478bd9Sstevel@tonic-gate 		goto done;
7437c478bd9Sstevel@tonic-gate 	}
744cc2b7f04Sdduvall 
7457c478bd9Sstevel@tonic-gate 	namelen = strlen(res.client_name);
7467c478bd9Sstevel@tonic-gate 	if (namelen > sizeof (utsname.nodename)) {
7477c478bd9Sstevel@tonic-gate 		printf("whoami: hostname too long");
7487c478bd9Sstevel@tonic-gate 		rc = ENAMETOOLONG;
7497c478bd9Sstevel@tonic-gate 		goto done;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	if (namelen != 0) {
7527c478bd9Sstevel@tonic-gate 		bcopy(res.client_name, &utsname.nodename, namelen);
7537c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?hostname: %s\n", utsname.nodename);
7547c478bd9Sstevel@tonic-gate 	} else {
7557c478bd9Sstevel@tonic-gate 		printf("whoami: no host name\n");
7567c478bd9Sstevel@tonic-gate 		rc = ENXIO;
7577c478bd9Sstevel@tonic-gate 		goto done;
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	namelen = strlen(res.domain_name);
7617c478bd9Sstevel@tonic-gate 	if (namelen != 0) {
7627c478bd9Sstevel@tonic-gate 		if (namelen > SYS_NMLN) {
7637c478bd9Sstevel@tonic-gate 			printf("whoami: domainname too long");
7647c478bd9Sstevel@tonic-gate 			rc = ENAMETOOLONG;
7657c478bd9Sstevel@tonic-gate 			goto done;
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 		bcopy(res.domain_name, &srpc_domain, namelen);
7687c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?domainname: %s\n", srpc_domain);
7697c478bd9Sstevel@tonic-gate 	} else {
7707c478bd9Sstevel@tonic-gate 		printf("whoami: no domain name\n");
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	if (res.router_address.address_type == IP_ADDR_TYPE) {
7747c478bd9Sstevel@tonic-gate 		struct rtentry		rtentry;
7757c478bd9Sstevel@tonic-gate 		struct sockaddr_in	*sin;
776cc2b7f04Sdduvall 		struct in_addr		ipaddr;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 		bcopy(&res.router_address.bp_address.ip_addr, &ipaddr,
779cc2b7f04Sdduvall 		    sizeof (struct in_addr));
7807c478bd9Sstevel@tonic-gate 
781cc2b7f04Sdduvall 		if (ipaddr.s_addr != (uint32_t)0) {
7827c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&rtentry.rt_dst;
7837c478bd9Sstevel@tonic-gate 			bzero(sin, sizeof (*sin));
7847c478bd9Sstevel@tonic-gate 			sin->sin_family = AF_INET;
785cc2b7f04Sdduvall 
7867c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&rtentry.rt_gateway;
7877c478bd9Sstevel@tonic-gate 			bzero(sin, sizeof (*sin));
7887c478bd9Sstevel@tonic-gate 			sin->sin_family = AF_INET;
789cc2b7f04Sdduvall 			sin->sin_addr.s_addr = ipaddr.s_addr;
790cc2b7f04Sdduvall 
7917c478bd9Sstevel@tonic-gate 			rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
792cc2b7f04Sdduvall 
7937c478bd9Sstevel@tonic-gate 			if (rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) {
7947c478bd9Sstevel@tonic-gate 				nfs_perror(rc,
7957c478bd9Sstevel@tonic-gate 				    "whoami: couldn't add route: %m.\n");
7967c478bd9Sstevel@tonic-gate 				goto done;
7977c478bd9Sstevel@tonic-gate 			}
7987c478bd9Sstevel@tonic-gate 		}
7997c478bd9Sstevel@tonic-gate 	} else {
8007c478bd9Sstevel@tonic-gate 		printf("whoami: unknown gateway addr family %d\n",
8017c478bd9Sstevel@tonic-gate 		    res.router_address.address_type);
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate done:
8047c478bd9Sstevel@tonic-gate 	kmem_free(res.client_name, MAX_MACHINE_NAME + 1);
8057c478bd9Sstevel@tonic-gate 	kmem_free(res.domain_name, MAX_MACHINE_NAME + 1);
8067c478bd9Sstevel@tonic-gate 	free_netbuf(&sa);
8077c478bd9Sstevel@tonic-gate 	(void) t_kclose(tiptr, 0);
8087c478bd9Sstevel@tonic-gate 	return (rc);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /*
8127c478bd9Sstevel@tonic-gate  * Returns:
8137c478bd9Sstevel@tonic-gate  *	1) The ascii form of our root servers name in `server_name'.
8147c478bd9Sstevel@tonic-gate  *	2) Actual network address of our root server in `server_address'.
8157c478bd9Sstevel@tonic-gate  *	3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in
8167c478bd9Sstevel@tonic-gate  *	   `server_path'.  If fileid is "root", it is the pathname of our
8177c478bd9Sstevel@tonic-gate  *	   root on the server.
8187c478bd9Sstevel@tonic-gate  */
8197c478bd9Sstevel@tonic-gate static int
getfile(char * fileid,char * server_name,struct netbuf * server_address,char * server_path)8207c478bd9Sstevel@tonic-gate getfile(char *fileid,
821f3de0dd9SToomas Soome     char *server_name, struct netbuf *server_address, char *server_path)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	struct bp_getfile_arg arg;
8247c478bd9Sstevel@tonic-gate 	struct bp_getfile_res res;
8257c478bd9Sstevel@tonic-gate 	enum clnt_stat stat;
8267c478bd9Sstevel@tonic-gate 	int root = FALSE;
8277c478bd9Sstevel@tonic-gate 	static int using_cache = FALSE;
828cc2b7f04Sdduvall 	struct in_addr ipaddr;
8297c478bd9Sstevel@tonic-gate 	int timeo = DEFAULT_TIMEO;
8307c478bd9Sstevel@tonic-gate 	int retries = DEFAULT_RETRIES;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	if (dldebug)
8337c478bd9Sstevel@tonic-gate 		printf("getfile: entered\n");
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	/*
8367c478bd9Sstevel@tonic-gate 	 * Call cacheinfo() to see whether we can satisfy this request by using
8377c478bd9Sstevel@tonic-gate 	 * the information cached in memory by the boot program's DHCP
8387c478bd9Sstevel@tonic-gate 	 * implementation or boot properties rather than consult BOOTPARAMS,
8397c478bd9Sstevel@tonic-gate 	 * but while preserving the semantics of getfile(). We know that
8407c478bd9Sstevel@tonic-gate 	 * the server name is SYS_NMLN in length, and server_path is
8417c478bd9Sstevel@tonic-gate 	 * MAXPATHLEN (pn_alloc).
8427c478bd9Sstevel@tonic-gate 	 */
8437c478bd9Sstevel@tonic-gate 	if (strcmp(fileid, "root") == 0) {
8447c478bd9Sstevel@tonic-gate 		if (cacheinfo(server_name, SYS_NMLN, server_address,
8457c478bd9Sstevel@tonic-gate 		    server_path, MAXPATHLEN) == 0) {
8467c478bd9Sstevel@tonic-gate 			using_cache = TRUE;
8477c478bd9Sstevel@tonic-gate 			return (0);
8487c478bd9Sstevel@tonic-gate 		}
8497c478bd9Sstevel@tonic-gate 		root = TRUE;
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/*
8537c478bd9Sstevel@tonic-gate 	 * If using cache, rootopts is already available.
8547c478bd9Sstevel@tonic-gate 	 */
8557c478bd9Sstevel@tonic-gate 	if (strcmp(fileid, "rootopts") == 0 && using_cache == TRUE) {
8567c478bd9Sstevel@tonic-gate 		return (rootopts[0] != 0 ? 0 : ENXIO);
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	if (bootparam_addr.len == 0) {
8607c478bd9Sstevel@tonic-gate 		return (ENXIO);
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 	arg.client_name = (caddr_t)&utsname.nodename;
8637c478bd9Sstevel@tonic-gate 	arg.file_id = fileid;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	bzero(&res, sizeof (res));
8667c478bd9Sstevel@tonic-gate 	res.server_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
8677c478bd9Sstevel@tonic-gate 	res.server_path = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	/*
8707c478bd9Sstevel@tonic-gate 	 * If we are not looking up the root file, we are looking
8717c478bd9Sstevel@tonic-gate 	 * up a non-critical option that should timeout quickly.
8727c478bd9Sstevel@tonic-gate 	 */
8737c478bd9Sstevel@tonic-gate 	if (!root) {
8747c478bd9Sstevel@tonic-gate 		timeo = GETFILE_TIMEO;
8757c478bd9Sstevel@tonic-gate 		retries = GETFILE_RETRIES;
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	/*
8797c478bd9Sstevel@tonic-gate 	 * bootparam_addr was filled in by the call to
8807c478bd9Sstevel@tonic-gate 	 * whoami(), so now send an rpc message to the
8817c478bd9Sstevel@tonic-gate 	 * bootparam daemon requesting our server information.
8827c478bd9Sstevel@tonic-gate 	 * Use UDP to talk to bootparms.
8837c478bd9Sstevel@tonic-gate 	 */
8847c478bd9Sstevel@tonic-gate 	stat = mycallrpc(&dl_udp_netconf, &bootparam_addr,
8857c478bd9Sstevel@tonic-gate 	    (rpcprog_t)BOOTPARAMPROG, (rpcvers_t)BOOTPARAMVERS,
8867c478bd9Sstevel@tonic-gate 	    (rpcproc_t)BOOTPARAMPROC_GETFILE,
8877c478bd9Sstevel@tonic-gate 	    xdr_bp_getfile_arg, (caddr_t)&arg,
8887c478bd9Sstevel@tonic-gate 	    xdr_bp_getfile_res, (caddr_t)&res,
8897c478bd9Sstevel@tonic-gate 	    timeo, retries);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	if (stat == RPC_SUCCESS) {
8927c478bd9Sstevel@tonic-gate 		(void) strcpy(server_name, res.server_name);
8937c478bd9Sstevel@tonic-gate 		(void) strcpy(server_path, res.server_path);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	kmem_free(res.server_name, MAX_MACHINE_NAME + 1);
8977c478bd9Sstevel@tonic-gate 	kmem_free(res.server_path, MAX_MACHINE_NAME + 1);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if (stat != RPC_SUCCESS) {
9007c478bd9Sstevel@tonic-gate 		if (root)
9017c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "getfile: RPC failed: error %d (%s).",
9027c478bd9Sstevel@tonic-gate 			    stat, clnt_sperrno(stat));
9037c478bd9Sstevel@tonic-gate 		return ((stat == RPC_TIMEDOUT) ? ETIMEDOUT : ENXIO); /* XXX */
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (*server_path == '\0')
9077c478bd9Sstevel@tonic-gate 		return (EINVAL);
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/*
9107c478bd9Sstevel@tonic-gate 	 * If the fileid is "root", we must get back a server name, for
9117c478bd9Sstevel@tonic-gate 	 * other parameters a server name is not required
9127c478bd9Sstevel@tonic-gate 	 */
9137c478bd9Sstevel@tonic-gate 	if (!root) {
9147c478bd9Sstevel@tonic-gate 		if (dldebug)
9157c478bd9Sstevel@tonic-gate 			printf("getfile: leaving: non-root\n");
9167c478bd9Sstevel@tonic-gate 		return (0);
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	if (*server_name == '\0')
9207c478bd9Sstevel@tonic-gate 		return (EINVAL);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	switch (res.server_address.address_type) {
9237c478bd9Sstevel@tonic-gate 	case IP_ADDR_TYPE:
9247c478bd9Sstevel@tonic-gate 		/*
9257c478bd9Sstevel@tonic-gate 		 * server_address is where we will get our root
9267c478bd9Sstevel@tonic-gate 		 * from.
9277c478bd9Sstevel@tonic-gate 		 */
9287c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)server_address->buf)->sin_family =
9297c478bd9Sstevel@tonic-gate 		    AF_INET;
9307c478bd9Sstevel@tonic-gate 		bcopy(&res.server_address.bp_address.ip_addr,
9317c478bd9Sstevel@tonic-gate 		    &ipaddr, sizeof (ipaddr));
932cc2b7f04Sdduvall 		if (ipaddr.s_addr == 0)
9337c478bd9Sstevel@tonic-gate 			return (EINVAL);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr =
936cc2b7f04Sdduvall 		    ipaddr.s_addr;
9377c478bd9Sstevel@tonic-gate 		server_address->len = sizeof (struct sockaddr_in);
9387c478bd9Sstevel@tonic-gate 		break;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	default:
9417c478bd9Sstevel@tonic-gate 		printf("getfile: unknown address type %d\n",
9427c478bd9Sstevel@tonic-gate 		    res.server_address.address_type);
9437c478bd9Sstevel@tonic-gate 		return (EPROTONOSUPPORT);
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 	if (dldebug)
9467c478bd9Sstevel@tonic-gate 		printf("getfile: leaving\n");
9477c478bd9Sstevel@tonic-gate 	return (0);
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate /*
951986fd29aSsetje  * If the boot property "bootp-response" exists, then OBP performed a
9527c478bd9Sstevel@tonic-gate  * successful DHCP lease acquisition for us and left the resultant ACK packet
9537c478bd9Sstevel@tonic-gate  * encoded at that location.
9547c478bd9Sstevel@tonic-gate  *
9557c478bd9Sstevel@tonic-gate  * If no such property exists (or the information is incomplete or garbled),
9567c478bd9Sstevel@tonic-gate  * the function returns -1.
9577c478bd9Sstevel@tonic-gate  */
9587c478bd9Sstevel@tonic-gate int
dhcpinit(void)9597c478bd9Sstevel@tonic-gate dhcpinit(void)
9607c478bd9Sstevel@tonic-gate {
9617c478bd9Sstevel@tonic-gate 	int rc, i;
9627c478bd9Sstevel@tonic-gate 	char *p;
9637c478bd9Sstevel@tonic-gate 	struct in_addr braddr;
9647c478bd9Sstevel@tonic-gate 	struct in_addr subnet;
9657c478bd9Sstevel@tonic-gate 	DHCP_OPT *doptp;
9667c478bd9Sstevel@tonic-gate 	TIUSER *tiptr;
9677c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
9687c478bd9Sstevel@tonic-gate 	static int once_only = 0;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	if (once_only == 1) {
9717c478bd9Sstevel@tonic-gate 		return (0);
9727c478bd9Sstevel@tonic-gate 	}
9737c478bd9Sstevel@tonic-gate 	once_only = 1;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	if (dhcack == NULL) {
9767c478bd9Sstevel@tonic-gate 		return (-1);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	if (dldebug) {
9807c478bd9Sstevel@tonic-gate 		printf("dhcp:  dhcack %p, len %d\n", (void *)dhcack,
981986fd29aSsetje 		    dhcacklen);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP);
985986fd29aSsetje 	pl->len = dhcacklen;
9867c478bd9Sstevel@tonic-gate 	pl->pkt = kmem_alloc(pl->len, KM_SLEEP);
987986fd29aSsetje 	bcopy(dhcack, pl->pkt, dhcacklen);
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	/*
990986fd29aSsetje 	 * For x86, ifname is not initialized
9917c478bd9Sstevel@tonic-gate 	 * in the netinstall case and dhcack interface name is
9927c478bd9Sstevel@tonic-gate 	 * set in strplumb(). So we only copy the name if ifname
9937c478bd9Sstevel@tonic-gate 	 * is set properly.
9947c478bd9Sstevel@tonic-gate 	 */
9957c478bd9Sstevel@tonic-gate 	if (ifname[0])
996986fd29aSsetje 		(void) strlcpy(dhcifname, ifname, sizeof (dhcifname));
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	/* remember the server_ip in dhcack */
9997c478bd9Sstevel@tonic-gate 	bcopy((uchar_t *)pl->pkt + 20, dhcp_server_ip, 4);
10007c478bd9Sstevel@tonic-gate 	bzero(pl->opts, (DHCP_LAST_OPT + 1) * sizeof (DHCP_OPT *));
10017c478bd9Sstevel@tonic-gate 	bzero(pl->vs, (VS_OPTION_END - VS_OPTION_START + 1) *
10027c478bd9Sstevel@tonic-gate 	    sizeof (DHCP_OPT *));
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	if (dhcp_options_scan(pl, B_TRUE) != 0) {
10057c478bd9Sstevel@tonic-gate 		/* garbled packet */
10067c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "dhcp: DHCP packet parsing failed");
10077c478bd9Sstevel@tonic-gate 		kmem_free(pl->pkt, pl->len);
10087c478bd9Sstevel@tonic-gate 		kmem_free(pl, sizeof (PKT_LIST));
10097c478bd9Sstevel@tonic-gate 		pl = NULL;
10107c478bd9Sstevel@tonic-gate 		return (-1);
10117c478bd9Sstevel@tonic-gate 	}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/* set node name */
10147c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_HOSTNAME] != NULL) {
10157c478bd9Sstevel@tonic-gate 		doptp = pl->opts[CD_HOSTNAME];
10167c478bd9Sstevel@tonic-gate 		i = doptp->len;
10177c478bd9Sstevel@tonic-gate 		if (i >= SYS_NMLN) {
10187c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "dhcp: Hostname is too long");
10197c478bd9Sstevel@tonic-gate 		} else {
10207c478bd9Sstevel@tonic-gate 			bcopy(doptp->value, utsname.nodename, i);
10217c478bd9Sstevel@tonic-gate 			utsname.nodename[i] = '\0';
10227c478bd9Sstevel@tonic-gate 			if (dldebug) {
10237c478bd9Sstevel@tonic-gate 				printf("hostname is %s\n",
10247c478bd9Sstevel@tonic-gate 				    utsname.nodename);
10257c478bd9Sstevel@tonic-gate 			}
10267c478bd9Sstevel@tonic-gate 		}
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/* Set NIS domain name. */
10307c478bd9Sstevel@tonic-gate 	p = NULL;
10317c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_NIS_DOMAIN] != NULL) {
10327c478bd9Sstevel@tonic-gate 		doptp = pl->opts[CD_NIS_DOMAIN];
10337c478bd9Sstevel@tonic-gate 		i = doptp->len;
10347c478bd9Sstevel@tonic-gate 		p = (caddr_t)doptp->value;
10357c478bd9Sstevel@tonic-gate 	}
10367c478bd9Sstevel@tonic-gate 	if (p != NULL) {
10377c478bd9Sstevel@tonic-gate 		if (i > SYS_NMLN) {
10387c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
10397c478bd9Sstevel@tonic-gate 			    "dhcp: NIS domainname too long.");
10407c478bd9Sstevel@tonic-gate 		} else {
10417c478bd9Sstevel@tonic-gate 			bcopy(p, srpc_domain, i);
10427c478bd9Sstevel@tonic-gate 			srpc_domain[i] = '\0';
10437c478bd9Sstevel@tonic-gate 			if (dldebug)
10447c478bd9Sstevel@tonic-gate 				printf("dhcp: NIS domain name is %s\n",
10457c478bd9Sstevel@tonic-gate 				    srpc_domain);
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	/* fetch netmask */
10507c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_SUBNETMASK] != NULL) {
10517c478bd9Sstevel@tonic-gate 		doptp = pl->opts[CD_SUBNETMASK];
10527c478bd9Sstevel@tonic-gate 		if (doptp->len != sizeof (struct in_addr)) {
10537c478bd9Sstevel@tonic-gate 			pl->opts[CD_SUBNETMASK] = NULL;
10547c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "dhcp: netmask option malformed");
10557c478bd9Sstevel@tonic-gate 		} else {
10567c478bd9Sstevel@tonic-gate 			bcopy(doptp->value, &subnet, sizeof (struct in_addr));
10577c478bd9Sstevel@tonic-gate 			if (dldebug)
10587c478bd9Sstevel@tonic-gate 				printf("dhcp:  setting netmask to: %s\n",
10597c478bd9Sstevel@tonic-gate 				    inet_ntoa(subnet));
10607c478bd9Sstevel@tonic-gate 		}
10617c478bd9Sstevel@tonic-gate 	} else {
10627c478bd9Sstevel@tonic-gate 		struct in_addr myIPaddr;
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 		myIPaddr.s_addr = pl->pkt->yiaddr.s_addr;
10657c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "dhcp:  no subnet mask supplied - inferring");
10667c478bd9Sstevel@tonic-gate 		if (IN_CLASSA(ntohl(myIPaddr.s_addr)))
10677c478bd9Sstevel@tonic-gate 			subnet.s_addr = htonl(IN_CLASSA_NET);
10687c478bd9Sstevel@tonic-gate 		else if (IN_CLASSB(ntohl(myIPaddr.s_addr)))
10697c478bd9Sstevel@tonic-gate 			subnet.s_addr = htonl(IN_CLASSB_NET);
10707c478bd9Sstevel@tonic-gate 		else if (IN_CLASSC(ntohl(myIPaddr.s_addr)))
10717c478bd9Sstevel@tonic-gate 			subnet.s_addr = htonl(IN_CLASSC_NET);
10722a9459bdSsangeeta 		else if (IN_CLASSD(ntohl(myIPaddr.s_addr)))
10737c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "dhcp:  bad IP address (%s)",
10747c478bd9Sstevel@tonic-gate 			    inet_ntoa(myIPaddr));
10752a9459bdSsangeeta 		else
10762a9459bdSsangeeta 			subnet.s_addr = htonl(IN_CLASSE_NET);
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 	/* and broadcast address */
10797c478bd9Sstevel@tonic-gate 	if (pl->opts[CD_BROADCASTADDR] != NULL) {
10807c478bd9Sstevel@tonic-gate 		doptp = pl->opts[CD_BROADCASTADDR];
10817c478bd9Sstevel@tonic-gate 		if (doptp->len != sizeof (struct in_addr)) {
10827c478bd9Sstevel@tonic-gate 			pl->opts[CD_BROADCASTADDR] = NULL;
10837c478bd9Sstevel@tonic-gate 			if (dldebug)
10847c478bd9Sstevel@tonic-gate 				printf("dhcp:  broadcast address len %d\n",
10857c478bd9Sstevel@tonic-gate 				    doptp->len);
10867c478bd9Sstevel@tonic-gate 		} else {
10877c478bd9Sstevel@tonic-gate 			bcopy(doptp->value, &braddr, sizeof (struct in_addr));
10887c478bd9Sstevel@tonic-gate 			if (dldebug)
10897c478bd9Sstevel@tonic-gate 				printf("dhcp:  setting broadcast addr to: %s\n",
10907c478bd9Sstevel@tonic-gate 				    inet_ntoa(braddr));
10917c478bd9Sstevel@tonic-gate 		}
10927c478bd9Sstevel@tonic-gate 	} else {
10937c478bd9Sstevel@tonic-gate 		if (dldebug)
10947c478bd9Sstevel@tonic-gate 			printf("dhcp:  no broadcast address supplied\n");
10957c478bd9Sstevel@tonic-gate 		braddr.s_addr = htonl(INADDR_BROADCAST);
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 	/* and plumb and initialize interface */
10987c478bd9Sstevel@tonic-gate 	if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
10997c478bd9Sstevel@tonic-gate 	    FREAD|FWRITE, &tiptr, CRED())) == 0) {
11007c478bd9Sstevel@tonic-gate 		if (rc = dlifconfig(tiptr, &pl->pkt->yiaddr, &subnet,
1101843e1988Sjohnlev 		    &braddr, IFF_DHCPRUNNING)) {
11027c478bd9Sstevel@tonic-gate 			nfs_perror(