xref: /freebsd/sys/nfs/nfs_diskless.c (revision fbbd9655)
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.
16fbbd9655SWarner Losh  * 3. 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 
60e488229bSIan Lepore #define	NFS_IFACE_TIMEOUT_SECS	10 /* Timeout for interface to appear. */
61e488229bSIan Lepore 
627c208ed6SRick Macklem static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa);
637c208ed6SRick Macklem static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa);
647c208ed6SRick Macklem static int decode_nfshandle(char *ev, u_char *fh, int maxfh);
657c208ed6SRick Macklem 
667c208ed6SRick Macklem /*
677c208ed6SRick Macklem  * This structure must be filled in by a primary bootstrap or bootstrap
687c208ed6SRick Macklem  * server for a diskless/dataless machine. It is initialized below just
697c208ed6SRick Macklem  * to ensure that it is allocated to initialized data (.data not .bss).
707c208ed6SRick Macklem  */
717c208ed6SRick Macklem struct nfs_diskless	nfs_diskless = { { { 0 } } };
727c208ed6SRick Macklem struct nfsv3_diskless	nfsv3_diskless = { { { 0 } } };
737c208ed6SRick Macklem int			nfs_diskless_valid = 0;
747c208ed6SRick Macklem 
757c208ed6SRick Macklem /*
767c208ed6SRick Macklem  * Validate/sanity check a rsize/wsize parameter.
777c208ed6SRick Macklem  */
787c208ed6SRick Macklem static int
797c208ed6SRick Macklem checkrwsize(unsigned long v, const char *name)
807c208ed6SRick Macklem {
817c208ed6SRick Macklem 	/*
827c208ed6SRick Macklem 	 * 32K is used as an upper bound because most servers
837c208ed6SRick Macklem 	 * limit block size to satisfy IPv4's limit of
847c208ed6SRick Macklem 	 * 64K/reassembled packet.  The lower bound is pretty
857c208ed6SRick Macklem 	 * much arbitrary.
867c208ed6SRick Macklem 	 */
877c208ed6SRick Macklem 	if (!(4 <= v && v <= 32*1024)) {
887c208ed6SRick Macklem 		printf("nfs_parse_options: invalid %s %lu ignored\n", name, v);
897c208ed6SRick Macklem 		return 0;
907c208ed6SRick Macklem 	} else
917c208ed6SRick Macklem 		return 1;
927c208ed6SRick Macklem }
937c208ed6SRick Macklem 
947c208ed6SRick Macklem /*
957c208ed6SRick Macklem  * Parse mount options and apply them to the supplied
967c208ed6SRick Macklem  * nfs_diskless state.  Used also by bootp/dhcp support.
977c208ed6SRick Macklem  */
987c208ed6SRick Macklem void
997c208ed6SRick Macklem nfs_parse_options(const char *envopts, struct nfs_args *nd)
1007c208ed6SRick Macklem {
1017c208ed6SRick Macklem 	char *opts, *o, *otmp;
1027c208ed6SRick Macklem 	unsigned long v;
1037c208ed6SRick Macklem 
1047c208ed6SRick Macklem 	opts = strdup(envopts, M_TEMP);
1057c208ed6SRick Macklem 	otmp = opts;
1067c208ed6SRick Macklem 	while ((o = strsep(&otmp, ":;, ")) != NULL) {
1077c208ed6SRick Macklem 		if (*o == '\0')
1087c208ed6SRick Macklem 			; /* Skip empty options. */
1097c208ed6SRick Macklem 		else if (strcmp(o, "soft") == 0)
1107c208ed6SRick Macklem 			nd->flags |= NFSMNT_SOFT;
1117c208ed6SRick Macklem 		else if (strcmp(o, "intr") == 0)
1127c208ed6SRick Macklem 			nd->flags |= NFSMNT_INT;
1137c208ed6SRick Macklem 		else if (strcmp(o, "conn") == 0)
1147c208ed6SRick Macklem 			nd->flags |= NFSMNT_NOCONN;
1157c208ed6SRick Macklem 		else if (strcmp(o, "nolockd") == 0)
1167c208ed6SRick Macklem 			nd->flags |= NFSMNT_NOLOCKD;
117e2f2b370SRuslan Ermilov 		else if (strcmp(o, "nocto") == 0)
118e2f2b370SRuslan Ermilov 			nd->flags |= NFSMNT_NOCTO;
1197c208ed6SRick Macklem 		else if (strcmp(o, "nfsv2") == 0)
1207c208ed6SRick Macklem 			nd->flags &= ~(NFSMNT_NFSV3 | NFSMNT_NFSV4);
1217c208ed6SRick Macklem 		else if (strcmp(o, "nfsv3") == 0) {
1227c208ed6SRick Macklem 			nd->flags &= ~NFSMNT_NFSV4;
1237c208ed6SRick Macklem 			nd->flags |= NFSMNT_NFSV3;
1247c208ed6SRick Macklem 		} else if (strcmp(o, "tcp") == 0)
1257c208ed6SRick Macklem 			nd->sotype = SOCK_STREAM;
1267c208ed6SRick Macklem 		else if (strcmp(o, "udp") == 0)
1277c208ed6SRick Macklem 			nd->sotype = SOCK_DGRAM;
1287c208ed6SRick Macklem 		else if (strncmp(o, "rsize=", 6) == 0) {
1297c208ed6SRick Macklem 			v = strtoul(o+6, NULL, 10);
1307c208ed6SRick Macklem 			if (checkrwsize(v, "rsize")) {
1317c208ed6SRick Macklem 				nd->rsize = (int) v;
1327c208ed6SRick Macklem 				nd->flags |= NFSMNT_RSIZE;
1337c208ed6SRick Macklem 			}
1347c208ed6SRick Macklem 		} else if (strncmp(o, "wsize=", 6) == 0) {
1357c208ed6SRick Macklem 			v = strtoul(o+6, NULL, 10);
1367c208ed6SRick Macklem 			if (checkrwsize(v, "wsize")) {
1377c208ed6SRick Macklem 				nd->wsize = (int) v;
1387c208ed6SRick Macklem 				nd->flags |= NFSMNT_WSIZE;
1397c208ed6SRick Macklem 			}
1407c208ed6SRick Macklem 		} else
1417c208ed6SRick Macklem 			printf("%s: skipping unknown option \"%s\"\n",
1427c208ed6SRick Macklem 			    __func__, o);
1437c208ed6SRick Macklem 	}
1447c208ed6SRick Macklem 	free(opts, M_TEMP);
1457c208ed6SRick Macklem }
1467c208ed6SRick Macklem 
1477c208ed6SRick Macklem /*
1487c208ed6SRick Macklem  * Populate the essential fields in the nfsv3_diskless structure.
1497c208ed6SRick Macklem  *
1507c208ed6SRick Macklem  * The loader is expected to export the following environment variables:
1517c208ed6SRick Macklem  *
1527c208ed6SRick Macklem  * boot.netif.name		name of boot interface
1537c208ed6SRick Macklem  * boot.netif.ip		IP address on boot interface
1547c208ed6SRick Macklem  * boot.netif.netmask		netmask on boot interface
1557c208ed6SRick Macklem  * boot.netif.gateway		default gateway (optional)
1567c208ed6SRick Macklem  * boot.netif.hwaddr		hardware address of boot interface
157b50d46dfSIan Lepore  * boot.netif.mtu		interface mtu from bootp/dhcp (optional)
1587c208ed6SRick Macklem  * boot.nfsroot.server		IP address of root filesystem server
1597c208ed6SRick Macklem  * boot.nfsroot.path		path of the root filesystem on server
1607c208ed6SRick Macklem  * boot.nfsroot.nfshandle	NFS handle for root filesystem on server
1617c208ed6SRick Macklem  * boot.nfsroot.nfshandlelen	and length of this handle (for NFSv3 only)
1627c208ed6SRick Macklem  * boot.nfsroot.options		NFS options for the root filesystem
1637c208ed6SRick Macklem  */
1647c208ed6SRick Macklem void
1657c208ed6SRick Macklem nfs_setup_diskless(void)
1667c208ed6SRick Macklem {
1677c208ed6SRick Macklem 	struct nfs_diskless *nd = &nfs_diskless;
1687c208ed6SRick Macklem 	struct nfsv3_diskless *nd3 = &nfsv3_diskless;
1697c208ed6SRick Macklem 	struct ifnet *ifp;
1707c208ed6SRick Macklem 	struct ifaddr *ifa;
1717c208ed6SRick Macklem 	struct sockaddr_dl *sdl, ourdl;
1727c208ed6SRick Macklem 	struct sockaddr_in myaddr, netmask;
1737c208ed6SRick Macklem 	char *cp;
1747c208ed6SRick Macklem 	int cnt, fhlen, is_nfsv3;
1757c208ed6SRick Macklem 	uint32_t len;
176e488229bSIan Lepore 	time_t timeout_at;
1777c208ed6SRick Macklem 
1787c208ed6SRick Macklem 	if (nfs_diskless_valid != 0)
1797c208ed6SRick Macklem 		return;
1807c208ed6SRick Macklem 
1817c208ed6SRick Macklem 	/* get handle size. If this succeeds, it's an NFSv3 setup. */
1822be111bfSDavide Italiano 	if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) {
1837c208ed6SRick Macklem 		cnt = sscanf(cp, "%d", &len);
1847c208ed6SRick Macklem 		freeenv(cp);
1857c208ed6SRick Macklem 		if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) {
1867c208ed6SRick Macklem 			printf("nfs_diskless: bad NFS handle len\n");
1877c208ed6SRick Macklem 			return;
1887c208ed6SRick Macklem 		}
1897c208ed6SRick Macklem 		nd3->root_fhsize = len;
1907c208ed6SRick Macklem 		is_nfsv3 = 1;
1917c208ed6SRick Macklem 	} else
1927c208ed6SRick Macklem 		is_nfsv3 = 0;
1937c208ed6SRick Macklem 	/* set up interface */
1947c208ed6SRick Macklem 	if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
1957c208ed6SRick Macklem 		return;
1967c208ed6SRick Macklem 	if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
1977c208ed6SRick Macklem 		printf("nfs_diskless: no netmask\n");
1987c208ed6SRick Macklem 		return;
1997c208ed6SRick Macklem 	}
2007c208ed6SRick Macklem 	if (is_nfsv3 != 0) {
2017c208ed6SRick Macklem 		bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr));
2027c208ed6SRick Macklem 		bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr));
2037c208ed6SRick Macklem 		((struct sockaddr_in *)
2047c208ed6SRick Macklem 		   &nd3->myif.ifra_broadaddr)->sin_addr.s_addr =
2057c208ed6SRick Macklem 		    myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
2067c208ed6SRick Macklem 		bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask));
2077c208ed6SRick Macklem 	} else {
2087c208ed6SRick Macklem 		bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
2097c208ed6SRick Macklem 		bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
2107c208ed6SRick Macklem 		((struct sockaddr_in *)
2117c208ed6SRick Macklem 		   &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
2127c208ed6SRick Macklem 		    myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
2137c208ed6SRick Macklem 		bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
2147c208ed6SRick Macklem 	}
2157c208ed6SRick Macklem 
2167c208ed6SRick Macklem 	if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
2177c208ed6SRick Macklem 		printf("nfs_diskless: no hardware address\n");
2187c208ed6SRick Macklem 		return;
2197c208ed6SRick Macklem 	}
2207c208ed6SRick Macklem 	ifa = NULL;
221e488229bSIan Lepore 	timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS;
222e488229bSIan Lepore retry:
2237c208ed6SRick Macklem 	CURVNET_SET(TD_TO_VNET(curthread));
2247c208ed6SRick Macklem 	IFNET_RLOCK();
2257c208ed6SRick Macklem 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2267c208ed6SRick Macklem 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2277c208ed6SRick Macklem 			if (ifa->ifa_addr->sa_family == AF_LINK) {
2287c208ed6SRick Macklem 				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
2297c208ed6SRick Macklem 				if ((sdl->sdl_type == ourdl.sdl_type) &&
2307c208ed6SRick Macklem 				    (sdl->sdl_alen == ourdl.sdl_alen) &&
2317c208ed6SRick Macklem 				    !bcmp(LLADDR(sdl),
2327c208ed6SRick Macklem 					  LLADDR(&ourdl),
2337c208ed6SRick Macklem 					  sdl->sdl_alen)) {
2347c208ed6SRick Macklem 				    IFNET_RUNLOCK();
2357c208ed6SRick Macklem 				    CURVNET_RESTORE();
2367c208ed6SRick Macklem 				    goto match_done;
2377c208ed6SRick Macklem 				}
2387c208ed6SRick Macklem 			}
2397c208ed6SRick Macklem 		}
2407c208ed6SRick Macklem 	}
2417c208ed6SRick Macklem 	IFNET_RUNLOCK();
2427c208ed6SRick Macklem 	CURVNET_RESTORE();
243e488229bSIan Lepore 	if (time_uptime < timeout_at) {
244e488229bSIan Lepore 		pause("nfssdl", hz / 5);
245e488229bSIan Lepore 		goto retry;
246e488229bSIan Lepore 	}
2477c208ed6SRick Macklem 	printf("nfs_diskless: no interface\n");
2487c208ed6SRick Macklem 	return;	/* no matching interface */
2497c208ed6SRick Macklem match_done:
2502be111bfSDavide Italiano 	kern_setenv("boot.netif.name", ifp->if_xname);
2517c208ed6SRick Macklem 	if (is_nfsv3 != 0) {
2527c208ed6SRick Macklem 		strlcpy(nd3->myif.ifra_name, ifp->if_xname,
2537c208ed6SRick Macklem 		    sizeof(nd3->myif.ifra_name));
2547c208ed6SRick Macklem 
2557c208ed6SRick Macklem 		/* set up gateway */
2567c208ed6SRick Macklem 		inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway);
2577c208ed6SRick Macklem 
2587c208ed6SRick Macklem 		/* set up root mount */
2597c208ed6SRick Macklem 		nd3->root_args.rsize = 32768;		/* XXX tunable? */
2607c208ed6SRick Macklem 		nd3->root_args.wsize = 32768;
2617c208ed6SRick Macklem 		nd3->root_args.sotype = SOCK_STREAM;
2627c208ed6SRick Macklem 		nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE |
2637c208ed6SRick Macklem 		    NFSMNT_RSIZE | NFSMNT_RESVPORT);
2647c208ed6SRick Macklem 		if (inaddr_to_sockaddr("boot.nfsroot.server",
2657c208ed6SRick Macklem 		    &nd3->root_saddr)) {
2667c208ed6SRick Macklem 			printf("nfs_diskless: no server\n");
2677c208ed6SRick Macklem 			return;
2687c208ed6SRick Macklem 		}
2697c208ed6SRick Macklem 		nd3->root_saddr.sin_port = htons(NFS_PORT);
2707c208ed6SRick Macklem 		fhlen = decode_nfshandle("boot.nfsroot.nfshandle",
2717c208ed6SRick Macklem 		    &nd3->root_fh[0], NFSX_V3FHMAX);
2727c208ed6SRick Macklem 		if (fhlen == 0) {
2737c208ed6SRick Macklem 			printf("nfs_diskless: no NFS handle\n");
2747c208ed6SRick Macklem 			return;
2757c208ed6SRick Macklem 		}
2767c208ed6SRick Macklem 		if (fhlen != nd3->root_fhsize) {
2777c208ed6SRick Macklem 			printf("nfs_diskless: bad NFS handle len=%d\n", fhlen);
2787c208ed6SRick Macklem 			return;
2797c208ed6SRick Macklem 		}
2802be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
2817c208ed6SRick Macklem 			strncpy(nd3->root_hostnam, cp, MNAMELEN - 1);
2827c208ed6SRick Macklem 			freeenv(cp);
2837c208ed6SRick Macklem 		}
2842be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) {
2857c208ed6SRick Macklem 			nfs_parse_options(cp, &nd3->root_args);
2867c208ed6SRick Macklem 			freeenv(cp);
2877c208ed6SRick Macklem 		}
2887c208ed6SRick Macklem 
2897c208ed6SRick Macklem 		nfs_diskless_valid = 3;
2907c208ed6SRick Macklem 	} else {
2917c208ed6SRick Macklem 		strlcpy(nd->myif.ifra_name, ifp->if_xname,
2927c208ed6SRick Macklem 		    sizeof(nd->myif.ifra_name));
2937c208ed6SRick Macklem 
2947c208ed6SRick Macklem 		/* set up gateway */
2957c208ed6SRick Macklem 		inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
2967c208ed6SRick Macklem 
2977c208ed6SRick Macklem 		/* set up root mount */
2987c208ed6SRick Macklem 		nd->root_args.rsize = 8192;		/* XXX tunable? */
2997c208ed6SRick Macklem 		nd->root_args.wsize = 8192;
3007c208ed6SRick Macklem 		nd->root_args.sotype = SOCK_STREAM;
3017c208ed6SRick Macklem 		nd->root_args.flags = (NFSMNT_WSIZE |
3027c208ed6SRick Macklem 		    NFSMNT_RSIZE | NFSMNT_RESVPORT);
3037c208ed6SRick Macklem 		if (inaddr_to_sockaddr("boot.nfsroot.server",
3047c208ed6SRick Macklem 		    &nd->root_saddr)) {
3057c208ed6SRick Macklem 			printf("nfs_diskless: no server\n");
3067c208ed6SRick Macklem 			return;
3077c208ed6SRick Macklem 		}
3087c208ed6SRick Macklem 		nd->root_saddr.sin_port = htons(NFS_PORT);
3097c208ed6SRick Macklem 		if (decode_nfshandle("boot.nfsroot.nfshandle",
3107c208ed6SRick Macklem 		    &nd->root_fh[0], NFSX_V2FH) == 0) {
3117c208ed6SRick Macklem 			printf("nfs_diskless: no NFS handle\n");
3127c208ed6SRick Macklem 			return;
3137c208ed6SRick Macklem 		}
3142be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
3157c208ed6SRick Macklem 			strncpy(nd->root_hostnam, cp, MNAMELEN - 1);
3167c208ed6SRick Macklem 			freeenv(cp);
3177c208ed6SRick Macklem 		}
3182be111bfSDavide Italiano 		if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) {
3197c208ed6SRick Macklem 			struct nfs_args args;
3207c208ed6SRick Macklem 
3217c208ed6SRick Macklem 			/*
3227c208ed6SRick Macklem 			 * XXX yech, convert between old and current
3237c208ed6SRick Macklem 			 * arg format
3247c208ed6SRick Macklem 			 */
3257c208ed6SRick Macklem 			args.flags = nd->root_args.flags;
3267c208ed6SRick Macklem 			args.sotype = nd->root_args.sotype;
3277c208ed6SRick Macklem 			args.rsize = nd->root_args.rsize;
3287c208ed6SRick Macklem 			args.wsize = nd->root_args.wsize;
3297c208ed6SRick Macklem 			nfs_parse_options(cp, &args);
3307c208ed6SRick Macklem 			nd->root_args.flags = args.flags;
3317c208ed6SRick Macklem 			nd->root_args.sotype = args.sotype;
3327c208ed6SRick Macklem 			nd->root_args.rsize = args.rsize;
3337c208ed6SRick Macklem 			nd->root_args.wsize = args.wsize;
3347c208ed6SRick Macklem 			freeenv(cp);
3357c208ed6SRick Macklem 		}
3367c208ed6SRick Macklem 
3377c208ed6SRick Macklem 		nfs_diskless_valid = 1;
3387c208ed6SRick Macklem 	}
3397c208ed6SRick Macklem }
3407c208ed6SRick Macklem 
3417c208ed6SRick Macklem static int
3427c208ed6SRick Macklem inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa)
3437c208ed6SRick Macklem {
3447c208ed6SRick Macklem 	u_int32_t a[4];
3457c208ed6SRick Macklem 	char *cp;
3467c208ed6SRick Macklem 	int count;
3477c208ed6SRick Macklem 
3487c208ed6SRick Macklem 	bzero(sa, sizeof(*sa));
3497c208ed6SRick Macklem 	sa->sin_len = sizeof(*sa);
3507c208ed6SRick Macklem 	sa->sin_family = AF_INET;
3517c208ed6SRick Macklem 
3522be111bfSDavide Italiano 	if ((cp = kern_getenv(ev)) == NULL)
3537c208ed6SRick Macklem 		return (1);
3547c208ed6SRick Macklem 	count = sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
3557c208ed6SRick Macklem 	freeenv(cp);
3567c208ed6SRick Macklem 	if (count != 4)
3577c208ed6SRick Macklem 		return (1);
3587c208ed6SRick Macklem 	sa->sin_addr.s_addr =
3597c208ed6SRick Macklem 	    htonl((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
3607c208ed6SRick Macklem 	return (0);
3617c208ed6SRick Macklem }
3627c208ed6SRick Macklem 
3637c208ed6SRick Macklem static int
3647c208ed6SRick Macklem hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
3657c208ed6SRick Macklem {
3667c208ed6SRick Macklem 	char *cp;
3677c208ed6SRick Macklem 	u_int32_t a[6];
3687c208ed6SRick Macklem 	int count;
3697c208ed6SRick Macklem 
3707c208ed6SRick Macklem 	bzero(sa, sizeof(*sa));
3717c208ed6SRick Macklem 	sa->sdl_len = sizeof(*sa);
3727c208ed6SRick Macklem 	sa->sdl_family = AF_LINK;
3737c208ed6SRick Macklem 	sa->sdl_type = IFT_ETHER;
3747c208ed6SRick Macklem 	sa->sdl_alen = ETHER_ADDR_LEN;
3752be111bfSDavide Italiano 	if ((cp = kern_getenv(ev)) == NULL)
3767c208ed6SRick Macklem 		return (1);
3777c208ed6SRick Macklem 	count = sscanf(cp, "%x:%x:%x:%x:%x:%x",
3787c208ed6SRick Macklem 	    &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);
3797c208ed6SRick Macklem 	freeenv(cp);
3807c208ed6SRick Macklem 	if (count != 6)
3817c208ed6SRick Macklem 		return (1);
3827c208ed6SRick Macklem 	sa->sdl_data[0] = a[0];
3837c208ed6SRick Macklem 	sa->sdl_data[1] = a[1];
3847c208ed6SRick Macklem 	sa->sdl_data[2] = a[2];
3857c208ed6SRick Macklem 	sa->sdl_data[3] = a[3];
3867c208ed6SRick Macklem 	sa->sdl_data[4] = a[4];
3877c208ed6SRick Macklem 	sa->sdl_data[5] = a[5];
3887c208ed6SRick Macklem 	return (0);
3897c208ed6SRick Macklem }
3907c208ed6SRick Macklem 
3917c208ed6SRick Macklem static int
3927c208ed6SRick Macklem decode_nfshandle(char *ev, u_char *fh, int maxfh)
3937c208ed6SRick Macklem {
3947c208ed6SRick Macklem 	u_char *cp, *ep;
3957c208ed6SRick Macklem 	int len, val;
3967c208ed6SRick Macklem 
3972be111bfSDavide Italiano 	ep = cp = kern_getenv(ev);
3987c208ed6SRick Macklem 	if (cp == NULL)
3997c208ed6SRick Macklem 		return (0);
4007c208ed6SRick Macklem 	if ((strlen(cp) < 2) || (*cp != 'X')) {
4017c208ed6SRick Macklem 		freeenv(ep);
4027c208ed6SRick Macklem 		return (0);
4037c208ed6SRick Macklem 	}
4047c208ed6SRick Macklem 	len = 0;
4057c208ed6SRick Macklem 	cp++;
4067c208ed6SRick Macklem 	for (;;) {
4077c208ed6SRick Macklem 		if (*cp == 'X') {
4087c208ed6SRick Macklem 			freeenv(ep);
4097c208ed6SRick Macklem 			return (len);
4107c208ed6SRick Macklem 		}
4117c208ed6SRick Macklem 		if ((sscanf(cp, "%2x", &val) != 1) || (val > 0xff)) {
4127c208ed6SRick Macklem 			freeenv(ep);
4137c208ed6SRick Macklem 			return (0);
4147c208ed6SRick Macklem 		}
4157c208ed6SRick Macklem 		*(fh++) = val;
4167c208ed6SRick Macklem 		len++;
4177c208ed6SRick Macklem 		cp += 2;
4187c208ed6SRick Macklem 		if (len > maxfh) {
4197c208ed6SRick Macklem 		    freeenv(ep);
4207c208ed6SRick Macklem 		    return (0);
4217c208ed6SRick Macklem 		}
4227c208ed6SRick Macklem 	}
4237c208ed6SRick Macklem }
4247c208ed6SRick Macklem 
4257c208ed6SRick Macklem #if !defined(BOOTP_NFSROOT)
4267c208ed6SRick Macklem static void
4277c208ed6SRick Macklem nfs_rootconf(void)
4287c208ed6SRick Macklem {
4297c208ed6SRick Macklem 
4307c208ed6SRick Macklem 	nfs_setup_diskless();
4317c208ed6SRick Macklem 	if (nfs_diskless_valid)
4327c208ed6SRick Macklem 		rootdevnames[0] = "nfs:";
4337c208ed6SRick Macklem }
4347c208ed6SRick Macklem 
4357c208ed6SRick Macklem SYSINIT(cpu_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, nfs_rootconf, NULL);
4367c208ed6SRick Macklem #endif
4377c208ed6SRick Macklem 
438