xref: /freebsd/sys/nfs/nfs_diskless.c (revision 29363fb4)
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 
357c208ed6SRick Macklem #include <sys/cdefs.h>
367c208ed6SRick Macklem #include "opt_bootp.h"
377c208ed6SRick Macklem 
387c208ed6SRick Macklem #include <sys/param.h>
397c208ed6SRick Macklem #include <sys/systm.h>
407c208ed6SRick Macklem #include <sys/jail.h>
417c208ed6SRick Macklem #include <sys/kernel.h>
427c208ed6SRick Macklem #include <sys/malloc.h>
437c208ed6SRick Macklem #include <sys/mount.h>
447c208ed6SRick Macklem #include <sys/socket.h>
457c208ed6SRick Macklem 
467c208ed6SRick Macklem #include <net/if.h>
477c208ed6SRick Macklem #include <net/if_dl.h>
487c208ed6SRick Macklem #include <net/if_types.h>
497c208ed6SRick Macklem #include <net/if_var.h>
507c208ed6SRick Macklem #include <net/ethernet.h>
517c208ed6SRick Macklem #include <net/vnet.h>
527c208ed6SRick Macklem 
537c208ed6SRick Macklem #include <netinet/in.h>
547c208ed6SRick Macklem #include <nfs/nfsproto.h>
557c208ed6SRick Macklem #include <nfsclient/nfs.h>
567c208ed6SRick Macklem #include <nfs/nfsdiskless.h>
577c208ed6SRick Macklem 
58e488229bSIan Lepore #define	NFS_IFACE_TIMEOUT_SECS	10 /* Timeout for interface to appear. */
59e488229bSIan Lepore 
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
checkrwsize(unsigned long v,const char * name)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
nfs_parse_options(const char * envopts,struct nfs_args * nd)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;
115e2f2b370SRuslan Ermilov 		else if (strcmp(o, "nocto") == 0)
116e2f2b370SRuslan Ermilov 			nd->flags |= NFSMNT_NOCTO;
1177c208ed6SRick Macklem 		else if (strcmp(o, "nfsv2") == 0)
1187c208ed6SRick Macklem 			nd->flags &= ~(NFSMNT_NFSV3 | NFSMNT_NFSV4);
1197c208ed6SRick Macklem 		else if (strcmp(o, "nfsv3") == 0) {
1207c208ed6SRick Macklem 			nd->flags &= ~NFSMNT_NFSV4;
1217c208ed6SRick Macklem 			nd->flags |= NFSMNT_NFSV3;
1227c208ed6SRick Macklem 		} else if (strcmp(o, "tcp") == 0)
1237c208ed6SRick Macklem 			nd->sotype = SOCK_STREAM;
1247c208ed6SRick Macklem 		else if (strcmp(o, "udp") == 0)
1257c208ed6SRick Macklem 			nd->sotype = SOCK_DGRAM;
1267c208ed6SRick Macklem 		else if (strncmp(o, "rsize=", 6) == 0) {
1277c208ed6SRick Macklem 			v = strtoul(o+6, NULL, 10);
1287c208ed6SRick Macklem 			if (checkrwsize(v, "rsize")) {
1297c208ed6SRick Macklem 				nd->rsize = (int) v;
1307c208ed6SRick Macklem 				nd->flags |= NFSMNT_RSIZE;
1317c208ed6SRick Macklem 			}
1327c208ed6SRick Macklem 		} else if (strncmp(o, "wsize=", 6) == 0) {
1337c208ed6SRick Macklem 			v = strtoul(o+6, NULL, 10);
1347c208ed6SRick Macklem 			if (checkrwsize(v, "wsize")) {
1357c208ed6SRick Macklem 				nd->wsize = (int) v;
1367c208ed6SRick Macklem 				nd->flags |= NFSMNT_WSIZE;
1377c208ed6SRick Macklem 			}
1387c208ed6SRick Macklem 		} else
1397c208ed6SRick Macklem 			printf("%s: skipping unknown option \"%s\"\n",
1407c208ed6SRick Macklem 			    __func__, o);
1417c208ed6SRick Macklem 	}
1427c208ed6SRick Macklem 	free(opts, M_TEMP);
1437c208ed6SRick Macklem }
1447c208ed6SRick Macklem 
1450785c323SJustin Hibbits static u_int
nfs_setup_diskless_ifa_cb(void * arg,struct sockaddr_dl * sdl,u_int count)1460785c323SJustin Hibbits nfs_setup_diskless_ifa_cb(void *arg, struct sockaddr_dl *sdl, u_int count)
1470785c323SJustin Hibbits {
1480785c323SJustin Hibbits 	struct sockaddr_dl *ourdl = arg;
1490785c323SJustin Hibbits 
1500785c323SJustin Hibbits 	if ((sdl->sdl_type == ourdl->sdl_type) &&
1510785c323SJustin Hibbits 	    (sdl->sdl_alen == ourdl->sdl_alen) &&
1520785c323SJustin Hibbits 	    !bcmp(LLADDR(sdl), LLADDR(ourdl), sdl->sdl_alen))
1530785c323SJustin Hibbits 		return (1);
1540785c323SJustin Hibbits 
1550785c323SJustin Hibbits 	return (0);
1560785c323SJustin Hibbits }
1570785c323SJustin Hibbits 
1587c208ed6SRick Macklem /*
1597c208ed6SRick Macklem  * Populate the essential fields in the nfsv3_diskless structure.
1607c208ed6SRick Macklem  *
1617c208ed6SRick Macklem  * The loader is expected to export the following environment variables:
1627c208ed6SRick Macklem  *
1637c208ed6SRick Macklem  * boot.netif.name		name of boot interface
1647c208ed6SRick Macklem  * boot.netif.ip		IP address on boot interface
1657c208ed6SRick Macklem  * boot.netif.netmask		netmask on boot interface
1667c208ed6SRick Macklem  * boot.netif.gateway		default gateway (optional)
1677c208ed6SRick Macklem  * boot.netif.hwaddr		hardware address of boot interface
168b50d46dfSIan Lepore  * boot.netif.mtu		interface mtu from bootp/dhcp (optional)
1697c208ed6SRick Macklem  * boot.nfsroot.server		IP address of root filesystem server
1707c208ed6SRick Macklem  * boot.nfsroot.path		path of the root filesystem on server
1717c208ed6SRick Macklem  * boot.nfsroot.nfshandle	NFS handle for root filesystem on server
1727c208ed6SRick Macklem  * boot.nfsroot.nfshandlelen	and length of this handle (for NFSv3 only)
1737c208ed6SRick Macklem  * boot.nfsroot.options		NFS options for the root filesystem
1747c208ed6SRick Macklem  */
1757c208ed6SRick Macklem void
nfs_setup_diskless(void)1767c208ed6SRick Macklem nfs_setup_diskless(void)
1777c208ed6SRick Macklem {
1780785c323SJustin Hibbits 	struct epoch_tracker et;
1790785c323SJustin Hibbits 	struct if_iter iter;
1807c208ed6SRick Macklem 	struct nfs_diskless *nd = &nfs_diskless;
1817c208ed6SRick Macklem 	struct nfsv3_diskless *nd3 = &nfsv3_diskless;
1820785c323SJustin Hibbits 	if_t ifp;
1830785c323SJustin Hibbits 	struct sockaddr_dl ourdl;
1847c208ed6SRick Macklem 	struct sockaddr_in myaddr, netmask;
1857c208ed6SRick Macklem 	char *cp;
1867c208ed6SRick Macklem 	int cnt, fhlen, is_nfsv3;
1877c208ed6SRick Macklem 	uint32_t len;
188e488229bSIan Lepore 	time_t timeout_at;
1897c208ed6SRick Macklem 
1907c208ed6SRick Macklem 	if (nfs_diskless_valid != 0)
1917c208ed6SRick Macklem 		return;
1927c208ed6SRick Macklem 
1937c208ed6SRick Macklem 	/* get handle size. If this succeeds, it's an NFSv3 setup. */
1942be111bfSDavide Italiano 	if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) {
1957c208ed6SRick Macklem 		cnt = sscanf(cp, "%d", &len);
1967c208ed6SRick Macklem 		freeenv(cp);
1977c208ed6SRick Macklem 		if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) {
1987c208ed6SRick Macklem 			printf("nfs_diskless: bad NFS handle len\n");
1997c208ed6SRick Macklem 			return;
2007c208ed6SRick Macklem 		}
2017c208ed6SRick Macklem 		nd3->root_fhsize = len;
2027c208ed6SRick Macklem 		is_nfsv3 = 1;
2037c208ed6SRick Macklem 	} else
2047c208ed6SRick Macklem 		is_nfsv3 = 0;
2057c208ed6SRick Macklem 	/* set up interface */
2067c208ed6SRick Macklem 	if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
2077c208ed6SRick Macklem 		return;
2087c208ed6SRick Macklem 	if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
2097c208ed6SRick Macklem 		printf("nfs_diskless: no netmask\n");
2107c208ed6SRick Macklem 		return;
2117c208ed6SRick Macklem 	}
2127c208ed6SRick Macklem 	if (is_nfsv3 != 0) {
2137c208ed6SRick Macklem 		bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr));
2147c208ed6SRick Macklem 		bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr));
2157c208ed6SRick Macklem 		((struct sockaddr_in *)
2167c208ed6SRick Macklem 		   &nd3->myif.ifra_broadaddr)->sin_addr.s_addr =
2177c208ed6SRick Macklem 		    myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
2187c208ed6SRick Macklem 		bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask));
2197c208ed6SRick Macklem 	} else {
2207c208ed6SRick Macklem 		bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
2217c208ed6SRick Macklem 		bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
2227c208ed6SRick Macklem 		((struct sockaddr_in *)
2237c208ed6SRick Macklem 		   &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
2247c208ed6SRick Macklem 		    myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
2257c208ed6SRick Macklem 		bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
2267c208ed6SRick Macklem 	}
2277c208ed6SRick Macklem 
2287c208ed6SRick Macklem 	if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
2297c208ed6SRick Macklem 		printf("nfs_diskless: no hardware address\n");
2307c208ed6SRick Macklem 		return;
2317c208ed6SRick Macklem 	}
232e488229bSIan Lepore 	timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS;
233e488229bSIan Lepore retry:
2347c208ed6SRick Macklem 	CURVNET_SET(TD_TO_VNET(curthread));
2350785c323SJustin Hibbits 	NET_EPOCH_ENTER(et);
2360785c323SJustin Hibbits 	for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) {
23730ff1255SAlexander Motin 		cnt = if_foreach_lladdr(ifp, nfs_setup_diskless_ifa_cb, &ourdl);
23830ff1255SAlexander Motin 		if (cnt > 0)
2390785c323SJustin Hibbits 			break;
2400785c323SJustin Hibbits 	}
2410785c323SJustin Hibbits 	if_iter_finish(&iter);
2420785c323SJustin Hibbits 	NET_EPOCH_EXIT(et);
2437c208ed6SRick Macklem 	CURVNET_RESTORE();
24430ff1255SAlexander Motin 	if (ifp != NULL)
2457c208ed6SRick Macklem 		goto match_done;
2460785c323SJustin Hibbits 
247e488229bSIan Lepore 	if (time_uptime < timeout_at) {
248e488229bSIan Lepore 		pause("nfssdl", hz / 5);
249e488229bSIan Lepore 		goto retry;
250e488229bSIan Lepore 	}
2517c208ed6SRick Macklem 	printf("nfs_diskless: no interface\n");
2527c208ed6SRick Macklem 	return;	/* no matching interface */
2537c208ed6SRick Macklem match_done:
2540785c323SJustin Hibbits 	kern_setenv("boot.netif.name", if_name(ifp));
2557c208ed6SRick Macklem 	if (is_nfsv3 != 0) {
2560785c323SJustin Hibbits 		strlcpy(nd3->myif.ifra_name, if_name(ifp),
2577c208ed6SRick Macklem 		    sizeof(nd3->myif.ifra_name));
2587c208ed6SRick Macklem 
2597c208ed6SRick Macklem 		/* set up gateway */
2607c208ed6SRick Macklem 		inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway);
2617c208ed6SRick Macklem 
2627c208ed6SRick Macklem 		/* set up root mount */
2637c208ed6SRick Macklem 		nd3->root_args.rsize = 32768;		/* XXX tunable? */
2647c208ed6SRick Macklem 		nd3->root_args.wsize = 32768;
2657c208ed6SRick Macklem 		nd3->root_args.sotype = SOCK_STREAM;
2667c208ed6SRick Macklem 		nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE |
2677c208ed6SRick Macklem 		    NFSMNT_RSIZE | NFSMNT_RESVPORT);
2687c208ed6SRick Macklem 		if (inaddr_to_sockaddr("boot.nfsroot.server",
2697c208ed6SRick Macklem 		    &nd3->root_saddr)) {
2707c208ed6SRick Macklem 			printf("nfs_diskless: no server\n");
2717c208ed6SRick Macklem 			return;
2727c208ed6SRick Macklem 		}
2737c208ed6SRick Macklem 		nd3->root_saddr.sin_port = htons(NFS_PORT);
2747c208ed6SRick Macklem 		fhlen = decode_nfshandle("boot.nfsroot.nfshandle",
2757c208ed6SRick Macklem 		    &nd3->root_fh[0], NFSX_V3FHMAX);
2767c208ed6SRick Macklem 		if (fhlen == 0) {
2777c208ed6SRick Macklem 			printf("nfs_diskless: no NFS handle\n");
2787c208ed6SRick Macklem 			return;
2797c208ed6SRick Macklem 		}
2807c208ed6SRick Macklem 		if (fhlen != nd3->root_fhsize) {
2817c208ed6SRick Macklem 			printf("nfs_diskless: bad NFS handle len=%d\n", fhlen);
2827c208ed6SRick Macklem 			return;
2837c208ed6SRick Macklem 		}
2842be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
2857c208ed6SRick Macklem 			strncpy(nd3->root_hostnam, cp, MNAMELEN - 1);
2867c208ed6SRick Macklem 			freeenv(cp);
2877c208ed6SRick Macklem 		}
2882be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) {
2897c208ed6SRick Macklem 			nfs_parse_options(cp, &nd3->root_args);
2907c208ed6SRick Macklem 			freeenv(cp);
2917c208ed6SRick Macklem 		}
2927c208ed6SRick Macklem 
2937c208ed6SRick Macklem 		nfs_diskless_valid = 3;
2947c208ed6SRick Macklem 	} else {
2950785c323SJustin Hibbits 		strlcpy(nd->myif.ifra_name, if_name(ifp),
2967c208ed6SRick Macklem 		    sizeof(nd->myif.ifra_name));
2977c208ed6SRick Macklem 
2987c208ed6SRick Macklem 		/* set up gateway */
2997c208ed6SRick Macklem 		inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
3007c208ed6SRick Macklem 
3017c208ed6SRick Macklem 		/* set up root mount */
3027c208ed6SRick Macklem 		nd->root_args.rsize = 8192;		/* XXX tunable? */
3037c208ed6SRick Macklem 		nd->root_args.wsize = 8192;
3047c208ed6SRick Macklem 		nd->root_args.sotype = SOCK_STREAM;
3057c208ed6SRick Macklem 		nd->root_args.flags = (NFSMNT_WSIZE |
3067c208ed6SRick Macklem 		    NFSMNT_RSIZE | NFSMNT_RESVPORT);
3077c208ed6SRick Macklem 		if (inaddr_to_sockaddr("boot.nfsroot.server",
3087c208ed6SRick Macklem 		    &nd->root_saddr)) {
3097c208ed6SRick Macklem 			printf("nfs_diskless: no server\n");
3107c208ed6SRick Macklem 			return;
3117c208ed6SRick Macklem 		}
3127c208ed6SRick Macklem 		nd->root_saddr.sin_port = htons(NFS_PORT);
3137c208ed6SRick Macklem 		if (decode_nfshandle("boot.nfsroot.nfshandle",
3147c208ed6SRick Macklem 		    &nd->root_fh[0], NFSX_V2FH) == 0) {
3157c208ed6SRick Macklem 			printf("nfs_diskless: no NFS handle\n");
3167c208ed6SRick Macklem 			return;
3177c208ed6SRick Macklem 		}
3182be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
3197c208ed6SRick Macklem 			strncpy(nd->root_hostnam, cp, MNAMELEN - 1);
3207c208ed6SRick Macklem 			freeenv(cp);
3217c208ed6SRick Macklem 		}
3222be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) {
3237c208ed6SRick Macklem 			struct nfs_args args;
3247c208ed6SRick Macklem 
3257c208ed6SRick Macklem 			/*
3267c208ed6SRick Macklem 			 * XXX yech, convert between old and current
3277c208ed6SRick Macklem 			 * arg format
3287c208ed6SRick Macklem 			 */
3297c208ed6SRick Macklem 			args.flags = nd->root_args.flags;
3307c208ed6SRick Macklem 			args.sotype = nd->root_args.sotype;
3317c208ed6SRick Macklem 			args.rsize = nd->root_args.rsize;
3327c208ed6SRick Macklem 			args.wsize = nd->root_args.wsize;
3337c208ed6SRick Macklem 			nfs_parse_options(cp, &args);
3347c208ed6SRick Macklem 			nd->root_args.flags = args.flags;
3357c208ed6SRick Macklem 			nd->root_args.sotype = args.sotype;
3367c208ed6SRick Macklem 			nd->root_args.rsize = args.rsize;
3377c208ed6SRick Macklem 			nd->root_args.wsize = args.wsize;
3387c208ed6SRick Macklem 			freeenv(cp);
3397c208ed6SRick Macklem 		}
3407c208ed6SRick Macklem 
3417c208ed6SRick Macklem 		nfs_diskless_valid = 1;
3427c208ed6SRick Macklem 	}
3437c208ed6SRick Macklem }
3447c208ed6SRick Macklem 
3457c208ed6SRick Macklem static int
inaddr_to_sockaddr(char * ev,struct sockaddr_in * sa)3467c208ed6SRick Macklem inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa)
3477c208ed6SRick Macklem {
3487c208ed6SRick Macklem 	u_int32_t a[4];
3497c208ed6SRick Macklem 	char *cp;
3507c208ed6SRick Macklem 	int count;
3517c208ed6SRick Macklem 
3527c208ed6SRick Macklem 	bzero(sa, sizeof(*sa));
3537c208ed6SRick Macklem 	sa->sin_len = sizeof(*sa);
3547c208ed6SRick Macklem 	sa->sin_family = AF_INET;
3557c208ed6SRick Macklem 
3562be111bfSDavide Italiano 	if ((cp = kern_getenv(ev)) == NULL)
3577c208ed6SRick Macklem 		return (1);
3587c208ed6SRick Macklem 	count = sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
3597c208ed6SRick Macklem 	freeenv(cp);
3607c208ed6SRick Macklem 	if (count != 4)
3617c208ed6SRick Macklem 		return (1);
3627c208ed6SRick Macklem 	sa->sin_addr.s_addr =
3637c208ed6SRick Macklem 	    htonl((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
3647c208ed6SRick Macklem 	return (0);
3657c208ed6SRick Macklem }
3667c208ed6SRick Macklem 
3677c208ed6SRick Macklem static int
hwaddr_to_sockaddr(char * ev,struct sockaddr_dl * sa)3687c208ed6SRick Macklem hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
3697c208ed6SRick Macklem {
3707c208ed6SRick Macklem 	char *cp;
3717c208ed6SRick Macklem 	u_int32_t a[6];
3727c208ed6SRick Macklem 	int count;
3737c208ed6SRick Macklem 
3747c208ed6SRick Macklem 	bzero(sa, sizeof(*sa));
3757c208ed6SRick Macklem 	sa->sdl_len = sizeof(*sa);
3767c208ed6SRick Macklem 	sa->sdl_family = AF_LINK;
3777c208ed6SRick Macklem 	sa->sdl_type = IFT_ETHER;
3787c208ed6SRick Macklem 	sa->sdl_alen = ETHER_ADDR_LEN;
3792be111bfSDavide Italiano 	if ((cp = kern_getenv(ev)) == NULL)
3807c208ed6SRick Macklem 		return (1);
3817c208ed6SRick Macklem 	count = sscanf(cp, "%x:%x:%x:%x:%x:%x",
3827c208ed6SRick Macklem 	    &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);
3837c208ed6SRick Macklem 	freeenv(cp);
3847c208ed6SRick Macklem 	if (count != 6)
3857c208ed6SRick Macklem 		return (1);
3867c208ed6SRick Macklem 	sa->sdl_data[0] = a[0];
3877c208ed6SRick Macklem 	sa->sdl_data[1] = a[1];
3887c208ed6SRick Macklem 	sa->sdl_data[2] = a[2];
3897c208ed6SRick Macklem 	sa->sdl_data[3] = a[3];
3907c208ed6SRick Macklem 	sa->sdl_data[4] = a[4];
3917c208ed6SRick Macklem 	sa->sdl_data[5] = a[5];
3927c208ed6SRick Macklem 	return (0);
3937c208ed6SRick Macklem }
3947c208ed6SRick Macklem 
3957c208ed6SRick Macklem static int
decode_nfshandle(char * ev,u_char * fh,int maxfh)3967c208ed6SRick Macklem decode_nfshandle(char *ev, u_char *fh, int maxfh)
3977c208ed6SRick Macklem {
3987c208ed6SRick Macklem 	u_char *cp, *ep;
3997c208ed6SRick Macklem 	int len, val;
4007c208ed6SRick Macklem 
4012be111bfSDavide Italiano 	ep = cp = kern_getenv(ev);
4027c208ed6SRick Macklem 	if (cp == NULL)
4037c208ed6SRick Macklem 		return (0);
4047c208ed6SRick Macklem 	if ((strlen(cp) < 2) || (*cp != 'X')) {
4057c208ed6SRick Macklem 		freeenv(ep);
4067c208ed6SRick Macklem 		return (0);
4077c208ed6SRick Macklem 	}
4087c208ed6SRick Macklem 	len = 0;
4097c208ed6SRick Macklem 	cp++;
4107c208ed6SRick Macklem 	for (;;) {
4117c208ed6SRick Macklem 		if (*cp == 'X') {
4127c208ed6SRick Macklem 			freeenv(ep);
4137c208ed6SRick Macklem 			return (len);
4147c208ed6SRick Macklem 		}
4157c208ed6SRick Macklem 		if ((sscanf(cp, "%2x", &val) != 1) || (val > 0xff)) {
4167c208ed6SRick Macklem 			freeenv(ep);
4177c208ed6SRick Macklem 			return (0);
4187c208ed6SRick Macklem 		}
4197c208ed6SRick Macklem 		*(fh++) = val;
4207c208ed6SRick Macklem 		len++;
4217c208ed6SRick Macklem 		cp += 2;
4227c208ed6SRick Macklem 		if (len > maxfh) {
4237c208ed6SRick Macklem 		    freeenv(ep);
4247c208ed6SRick Macklem 		    return (0);
4257c208ed6SRick Macklem 		}
4267c208ed6SRick Macklem 	}
4277c208ed6SRick Macklem }
4287c208ed6SRick Macklem 
4297c208ed6SRick Macklem #if !defined(BOOTP_NFSROOT)
4307c208ed6SRick Macklem static void
nfs_rootconf(void)4317c208ed6SRick Macklem nfs_rootconf(void)
4327c208ed6SRick Macklem {
4337c208ed6SRick Macklem 
4347c208ed6SRick Macklem 	nfs_setup_diskless();
4357c208ed6SRick Macklem 	if (nfs_diskless_valid)
4367c208ed6SRick Macklem 		rootdevnames[0] = "nfs:";
4377c208ed6SRick Macklem }
4387c208ed6SRick Macklem 
4397c208ed6SRick Macklem SYSINIT(cpu_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, nfs_rootconf, NULL);
4407c208ed6SRick Macklem #endif
441