]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/nfs/nfs_boot.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_boot.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 <nfs/nfs_conf.h>
96#if CONFIG_NFS_CLIENT
97
98#include <sys/param.h>
99#include <sys/systm.h>
100#include <sys/kernel.h>
101#include <sys/conf.h>
102#include <sys/ioctl.h>
103#include <sys/proc.h>
104#include <sys/mount_internal.h>
105#include <sys/kpi_mbuf.h>
106
107#include <sys/malloc.h>
108#include <sys/socket.h>
109
110#include <net/if.h>
111#include <net/if_dl.h>
112#include <net/if_types.h>
113#include <net/route.h>
114
115#include <netinet/in.h>
116#include <netinet/if_ether.h>
117
118#include <nfs/rpcv2.h>
119#include <nfs/nfsproto.h>
120#include <nfs/nfs.h>
121#include <nfs/nfsdiskless.h>
122#include <nfs/krpc.h>
123
124#include <pexpert/pexpert.h>
125
126#include "ether.h"
127
128#include <libkern/libkern.h>
129
130
131#if NETHER == 0
132
133int
134nfs_boot_init(__unused struct nfs_diskless *nd)
135{
136 panic("nfs_boot_init: no ether");
137}
138
139int
140nfs_boot_getfh(__unused struct nfs_diskless *nd, __unused int v3, __unused int sotype)
141{
142 panic("nfs_boot_getfh: no ether");
143}
144
145#else /* NETHER */
146
147/*
148 * Support for NFS diskless booting, specifically getting information
149 * about where to boot from, what pathnames, etc.
150 *
151 * This implememtation uses RARP and the bootparam RPC.
152 * We are forced to implement RPC anyway (to get file handles)
153 * so we might as well take advantage of it for bootparam too.
154 *
155 * The diskless boot sequence goes as follows:
156 * (1) Use RARP to get our interface address
157 * (2) Use RPC/bootparam/whoami to get our hostname,
158 * our IP address, and the server's IP address.
159 * (3) Use RPC/bootparam/getfile to get the root path
160 * (4) Use RPC/mountd to get the root file handle
161 * (5) Use RPC/bootparam/getfile to get the swap path
162 * (6) Use RPC/mountd to get the swap file handle
163 *
164 * (This happens to be the way Sun does it too.)
165 */
166
167/* bootparam RPC */
168static int bp_whoami(struct sockaddr_in *bpsin,
169 struct in_addr *my_ip, struct in_addr *gw_ip);
170static int bp_getfile(struct sockaddr_in *bpsin, const char *key,
171 struct sockaddr_in *mdsin, char *servname, char *path);
172
173/* mountd RPC */
174static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype,
175 u_char *fhp, u_int32_t *fhlenp);
176
177/* other helpers */
178static int get_file_handle(struct nfs_dlmount *ndmntp);
179
180
181#define IP_FORMAT "%d.%d.%d.%d"
182#define IP_CH(ip) ((u_char *)ip)
183#define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
184
185#include <sys/netboot.h>
186
187/*
188 * Called with an empty nfs_diskless struct to be filled in.
189 */
190int
191nfs_boot_init(struct nfs_diskless *nd)
192{
193 struct sockaddr_in bp_sin;
194 boolean_t do_bpwhoami = TRUE;
195 boolean_t do_bpgetfile = TRUE;
196 int error = 0;
197 struct in_addr my_ip;
198 struct sockaddr_in * sin_p;
199
200 /* make sure mbuf constants are set up */
201 if (!nfs_mbuf_mhlen) {
202 nfs_mbuf_init();
203 }
204
205 /* by this point, networking must already have been configured */
206 if (netboot_iaddr(&my_ip) == FALSE) {
207 printf("nfs_boot: networking is not initialized\n");
208 error = ENXIO;
209 goto failed;
210 }
211
212 /* get the root path information */
213 nd->nd_root.ndm_path = zalloc(ZV_NAMEI);
214 nd->nd_root.ndm_mntfrom = zalloc(ZV_NAMEI);
215
216 sin_p = &nd->nd_root.ndm_saddr;
217 bzero((caddr_t)sin_p, sizeof(*sin_p));
218 sin_p->sin_len = sizeof(*sin_p);
219 sin_p->sin_family = AF_INET;
220 if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host,
221 sizeof(nd->nd_root.ndm_host),
222 nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) {
223 do_bpgetfile = FALSE;
224 do_bpwhoami = FALSE;
225 }
226 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
227
228 if (do_bpwhoami) {
229 struct in_addr router;
230 /*
231 * Get client name and gateway address.
232 * RPC: bootparam/whoami
233 * Use the old broadcast address for the WHOAMI
234 * call because we do not yet know our netmask.
235 * The server address returned by the WHOAMI call
236 * is used for all subsequent booptaram RPCs.
237 */
238 bzero((caddr_t)&bp_sin, sizeof(bp_sin));
239 bp_sin.sin_len = sizeof(bp_sin);
240 bp_sin.sin_family = AF_INET;
241 bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
242 router.s_addr = 0;
243 error = bp_whoami(&bp_sin, &my_ip, &router);
244 if (error) {
245 printf("nfs_boot: bootparam whoami, error=%d", error);
246 goto failed;
247 }
248 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
249 IP_LIST(&bp_sin.sin_addr));
250 lck_mtx_lock(&hostname_lock);
251 printf("nfs_boot: hostname %s\n", hostname);
252 lck_mtx_unlock(&hostname_lock);
253 }
254 if (do_bpgetfile) {
255 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
256 nd->nd_root.ndm_host, nd->nd_root.ndm_path);
257 if (error) {
258 printf("nfs_boot: bootparam get root: %d\n", error);
259 goto failed;
260 }
261 }
262
263#if !defined(NO_MOUNT_PRIVATE)
264 if (do_bpgetfile) { /* get private path */
265 nd->nd_private.ndm_path = zalloc(ZV_NAMEI);
266 nd->nd_private.ndm_mntfrom = zalloc(ZV_NAMEI);
267 error = bp_getfile(&bp_sin, "private",
268 &nd->nd_private.ndm_saddr,
269 nd->nd_private.ndm_host,
270 nd->nd_private.ndm_path);
271 if (!error) {
272 char * check_path = NULL;
273
274 check_path = zalloc(ZV_NAMEI);
275 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path);
276 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
277 == nd->nd_private.ndm_saddr.sin_addr.s_addr)
278 && (strncmp(check_path, nd->nd_private.ndm_path, MAXPATHLEN) == 0)) {
279 /* private path is prefix of root path, don't mount */
280 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
281 }
282 NFS_ZFREE(ZV_NAMEI, check_path);
283 } else {
284 /* private key not defined, don't mount */
285 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
286 }
287 } else {
288 error = 0;
289 }
290#endif /* NO_MOUNT_PRIVATE */
291failed:
292 return error;
293}
294
295/*
296 * Called with a partially initialized nfs_diskless struct
297 * with file handles to be filled in.
298 */
299int
300nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype)
301{
302 int error = 0;
303
304 nd->nd_root.ndm_nfsv3 = v3;
305 nd->nd_root.ndm_sotype = sotype;
306 error = get_file_handle(&nd->nd_root);
307 if (error) {
308 printf("nfs_boot: get_file_handle(v%d) root failed, %d\n",
309 v3 ? 3 : 2, error);
310 goto failed;
311 }
312
313#if !defined(NO_MOUNT_PRIVATE)
314 if (nd->nd_private.ndm_saddr.sin_addr.s_addr) {
315 /* get private file handle */
316 nd->nd_private.ndm_nfsv3 = v3;
317 nd->nd_private.ndm_sotype = sotype;
318 error = get_file_handle(&nd->nd_private);
319 if (error) {
320 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n",
321 v3 ? 3 : 2, error);
322 goto failed;
323 }
324 }
325#endif /* NO_MOUNT_PRIVATE */
326failed:
327 return error;
328}
329
330static int
331get_file_handle(struct nfs_dlmount *ndmntp)
332{
333 char *sp, *dp, *endp;
334 int error;
335
336 /*
337 * Get file handle for "key" (root or swap)
338 * using RPC to mountd/mount
339 */
340 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3,
341 ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen);
342 if (error) {
343 return error;
344 }
345
346 /* Construct remote path (for getmntinfo(3)) */
347 dp = ndmntp->ndm_mntfrom;
348 endp = dp + MAXPATHLEN - 1;
349 for (sp = ndmntp->ndm_host; *sp && dp < endp;) {
350 *dp++ = *sp++;
351 }
352 if (dp < endp) {
353 *dp++ = ':';
354 }
355 for (sp = ndmntp->ndm_path; *sp && dp < endp;) {
356 *dp++ = *sp++;
357 }
358 *dp = '\0';
359 return 0;
360}
361
362
363/*
364 * Get an mbuf with the given length, and
365 * initialize the pkthdr length field.
366 */
367static int
368mbuf_get_with_len(size_t msg_len, mbuf_t *m)
369{
370 int error;
371 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, m);
372 if (error) {
373 return error;
374 }
375 if (msg_len > mbuf_maxlen(*m)) {
376 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, m);
377 if (error) {
378 mbuf_freem(*m);
379 return error;
380 }
381 if (msg_len > mbuf_maxlen(*m)) {
382 panic("nfs_boot: msg_len > MCLBYTES");
383 }
384 }
385 mbuf_setlen(*m, msg_len);
386 mbuf_pkthdr_setlen(*m, msg_len);
387 return 0;
388}
389
390
391/*
392 * String representation for RPC.
393 */
394struct rpc_string {
395 size_t len; /* length without null or padding */
396 u_char data[4]; /* data (longer, of course) */
397 /* data is padded to a long-word boundary */
398};
399/* Compute space used given string length. */
400#define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
401
402/*
403 * Inet address in RPC messages
404 * (Note, really four 32-bit ints, NOT chars. Blech.)
405 */
406struct bp_inaddr {
407 u_int32_t atype;
408 int32_t addr[4];
409};
410
411
412/*
413 * RPC: bootparam/whoami
414 * Given client IP address, get:
415 * client name (hostname)
416 * domain name (domainname)
417 * gateway address
418 *
419 * The hostname and domainname are set here for convenience.
420 *
421 * Note - bpsin is initialized to the broadcast address,
422 * and will be replaced with the bootparam server address
423 * after this call is complete. Have to use PMAP_PROC_CALL
424 * to make sure we get responses only from a servers that
425 * know about us (don't want to broadcast a getport call).
426 */
427static int
428bp_whoami(struct sockaddr_in *bpsin,
429 struct in_addr *my_ip,
430 struct in_addr *gw_ip)
431{
432 /* RPC structures for PMAPPROC_CALLIT */
433 struct whoami_call {
434 u_int32_t call_prog;
435 u_int32_t call_vers;
436 u_int32_t call_proc;
437 u_int32_t call_arglen;
438 struct bp_inaddr call_ia;
439 } *call;
440
441 struct rpc_string *str;
442 struct bp_inaddr *bia;
443 mbuf_t m;
444 struct sockaddr_in sin;
445 int error;
446 size_t msg_len, cn_len, dn_len;
447 u_char *p;
448 int32_t *lp;
449 size_t encapsulated_size;
450
451 /*
452 * Get message buffer of sufficient size.
453 */
454 msg_len = sizeof(*call);
455 error = mbuf_get_with_len(msg_len, &m);
456 if (error) {
457 return error;
458 }
459
460 /*
461 * Build request message for PMAPPROC_CALLIT.
462 */
463 call = mbuf_data(m);
464 call->call_prog = htonl(BOOTPARAM_PROG);
465 call->call_vers = htonl(BOOTPARAM_VERS);
466 call->call_proc = htonl(BOOTPARAM_WHOAMI);
467 call->call_arglen = htonl(sizeof(struct bp_inaddr));
468
469 /* client IP address */
470 call->call_ia.atype = htonl(1);
471 p = (u_char*)my_ip;
472 lp = call->call_ia.addr;
473 *lp++ = htonl(*p); p++;
474 *lp++ = htonl(*p); p++;
475 *lp++ = htonl(*p); p++;
476 *lp++ = htonl(*p); p++;
477
478 /* RPC: portmap/callit */
479 bpsin->sin_port = htons(PMAPPORT);
480
481 error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin);
482 if (error) {
483 return error;
484 }
485
486 /*
487 * Parse result message.
488 */
489 msg_len = mbuf_len(m);
490 lp = mbuf_data(m);
491
492 /* bootparam server port (also grab from address). */
493 if (msg_len < sizeof(*lp)) {
494 goto bad;
495 }
496 msg_len -= sizeof(*lp);
497 bpsin->sin_port = htons((short)ntohl(*lp++));
498 bpsin->sin_addr.s_addr = sin.sin_addr.s_addr;
499
500 /* length of encapsulated results */
501 if (os_add_overflow((size_t) ntohl(*lp), sizeof(*lp), &encapsulated_size)
502 || msg_len < encapsulated_size) {
503 goto bad;
504 }
505 msg_len = ntohl(*lp++);
506 p = (u_char*)lp;
507
508 /* client name */
509 if (msg_len < sizeof(*str)) {
510 goto bad;
511 }
512 str = (struct rpc_string *)p;
513 cn_len = ntohll(str->len);
514 if ((msg_len - 4) < cn_len) {
515 goto bad;
516 }
517 if (cn_len >= MAXHOSTNAMELEN) {
518 goto bad;
519 }
520 lck_mtx_lock(&hostname_lock);
521 bcopy(str->data, hostname, cn_len);
522 hostname[cn_len] = '\0';
523 lck_mtx_unlock(&hostname_lock);
524 p += RPC_STR_SIZE(cn_len);
525 msg_len -= RPC_STR_SIZE(cn_len);
526
527 /* domain name */
528 if (msg_len < sizeof(*str)) {
529 goto bad;
530 }
531 str = (struct rpc_string *)p;
532 dn_len = ntohll(str->len);
533 if ((msg_len - 4) < dn_len) {
534 goto bad;
535 }
536 if (dn_len >= MAXHOSTNAMELEN) {
537 goto bad;
538 }
539 lck_mtx_lock(&domainname_lock);
540 bcopy(str->data, domainname, dn_len);
541 domainname[dn_len] = '\0';
542 lck_mtx_unlock(&domainname_lock);
543 p += RPC_STR_SIZE(dn_len);
544 msg_len -= RPC_STR_SIZE(dn_len);
545
546 /* gateway address */
547 if (msg_len < sizeof(*bia)) {
548 goto bad;
549 }
550 bia = (struct bp_inaddr *)p;
551 if (bia->atype != htonl(1)) {
552 goto bad;
553 }
554 p = (u_char*)gw_ip;
555 *p++ = ntohl(bia->addr[0]) & 0xff;
556 *p++ = ntohl(bia->addr[1]) & 0xff;
557 *p++ = ntohl(bia->addr[2]) & 0xff;
558 *p++ = ntohl(bia->addr[3]) & 0xff;
559 goto out;
560
561bad:
562 printf("nfs_boot: bootparam_whoami: bad reply\n");
563 error = EBADRPC;
564
565out:
566 mbuf_freem(m);
567 return error;
568}
569
570
571/*
572 * RPC: bootparam/getfile
573 * Given client name and file "key", get:
574 * server name
575 * server IP address
576 * server pathname
577 */
578static int
579bp_getfile(struct sockaddr_in *bpsin,
580 const char *key,
581 struct sockaddr_in *md_sin,
582 char *serv_name,
583 char *pathname)
584{
585 struct rpc_string *str;
586 mbuf_t m;
587 struct bp_inaddr *bia;
588 struct sockaddr_in *sin;
589 u_char *p, *q;
590 int error;
591 size_t msg_len, cn_len, key_len, sn_len, path_len;
592
593 /*
594 * Get message buffer of sufficient size.
595 */
596 lck_mtx_lock(&hostname_lock);
597 cn_len = strlen(hostname);
598 lck_mtx_unlock(&hostname_lock);
599 key_len = strlen(key);
600 msg_len = 0;
601 msg_len += RPC_STR_SIZE(cn_len);
602 msg_len += RPC_STR_SIZE(key_len);
603 error = mbuf_get_with_len(msg_len, &m);
604 if (error) {
605 return error;
606 }
607
608 /*
609 * Build request message.
610 */
611 p = mbuf_data(m);
612 bzero(p, msg_len);
613 /* client name (hostname) */
614 str = (struct rpc_string *)p;
615 str->len = htonll(cn_len);
616 lck_mtx_lock(&hostname_lock);
617 bcopy(hostname, str->data, cn_len);
618 lck_mtx_unlock(&hostname_lock);
619 p += RPC_STR_SIZE(cn_len);
620 /* key name (root or swap) */
621 str = (struct rpc_string *)p;
622 str->len = htonll(key_len);
623 bcopy(key, str->data, key_len);
624
625 /* RPC: bootparam/getfile */
626 error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS,
627 BOOTPARAM_GETFILE, &m, NULL);
628 if (error) {
629 return error;
630 }
631
632 /*
633 * Parse result message.
634 */
635 p = mbuf_data(m);
636 msg_len = mbuf_len(m);
637
638 /* server name */
639 if (msg_len < sizeof(*str)) {
640 goto bad;
641 }
642 str = (struct rpc_string *)p;
643 sn_len = ntohll(str->len);
644 if ((msg_len - 4) < sn_len) {
645 goto bad;
646 }
647 if (sn_len >= MAXHOSTNAMELEN) {
648 goto bad;
649 }
650 bcopy(str->data, serv_name, sn_len);
651 serv_name[sn_len] = '\0';
652 p += RPC_STR_SIZE(sn_len);
653 msg_len -= RPC_STR_SIZE(sn_len);
654
655 /* server IP address (mountd) */
656 if (msg_len < sizeof(*bia)) {
657 goto bad;
658 }
659 bia = (struct bp_inaddr *)p;
660 if (bia->atype != htonl(1)) {
661 goto bad;
662 }
663 sin = md_sin;
664 bzero((caddr_t)sin, sizeof(*sin));
665 sin->sin_len = sizeof(*sin);
666 sin->sin_family = AF_INET;
667 q = (u_char*) &sin->sin_addr;
668 *q++ = ntohl(bia->addr[0]) & 0xff;
669 *q++ = ntohl(bia->addr[1]) & 0xff;
670 *q++ = ntohl(bia->addr[2]) & 0xff;
671 *q++ = ntohl(bia->addr[3]) & 0xff;
672 p += sizeof(*bia);
673 msg_len -= sizeof(*bia);
674
675 /* server pathname */
676 if (msg_len < sizeof(*str)) {
677 goto bad;
678 }
679 str = (struct rpc_string *)p;
680 path_len = ntohll(str->len);
681 if ((msg_len - 4) < path_len) {
682 goto bad;
683 }
684 if (path_len >= MAXPATHLEN) {
685 goto bad;
686 }
687 bcopy(str->data, pathname, path_len);
688 pathname[path_len] = '\0';
689 goto out;
690
691bad:
692 printf("nfs_boot: bootparam_getfile: bad reply\n");
693 error = EBADRPC;
694
695out:
696 mbuf_freem(m);
697 return 0;
698}
699
700
701/*
702 * RPC: mountd/mount
703 * Given a server pathname, get an NFS file handle.
704 * Also, sets sin->sin_port to the NFS service port.
705 */
706static int
707md_mount(struct sockaddr_in *mdsin, /* mountd server address */
708 char *path,
709 int v3,
710 int sotype,
711 u_char *fhp,
712 u_int32_t *fhlenp)
713{
714 /* The RPC structures */
715 struct rpc_string *str;
716 struct rdata {
717 u_int32_t errno;
718 u_char data[NFSX_V3FHMAX + sizeof(u_int32_t)];
719 } *rdata;
720 mbuf_t m;
721 size_t mlen, slen;
722 int error;
723 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1;
724 int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP;
725 in_port_t mntport, nfsport;
726
727 /* Get port number for MOUNTD. */
728 error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion, proto, &mntport);
729 if (error) {
730 return error;
731 }
732
733 /* Get port number for NFS use. */
734 /* (If NFS/proto unavailable, don't bother with the mount call) */
735 error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2, proto, &nfsport);
736 if (error) {
737 return error;
738 }
739
740 /* Set port number for MOUNTD */
741 mdsin->sin_port = mntport;
742
743 slen = strlen(path);
744 mlen = RPC_STR_SIZE(slen);
745
746 error = mbuf_get_with_len(mlen, &m);
747 if (error) {
748 return error;
749 }
750 str = mbuf_data(m);
751 str->len = htonll(slen);
752 bcopy(path, str->data, slen);
753
754 /* Do RPC to mountd. */
755 error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL);
756 if (error) {
757 return error; /* message already freed */
758 }
759 /*
760 * the reply must be long enough to hold the errno plus either of:
761 * + a v2 filehandle
762 * + a v3 filehandle length + a v3 filehandle
763 */
764 mlen = mbuf_len(m);
765 if (mlen < sizeof(u_int32_t)) {
766 goto bad;
767 }
768 rdata = mbuf_data(m);
769 error = ntohl(rdata->errno);
770 if (error) {
771 goto out;
772 }
773 if (v3) {
774 u_int32_t fhlen;
775 u_char *fh;
776 if (mlen < sizeof(u_int32_t) * 2) {
777 goto bad;
778 }
779 fhlen = ntohl(*(u_int32_t*)rdata->data);
780 fh = rdata->data + sizeof(u_int32_t);
781 if (mlen < (sizeof(u_int32_t) * 2 + fhlen)
782 || fhlen >= (NFSX_V3FHMAX + sizeof(u_int32_t))) {
783 goto bad;
784 }
785 bcopy(fh, fhp, fhlen);
786 *fhlenp = fhlen;
787 } else {
788 if (mlen < (sizeof(u_int32_t) + NFSX_V2FH)) {
789 goto bad;
790 }
791 bcopy(rdata->data, fhp, NFSX_V2FH);
792 *fhlenp = NFSX_V2FH;
793 }
794
795 /* Set port number for NFS use. */
796 mdsin->sin_port = nfsport;
797 goto out;
798
799bad:
800 error = EBADRPC;
801
802out:
803 mbuf_freem(m);
804 return error;
805}
806
807#endif /* NETHER */
808
809#endif /* CONFIG_NFS_CLIENT */