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