xref: /openbsd/sys/nfs/nfs_boot.c (revision df930be7)
1*df930be7Sderaadt /*    $NetBSD: nfs_boot.c,v 1.19 1995/06/12 00:48:31 mycroft Exp $ */
2*df930be7Sderaadt 
3*df930be7Sderaadt /*
4*df930be7Sderaadt  * Copyright (c) 1995 Adam Glass, Gordon Ross
5*df930be7Sderaadt  * All rights reserved.
6*df930be7Sderaadt  *
7*df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
8*df930be7Sderaadt  * modification, are permitted provided that the following conditions
9*df930be7Sderaadt  * are met:
10*df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
11*df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
12*df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
13*df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
14*df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
15*df930be7Sderaadt  * 3. The name of the authors may not be used to endorse or promote products
16*df930be7Sderaadt  *    derived from this software without specific prior written permission.
17*df930be7Sderaadt  *
18*df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19*df930be7Sderaadt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20*df930be7Sderaadt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21*df930be7Sderaadt  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22*df930be7Sderaadt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23*df930be7Sderaadt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*df930be7Sderaadt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*df930be7Sderaadt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*df930be7Sderaadt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27*df930be7Sderaadt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*df930be7Sderaadt  */
29*df930be7Sderaadt 
30*df930be7Sderaadt #include <sys/param.h>
31*df930be7Sderaadt #include <sys/systm.h>
32*df930be7Sderaadt #include <sys/kernel.h>
33*df930be7Sderaadt #include <sys/conf.h>
34*df930be7Sderaadt #include <sys/ioctl.h>
35*df930be7Sderaadt #include <sys/proc.h>
36*df930be7Sderaadt #include <sys/mount.h>
37*df930be7Sderaadt #include <sys/mbuf.h>
38*df930be7Sderaadt #include <sys/reboot.h>
39*df930be7Sderaadt #include <sys/socket.h>
40*df930be7Sderaadt #include <sys/socketvar.h>
41*df930be7Sderaadt 
42*df930be7Sderaadt #include <net/if.h>
43*df930be7Sderaadt #include <net/route.h>
44*df930be7Sderaadt 
45*df930be7Sderaadt #include <netinet/in.h>
46*df930be7Sderaadt #include <netinet/if_ether.h>
47*df930be7Sderaadt 
48*df930be7Sderaadt #include <nfs/rpcv2.h>
49*df930be7Sderaadt #include <nfs/nfsv2.h>
50*df930be7Sderaadt #include <nfs/nfs.h>
51*df930be7Sderaadt #include <nfs/nfsdiskless.h>
52*df930be7Sderaadt #include <nfs/krpc.h>
53*df930be7Sderaadt #include <nfs/xdr_subs.h>
54*df930be7Sderaadt 
55*df930be7Sderaadt #include "ether.h"
56*df930be7Sderaadt #if NETHER == 0
57*df930be7Sderaadt 
58*df930be7Sderaadt int nfs_boot_init(nd, procp)
59*df930be7Sderaadt 	struct nfs_diskless *nd;
60*df930be7Sderaadt 	struct proc *procp;
61*df930be7Sderaadt {
62*df930be7Sderaadt 	panic("nfs_boot_init: no ether");
63*df930be7Sderaadt }
64*df930be7Sderaadt 
65*df930be7Sderaadt #else /* NETHER */
66*df930be7Sderaadt 
67*df930be7Sderaadt /*
68*df930be7Sderaadt  * Support for NFS diskless booting, specifically getting information
69*df930be7Sderaadt  * about where to boot from, what pathnames, etc.
70*df930be7Sderaadt  *
71*df930be7Sderaadt  * This implememtation uses RARP and the bootparam RPC.
72*df930be7Sderaadt  * We are forced to implement RPC anyway (to get file handles)
73*df930be7Sderaadt  * so we might as well take advantage of it for bootparam too.
74*df930be7Sderaadt  *
75*df930be7Sderaadt  * The diskless boot sequence goes as follows:
76*df930be7Sderaadt  * (1) Use RARP to get our interface address
77*df930be7Sderaadt  * (2) Use RPC/bootparam/whoami to get our hostname,
78*df930be7Sderaadt  *     our IP address, and the server's IP address.
79*df930be7Sderaadt  * (3) Use RPC/bootparam/getfile to get the root path
80*df930be7Sderaadt  * (4) Use RPC/mountd to get the root file handle
81*df930be7Sderaadt  * (5) Use RPC/bootparam/getfile to get the swap path
82*df930be7Sderaadt  * (6) Use RPC/mountd to get the swap file handle
83*df930be7Sderaadt  *
84*df930be7Sderaadt  * (This happens to be the way Sun does it too.)
85*df930be7Sderaadt  */
86*df930be7Sderaadt 
87*df930be7Sderaadt /* bootparam RPC */
88*df930be7Sderaadt static int bp_whoami __P((struct sockaddr_in *bpsin,
89*df930be7Sderaadt 	struct in_addr *my_ip, struct in_addr *gw_ip));
90*df930be7Sderaadt static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
91*df930be7Sderaadt 	struct sockaddr_in *mdsin, char *servname, char *path));
92*df930be7Sderaadt 
93*df930be7Sderaadt /* mountd RPC */
94*df930be7Sderaadt static int md_mount __P((struct sockaddr_in *mdsin, char *path,
95*df930be7Sderaadt 	u_char *fh));
96*df930be7Sderaadt 
97*df930be7Sderaadt /* other helpers */
98*df930be7Sderaadt static void get_path_and_handle __P((struct sockaddr_in *bpsin,
99*df930be7Sderaadt 	char *key, struct nfs_dlmount *ndmntp));
100*df930be7Sderaadt 
101*df930be7Sderaadt char	*nfsbootdevname;
102*df930be7Sderaadt 
103*df930be7Sderaadt /*
104*df930be7Sderaadt  * Called with an empty nfs_diskless struct to be filled in.
105*df930be7Sderaadt  */
106*df930be7Sderaadt int
107*df930be7Sderaadt nfs_boot_init(nd, procp)
108*df930be7Sderaadt 	struct nfs_diskless *nd;
109*df930be7Sderaadt 	struct proc *procp;
110*df930be7Sderaadt {
111*df930be7Sderaadt 	struct ifreq ireq;
112*df930be7Sderaadt 	struct in_addr my_ip, gw_ip;
113*df930be7Sderaadt 	struct sockaddr_in bp_sin;
114*df930be7Sderaadt 	struct sockaddr_in *sin;
115*df930be7Sderaadt 	struct ifnet *ifp;
116*df930be7Sderaadt 	struct socket *so;
117*df930be7Sderaadt 	int error;
118*df930be7Sderaadt 
119*df930be7Sderaadt 	/*
120*df930be7Sderaadt 	 * Find an interface, rarp for its ip address, stuff it, the
121*df930be7Sderaadt 	 * implied broadcast addr, and netmask into a nfs_diskless struct.
122*df930be7Sderaadt 	 *
123*df930be7Sderaadt 	 * This was moved here from nfs_vfsops.c because this procedure
124*df930be7Sderaadt 	 * would be quite different if someone decides to write (i.e.) a
125*df930be7Sderaadt 	 * BOOTP version of this file (might not use RARP, etc.)
126*df930be7Sderaadt 	 */
127*df930be7Sderaadt 
128*df930be7Sderaadt 	/*
129*df930be7Sderaadt 	 * Find a network interface.
130*df930be7Sderaadt 	 */
131*df930be7Sderaadt 	if (nfsbootdevname)
132*df930be7Sderaadt 		ifp = ifunit(nfsbootdevname);
133*df930be7Sderaadt 	else
134*df930be7Sderaadt 		for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
135*df930be7Sderaadt 			if ((ifp->if_flags &
136*df930be7Sderaadt 			     (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
137*df930be7Sderaadt 				break;
138*df930be7Sderaadt 	if (ifp == NULL)
139*df930be7Sderaadt 		panic("nfs_boot: no suitable interface");
140*df930be7Sderaadt 	sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
141*df930be7Sderaadt 	printf("nfs_boot: using network interface '%s'\n",
142*df930be7Sderaadt 	    ireq.ifr_name);
143*df930be7Sderaadt 
144*df930be7Sderaadt 	/*
145*df930be7Sderaadt 	 * Bring up the interface.
146*df930be7Sderaadt 	 *
147*df930be7Sderaadt 	 * Get the old interface flags and or IFF_UP into them; if
148*df930be7Sderaadt 	 * IFF_UP set blindly, interface selection can be clobbered.
149*df930be7Sderaadt 	 */
150*df930be7Sderaadt 	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
151*df930be7Sderaadt 		panic("nfs_boot: socreate, error=%d", error);
152*df930be7Sderaadt 	error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
153*df930be7Sderaadt 	if (error)
154*df930be7Sderaadt 		panic("nfs_boot: GIFFLAGS, error=%d", error);
155*df930be7Sderaadt 	ireq.ifr_flags |= IFF_UP;
156*df930be7Sderaadt 	error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
157*df930be7Sderaadt 	if (error)
158*df930be7Sderaadt 		panic("nfs_boot: SIFFLAGS, error=%d", error);
159*df930be7Sderaadt 
160*df930be7Sderaadt 	/*
161*df930be7Sderaadt 	 * Do RARP for the interface address.
162*df930be7Sderaadt 	 */
163*df930be7Sderaadt 	if ((error = revarpwhoami(&my_ip, ifp)) != 0)
164*df930be7Sderaadt 		panic("revarp failed, error=%d", error);
165*df930be7Sderaadt 	printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
166*df930be7Sderaadt 
167*df930be7Sderaadt 	/*
168*df930be7Sderaadt 	 * Do enough of ifconfig(8) so that the chosen interface
169*df930be7Sderaadt 	 * can talk to the servers.  (just set the address)
170*df930be7Sderaadt 	 */
171*df930be7Sderaadt 	sin = (struct sockaddr_in *)&ireq.ifr_addr;
172*df930be7Sderaadt 	bzero((caddr_t)sin, sizeof(*sin));
173*df930be7Sderaadt 	sin->sin_len = sizeof(*sin);
174*df930be7Sderaadt 	sin->sin_family = AF_INET;
175*df930be7Sderaadt 	sin->sin_addr.s_addr = my_ip.s_addr;
176*df930be7Sderaadt 	error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
177*df930be7Sderaadt 	if (error)
178*df930be7Sderaadt 		panic("nfs_boot: set if addr, error=%d", error);
179*df930be7Sderaadt 
180*df930be7Sderaadt 	soclose(so);
181*df930be7Sderaadt 
182*df930be7Sderaadt 	/*
183*df930be7Sderaadt 	 * Get client name and gateway address.
184*df930be7Sderaadt 	 * RPC: bootparam/whoami
185*df930be7Sderaadt 	 * Use the old broadcast address for the WHOAMI
186*df930be7Sderaadt 	 * call because we do not yet know our netmask.
187*df930be7Sderaadt 	 * The server address returned by the WHOAMI call
188*df930be7Sderaadt 	 * is used for all subsequent booptaram RPCs.
189*df930be7Sderaadt 	 */
190*df930be7Sderaadt 	bzero((caddr_t)&bp_sin, sizeof(bp_sin));
191*df930be7Sderaadt 	bp_sin.sin_len = sizeof(bp_sin);
192*df930be7Sderaadt 	bp_sin.sin_family = AF_INET;
193*df930be7Sderaadt 	bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
194*df930be7Sderaadt 	hostnamelen = MAXHOSTNAMELEN;
195*df930be7Sderaadt 
196*df930be7Sderaadt 	/* this returns gateway IP address */
197*df930be7Sderaadt 	error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
198*df930be7Sderaadt 	if (error)
199*df930be7Sderaadt 		panic("nfs_boot: bootparam whoami, error=%d", error);
200*df930be7Sderaadt 	printf("nfs_boot: server_addr=0x%x\n",
201*df930be7Sderaadt 		   ntohl(bp_sin.sin_addr.s_addr));
202*df930be7Sderaadt 	printf("nfs_boot: hostname=%s\n", hostname);
203*df930be7Sderaadt 
204*df930be7Sderaadt #ifdef	NFS_BOOT_GATEWAY
205*df930be7Sderaadt 	/*
206*df930be7Sderaadt 	 * XXX - This code is conditionally compiled only because
207*df930be7Sderaadt 	 * many bootparam servers (in particular, SunOS 4.1.3)
208*df930be7Sderaadt 	 * always set the gateway address to their own address.
209*df930be7Sderaadt 	 * The bootparam server is not necessarily the gateway.
210*df930be7Sderaadt 	 * We could just believe the server, and at worst you would
211*df930be7Sderaadt 	 * need to delete the incorrect default route before adding
212*df930be7Sderaadt 	 * the correct one, but for simplicity, ignore the gateway.
213*df930be7Sderaadt 	 * If your server is OK, you can turn on this option.
214*df930be7Sderaadt 	 *
215*df930be7Sderaadt 	 * If the gateway address is set, add a default route.
216*df930be7Sderaadt 	 * (The mountd RPCs may go across a gateway.)
217*df930be7Sderaadt 	 */
218*df930be7Sderaadt 	if (gw_ip.s_addr) {
219*df930be7Sderaadt 		struct sockaddr dst, gw, mask;
220*df930be7Sderaadt 		/* Destination: (default) */
221*df930be7Sderaadt 		bzero((caddr_t)&dst, sizeof(dst));
222*df930be7Sderaadt 		dst.sa_len = sizeof(dst);
223*df930be7Sderaadt 		dst.sa_family = AF_INET;
224*df930be7Sderaadt 		/* Gateway: */
225*df930be7Sderaadt 		bzero((caddr_t)&gw, sizeof(gw));
226*df930be7Sderaadt 		sin = (struct sockaddr_in *)&gw;
227*df930be7Sderaadt 		sin->sin_len = sizeof(gw);
228*df930be7Sderaadt 		sin->sin_family = AF_INET;
229*df930be7Sderaadt 		sin->sin_addr.s_addr = gw_ip.s_addr;
230*df930be7Sderaadt 		/* Mask: (zero length) */
231*df930be7Sderaadt 		bzero(&mask, sizeof(mask));
232*df930be7Sderaadt 
233*df930be7Sderaadt 		printf("nfs_boot: gateway=0x%x\n", ntohl(gw_ip.s_addr));
234*df930be7Sderaadt 		/* add, dest, gw, mask, flags, 0 */
235*df930be7Sderaadt 		error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw,
236*df930be7Sderaadt 		    &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
237*df930be7Sderaadt 		if (error)
238*df930be7Sderaadt 			printf("nfs_boot: add route, error=%d\n", error);
239*df930be7Sderaadt 	}
240*df930be7Sderaadt #endif
241*df930be7Sderaadt 
242*df930be7Sderaadt 	get_path_and_handle(&bp_sin, "root", &nd->nd_root);
243*df930be7Sderaadt 	get_path_and_handle(&bp_sin, "swap", &nd->nd_swap);
244*df930be7Sderaadt 
245*df930be7Sderaadt 	return (0);
246*df930be7Sderaadt }
247*df930be7Sderaadt 
248*df930be7Sderaadt static void
249*df930be7Sderaadt get_path_and_handle(bpsin, key, ndmntp)
250*df930be7Sderaadt 	struct sockaddr_in *bpsin;	/* bootparam server */
251*df930be7Sderaadt 	char *key;			/* root or swap */
252*df930be7Sderaadt 	struct nfs_dlmount *ndmntp;	/* output */
253*df930be7Sderaadt {
254*df930be7Sderaadt 	char pathname[MAXPATHLEN];
255*df930be7Sderaadt 	char *sp, *dp, *endp;
256*df930be7Sderaadt 	int error;
257*df930be7Sderaadt 
258*df930be7Sderaadt 	/*
259*df930be7Sderaadt 	 * Get server:pathname for "key" (root or swap)
260*df930be7Sderaadt 	 * using RPC to bootparam/getfile
261*df930be7Sderaadt 	 */
262*df930be7Sderaadt 	error = bp_getfile(bpsin, key, &ndmntp->ndm_saddr,
263*df930be7Sderaadt 	    ndmntp->ndm_host, pathname);
264*df930be7Sderaadt 	if (error)
265*df930be7Sderaadt 		panic("nfs_boot: bootparam get %s: %d", key, error);
266*df930be7Sderaadt 
267*df930be7Sderaadt 	/*
268*df930be7Sderaadt 	 * Get file handle for "key" (root or swap)
269*df930be7Sderaadt 	 * using RPC to mountd/mount
270*df930be7Sderaadt 	 */
271*df930be7Sderaadt 	error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh);
272*df930be7Sderaadt 	if (error)
273*df930be7Sderaadt 		panic("nfs_boot: mountd %s, error=%d", key, error);
274*df930be7Sderaadt 
275*df930be7Sderaadt 	/* Construct remote path (for getmntinfo(3)) */
276*df930be7Sderaadt 	dp = ndmntp->ndm_host;
277*df930be7Sderaadt 	endp = dp + MNAMELEN - 1;
278*df930be7Sderaadt 	dp += strlen(dp);
279*df930be7Sderaadt 	*dp++ = ':';
280*df930be7Sderaadt 	for (sp = pathname; *sp && dp < endp;)
281*df930be7Sderaadt 		*dp++ = *sp++;
282*df930be7Sderaadt 	*dp = '\0';
283*df930be7Sderaadt 
284*df930be7Sderaadt }
285*df930be7Sderaadt 
286*df930be7Sderaadt 
287*df930be7Sderaadt /*
288*df930be7Sderaadt  * RPC: bootparam/whoami
289*df930be7Sderaadt  * Given client IP address, get:
290*df930be7Sderaadt  *	client name	(hostname)
291*df930be7Sderaadt  *	domain name (domainname)
292*df930be7Sderaadt  *	gateway address
293*df930be7Sderaadt  *
294*df930be7Sderaadt  * The hostname and domainname are set here for convenience.
295*df930be7Sderaadt  *
296*df930be7Sderaadt  * Note - bpsin is initialized to the broadcast address,
297*df930be7Sderaadt  * and will be replaced with the bootparam server address
298*df930be7Sderaadt  * after this call is complete.  Have to use PMAP_PROC_CALL
299*df930be7Sderaadt  * to make sure we get responses only from a servers that
300*df930be7Sderaadt  * know about us (don't want to broadcast a getport call).
301*df930be7Sderaadt  */
302*df930be7Sderaadt static int
303*df930be7Sderaadt bp_whoami(bpsin, my_ip, gw_ip)
304*df930be7Sderaadt 	struct sockaddr_in *bpsin;
305*df930be7Sderaadt 	struct in_addr *my_ip;
306*df930be7Sderaadt 	struct in_addr *gw_ip;
307*df930be7Sderaadt {
308*df930be7Sderaadt 	/* RPC structures for PMAPPROC_CALLIT */
309*df930be7Sderaadt 	struct whoami_call {
310*df930be7Sderaadt 		u_int32_t call_prog;
311*df930be7Sderaadt 		u_int32_t call_vers;
312*df930be7Sderaadt 		u_int32_t call_proc;
313*df930be7Sderaadt 		u_int32_t call_arglen;
314*df930be7Sderaadt 	} *call;
315*df930be7Sderaadt 	struct callit_reply {
316*df930be7Sderaadt 		u_int32_t port;
317*df930be7Sderaadt 		u_int32_t encap_len;
318*df930be7Sderaadt 		/* encapsulated data here */
319*df930be7Sderaadt 	} *reply;
320*df930be7Sderaadt 
321*df930be7Sderaadt 	struct mbuf *m, *from;
322*df930be7Sderaadt 	struct sockaddr_in *sin;
323*df930be7Sderaadt 	int error, msg_len;
324*df930be7Sderaadt 	int16_t port;
325*df930be7Sderaadt 
326*df930be7Sderaadt 	/*
327*df930be7Sderaadt 	 * Build request message for PMAPPROC_CALLIT.
328*df930be7Sderaadt 	 */
329*df930be7Sderaadt 	m = m_get(M_WAIT, MT_DATA);
330*df930be7Sderaadt 	call = mtod(m, struct whoami_call *);
331*df930be7Sderaadt 	m->m_len = sizeof(*call);
332*df930be7Sderaadt 	call->call_prog = txdr_unsigned(BOOTPARAM_PROG);
333*df930be7Sderaadt 	call->call_vers = txdr_unsigned(BOOTPARAM_VERS);
334*df930be7Sderaadt 	call->call_proc = txdr_unsigned(BOOTPARAM_WHOAMI);
335*df930be7Sderaadt 
336*df930be7Sderaadt 	/*
337*df930be7Sderaadt 	 * append encapsulated data (client IP address)
338*df930be7Sderaadt 	 */
339*df930be7Sderaadt 	m->m_next = xdr_inaddr_encode(my_ip);
340*df930be7Sderaadt 	call->call_arglen = txdr_unsigned(m->m_next->m_len);
341*df930be7Sderaadt 
342*df930be7Sderaadt 	/* RPC: portmap/callit */
343*df930be7Sderaadt 	bpsin->sin_port = htons(PMAPPORT);
344*df930be7Sderaadt 	from = NULL;
345*df930be7Sderaadt 	error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
346*df930be7Sderaadt 			PMAPPROC_CALLIT, &m, &from);
347*df930be7Sderaadt 	if (error)
348*df930be7Sderaadt 		return error;
349*df930be7Sderaadt 
350*df930be7Sderaadt 	/*
351*df930be7Sderaadt 	 * Parse result message.
352*df930be7Sderaadt 	 */
353*df930be7Sderaadt 	if (m->m_len < sizeof(*reply)) {
354*df930be7Sderaadt 		m = m_pullup(m, sizeof(*reply));
355*df930be7Sderaadt 		if (m == NULL)
356*df930be7Sderaadt 			goto bad;
357*df930be7Sderaadt 	}
358*df930be7Sderaadt 	reply = mtod(m, struct callit_reply *);
359*df930be7Sderaadt 	port = fxdr_unsigned(u_int32_t, reply->port);
360*df930be7Sderaadt 	msg_len = fxdr_unsigned(u_int32_t, reply->encap_len);
361*df930be7Sderaadt 	m_adj(m, sizeof(*reply));
362*df930be7Sderaadt 
363*df930be7Sderaadt 	/*
364*df930be7Sderaadt 	 * Save bootparam server address
365*df930be7Sderaadt 	 */
366*df930be7Sderaadt 	sin = mtod(from, struct sockaddr_in *);
367*df930be7Sderaadt 	bpsin->sin_port = htons(port);
368*df930be7Sderaadt 	bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
369*df930be7Sderaadt 
370*df930be7Sderaadt 	/* client name */
371*df930be7Sderaadt 	hostnamelen = MAXHOSTNAMELEN-1;
372*df930be7Sderaadt 	m = xdr_string_decode(m, hostname, &hostnamelen);
373*df930be7Sderaadt 	if (m == NULL)
374*df930be7Sderaadt 		goto bad;
375*df930be7Sderaadt 
376*df930be7Sderaadt 	/* domain name */
377*df930be7Sderaadt 	domainnamelen = MAXHOSTNAMELEN-1;
378*df930be7Sderaadt 	m = xdr_string_decode(m, domainname, &domainnamelen);
379*df930be7Sderaadt 	if (m == NULL)
380*df930be7Sderaadt 		goto bad;
381*df930be7Sderaadt 
382*df930be7Sderaadt 	/* gateway address */
383*df930be7Sderaadt 	m = xdr_inaddr_decode(m, gw_ip);
384*df930be7Sderaadt 	if (m == NULL)
385*df930be7Sderaadt 		goto bad;
386*df930be7Sderaadt 
387*df930be7Sderaadt 	/* success */
388*df930be7Sderaadt 	goto out;
389*df930be7Sderaadt 
390*df930be7Sderaadt bad:
391*df930be7Sderaadt 	printf("nfs_boot: bootparam_whoami: bad reply\n");
392*df930be7Sderaadt 	error = EBADRPC;
393*df930be7Sderaadt 
394*df930be7Sderaadt out:
395*df930be7Sderaadt 	if (from)
396*df930be7Sderaadt 		m_freem(from);
397*df930be7Sderaadt 	if (m)
398*df930be7Sderaadt 		m_freem(m);
399*df930be7Sderaadt 	return(error);
400*df930be7Sderaadt }
401*df930be7Sderaadt 
402*df930be7Sderaadt 
403*df930be7Sderaadt /*
404*df930be7Sderaadt  * RPC: bootparam/getfile
405*df930be7Sderaadt  * Given client name and file "key", get:
406*df930be7Sderaadt  *	server name
407*df930be7Sderaadt  *	server IP address
408*df930be7Sderaadt  *	server pathname
409*df930be7Sderaadt  */
410*df930be7Sderaadt static int
411*df930be7Sderaadt bp_getfile(bpsin, key, md_sin, serv_name, pathname)
412*df930be7Sderaadt 	struct sockaddr_in *bpsin;
413*df930be7Sderaadt 	char *key;
414*df930be7Sderaadt 	struct sockaddr_in *md_sin;
415*df930be7Sderaadt 	char *serv_name;
416*df930be7Sderaadt 	char *pathname;
417*df930be7Sderaadt {
418*df930be7Sderaadt 	struct mbuf *m;
419*df930be7Sderaadt 	struct sockaddr_in *sin;
420*df930be7Sderaadt 	struct in_addr inaddr;
421*df930be7Sderaadt 	int error, sn_len, path_len;
422*df930be7Sderaadt 
423*df930be7Sderaadt 	/*
424*df930be7Sderaadt 	 * Build request message.
425*df930be7Sderaadt 	 */
426*df930be7Sderaadt 
427*df930be7Sderaadt 	/* client name (hostname) */
428*df930be7Sderaadt 	m  = xdr_string_encode(hostname, hostnamelen);
429*df930be7Sderaadt 
430*df930be7Sderaadt 	/* key name (root or swap) */
431*df930be7Sderaadt 	m->m_next = xdr_string_encode(key, strlen(key));
432*df930be7Sderaadt 
433*df930be7Sderaadt 	/* RPC: bootparam/getfile */
434*df930be7Sderaadt 	error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
435*df930be7Sderaadt 			BOOTPARAM_GETFILE, &m, NULL);
436*df930be7Sderaadt 	if (error)
437*df930be7Sderaadt 		return error;
438*df930be7Sderaadt 
439*df930be7Sderaadt 	/*
440*df930be7Sderaadt 	 * Parse result message.
441*df930be7Sderaadt 	 */
442*df930be7Sderaadt 
443*df930be7Sderaadt 	/* server name */
444*df930be7Sderaadt 	sn_len = MNAMELEN-1;
445*df930be7Sderaadt 	m = xdr_string_decode(m, serv_name, &sn_len);
446*df930be7Sderaadt 	if (m == NULL)
447*df930be7Sderaadt 		goto bad;
448*df930be7Sderaadt 
449*df930be7Sderaadt 	/* server IP address (mountd/NFS) */
450*df930be7Sderaadt 	m = xdr_inaddr_decode(m, &inaddr);
451*df930be7Sderaadt 	if (m == NULL)
452*df930be7Sderaadt 		goto bad;
453*df930be7Sderaadt 
454*df930be7Sderaadt 	/* server pathname */
455*df930be7Sderaadt 	path_len = MAXPATHLEN-1;
456*df930be7Sderaadt 	m = xdr_string_decode(m, pathname, &path_len);
457*df930be7Sderaadt 	if (m == NULL)
458*df930be7Sderaadt 		goto bad;
459*df930be7Sderaadt 
460*df930be7Sderaadt 	/* setup server socket address */
461*df930be7Sderaadt 	sin = md_sin;
462*df930be7Sderaadt 	bzero((caddr_t)sin, sizeof(*sin));
463*df930be7Sderaadt 	sin->sin_len = sizeof(*sin);
464*df930be7Sderaadt 	sin->sin_family = AF_INET;
465*df930be7Sderaadt 	sin->sin_addr = inaddr;
466*df930be7Sderaadt 
467*df930be7Sderaadt 	/* success */
468*df930be7Sderaadt 	goto out;
469*df930be7Sderaadt 
470*df930be7Sderaadt bad:
471*df930be7Sderaadt 	printf("nfs_boot: bootparam_getfile: bad reply\n");
472*df930be7Sderaadt 	error = EBADRPC;
473*df930be7Sderaadt 
474*df930be7Sderaadt out:
475*df930be7Sderaadt 	m_freem(m);
476*df930be7Sderaadt 	return(0);
477*df930be7Sderaadt }
478*df930be7Sderaadt 
479*df930be7Sderaadt 
480*df930be7Sderaadt /*
481*df930be7Sderaadt  * RPC: mountd/mount
482*df930be7Sderaadt  * Given a server pathname, get an NFS file handle.
483*df930be7Sderaadt  * Also, sets sin->sin_port to the NFS service port.
484*df930be7Sderaadt  */
485*df930be7Sderaadt static int
486*df930be7Sderaadt md_mount(mdsin, path, fhp)
487*df930be7Sderaadt 	struct sockaddr_in *mdsin;		/* mountd server address */
488*df930be7Sderaadt 	char *path;
489*df930be7Sderaadt 	u_char *fhp;
490*df930be7Sderaadt {
491*df930be7Sderaadt 	/* The RPC structures */
492*df930be7Sderaadt 	struct rdata {
493*df930be7Sderaadt 		u_int32_t	errno;
494*df930be7Sderaadt 		u_char	fh[NFS_FHSIZE];
495*df930be7Sderaadt 	} *rdata;
496*df930be7Sderaadt 	struct mbuf *m;
497*df930be7Sderaadt 	int error;
498*df930be7Sderaadt 
499*df930be7Sderaadt 	/* Get port number for MOUNTD. */
500*df930be7Sderaadt 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
501*df930be7Sderaadt 						 &mdsin->sin_port);
502*df930be7Sderaadt 	if (error) return error;
503*df930be7Sderaadt 
504*df930be7Sderaadt 	m = xdr_string_encode(path, strlen(path));
505*df930be7Sderaadt 
506*df930be7Sderaadt 	/* Do RPC to mountd. */
507*df930be7Sderaadt 	error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
508*df930be7Sderaadt 			RPCMNT_MOUNT, &m, NULL);
509*df930be7Sderaadt 	if (error)
510*df930be7Sderaadt 		return error;	/* message already freed */
511*df930be7Sderaadt 
512*df930be7Sderaadt 	if (m->m_len < sizeof(*rdata)) {
513*df930be7Sderaadt 		m = m_pullup(m, sizeof(*rdata));
514*df930be7Sderaadt 		if (m == NULL)
515*df930be7Sderaadt 			goto bad;
516*df930be7Sderaadt 	}
517*df930be7Sderaadt 	rdata = mtod(m, struct rdata *);
518*df930be7Sderaadt 	error = fxdr_unsigned(u_int32_t, rdata->errno);
519*df930be7Sderaadt 	if (error)
520*df930be7Sderaadt 		goto bad;
521*df930be7Sderaadt 	bcopy(rdata->fh, fhp, NFS_FHSIZE);
522*df930be7Sderaadt 
523*df930be7Sderaadt 	/* Set port number for NFS use. */
524*df930be7Sderaadt 	error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2,
525*df930be7Sderaadt 						 &mdsin->sin_port);
526*df930be7Sderaadt 	goto out;
527*df930be7Sderaadt 
528*df930be7Sderaadt bad:
529*df930be7Sderaadt 	error = EBADRPC;
530*df930be7Sderaadt 
531*df930be7Sderaadt out:
532*df930be7Sderaadt 	m_freem(m);
533*df930be7Sderaadt 	return error;
534*df930be7Sderaadt }
535*df930be7Sderaadt 
536*df930be7Sderaadt #endif /* NETHER */
537