]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_boot.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_boot.c
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39037602 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39037602 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1994 Adam Glass, Gordon Ross
31 * All rights reserved.
32 *
33 * This software was developed by the Computer Systems Engineering group
34 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
35 * contributed to Berkeley.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Lawrence Berkeley Laboratory and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * History:
66 * 14-March-97 Dieter Siegmund (dieter@next.com)
67 * - Use BOOTP instead of RARP to get the IP address at boot time
68 *
69 * 23-May-97 Umesh Vaishampayan (umeshv@apple.com)
70 * - Added the ability to mount "/private" separately.
71 *
72 * 30-May-97 Dieter Siegmund (dieter@next.com)
73 * - Clear out the ireq structure before using it to prevent
74 * our sending using a bogus source IP address, we should use
75 * an IP address of all zeroes
76 * - Right after BOOTP, get the correct netmask using AUTONETMASK
77 * 18-Jul-97 Dieter Siegmund (dieter@apple.com)
78 * - we can't restrict the netmask until we have a default route,
79 * removed AUTONETMASK call (ifdef'd out)
80 * 5-Aug-97 Dieter Siegmund (dieter@apple.com)
81 * - use the default route from the bpwhoami call, enabled autonetmask
82 * again
83 * 19-Feb-1999 Dieter Siegmund (dieter@apple.com)
84 * - use new BOOTP routine to get the subnet mask and router
85 * and stop using SIOCAUTOADDR
86 * - don't bother mounting private separately if it's not
87 * specified or not required because they are substrings of
88 * one another ie. root=host:/A and private=host:/A/private
89 * - allow the root path to be specified in the boot variable
90 * "rp" (AKA "rootpath")
91 * 19-Jul-1999 Dieter Siegmund (dieter@apple.com)
92 * - replaced big automatic arrays with MALLOC'd data
93 */
94
95#include <sys/param.h>
96#include <sys/systm.h>
97#include <sys/kernel.h>
98#include <sys/conf.h>
99#include <sys/ioctl.h>
100#include <sys/proc.h>
91447636
A
101#include <sys/mount_internal.h>
102#include <sys/kpi_mbuf.h>
1c79356b
A
103
104#include <sys/malloc.h>
105#include <sys/socket.h>
1c79356b
A
106
107#include <net/if.h>
108#include <net/if_dl.h>
109#include <net/if_types.h>
110#include <net/route.h>
111
112#include <netinet/in.h>
113#include <netinet/if_ether.h>
114
115#include <nfs/rpcv2.h>
116#include <nfs/nfsproto.h>
117#include <nfs/nfs.h>
118#include <nfs/nfsdiskless.h>
119#include <nfs/krpc.h>
120
121#include <pexpert/pexpert.h>
122
123#include "ether.h"
124
125#include <libkern/libkern.h>
126
1c79356b
A
127
128#if NETHER == 0
129
0a7de745
A
130int
131nfs_boot_init(__unused struct nfs_diskless *nd)
1c79356b
A
132{
133 panic("nfs_boot_init: no ether");
134}
135
0a7de745
A
136int
137nfs_boot_getfh(__unused struct nfs_diskless *nd, __unused int v3, __unused int sotype)
90556fb8
A
138{
139 panic("nfs_boot_getfh: no ether");
140}
141
1c79356b
A
142#else /* NETHER */
143
144/*
145 * Support for NFS diskless booting, specifically getting information
146 * about where to boot from, what pathnames, etc.
147 *
148 * This implememtation uses RARP and the bootparam RPC.
149 * We are forced to implement RPC anyway (to get file handles)
150 * so we might as well take advantage of it for bootparam too.
151 *
152 * The diskless boot sequence goes as follows:
153 * (1) Use RARP to get our interface address
154 * (2) Use RPC/bootparam/whoami to get our hostname,
155 * our IP address, and the server's IP address.
156 * (3) Use RPC/bootparam/getfile to get the root path
157 * (4) Use RPC/mountd to get the root file handle
158 * (5) Use RPC/bootparam/getfile to get the swap path
159 * (6) Use RPC/mountd to get the swap file handle
160 *
161 * (This happens to be the way Sun does it too.)
162 */
163
1c79356b 164/* bootparam RPC */
91447636 165static int bp_whoami(struct sockaddr_in *bpsin,
0a7de745 166 struct in_addr *my_ip, struct in_addr *gw_ip);
91447636 167static int bp_getfile(struct sockaddr_in *bpsin, const char *key,
0a7de745 168 struct sockaddr_in *mdsin, char *servname, char *path);
1c79356b 169
1c79356b 170/* mountd RPC */
91447636 171static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype,
0a7de745 172 u_char *fhp, u_int32_t *fhlenp);
1c79356b
A
173
174/* other helpers */
91447636 175static int get_file_handle(struct nfs_dlmount *ndmntp);
9bccf70c 176
1c79356b 177
0a7de745
A
178#define IP_FORMAT "%d.%d.%d.%d"
179#define IP_CH(ip) ((u_char *)ip)
180#define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
9bccf70c 181
6d2010ae 182#include <sys/netboot.h>
9bccf70c 183
1c79356b
A
184/*
185 * Called with an empty nfs_diskless struct to be filled in.
186 */
187int
2d21ac55 188nfs_boot_init(struct nfs_diskless *nd)
1c79356b 189{
0a7de745
A
190 struct sockaddr_in bp_sin;
191 boolean_t do_bpwhoami = TRUE;
192 boolean_t do_bpgetfile = TRUE;
193 int error = 0;
194 struct in_addr my_ip;
195 struct sockaddr_in * sin_p;
9bccf70c 196
91447636 197 /* make sure mbuf constants are set up */
0a7de745 198 if (!nfs_mbuf_mhlen) {
91447636 199 nfs_mbuf_init();
0a7de745 200 }
91447636 201
9bccf70c
A
202 /* by this point, networking must already have been configured */
203 if (netboot_iaddr(&my_ip) == FALSE) {
0a7de745
A
204 printf("nfs_boot: networking is not initialized\n");
205 error = ENXIO;
206 goto failed;
9bccf70c 207 }
1c79356b 208
9bccf70c 209 /* get the root path information */
90556fb8 210 MALLOC_ZONE(nd->nd_root.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636 211 if (!nd->nd_root.ndm_path) {
0a7de745
A
212 printf("nfs_boot: can't allocate root path buffer\n");
213 error = ENOMEM;
214 goto failed;
91447636 215 }
b0d623f7
A
216 MALLOC_ZONE(nd->nd_root.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
217 if (!nd->nd_root.ndm_mntfrom) {
0a7de745
A
218 printf("nfs_boot: can't allocate root mntfrom buffer\n");
219 error = ENOMEM;
220 goto failed;
b0d623f7 221 }
9bccf70c
A
222 sin_p = &nd->nd_root.ndm_saddr;
223 bzero((caddr_t)sin_p, sizeof(*sin_p));
224 sin_p->sin_len = sizeof(*sin_p);
225 sin_p->sin_family = AF_INET;
b0d623f7 226 if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host,
0a7de745
A
227 sizeof(nd->nd_root.ndm_host),
228 nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) {
229 do_bpgetfile = FALSE;
230 do_bpwhoami = FALSE;
1c79356b 231 }
9bccf70c 232 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
1c79356b 233
1c79356b 234 if (do_bpwhoami) {
1c79356b 235 struct in_addr router;
9bccf70c
A
236 /*
237 * Get client name and gateway address.
238 * RPC: bootparam/whoami
239 * Use the old broadcast address for the WHOAMI
240 * call because we do not yet know our netmask.
241 * The server address returned by the WHOAMI call
242 * is used for all subsequent booptaram RPCs.
243 */
244 bzero((caddr_t)&bp_sin, sizeof(bp_sin));
245 bp_sin.sin_len = sizeof(bp_sin);
246 bp_sin.sin_family = AF_INET;
247 bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
1c79356b
A
248 router.s_addr = 0;
249 error = bp_whoami(&bp_sin, &my_ip, &router);
250 if (error) {
9bccf70c
A
251 printf("nfs_boot: bootparam whoami, error=%d", error);
252 goto failed;
1c79356b 253 }
0a7de745
A
254 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
255 IP_LIST(&bp_sin.sin_addr));
cb323159 256 lck_mtx_lock(&hostname_lock);
9bccf70c 257 printf("nfs_boot: hostname %s\n", hostname);
cb323159 258 lck_mtx_unlock(&hostname_lock);
1c79356b 259 }
1c79356b 260 if (do_bpgetfile) {
9bccf70c 261 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
0a7de745 262 nd->nd_root.ndm_host, nd->nd_root.ndm_path);
9bccf70c
A
263 if (error) {
264 printf("nfs_boot: bootparam get root: %d\n", error);
265 goto failed;
266 }
267 }
1c79356b 268
0a7de745 269#if !defined(NO_MOUNT_PRIVATE)
1c79356b 270 if (do_bpgetfile) { /* get private path */
90556fb8 271 MALLOC_ZONE(nd->nd_private.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636
A
272 if (!nd->nd_private.ndm_path) {
273 printf("nfs_boot: can't allocate private path buffer\n");
274 error = ENOMEM;
275 goto failed;
276 }
b0d623f7
A
277 MALLOC_ZONE(nd->nd_private.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
278 if (!nd->nd_private.ndm_mntfrom) {
279 printf("nfs_boot: can't allocate private host buffer\n");
280 error = ENOMEM;
281 goto failed;
282 }
0a7de745
A
283 error = bp_getfile(&bp_sin, "private",
284 &nd->nd_private.ndm_saddr,
285 nd->nd_private.ndm_host,
286 nd->nd_private.ndm_path);
9bccf70c
A
287 if (!error) {
288 char * check_path = NULL;
0a7de745 289
90556fb8 290 MALLOC_ZONE(check_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636
A
291 if (!check_path) {
292 printf("nfs_boot: can't allocate check_path buffer\n");
293 error = ENOMEM;
294 goto failed;
295 }
90556fb8 296 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path);
0a7de745
A
297 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
298 == nd->nd_private.ndm_saddr.sin_addr.s_addr)
2d21ac55 299 && (strncmp(check_path, nd->nd_private.ndm_path, MAXPATHLEN) == 0)) {
9bccf70c
A
300 /* private path is prefix of root path, don't mount */
301 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
302 }
90556fb8 303 FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI);
0a7de745 304 } else {
9bccf70c
A
305 /* private key not defined, don't mount */
306 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
1c79356b 307 }
0a7de745 308 } else {
9bccf70c 309 error = 0;
1c79356b 310 }
55e303ae
A
311#endif /* NO_MOUNT_PRIVATE */
312failed:
0a7de745 313 return error;
90556fb8
A
314}
315
316/*
317 * Called with a partially initialized nfs_diskless struct
318 * with file handles to be filled in.
319 */
320int
2d21ac55 321nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype)
90556fb8
A
322{
323 int error = 0;
324
90556fb8 325 nd->nd_root.ndm_nfsv3 = v3;
91447636 326 nd->nd_root.ndm_sotype = sotype;
90556fb8
A
327 error = get_file_handle(&nd->nd_root);
328 if (error) {
329 printf("nfs_boot: get_file_handle(v%d) root failed, %d\n",
0a7de745 330 v3 ? 3 : 2, error);
90556fb8
A
331 goto failed;
332 }
333
0a7de745 334#if !defined(NO_MOUNT_PRIVATE)
90556fb8
A
335 if (nd->nd_private.ndm_saddr.sin_addr.s_addr) {
336 /* get private file handle */
337 nd->nd_private.ndm_nfsv3 = v3;
91447636 338 nd->nd_private.ndm_sotype = sotype;
90556fb8
A
339 error = get_file_handle(&nd->nd_private);
340 if (error) {
341 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n",
0a7de745 342 v3 ? 3 : 2, error);
90556fb8
A
343 goto failed;
344 }
345 }
55e303ae 346#endif /* NO_MOUNT_PRIVATE */
91447636 347failed:
0a7de745 348 return error;
1c79356b
A
349}
350
9bccf70c 351static int
39037602 352get_file_handle(struct nfs_dlmount *ndmntp)
1c79356b
A
353{
354 char *sp, *dp, *endp;
355 int error;
356
357 /*
358 * Get file handle for "key" (root or swap)
359 * using RPC to mountd/mount
360 */
90556fb8 361 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3,
0a7de745
A
362 ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen);
363 if (error) {
364 return error;
365 }
1c79356b
A
366
367 /* Construct remote path (for getmntinfo(3)) */
b0d623f7
A
368 dp = ndmntp->ndm_mntfrom;
369 endp = dp + MAXPATHLEN - 1;
0a7de745 370 for (sp = ndmntp->ndm_host; *sp && dp < endp;) {
b0d623f7 371 *dp++ = *sp++;
0a7de745
A
372 }
373 if (dp < endp) {
b0d623f7 374 *dp++ = ':';
0a7de745
A
375 }
376 for (sp = ndmntp->ndm_path; *sp && dp < endp;) {
1c79356b 377 *dp++ = *sp++;
0a7de745 378 }
1c79356b 379 *dp = '\0';
0a7de745 380 return 0;
1c79356b
A
381}
382
383
384/*
385 * Get an mbuf with the given length, and
386 * initialize the pkthdr length field.
387 */
91447636 388static int
2d21ac55 389mbuf_get_with_len(size_t msg_len, mbuf_t *m)
1c79356b 390{
91447636
A
391 int error;
392 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, m);
0a7de745
A
393 if (error) {
394 return error;
395 }
91447636
A
396 if (msg_len > mbuf_maxlen(*m)) {
397 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, m);
398 if (error) {
399 mbuf_freem(*m);
0a7de745 400 return error;
91447636 401 }
0a7de745 402 if (msg_len > mbuf_maxlen(*m)) {
1c79356b 403 panic("nfs_boot: msg_len > MCLBYTES");
0a7de745 404 }
1c79356b 405 }
91447636
A
406 mbuf_setlen(*m, msg_len);
407 mbuf_pkthdr_setlen(*m, msg_len);
0a7de745 408 return 0;
1c79356b
A
409}
410
411
412/*
413 * String representation for RPC.
414 */
415struct rpc_string {
0a7de745
A
416 u_int32_t len; /* length without null or padding */
417 u_char data[4]; /* data (longer, of course) */
418 /* data is padded to a long-word boundary */
1c79356b
A
419};
420/* Compute space used given string length. */
0a7de745 421#define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
1c79356b
A
422
423/*
424 * Inet address in RPC messages
b0d623f7 425 * (Note, really four 32-bit ints, NOT chars. Blech.)
1c79356b
A
426 */
427struct bp_inaddr {
b0d623f7 428 u_int32_t atype;
0a7de745 429 int32_t addr[4];
1c79356b
A
430};
431
432
433/*
434 * RPC: bootparam/whoami
435 * Given client IP address, get:
436 * client name (hostname)
437 * domain name (domainname)
438 * gateway address
439 *
440 * The hostname and domainname are set here for convenience.
441 *
442 * Note - bpsin is initialized to the broadcast address,
443 * and will be replaced with the bootparam server address
444 * after this call is complete. Have to use PMAP_PROC_CALL
445 * to make sure we get responses only from a servers that
446 * know about us (don't want to broadcast a getport call).
447 */
448static int
39037602 449bp_whoami(struct sockaddr_in *bpsin,
0a7de745
A
450 struct in_addr *my_ip,
451 struct in_addr *gw_ip)
1c79356b
A
452{
453 /* RPC structures for PMAPPROC_CALLIT */
454 struct whoami_call {
b0d623f7
A
455 u_int32_t call_prog;
456 u_int32_t call_vers;
457 u_int32_t call_proc;
458 u_int32_t call_arglen;
1c79356b
A
459 struct bp_inaddr call_ia;
460 } *call;
461
462 struct rpc_string *str;
463 struct bp_inaddr *bia;
91447636
A
464 mbuf_t m;
465 struct sockaddr_in sin;
2d21ac55
A
466 int error;
467 size_t msg_len, cn_len, dn_len;
1c79356b 468 u_char *p;
b0d623f7 469 int32_t *lp;
0a7de745 470 size_t encapsulated_size;
1c79356b
A
471
472 /*
473 * Get message buffer of sufficient size.
474 */
475 msg_len = sizeof(*call);
91447636 476 error = mbuf_get_with_len(msg_len, &m);
0a7de745 477 if (error) {
91447636 478 return error;
0a7de745 479 }
1c79356b
A
480
481 /*
482 * Build request message for PMAPPROC_CALLIT.
483 */
91447636 484 call = mbuf_data(m);
1c79356b
A
485 call->call_prog = htonl(BOOTPARAM_PROG);
486 call->call_vers = htonl(BOOTPARAM_VERS);
487 call->call_proc = htonl(BOOTPARAM_WHOAMI);
488 call->call_arglen = htonl(sizeof(struct bp_inaddr));
489
490 /* client IP address */
491 call->call_ia.atype = htonl(1);
492 p = (u_char*)my_ip;
493 lp = call->call_ia.addr;
0a7de745
A
494 *lp++ = htonl(*p); p++;
495 *lp++ = htonl(*p); p++;
496 *lp++ = htonl(*p); p++;
497 *lp++ = htonl(*p); p++;
1c79356b
A
498
499 /* RPC: portmap/callit */
500 bpsin->sin_port = htons(PMAPPORT);
501
91447636 502 error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin);
0a7de745 503 if (error) {
1c79356b 504 return error;
0a7de745 505 }
1c79356b
A
506
507 /*
508 * Parse result message.
509 */
91447636
A
510 msg_len = mbuf_len(m);
511 lp = mbuf_data(m);
1c79356b
A
512
513 /* bootparam server port (also grab from address). */
0a7de745 514 if (msg_len < sizeof(*lp)) {
1c79356b 515 goto bad;
0a7de745 516 }
1c79356b
A
517 msg_len -= sizeof(*lp);
518 bpsin->sin_port = htons((short)ntohl(*lp++));
91447636 519 bpsin->sin_addr.s_addr = sin.sin_addr.s_addr;
1c79356b
A
520
521 /* length of encapsulated results */
a39ff7e2 522 if (os_add_overflow((size_t) ntohl(*lp), sizeof(*lp), &encapsulated_size)
0a7de745 523 || msg_len < encapsulated_size) {
1c79356b 524 goto bad;
a39ff7e2 525 }
1c79356b 526 msg_len = ntohl(*lp++);
2d21ac55 527 p = (u_char*)lp;
1c79356b
A
528
529 /* client name */
0a7de745 530 if (msg_len < sizeof(*str)) {
1c79356b 531 goto bad;
0a7de745 532 }
1c79356b
A
533 str = (struct rpc_string *)p;
534 cn_len = ntohl(str->len);
0a7de745 535 if ((msg_len - 4) < cn_len) {
1c79356b 536 goto bad;
0a7de745
A
537 }
538 if (cn_len >= MAXHOSTNAMELEN) {
1c79356b 539 goto bad;
0a7de745 540 }
cb323159 541 lck_mtx_lock(&hostname_lock);
1c79356b
A
542 bcopy(str->data, hostname, cn_len);
543 hostname[cn_len] = '\0';
cb323159 544 lck_mtx_unlock(&hostname_lock);
1c79356b
A
545 p += RPC_STR_SIZE(cn_len);
546 msg_len -= RPC_STR_SIZE(cn_len);
547
548 /* domain name */
0a7de745 549 if (msg_len < sizeof(*str)) {
1c79356b 550 goto bad;
0a7de745 551 }
1c79356b
A
552 str = (struct rpc_string *)p;
553 dn_len = ntohl(str->len);
0a7de745 554 if ((msg_len - 4) < dn_len) {
1c79356b 555 goto bad;
0a7de745
A
556 }
557 if (dn_len >= MAXHOSTNAMELEN) {
1c79356b 558 goto bad;
0a7de745 559 }
cb323159 560 lck_mtx_lock(&domainname_lock);
1c79356b
A
561 bcopy(str->data, domainname, dn_len);
562 domainname[dn_len] = '\0';
cb323159 563 lck_mtx_unlock(&domainname_lock);
1c79356b
A
564 p += RPC_STR_SIZE(dn_len);
565 msg_len -= RPC_STR_SIZE(dn_len);
566
567 /* gateway address */
0a7de745 568 if (msg_len < sizeof(*bia)) {
1c79356b 569 goto bad;
0a7de745 570 }
1c79356b 571 bia = (struct bp_inaddr *)p;
0a7de745 572 if (bia->atype != htonl(1)) {
1c79356b 573 goto bad;
0a7de745 574 }
1c79356b
A
575 p = (u_char*)gw_ip;
576 *p++ = ntohl(bia->addr[0]);
577 *p++ = ntohl(bia->addr[1]);
578 *p++ = ntohl(bia->addr[2]);
579 *p++ = ntohl(bia->addr[3]);
580 goto out;
581
582bad:
583 printf("nfs_boot: bootparam_whoami: bad reply\n");
584 error = EBADRPC;
585
586out:
91447636 587 mbuf_freem(m);
0a7de745 588 return error;
1c79356b
A
589}
590
591
592/*
593 * RPC: bootparam/getfile
594 * Given client name and file "key", get:
595 * server name
596 * server IP address
597 * server pathname
598 */
599static int
39037602 600bp_getfile(struct sockaddr_in *bpsin,
0a7de745
A
601 const char *key,
602 struct sockaddr_in *md_sin,
603 char *serv_name,
604 char *pathname)
1c79356b
A
605{
606 struct rpc_string *str;
91447636 607 mbuf_t m;
1c79356b
A
608 struct bp_inaddr *bia;
609 struct sockaddr_in *sin;
610 u_char *p, *q;
a39ff7e2
A
611 int error;
612 size_t msg_len, cn_len, key_len, sn_len, path_len;
1c79356b
A
613
614 /*
615 * Get message buffer of sufficient size.
616 */
cb323159
A
617 lck_mtx_lock(&hostname_lock);
618 cn_len = strlen(hostname);
619 lck_mtx_unlock(&hostname_lock);
1c79356b
A
620 key_len = strlen(key);
621 msg_len = 0;
622 msg_len += RPC_STR_SIZE(cn_len);
623 msg_len += RPC_STR_SIZE(key_len);
91447636 624 error = mbuf_get_with_len(msg_len, &m);
0a7de745 625 if (error) {
91447636 626 return error;
0a7de745 627 }
1c79356b
A
628
629 /*
630 * Build request message.
631 */
91447636 632 p = mbuf_data(m);
1c79356b
A
633 bzero(p, msg_len);
634 /* client name (hostname) */
635 str = (struct rpc_string *)p;
636 str->len = htonl(cn_len);
cb323159 637 lck_mtx_lock(&hostname_lock);
1c79356b 638 bcopy(hostname, str->data, cn_len);
cb323159 639 lck_mtx_unlock(&hostname_lock);
1c79356b
A
640 p += RPC_STR_SIZE(cn_len);
641 /* key name (root or swap) */
642 str = (struct rpc_string *)p;
643 str->len = htonl(key_len);
644 bcopy(key, str->data, key_len);
645
646 /* RPC: bootparam/getfile */
91447636 647 error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS,
0a7de745
A
648 BOOTPARAM_GETFILE, &m, NULL);
649 if (error) {
1c79356b 650 return error;
0a7de745 651 }
1c79356b
A
652
653 /*
654 * Parse result message.
655 */
91447636
A
656 p = mbuf_data(m);
657 msg_len = mbuf_len(m);
1c79356b
A
658
659 /* server name */
0a7de745 660 if (msg_len < sizeof(*str)) {
1c79356b 661 goto bad;
0a7de745 662 }
1c79356b
A
663 str = (struct rpc_string *)p;
664 sn_len = ntohl(str->len);
0a7de745 665 if ((msg_len - 4) < sn_len) {
1c79356b 666 goto bad;
0a7de745
A
667 }
668 if (sn_len >= MAXHOSTNAMELEN) {
1c79356b 669 goto bad;
0a7de745 670 }
1c79356b
A
671 bcopy(str->data, serv_name, sn_len);
672 serv_name[sn_len] = '\0';
673 p += RPC_STR_SIZE(sn_len);
674 msg_len -= RPC_STR_SIZE(sn_len);
675
676 /* server IP address (mountd) */
0a7de745 677 if (msg_len < sizeof(*bia)) {
1c79356b 678 goto bad;
0a7de745 679 }
1c79356b 680 bia = (struct bp_inaddr *)p;
0a7de745 681 if (bia->atype != htonl(1)) {
1c79356b 682 goto bad;
0a7de745 683 }
1c79356b
A
684 sin = md_sin;
685 bzero((caddr_t)sin, sizeof(*sin));
686 sin->sin_len = sizeof(*sin);
687 sin->sin_family = AF_INET;
688 q = (u_char*) &sin->sin_addr;
689 *q++ = ntohl(bia->addr[0]);
690 *q++ = ntohl(bia->addr[1]);
691 *q++ = ntohl(bia->addr[2]);
692 *q++ = ntohl(bia->addr[3]);
693 p += sizeof(*bia);
694 msg_len -= sizeof(*bia);
695
696 /* server pathname */
0a7de745 697 if (msg_len < sizeof(*str)) {
1c79356b 698 goto bad;
0a7de745 699 }
1c79356b
A
700 str = (struct rpc_string *)p;
701 path_len = ntohl(str->len);
0a7de745 702 if ((msg_len - 4) < path_len) {
1c79356b 703 goto bad;
0a7de745
A
704 }
705 if (path_len >= MAXPATHLEN) {
1c79356b 706 goto bad;
0a7de745 707 }
1c79356b
A
708 bcopy(str->data, pathname, path_len);
709 pathname[path_len] = '\0';
710 goto out;
711
712bad:
713 printf("nfs_boot: bootparam_getfile: bad reply\n");
714 error = EBADRPC;
715
716out:
91447636 717 mbuf_freem(m);
0a7de745 718 return 0;
1c79356b
A
719}
720
721
722/*
723 * RPC: mountd/mount
724 * Given a server pathname, get an NFS file handle.
725 * Also, sets sin->sin_port to the NFS service port.
726 */
727static int
0a7de745
A
728md_mount(struct sockaddr_in *mdsin, /* mountd server address */
729 char *path,
730 int v3,
731 int sotype,
732 u_char *fhp,
733 u_int32_t *fhlenp)
1c79356b
A
734{
735 /* The RPC structures */
736 struct rpc_string *str;
737 struct rdata {
0a7de745
A
738 u_int32_t errno;
739 u_char data[NFSX_V3FHMAX + sizeof(u_int32_t)];
1c79356b 740 } *rdata;
91447636 741 mbuf_t m;
a39ff7e2
A
742 size_t mlen;
743 int error, slen;
90556fb8 744 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1;
91447636
A
745 int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP;
746 in_port_t mntport, nfsport;
1c79356b
A
747
748 /* Get port number for MOUNTD. */
91447636 749 error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion, proto, &mntport);
0a7de745 750 if (error) {
91447636 751 return error;
0a7de745 752 }
91447636
A
753
754 /* Get port number for NFS use. */
755 /* (If NFS/proto unavailable, don't bother with the mount call) */
756 error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2, proto, &nfsport);
0a7de745 757 if (error) {
91447636 758 return error;
0a7de745 759 }
91447636
A
760
761 /* Set port number for MOUNTD */
762 mdsin->sin_port = mntport;
1c79356b
A
763
764 slen = strlen(path);
765 mlen = RPC_STR_SIZE(slen);
766
91447636 767 error = mbuf_get_with_len(mlen, &m);
0a7de745 768 if (error) {
91447636 769 return error;
0a7de745 770 }
91447636 771 str = mbuf_data(m);
1c79356b
A
772 str->len = htonl(slen);
773 bcopy(path, str->data, slen);
774
775 /* Do RPC to mountd. */
91447636 776 error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL);
0a7de745
A
777 if (error) {
778 return error; /* message already freed */
779 }
90556fb8
A
780 /*
781 * the reply must be long enough to hold the errno plus either of:
782 * + a v2 filehandle
783 * + a v3 filehandle length + a v3 filehandle
784 */
91447636 785 mlen = mbuf_len(m);
0a7de745 786 if (mlen < sizeof(u_int32_t)) {
1c79356b 787 goto bad;
0a7de745 788 }
91447636 789 rdata = mbuf_data(m);
1c79356b 790 error = ntohl(rdata->errno);
0a7de745 791 if (error) {
90556fb8 792 goto out;
0a7de745 793 }
90556fb8 794 if (v3) {
b0d623f7 795 u_int32_t fhlen;
90556fb8 796 u_char *fh;
0a7de745 797 if (mlen < sizeof(u_int32_t) * 2) {
90556fb8 798 goto bad;
0a7de745 799 }
b0d623f7
A
800 fhlen = ntohl(*(u_int32_t*)rdata->data);
801 fh = rdata->data + sizeof(u_int32_t);
0a7de745
A
802 if (mlen < (sizeof(u_int32_t) * 2 + fhlen)
803 || fhlen >= (NFSX_V3FHMAX + sizeof(u_int32_t))) {
90556fb8 804 goto bad;
0a7de745 805 }
90556fb8
A
806 bcopy(fh, fhp, fhlen);
807 *fhlenp = fhlen;
808 } else {
0a7de745 809 if (mlen < (sizeof(u_int32_t) + NFSX_V2FH)) {
90556fb8 810 goto bad;
0a7de745 811 }
90556fb8
A
812 bcopy(rdata->data, fhp, NFSX_V2FH);
813 *fhlenp = NFSX_V2FH;
814 }
1c79356b
A
815
816 /* Set port number for NFS use. */
91447636 817 mdsin->sin_port = nfsport;
1c79356b
A
818 goto out;
819
820bad:
821 error = EBADRPC;
822
823out:
91447636 824 mbuf_freem(m);
1c79356b
A
825 return error;
826}
827
828#endif /* NETHER */