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