xref: /freebsd/sys/nfs/nfs_diskless.c (revision 7c208ed6)
17c208ed6SRick Macklem /*-
27c208ed6SRick Macklem  * Copyright (c) 1990 The Regents of the University of California.
37c208ed6SRick Macklem  * All rights reserved.
47c208ed6SRick Macklem  *
57c208ed6SRick Macklem  * This code is derived from software contributed to Berkeley by
67c208ed6SRick Macklem  * William Jolitz.
77c208ed6SRick Macklem  *
87c208ed6SRick Macklem  * Redistribution and use in source and binary forms, with or without
97c208ed6SRick Macklem  * modification, are permitted provided that the following conditions
107c208ed6SRick Macklem  * are met:
117c208ed6SRick Macklem  * 1. Redistributions of source code must retain the above copyright
127c208ed6SRick Macklem  *    notice, this list of conditions and the following disclaimer.
137c208ed6SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
147c208ed6SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
157c208ed6SRick Macklem  *    documentation and/or other materials provided with the distribution.
167c208ed6SRick Macklem  * 4. Neither the name of the University nor the names of its contributors
177c208ed6SRick Macklem  *    may be used to endorse or promote products derived from this software
187c208ed6SRick Macklem  *    without specific prior written permission.
197c208ed6SRick Macklem  *
207c208ed6SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217c208ed6SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227c208ed6SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237c208ed6SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247c208ed6SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257c208ed6SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267c208ed6SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277c208ed6SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287c208ed6SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297c208ed6SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307c208ed6SRick Macklem  * SUCH DAMAGE.
317c208ed6SRick Macklem  *
327c208ed6SRick Macklem  *	from: @(#)autoconf.c	7.1 (Berkeley) 5/9/91
337c208ed6SRick Macklem  */
347c208ed6SRick Macklem 
357c208ed6SRick Macklem #include <sys/cdefs.h>
367c208ed6SRick Macklem __FBSDID("$FreeBSD$");
377c208ed6SRick Macklem 
387c208ed6SRick Macklem #include "opt_bootp.h"
397c208ed6SRick Macklem 
407c208ed6SRick Macklem #include <sys/param.h>
417c208ed6SRick Macklem #include <sys/systm.h>
427c208ed6SRick Macklem #include <sys/jail.h>
437c208ed6SRick Macklem #include <sys/kernel.h>
447c208ed6SRick Macklem #include <sys/malloc.h>
457c208ed6SRick Macklem #include <sys/mount.h>
467c208ed6SRick Macklem #include <sys/socket.h>
477c208ed6SRick Macklem 
487c208ed6SRick Macklem #include <net/if.h>
497c208ed6SRick Macklem #include <net/if_dl.h>
507c208ed6SRick Macklem #include <net/if_types.h>
517c208ed6SRick Macklem #include <net/if_var.h>
527c208ed6SRick Macklem #include <net/ethernet.h>
537c208ed6SRick Macklem #include <net/vnet.h>
547c208ed6SRick Macklem 
557c208ed6SRick Macklem #include <netinet/in.h>
567c208ed6SRick Macklem #include <nfs/nfsproto.h>
577c208ed6SRick Macklem #include <nfsclient/nfs.h>
587c208ed6SRick Macklem #include <nfs/nfsdiskless.h>
597c208ed6SRick Macklem 
607c208ed6SRick Macklem static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa);
617c208ed6SRick Macklem static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa);
627c208ed6SRick Macklem static int decode_nfshandle(char *ev, u_char *fh, int maxfh);
637c208ed6SRick Macklem 
647c208ed6SRick Macklem /*
657c208ed6SRick Macklem  * This structure must be filled in by a primary bootstrap or bootstrap
667c208ed6SRick Macklem  * server for a diskless/dataless machine. It is initialized below just
677c208ed6SRick Macklem  * to ensure that it is allocated to initialized data (.data not .bss).
687c208ed6SRick Macklem  */
697c208ed6SRick Macklem struct nfs_diskless	nfs_diskless = { { { 0 } } };
707c208ed6SRick Macklem struct nfsv3_diskless	nfsv3_diskless = { { { 0 } } };
717c208ed6SRick Macklem int			nfs_diskless_valid = 0;
727c208ed6SRick Macklem 
737c208ed6SRick Macklem /*
747c208ed6SRick Macklem  * Validate/sanity check a rsize/wsize parameter.
757c208ed6SRick Macklem  */
767c208ed6SRick Macklem static int
777c208ed6SRick Macklem checkrwsize(unsigned long v, const char *name)
787c208ed6SRick Macklem {
797c208ed6SRick Macklem 	/*
807c208ed6SRick Macklem 	 * 32K is used as an upper bound because most servers
817c208ed6SRick Macklem 	 * limit block size to satisfy IPv4's limit of
827c208ed6SRick Macklem 	 * 64K/reassembled packet.  The lower bound is pretty
837c208ed6SRick Macklem 	 * much arbitrary.
847c208ed6SRick Macklem 	 */
857c208ed6SRick Macklem 	if (!(4 <= v && v <= 32*1024)) {
867c208ed6SRick Macklem 		printf("nfs_parse_options: invalid %s %lu ignored\n", name, v);
877c208ed6SRick Macklem 		return 0;
887c208ed6SRick Macklem 	} else
897c208ed6SRick Macklem 		return 1;
907c208ed6SRick Macklem }
917c208ed6SRick Macklem 
927c208ed6SRick Macklem /*
937c208ed6SRick Macklem  * Parse mount options and apply them to the supplied
947c208ed6SRick Macklem  * nfs_diskless state.  Used also by bootp/dhcp support.
957c208ed6SRick Macklem  */
967c208ed6SRick Macklem void
977c208ed6SRick Macklem nfs_parse_options(const char *envopts, struct nfs_args *nd)
987c208ed6SRick Macklem {
997c208ed6SRick Macklem 	char *opts, *o, *otmp;
1007c208ed6SRick Macklem 	unsigned long v;
1017c208ed6SRick Macklem 
1027c208ed6SRick Macklem 	opts = strdup(envopts, M_TEMP);
1037c208ed6SRick Macklem 	otmp = opts;
1047c208ed6SRick Macklem 	while ((o = strsep(&otmp, ":;, ")) != NULL) {
1057c208ed6SRick Macklem 		if (*o == '\0')
1067c208ed6SRick Macklem 			; /* Skip empty options. */
1077c208ed6SRick Macklem 		else if (strcmp(o, "soft") == 0)
1087c208ed6SRick Macklem 			nd->flags |= NFSMNT_SOFT;
1097c208ed6SRick Macklem 		else if (strcmp(o, "intr") == 0)
1107c208ed6SRick Macklem 			nd->flags |= NFSMNT_INT;
1117c208ed6SRick Macklem 		else if (strcmp(o, "conn") == 0)
1127c208ed6SRick Macklem 			nd->flags |= NFSMNT_NOCONN;
1137c208ed6SRick Macklem 		else if (strcmp(o, "nolockd") == 0)
1147c208ed6SRick Macklem 			nd->flags |= NFSMNT_NOLOCKD;
1157c208ed6SRick Macklem 		else if (strcmp(o, "nfsv2") == 0)
1167c208ed6SRick Macklem 			nd->flags &= ~(NFSMNT_NFSV3 | NFSMNT_NFSV4);
1177c208ed6SRick Macklem 		else if (strcmp(o, "nfsv3") == 0) {
1187c208ed6SRick Macklem 			nd->flags &= ~NFSMNT_NFSV4;
1197c208ed6SRick Macklem 			nd->flags |= NFSMNT_NFSV3;
1207c208ed6SRick Macklem 		} else if (strcmp(o, "tcp") == 0)
1217c208ed6SRick Macklem 			nd->sotype = SOCK_STREAM;
1227c208ed6SRick Macklem 		else if (strcmp(o, "udp") == 0)
1237c208ed6SRick Macklem 			nd->sotype = SOCK_DGRAM;
1247c208ed6SRick Macklem 		else if (strncmp(o, "rsize=", 6) == 0) {
1257c208ed6SRick Macklem 			v = strtoul(o+6, NULL, 10);
1267c208ed6SRick Macklem 			if (checkrwsize(v, "rsize")) {
1277c208ed6SRick Macklem 				nd->rsize = (int) v;
1287c208ed6SRick Macklem 				nd->flags |= NFSMNT_RSIZE;
1297c208ed6SRick Macklem 			}
1307c208ed6SRick Macklem 		} else if (strncmp(o, "wsize=", 6) == 0) {
1317c208ed6SRick Macklem 			v = strtoul(o+6, NULL, 10);
1327c208ed6SRick Macklem 			if (checkrwsize(v, "wsize")) {
1337c208ed6SRick Macklem 				nd->wsize = (int) v;
1347c208ed6SRick Macklem 				nd->flags |= NFSMNT_WSIZE;
1357c208ed6SRick Macklem 			}
1367c208ed6SRick Macklem 		} else
1377c208ed6SRick Macklem 			printf("%s: skipping unknown option \"%s\"\n",
1387c208ed6SRick Macklem 			    __func__, o);
1397c208ed6SRick Macklem 	}
1407c208ed6SRick Macklem 	free(opts, M_TEMP);
1417c208ed6SRick Macklem }
1427c208ed6SRick Macklem 
1437c208ed6SRick Macklem /*
1447c208ed6SRick Macklem  * Populate the essential fields in the nfsv3_diskless structure.
1457c208ed6SRick Macklem  *
1467c208ed6SRick Macklem  * The loader is expected to export the following environment variables:
1477c208ed6SRick Macklem  *
1487c208ed6SRick Macklem  * boot.netif.name		name of boot interface
1497c208ed6SRick Macklem  * boot.netif.ip		IP address on boot interface
1507c208ed6SRick Macklem  * boot.netif.netmask		netmask on boot interface
1517c208ed6SRick Macklem  * boot.netif.gateway		default gateway (optional)
1527c208ed6SRick Macklem  * boot.netif.hwaddr		hardware address of boot interface
1537c208ed6SRick Macklem  * boot.nfsroot.server		IP address of root filesystem server
1547c208ed6SRick Macklem  * boot.nfsroot.path		path of the root filesystem on server
1557c208ed6SRick Macklem  * boot.nfsroot.nfshandle	NFS handle for root filesystem on server
1567c208ed6SRick Macklem  * boot.nfsroot.nfshandlelen	and length of this handle (for NFSv3 only)
1577c208ed6SRick Macklem  * boot.nfsroot.options		NFS options for the root filesystem
1587c208ed6SRick Macklem  */
1597c208ed6SRick Macklem void
1607c208ed6SRick Macklem nfs_setup_diskless(void)
1617c208ed6SRick Macklem {
1627c208ed6SRick Macklem 	struct nfs_diskless *nd = &nfs_diskless;
1637c208ed6SRick Macklem 	struct nfsv3_diskless *nd3 = &nfsv3_diskless;
1647c208ed6SRick Macklem 	struct ifnet *ifp;
1657c208ed6SRick Macklem 	struct ifaddr *ifa;
1667c208ed6SRick Macklem 	struct sockaddr_dl *sdl, ourdl;
1677c208ed6SRick Macklem 	struct sockaddr_in myaddr, netmask;
1687c208ed6SRick Macklem 	char *cp;
1697c208ed6SRick Macklem 	int cnt, fhlen, is_nfsv3;
1707c208ed6SRick Macklem 	uint32_t len;
1717c208ed6SRick Macklem 
1727c208ed6SRick Macklem 	if (nfs_diskless_valid != 0)
1737c208ed6SRick Macklem 		return;
1747c208ed6SRick Macklem 
1757c208ed6SRick Macklem 	/* get handle size. If this succeeds, it's an NFSv3 setup. */
1767c208ed6SRick Macklem 	if ((cp = getenv("boot.nfsroot.nfshandlelen")) != NULL) {
1777c208ed6SRick Macklem 		cnt = sscanf(cp, "%d", &len);
1787c208ed6SRick Macklem 		freeenv(cp);
1797c208ed6SRick Macklem 		if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) {
1807c208ed6SRick Macklem 			printf("nfs_diskless: bad NFS handle len\n");
1817c208ed6SRick Macklem 			return;
1827c208ed6SRick Macklem 		}
1837c208ed6SRick Macklem 		nd3->root_fhsize = len;
1847c208ed6SRick Macklem 		is_nfsv3 = 1;
1857c208ed6SRick Macklem 	} else
1867c208ed6SRick Macklem 		is_nfsv3 = 0;
1877c208ed6SRick Macklem 	/* set up interface */
1887c208ed6SRick Macklem 	if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
1897c208ed6SRick Macklem 		return;
1907c208ed6SRick Macklem 	if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
1917c208ed6SRick Macklem 		printf("nfs_diskless: no netmask\n");
1927c208ed6SRick Macklem 		return;
1937c208ed6SRick Macklem 	}
1947c208ed6SRick Macklem 	if (is_nfsv3 != 0) {
1957c208ed6SRick Macklem 		bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr));
1967c208ed6SRick Macklem 		bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr));
1977c208ed6SRick Macklem 		((struct sockaddr_in *)
1987c208ed6SRick Macklem 		   &nd3->myif.ifra_broadaddr)->sin_addr.s_addr =
1997c208ed6SRick Macklem 		    myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
2007c208ed6SRick Macklem 		bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask));
2017c208ed6SRick Macklem 	} else {
2027c208ed6SRick Macklem 		bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
2037c208ed6SRick Macklem 		bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
2047c208ed6SRick Macklem 		((struct sockaddr_in *)
2057c208ed6SRick Macklem 		   &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
2067c208ed6SRick Macklem 		    myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
2077c208ed6SRick Macklem 		bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
2087c208ed6SRick Macklem 	}
2097c208ed6SRick Macklem 
2107c208ed6SRick Macklem 	if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
2117c208ed6SRick Macklem 		printf("nfs_diskless: no hardware address\n");
2127c208ed6SRick Macklem 		return;
2137c208ed6SRick Macklem 	}
2147c208ed6SRick Macklem 	ifa = NULL;
2157c208ed6SRick Macklem 	CURVNET_SET(TD_TO_VNET(curthread));
2167c208ed6SRick Macklem 	IFNET_RLOCK();
2177c208ed6SRick Macklem 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2187c208ed6SRick Macklem 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2197c208ed6SRick Macklem 			if (ifa->ifa_addr->sa_family == AF_LINK) {
2207c208ed6SRick Macklem 				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
2217c208ed6SRick Macklem 				if ((sdl->sdl_type == ourdl.sdl_type) &&
2227c208ed6SRick Macklem 				    (sdl->sdl_alen == ourdl.sdl_alen) &&
2237c208ed6SRick Macklem 				    !bcmp(LLADDR(sdl),
2247c208ed6SRick Macklem 					  LLADDR(&ourdl),
2257c208ed6SRick Macklem 					  sdl->sdl_alen)) {
2267c208ed6SRick Macklem 				    IFNET_RUNLOCK();
2277c208ed6SRick Macklem 				    CURVNET_RESTORE();
2287c208ed6SRick Macklem 				    goto match_done;
2297c208ed6SRick Macklem 				}
2307c208ed6SRick Macklem 			}
2317c208ed6SRick Macklem 		}
2327c208ed6SRick Macklem 	}
2337c208ed6SRick Macklem 	IFNET_RUNLOCK();
2347c208ed6SRick Macklem 	CURVNET_RESTORE();
2357c208ed6SRick Macklem 	printf("nfs_diskless: no interface\n");
2367c208ed6SRick Macklem 	return;	/* no matching interface */
2377c208ed6SRick Macklem match_done:
2387c208ed6SRick Macklem 	setenv("boot.netif.name", ifp->if_xname);
2397c208ed6SRick Macklem 	if (is_nfsv3 != 0) {
2407c208ed6SRick Macklem 		strlcpy(nd3->myif.ifra_name, ifp->if_xname,
2417c208ed6SRick Macklem 		    sizeof(nd3->myif.ifra_name));
2427c208ed6SRick Macklem 
2437c208ed6SRick Macklem 		/* set up gateway */
2447c208ed6SRick Macklem 		inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway);
2457c208ed6SRick Macklem 
2467c208ed6SRick Macklem 		/* set up root mount */
2477c208ed6SRick Macklem 		nd3->root_args.rsize = 32768;		/* XXX tunable? */
2487c208ed6SRick Macklem 		nd3->root_args.wsize = 32768;
2497c208ed6SRick Macklem 		nd3->root_args.sotype = SOCK_STREAM;
2507c208ed6SRick Macklem 		nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE |
2517c208ed6SRick Macklem 		    NFSMNT_RSIZE | NFSMNT_RESVPORT);
2527c208ed6SRick Macklem 		if (inaddr_to_sockaddr("boot.nfsroot.server",
2537c208ed6SRick Macklem 		    &nd3->root_saddr)) {
2547c208ed6SRick Macklem 			printf("nfs_diskless: no server\n");
2557c208ed6SRick Macklem 			return;
2567c208ed6SRick Macklem 		}
2577c208ed6SRick Macklem 		nd3->root_saddr.sin_port = htons(NFS_PORT);
2587c208ed6SRick Macklem 		fhlen = decode_nfshandle("boot.nfsroot.nfshandle",
2597c208ed6SRick Macklem 		    &nd3->root_fh[0], NFSX_V3FHMAX);
2607c208ed6SRick Macklem 		if (fhlen == 0) {
2617c208ed6SRick Macklem 			printf("nfs_diskless: no NFS handle\n");
2627c208ed6SRick Macklem 			return;
2637c208ed6SRick Macklem 		}
2647c208ed6SRick Macklem 		if (fhlen != nd3->root_fhsize) {
2657c208ed6SRick Macklem 			printf("nfs_diskless: bad NFS handle len=%d\n", fhlen);
2667c208ed6SRick Macklem 			return;
2677c208ed6SRick Macklem 		}
2687c208ed6SRick Macklem 		if ((cp = getenv("boot.nfsroot.path")) != NULL) {
2697c208ed6SRick Macklem 			strncpy(nd3->root_hostnam, cp, MNAMELEN - 1);
2707c208ed6SRick Macklem 			freeenv(cp);
2717c208ed6SRick Macklem 		}
2727c208ed6SRick Macklem 		if ((cp = getenv("boot.nfsroot.options")) != NULL) {
2737c208ed6SRick Macklem 			nfs_parse_options(cp, &nd3->root_args);
2747c208ed6SRick Macklem 			freeenv(cp);
2757c208ed6SRick Macklem 		}
2767c208ed6SRick Macklem 
2777c208ed6SRick Macklem 		nfs_diskless_valid = 3;
2787c208ed6SRick Macklem 	} else {
2797c208ed6SRick Macklem 		strlcpy(nd->myif.ifra_name, ifp->if_xname,
2807c208ed6SRick Macklem 		    sizeof(nd->myif.ifra_name));
2817c208ed6SRick Macklem 
2827c208ed6SRick Macklem 		/* set up gateway */
2837c208ed6SRick Macklem 		inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
2847c208ed6SRick Macklem 
2857c208ed6SRick Macklem 		/* set up root mount */
2867c208ed6SRick Macklem 		nd->root_args.rsize = 8192;		/* XXX tunable? */
2877c208ed6SRick Macklem 		nd->root_args.wsize = 8192;
2887c208ed6SRick Macklem 		nd->root_args.sotype = SOCK_STREAM;
2897c208ed6SRick Macklem 		nd->root_args.flags = (NFSMNT_WSIZE |
2907c208ed6SRick Macklem 		    NFSMNT_RSIZE | NFSMNT_RESVPORT);
2917c208ed6SRick Macklem 		if (inaddr_to_sockaddr("boot.nfsroot.server",
2927c208ed6SRick Macklem 		    &nd->root_saddr)) {
2937c208ed6SRick Macklem 			printf("nfs_diskless: no server\n");
2947c208ed6SRick Macklem 			return;
2957c208ed6SRick Macklem 		}
2967c208ed6SRick Macklem 		nd->root_saddr.sin_port = htons(NFS_PORT);
2977c208ed6SRick Macklem 		if (decode_nfshandle("boot.nfsroot.nfshandle",
2987c208ed6SRick Macklem 		    &nd->root_fh[0], NFSX_V2FH) == 0) {
2997c208ed6SRick Macklem 			printf("nfs_diskless: no NFS handle\n");
3007c208ed6SRick Macklem 			return;
3017c208ed6SRick Macklem 		}
3027c208ed6SRick Macklem 		if ((cp = getenv("boot.nfsroot.path")) != NULL) {
3037c208ed6SRick Macklem 			strncpy(nd->root_hostnam, cp, MNAMELEN - 1);
3047c208ed6SRick Macklem 			freeenv(cp);
3057c208ed6SRick Macklem 		}
3067c208ed6SRick Macklem 		if ((cp = getenv("boot.nfsroot.options")) != NULL) {
3077c208ed6SRick Macklem 			struct nfs_args args;
3087c208ed6SRick Macklem 
3097c208ed6SRick Macklem 			/*
3107c208ed6SRick Macklem 			 * XXX yech, convert between old and current
3117c208ed6SRick Macklem 			 * arg format
3127c208ed6SRick Macklem 			 */
3137c208ed6SRick Macklem 			args.flags = nd->root_args.flags;
3147c208ed6SRick Macklem 			args.sotype = nd->root_args.sotype;
3157c208ed6SRick Macklem 			args.rsize = nd->root_args.rsize;
3167c208ed6SRick Macklem 			args.wsize = nd->root_args.wsize;
3177c208ed6SRick Macklem 			nfs_parse_options(cp, &args);
3187c208ed6SRick Macklem 			nd->root_args.flags = args.flags;
3197c208ed6SRick Macklem 			nd->root_args.sotype = args.sotype;
3207c208ed6SRick Macklem 			nd->root_args.rsize = args.rsize;
3217c208ed6SRick Macklem 			nd->root_args.wsize = args.wsize;
3227c208ed6SRick Macklem 			freeenv(cp);
3237c208ed6SRick Macklem 		}
3247c208ed6SRick Macklem 
3257c208ed6SRick Macklem 		nfs_diskless_valid = 1;
3267c208ed6SRick Macklem 	}
3277c208ed6SRick Macklem }
3287c208ed6SRick Macklem 
3297c208ed6SRick Macklem static int
3307c208ed6SRick Macklem inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa)
3317c208ed6SRick Macklem {
3327c208ed6SRick Macklem 	u_int32_t a[4];
3337c208ed6SRick Macklem 	char *cp;
3347c208ed6SRick Macklem 	int count;
3357c208ed6SRick Macklem 
3367c208ed6SRick Macklem 	bzero(sa, sizeof(*sa));
3377c208ed6SRick Macklem 	sa->sin_len = sizeof(*sa);
3387c208ed6SRick Macklem 	sa->sin_family = AF_INET;
3397c208ed6SRick Macklem 
3407c208ed6SRick Macklem 	if ((cp = getenv(ev)) == NULL)
3417c208ed6SRick Macklem 		return (1);
3427c208ed6SRick Macklem 	count = sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
3437c208ed6SRick Macklem 	freeenv(cp);
3447c208ed6SRick Macklem 	if (count != 4)
3457c208ed6SRick Macklem 		return (1);
3467c208ed6SRick Macklem 	sa->sin_addr.s_addr =
3477c208ed6SRick Macklem 	    htonl((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
3487c208ed6SRick Macklem 	return (0);
3497c208ed6SRick Macklem }
3507c208ed6SRick Macklem 
3517c208ed6SRick Macklem static int
3527c208ed6SRick Macklem hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
3537c208ed6SRick Macklem {
3547c208ed6SRick Macklem 	char *cp;
3557c208ed6SRick Macklem 	u_int32_t a[6];
3567c208ed6SRick Macklem 	int count;
3577c208ed6SRick Macklem 
3587c208ed6SRick Macklem 	bzero(sa, sizeof(*sa));
3597c208ed6SRick Macklem 	sa->sdl_len = sizeof(*sa);
3607c208ed6SRick Macklem 	sa->sdl_family = AF_LINK;
3617c208ed6SRick Macklem 	sa->sdl_type = IFT_ETHER;
3627c208ed6SRick Macklem 	sa->sdl_alen = ETHER_ADDR_LEN;
3637c208ed6SRick Macklem 	if ((cp = getenv(ev)) == NULL)
3647c208ed6SRick Macklem 		return (1);
3657c208ed6SRick Macklem 	count = sscanf(cp, "%x:%x:%x:%x:%x:%x",
3667c208ed6SRick Macklem 	    &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);
3677c208ed6SRick Macklem 	freeenv(cp);
3687c208ed6SRick Macklem 	if (count != 6)
3697c208ed6SRick Macklem 		return (1);
3707c208ed6SRick Macklem 	sa->sdl_data[0] = a[0];
3717c208ed6SRick Macklem 	sa->sdl_data[1] = a[1];
3727c208ed6SRick Macklem 	sa->sdl_data[2] = a[2];
3737c208ed6SRick Macklem 	sa->sdl_data[3] = a[3];
3747c208ed6SRick Macklem 	sa->sdl_data[4] = a[4];
3757c208ed6SRick Macklem 	sa->sdl_data[5] = a[5];
3767c208ed6SRick Macklem 	return (0);
3777c208ed6SRick Macklem }
3787c208ed6SRick Macklem 
3797c208ed6SRick Macklem static int
3807c208ed6SRick Macklem decode_nfshandle(char *ev, u_char *fh, int maxfh)
3817c208ed6SRick Macklem {
3827c208ed6SRick Macklem 	u_char *cp, *ep;
3837c208ed6SRick Macklem 	int len, val;
3847c208ed6SRick Macklem 
3857c208ed6SRick Macklem 	ep = cp = getenv(ev);
3867c208ed6SRick Macklem 	if (cp == NULL)
3877c208ed6SRick Macklem 		return (0);
3887c208ed6SRick Macklem 	if ((strlen(cp) < 2) || (*cp != 'X')) {
3897c208ed6SRick Macklem 		freeenv(ep);
3907c208ed6SRick Macklem 		return (0);
3917c208ed6SRick Macklem 	}
3927c208ed6SRick Macklem 	len = 0;
3937c208ed6SRick Macklem 	cp++;
3947c208ed6SRick Macklem 	for (;;) {
3957c208ed6SRick Macklem 		if (*cp == 'X') {
3967c208ed6SRick Macklem 			freeenv(ep);
3977c208ed6SRick Macklem 			return (len);
3987c208ed6SRick Macklem 		}
3997c208ed6SRick Macklem 		if ((sscanf(cp, "%2x", &val) != 1) || (val > 0xff)) {
4007c208ed6SRick Macklem 			freeenv(ep);
4017c208ed6SRick Macklem 			return (0);
4027c208ed6SRick Macklem 		}
4037c208ed6SRick Macklem 		*(fh++) = val;
4047c208ed6SRick Macklem 		len++;
4057c208ed6SRick Macklem 		cp += 2;
4067c208ed6SRick Macklem 		if (len > maxfh) {
4077c208ed6SRick Macklem 		    freeenv(ep);
4087c208ed6SRick Macklem 		    return (0);
4097c208ed6SRick Macklem 		}
4107c208ed6SRick Macklem 	}
4117c208ed6SRick Macklem }
4127c208ed6SRick Macklem 
4137c208ed6SRick Macklem #if !defined(BOOTP_NFSROOT)
4147c208ed6SRick Macklem static void
4157c208ed6SRick Macklem nfs_rootconf(void)
4167c208ed6SRick Macklem {
4177c208ed6SRick Macklem 
4187c208ed6SRick Macklem 	nfs_setup_diskless();
4197c208ed6SRick Macklem 	if (nfs_diskless_valid)
4207c208ed6SRick Macklem 		rootdevnames[0] = "nfs:";
4217c208ed6SRick Macklem }
4227c208ed6SRick Macklem 
4237c208ed6SRick Macklem SYSINIT(cpu_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, nfs_rootconf, NULL);
4247c208ed6SRick Macklem #endif
4257c208ed6SRick Macklem 
426