]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_boot.c
xnu-6153.101.6.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_boot.c
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
133 int
134 nfs_boot_init(__unused struct nfs_diskless *nd)
135 {
136 panic("nfs_boot_init: no ether");
137 }
138
139 int
140 nfs_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 */
168 static int bp_whoami(struct sockaddr_in *bpsin,
169 struct in_addr *my_ip, struct in_addr *gw_ip);
170 static int bp_getfile(struct sockaddr_in *bpsin, const char *key,
171 struct sockaddr_in *mdsin, char *servname, char *path);
172
173 /* mountd RPC */
174 static 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 */
178 static 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 */
190 int
191 nfs_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 MALLOC_ZONE(nd->nd_root.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
214 if (!nd->nd_root.ndm_path) {
215 printf("nfs_boot: can't allocate root path buffer\n");
216 error = ENOMEM;
217 goto failed;
218 }
219 MALLOC_ZONE(nd->nd_root.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
220 if (!nd->nd_root.ndm_mntfrom) {
221 printf("nfs_boot: can't allocate root mntfrom buffer\n");
222 error = ENOMEM;
223 goto failed;
224 }
225 sin_p = &nd->nd_root.ndm_saddr;
226 bzero((caddr_t)sin_p, sizeof(*sin_p));
227 sin_p->sin_len = sizeof(*sin_p);
228 sin_p->sin_family = AF_INET;
229 if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host,
230 sizeof(nd->nd_root.ndm_host),
231 nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) {
232 do_bpgetfile = FALSE;
233 do_bpwhoami = FALSE;
234 }
235 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
236
237 if (do_bpwhoami) {
238 struct in_addr router;
239 /*
240 * Get client name and gateway address.
241 * RPC: bootparam/whoami
242 * Use the old broadcast address for the WHOAMI
243 * call because we do not yet know our netmask.
244 * The server address returned by the WHOAMI call
245 * is used for all subsequent booptaram RPCs.
246 */
247 bzero((caddr_t)&bp_sin, sizeof(bp_sin));
248 bp_sin.sin_len = sizeof(bp_sin);
249 bp_sin.sin_family = AF_INET;
250 bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
251 router.s_addr = 0;
252 error = bp_whoami(&bp_sin, &my_ip, &router);
253 if (error) {
254 printf("nfs_boot: bootparam whoami, error=%d", error);
255 goto failed;
256 }
257 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
258 IP_LIST(&bp_sin.sin_addr));
259 lck_mtx_lock(&hostname_lock);
260 printf("nfs_boot: hostname %s\n", hostname);
261 lck_mtx_unlock(&hostname_lock);
262 }
263 if (do_bpgetfile) {
264 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
265 nd->nd_root.ndm_host, nd->nd_root.ndm_path);
266 if (error) {
267 printf("nfs_boot: bootparam get root: %d\n", error);
268 goto failed;
269 }
270 }
271
272 #if !defined(NO_MOUNT_PRIVATE)
273 if (do_bpgetfile) { /* get private path */
274 MALLOC_ZONE(nd->nd_private.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
275 if (!nd->nd_private.ndm_path) {
276 printf("nfs_boot: can't allocate private path buffer\n");
277 error = ENOMEM;
278 goto failed;
279 }
280 MALLOC_ZONE(nd->nd_private.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
281 if (!nd->nd_private.ndm_mntfrom) {
282 printf("nfs_boot: can't allocate private host buffer\n");
283 error = ENOMEM;
284 goto failed;
285 }
286 error = bp_getfile(&bp_sin, "private",
287 &nd->nd_private.ndm_saddr,
288 nd->nd_private.ndm_host,
289 nd->nd_private.ndm_path);
290 if (!error) {
291 char * check_path = NULL;
292
293 MALLOC_ZONE(check_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
294 if (!check_path) {
295 printf("nfs_boot: can't allocate check_path buffer\n");
296 error = ENOMEM;
297 goto failed;
298 }
299 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path);
300 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
301 == nd->nd_private.ndm_saddr.sin_addr.s_addr)
302 && (strncmp(check_path, nd->nd_private.ndm_path, MAXPATHLEN) == 0)) {
303 /* private path is prefix of root path, don't mount */
304 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
305 }
306 FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI);
307 } else {
308 /* private key not defined, don't mount */
309 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
310 }
311 } else {
312 error = 0;
313 }
314 #endif /* NO_MOUNT_PRIVATE */
315 failed:
316 return error;
317 }
318
319 /*
320 * Called with a partially initialized nfs_diskless struct
321 * with file handles to be filled in.
322 */
323 int
324 nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype)
325 {
326 int error = 0;
327
328 nd->nd_root.ndm_nfsv3 = v3;
329 nd->nd_root.ndm_sotype = sotype;
330 error = get_file_handle(&nd->nd_root);
331 if (error) {
332 printf("nfs_boot: get_file_handle(v%d) root failed, %d\n",
333 v3 ? 3 : 2, error);
334 goto failed;
335 }
336
337 #if !defined(NO_MOUNT_PRIVATE)
338 if (nd->nd_private.ndm_saddr.sin_addr.s_addr) {
339 /* get private file handle */
340 nd->nd_private.ndm_nfsv3 = v3;
341 nd->nd_private.ndm_sotype = sotype;
342 error = get_file_handle(&nd->nd_private);
343 if (error) {
344 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n",
345 v3 ? 3 : 2, error);
346 goto failed;
347 }
348 }
349 #endif /* NO_MOUNT_PRIVATE */
350 failed:
351 return error;
352 }
353
354 static int
355 get_file_handle(struct nfs_dlmount *ndmntp)
356 {
357 char *sp, *dp, *endp;
358 int error;
359
360 /*
361 * Get file handle for "key" (root or swap)
362 * using RPC to mountd/mount
363 */
364 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3,
365 ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen);
366 if (error) {
367 return error;
368 }
369
370 /* Construct remote path (for getmntinfo(3)) */
371 dp = ndmntp->ndm_mntfrom;
372 endp = dp + MAXPATHLEN - 1;
373 for (sp = ndmntp->ndm_host; *sp && dp < endp;) {
374 *dp++ = *sp++;
375 }
376 if (dp < endp) {
377 *dp++ = ':';
378 }
379 for (sp = ndmntp->ndm_path; *sp && dp < endp;) {
380 *dp++ = *sp++;
381 }
382 *dp = '\0';
383 return 0;
384 }
385
386
387 /*
388 * Get an mbuf with the given length, and
389 * initialize the pkthdr length field.
390 */
391 static int
392 mbuf_get_with_len(size_t msg_len, mbuf_t *m)
393 {
394 int error;
395 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, m);
396 if (error) {
397 return error;
398 }
399 if (msg_len > mbuf_maxlen(*m)) {
400 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, m);
401 if (error) {
402 mbuf_freem(*m);
403 return error;
404 }
405 if (msg_len > mbuf_maxlen(*m)) {
406 panic("nfs_boot: msg_len > MCLBYTES");
407 }
408 }
409 mbuf_setlen(*m, msg_len);
410 mbuf_pkthdr_setlen(*m, msg_len);
411 return 0;
412 }
413
414
415 /*
416 * String representation for RPC.
417 */
418 struct rpc_string {
419 u_int32_t len; /* length without null or padding */
420 u_char data[4]; /* data (longer, of course) */
421 /* data is padded to a long-word boundary */
422 };
423 /* Compute space used given string length. */
424 #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
425
426 /*
427 * Inet address in RPC messages
428 * (Note, really four 32-bit ints, NOT chars. Blech.)
429 */
430 struct bp_inaddr {
431 u_int32_t atype;
432 int32_t addr[4];
433 };
434
435
436 /*
437 * RPC: bootparam/whoami
438 * Given client IP address, get:
439 * client name (hostname)
440 * domain name (domainname)
441 * gateway address
442 *
443 * The hostname and domainname are set here for convenience.
444 *
445 * Note - bpsin is initialized to the broadcast address,
446 * and will be replaced with the bootparam server address
447 * after this call is complete. Have to use PMAP_PROC_CALL
448 * to make sure we get responses only from a servers that
449 * know about us (don't want to broadcast a getport call).
450 */
451 static int
452 bp_whoami(struct sockaddr_in *bpsin,
453 struct in_addr *my_ip,
454 struct in_addr *gw_ip)
455 {
456 /* RPC structures for PMAPPROC_CALLIT */
457 struct whoami_call {
458 u_int32_t call_prog;
459 u_int32_t call_vers;
460 u_int32_t call_proc;
461 u_int32_t call_arglen;
462 struct bp_inaddr call_ia;
463 } *call;
464
465 struct rpc_string *str;
466 struct bp_inaddr *bia;
467 mbuf_t m;
468 struct sockaddr_in sin;
469 int error;
470 size_t msg_len, cn_len, dn_len;
471 u_char *p;
472 int32_t *lp;
473 size_t encapsulated_size;
474
475 /*
476 * Get message buffer of sufficient size.
477 */
478 msg_len = sizeof(*call);
479 error = mbuf_get_with_len(msg_len, &m);
480 if (error) {
481 return error;
482 }
483
484 /*
485 * Build request message for PMAPPROC_CALLIT.
486 */
487 call = mbuf_data(m);
488 call->call_prog = htonl(BOOTPARAM_PROG);
489 call->call_vers = htonl(BOOTPARAM_VERS);
490 call->call_proc = htonl(BOOTPARAM_WHOAMI);
491 call->call_arglen = htonl(sizeof(struct bp_inaddr));
492
493 /* client IP address */
494 call->call_ia.atype = htonl(1);
495 p = (u_char*)my_ip;
496 lp = call->call_ia.addr;
497 *lp++ = htonl(*p); p++;
498 *lp++ = htonl(*p); p++;
499 *lp++ = htonl(*p); p++;
500 *lp++ = htonl(*p); p++;
501
502 /* RPC: portmap/callit */
503 bpsin->sin_port = htons(PMAPPORT);
504
505 error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin);
506 if (error) {
507 return error;
508 }
509
510 /*
511 * Parse result message.
512 */
513 msg_len = mbuf_len(m);
514 lp = mbuf_data(m);
515
516 /* bootparam server port (also grab from address). */
517 if (msg_len < sizeof(*lp)) {
518 goto bad;
519 }
520 msg_len -= sizeof(*lp);
521 bpsin->sin_port = htons((short)ntohl(*lp++));
522 bpsin->sin_addr.s_addr = sin.sin_addr.s_addr;
523
524 /* length of encapsulated results */
525 if (os_add_overflow((size_t) ntohl(*lp), sizeof(*lp), &encapsulated_size)
526 || msg_len < encapsulated_size) {
527 goto bad;
528 }
529 msg_len = ntohl(*lp++);
530 p = (u_char*)lp;
531
532 /* client name */
533 if (msg_len < sizeof(*str)) {
534 goto bad;
535 }
536 str = (struct rpc_string *)p;
537 cn_len = ntohl(str->len);
538 if ((msg_len - 4) < cn_len) {
539 goto bad;
540 }
541 if (cn_len >= MAXHOSTNAMELEN) {
542 goto bad;
543 }
544 lck_mtx_lock(&hostname_lock);
545 bcopy(str->data, hostname, cn_len);
546 hostname[cn_len] = '\0';
547 lck_mtx_unlock(&hostname_lock);
548 p += RPC_STR_SIZE(cn_len);
549 msg_len -= RPC_STR_SIZE(cn_len);
550
551 /* domain name */
552 if (msg_len < sizeof(*str)) {
553 goto bad;
554 }
555 str = (struct rpc_string *)p;
556 dn_len = ntohl(str->len);
557 if ((msg_len - 4) < dn_len) {
558 goto bad;
559 }
560 if (dn_len >= MAXHOSTNAMELEN) {
561 goto bad;
562 }
563 lck_mtx_lock(&domainname_lock);
564 bcopy(str->data, domainname, dn_len);
565 domainname[dn_len] = '\0';
566 lck_mtx_unlock(&domainname_lock);
567 p += RPC_STR_SIZE(dn_len);
568 msg_len -= RPC_STR_SIZE(dn_len);
569
570 /* gateway address */
571 if (msg_len < sizeof(*bia)) {
572 goto bad;
573 }
574 bia = (struct bp_inaddr *)p;
575 if (bia->atype != htonl(1)) {
576 goto bad;
577 }
578 p = (u_char*)gw_ip;
579 *p++ = ntohl(bia->addr[0]);
580 *p++ = ntohl(bia->addr[1]);
581 *p++ = ntohl(bia->addr[2]);
582 *p++ = ntohl(bia->addr[3]);
583 goto out;
584
585 bad:
586 printf("nfs_boot: bootparam_whoami: bad reply\n");
587 error = EBADRPC;
588
589 out:
590 mbuf_freem(m);
591 return error;
592 }
593
594
595 /*
596 * RPC: bootparam/getfile
597 * Given client name and file "key", get:
598 * server name
599 * server IP address
600 * server pathname
601 */
602 static int
603 bp_getfile(struct sockaddr_in *bpsin,
604 const char *key,
605 struct sockaddr_in *md_sin,
606 char *serv_name,
607 char *pathname)
608 {
609 struct rpc_string *str;
610 mbuf_t m;
611 struct bp_inaddr *bia;
612 struct sockaddr_in *sin;
613 u_char *p, *q;
614 int error;
615 size_t msg_len, cn_len, key_len, sn_len, path_len;
616
617 /*
618 * Get message buffer of sufficient size.
619 */
620 lck_mtx_lock(&hostname_lock);
621 cn_len = strlen(hostname);
622 lck_mtx_unlock(&hostname_lock);
623 key_len = strlen(key);
624 msg_len = 0;
625 msg_len += RPC_STR_SIZE(cn_len);
626 msg_len += RPC_STR_SIZE(key_len);
627 error = mbuf_get_with_len(msg_len, &m);
628 if (error) {
629 return error;
630 }
631
632 /*
633 * Build request message.
634 */
635 p = mbuf_data(m);
636 bzero(p, msg_len);
637 /* client name (hostname) */
638 str = (struct rpc_string *)p;
639 str->len = htonl(cn_len);
640 lck_mtx_lock(&hostname_lock);
641 bcopy(hostname, str->data, cn_len);
642 lck_mtx_unlock(&hostname_lock);
643 p += RPC_STR_SIZE(cn_len);
644 /* key name (root or swap) */
645 str = (struct rpc_string *)p;
646 str->len = htonl(key_len);
647 bcopy(key, str->data, key_len);
648
649 /* RPC: bootparam/getfile */
650 error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS,
651 BOOTPARAM_GETFILE, &m, NULL);
652 if (error) {
653 return error;
654 }
655
656 /*
657 * Parse result message.
658 */
659 p = mbuf_data(m);
660 msg_len = mbuf_len(m);
661
662 /* server name */
663 if (msg_len < sizeof(*str)) {
664 goto bad;
665 }
666 str = (struct rpc_string *)p;
667 sn_len = ntohl(str->len);
668 if ((msg_len - 4) < sn_len) {
669 goto bad;
670 }
671 if (sn_len >= MAXHOSTNAMELEN) {
672 goto bad;
673 }
674 bcopy(str->data, serv_name, sn_len);
675 serv_name[sn_len] = '\0';
676 p += RPC_STR_SIZE(sn_len);
677 msg_len -= RPC_STR_SIZE(sn_len);
678
679 /* server IP address (mountd) */
680 if (msg_len < sizeof(*bia)) {
681 goto bad;
682 }
683 bia = (struct bp_inaddr *)p;
684 if (bia->atype != htonl(1)) {
685 goto bad;
686 }
687 sin = md_sin;
688 bzero((caddr_t)sin, sizeof(*sin));
689 sin->sin_len = sizeof(*sin);
690 sin->sin_family = AF_INET;
691 q = (u_char*) &sin->sin_addr;
692 *q++ = ntohl(bia->addr[0]);
693 *q++ = ntohl(bia->addr[1]);
694 *q++ = ntohl(bia->addr[2]);
695 *q++ = ntohl(bia->addr[3]);
696 p += sizeof(*bia);
697 msg_len -= sizeof(*bia);
698
699 /* server pathname */
700 if (msg_len < sizeof(*str)) {
701 goto bad;
702 }
703 str = (struct rpc_string *)p;
704 path_len = ntohl(str->len);
705 if ((msg_len - 4) < path_len) {
706 goto bad;
707 }
708 if (path_len >= MAXPATHLEN) {
709 goto bad;
710 }
711 bcopy(str->data, pathname, path_len);
712 pathname[path_len] = '\0';
713 goto out;
714
715 bad:
716 printf("nfs_boot: bootparam_getfile: bad reply\n");
717 error = EBADRPC;
718
719 out:
720 mbuf_freem(m);
721 return 0;
722 }
723
724
725 /*
726 * RPC: mountd/mount
727 * Given a server pathname, get an NFS file handle.
728 * Also, sets sin->sin_port to the NFS service port.
729 */
730 static int
731 md_mount(struct sockaddr_in *mdsin, /* mountd server address */
732 char *path,
733 int v3,
734 int sotype,
735 u_char *fhp,
736 u_int32_t *fhlenp)
737 {
738 /* The RPC structures */
739 struct rpc_string *str;
740 struct rdata {
741 u_int32_t errno;
742 u_char data[NFSX_V3FHMAX + sizeof(u_int32_t)];
743 } *rdata;
744 mbuf_t m;
745 size_t mlen;
746 int error, slen;
747 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1;
748 int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP;
749 in_port_t mntport, nfsport;
750
751 /* Get port number for MOUNTD. */
752 error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion, proto, &mntport);
753 if (error) {
754 return error;
755 }
756
757 /* Get port number for NFS use. */
758 /* (If NFS/proto unavailable, don't bother with the mount call) */
759 error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2, proto, &nfsport);
760 if (error) {
761 return error;
762 }
763
764 /* Set port number for MOUNTD */
765 mdsin->sin_port = mntport;
766
767 slen = strlen(path);
768 mlen = RPC_STR_SIZE(slen);
769
770 error = mbuf_get_with_len(mlen, &m);
771 if (error) {
772 return error;
773 }
774 str = mbuf_data(m);
775 str->len = htonl(slen);
776 bcopy(path, str->data, slen);
777
778 /* Do RPC to mountd. */
779 error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL);
780 if (error) {
781 return error; /* message already freed */
782 }
783 /*
784 * the reply must be long enough to hold the errno plus either of:
785 * + a v2 filehandle
786 * + a v3 filehandle length + a v3 filehandle
787 */
788 mlen = mbuf_len(m);
789 if (mlen < sizeof(u_int32_t)) {
790 goto bad;
791 }
792 rdata = mbuf_data(m);
793 error = ntohl(rdata->errno);
794 if (error) {
795 goto out;
796 }
797 if (v3) {
798 u_int32_t fhlen;
799 u_char *fh;
800 if (mlen < sizeof(u_int32_t) * 2) {
801 goto bad;
802 }
803 fhlen = ntohl(*(u_int32_t*)rdata->data);
804 fh = rdata->data + sizeof(u_int32_t);
805 if (mlen < (sizeof(u_int32_t) * 2 + fhlen)
806 || fhlen >= (NFSX_V3FHMAX + sizeof(u_int32_t))) {
807 goto bad;
808 }
809 bcopy(fh, fhp, fhlen);
810 *fhlenp = fhlen;
811 } else {
812 if (mlen < (sizeof(u_int32_t) + NFSX_V2FH)) {
813 goto bad;
814 }
815 bcopy(rdata->data, fhp, NFSX_V2FH);
816 *fhlenp = NFSX_V2FH;
817 }
818
819 /* Set port number for NFS use. */
820 mdsin->sin_port = nfsport;
821 goto out;
822
823 bad:
824 error = EBADRPC;
825
826 out:
827 mbuf_freem(m);
828 return error;
829 }
830
831 #endif /* NETHER */
832
833 #endif /* CONFIG_NFS_CLIENT */