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 ([email protected])
67 * - Use BOOTP instead of RARP to get the IP address at boot time
68 *
69 * 23-May-97 Umesh Vaishampayan ([email protected])
70 * - Added the ability to mount "/private" separately.
71 *
72 * 30-May-97 Dieter Siegmund ([email protected])
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 ([email protected])
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 ([email protected])
81 * - use the default route from the bpwhoami call, enabled autonetmask
82 * again
83 * 19-Feb-1999 Dieter Siegmund ([email protected])
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 ([email protected])
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/vnode_internal.h>
106 #include <sys/kpi_mbuf.h>
107
108 #include <sys/malloc.h>
109 #include <sys/socket.h>
110
111 #include <net/if.h>
112 #include <net/if_dl.h>
113 #include <net/if_types.h>
114 #include <net/route.h>
115
116 #include <netinet/in.h>
117 #include <netinet/if_ether.h>
118
119 #include <nfs/rpcv2.h>
120 #include <nfs/nfsproto.h>
121 #include <nfs/nfs.h>
122 #include <nfs/nfsdiskless.h>
123 #include <nfs/krpc.h>
124 #include <nfs/xdr_subs.h>
125
126 #if CONFIG_MACF
127 #include <security/mac_framework.h>
128 #endif
129
130 #include <pexpert/pexpert.h>
131
132 #include "ether.h"
133
134 #include <libkern/libkern.h>
135
136 #if CONFIG_NETBOOT
137 static int nfs_mount_diskless(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t);
138 #if !defined(NO_MOUNT_PRIVATE)
139 static int nfs_mount_diskless_private(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t);
140 #endif /* NO_MOUNT_PRIVATE */
141 #endif
142
143 #if NETHER == 0
144
145 int
nfs_boot_init(__unused struct nfs_diskless * nd)146 nfs_boot_init(__unused struct nfs_diskless *nd)
147 {
148 panic("nfs_boot_init: no ether");
149 }
150
151 int
nfs_boot_getfh(__unused struct nfs_diskless * nd,__unused int v3,__unused int sotype)152 nfs_boot_getfh(__unused struct nfs_diskless *nd, __unused int v3, __unused int sotype)
153 {
154 panic("nfs_boot_getfh: no ether");
155 }
156
157 #else /* NETHER */
158
159 /*
160 * Support for NFS diskless booting, specifically getting information
161 * about where to boot from, what pathnames, etc.
162 *
163 * This implememtation uses RARP and the bootparam RPC.
164 * We are forced to implement RPC anyway (to get file handles)
165 * so we might as well take advantage of it for bootparam too.
166 *
167 * The diskless boot sequence goes as follows:
168 * (1) Use RARP to get our interface address
169 * (2) Use RPC/bootparam/whoami to get our hostname,
170 * our IP address, and the server's IP address.
171 * (3) Use RPC/bootparam/getfile to get the root path
172 * (4) Use RPC/mountd to get the root file handle
173 * (5) Use RPC/bootparam/getfile to get the swap path
174 * (6) Use RPC/mountd to get the swap file handle
175 *
176 * (This happens to be the way Sun does it too.)
177 */
178
179 /* bootparam RPC */
180 static int bp_whoami(struct sockaddr_in *bpsin,
181 struct in_addr *my_ip, struct in_addr *gw_ip);
182 static int bp_getfile(struct sockaddr_in *bpsin, const char *key,
183 struct sockaddr_in *mdsin, char *servname, char *path);
184
185 /* mountd RPC */
186 static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype,
187 u_char *fhp, u_int32_t *fhlenp);
188
189 /* other helpers */
190 static int get_file_handle(struct nfs_dlmount *ndmntp);
191
192
193 #define IP_FORMAT "%d.%d.%d.%d"
194 #define IP_CH(ip) ((u_char *)ip)
195 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
196
197 #include <sys/netboot.h>
198
199 /*
200 * Called with an empty nfs_diskless struct to be filled in.
201 */
202 int
nfs_boot_init(struct nfs_diskless * nd)203 nfs_boot_init(struct nfs_diskless *nd)
204 {
205 struct sockaddr_in bp_sin;
206 boolean_t do_bpwhoami = TRUE;
207 boolean_t do_bpgetfile = TRUE;
208 int error = 0;
209 struct in_addr my_ip;
210 struct sockaddr_in * sin_p;
211
212 /* make sure mbuf constants are set up */
213 if (!nfs_mbuf_mhlen) {
214 nfs_mbuf_init();
215 }
216
217 /* by this point, networking must already have been configured */
218 if (netboot_iaddr(&my_ip) == FALSE) {
219 printf("nfs_boot: networking is not initialized\n");
220 error = ENXIO;
221 goto failed;
222 }
223
224 /* get the root path information */
225 nd->nd_root.ndm_path = zalloc(ZV_NAMEI);
226 nd->nd_root.ndm_mntfrom = zalloc(ZV_NAMEI);
227
228 sin_p = &nd->nd_root.ndm_saddr;
229 bzero((caddr_t)sin_p, sizeof(*sin_p));
230 sin_p->sin_len = sizeof(*sin_p);
231 sin_p->sin_family = AF_INET;
232 if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host,
233 sizeof(nd->nd_root.ndm_host),
234 nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) {
235 do_bpgetfile = FALSE;
236 do_bpwhoami = FALSE;
237 }
238 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
239
240 if (do_bpwhoami) {
241 struct in_addr router;
242 /*
243 * Get client name and gateway address.
244 * RPC: bootparam/whoami
245 * Use the old broadcast address for the WHOAMI
246 * call because we do not yet know our netmask.
247 * The server address returned by the WHOAMI call
248 * is used for all subsequent booptaram RPCs.
249 */
250 bzero((caddr_t)&bp_sin, sizeof(bp_sin));
251 bp_sin.sin_len = sizeof(bp_sin);
252 bp_sin.sin_family = AF_INET;
253 bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
254 router.s_addr = 0;
255 error = bp_whoami(&bp_sin, &my_ip, &router);
256 if (error) {
257 printf("nfs_boot: bootparam whoami, error=%d", error);
258 goto failed;
259 }
260 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
261 IP_LIST(&bp_sin.sin_addr));
262 lck_mtx_lock(&hostname_lock);
263 printf("nfs_boot: hostname %s\n", hostname);
264 lck_mtx_unlock(&hostname_lock);
265 }
266 if (do_bpgetfile) {
267 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
268 nd->nd_root.ndm_host, nd->nd_root.ndm_path);
269 if (error) {
270 printf("nfs_boot: bootparam get root: %d\n", error);
271 goto failed;
272 }
273 }
274
275 #if !defined(NO_MOUNT_PRIVATE)
276 if (do_bpgetfile) { /* get private path */
277 nd->nd_private.ndm_path = zalloc(ZV_NAMEI);
278 nd->nd_private.ndm_mntfrom = zalloc(ZV_NAMEI);
279 error = bp_getfile(&bp_sin, "private",
280 &nd->nd_private.ndm_saddr,
281 nd->nd_private.ndm_host,
282 nd->nd_private.ndm_path);
283 if (!error) {
284 char * check_path = NULL;
285
286 check_path = zalloc(ZV_NAMEI);
287 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path);
288 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
289 == nd->nd_private.ndm_saddr.sin_addr.s_addr)
290 && (strncmp(check_path, nd->nd_private.ndm_path, MAXPATHLEN) == 0)) {
291 /* private path is prefix of root path, don't mount */
292 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
293 }
294 NFS_ZFREE(ZV_NAMEI, check_path);
295 } else {
296 /* private key not defined, don't mount */
297 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
298 }
299 } else {
300 error = 0;
301 }
302 #endif /* NO_MOUNT_PRIVATE */
303 failed:
304 return error;
305 }
306
307 /*
308 * Called with a partially initialized nfs_diskless struct
309 * with file handles to be filled in.
310 */
311 int
nfs_boot_getfh(struct nfs_diskless * nd,int v3,int sotype)312 nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype)
313 {
314 int error = 0;
315
316 nd->nd_root.ndm_nfsv3 = v3;
317 nd->nd_root.ndm_sotype = sotype;
318 error = get_file_handle(&nd->nd_root);
319 if (error) {
320 printf("nfs_boot: get_file_handle(v%d) root failed, %d\n",
321 v3 ? 3 : 2, error);
322 goto failed;
323 }
324
325 #if !defined(NO_MOUNT_PRIVATE)
326 if (nd->nd_private.ndm_saddr.sin_addr.s_addr) {
327 /* get private file handle */
328 nd->nd_private.ndm_nfsv3 = v3;
329 nd->nd_private.ndm_sotype = sotype;
330 error = get_file_handle(&nd->nd_private);
331 if (error) {
332 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n",
333 v3 ? 3 : 2, error);
334 goto failed;
335 }
336 }
337 #endif /* NO_MOUNT_PRIVATE */
338 failed:
339 return error;
340 }
341
342 static int
get_file_handle(struct nfs_dlmount * ndmntp)343 get_file_handle(struct nfs_dlmount *ndmntp)
344 {
345 char *sp, *dp, *endp;
346 int error;
347
348 /*
349 * Get file handle for "key" (root or swap)
350 * using RPC to mountd/mount
351 */
352 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3,
353 ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen);
354 if (error) {
355 return error;
356 }
357
358 /* Construct remote path (for getmntinfo(3)) */
359 dp = ndmntp->ndm_mntfrom;
360 endp = dp + MAXPATHLEN - 1;
361 for (sp = ndmntp->ndm_host; *sp && dp < endp;) {
362 *dp++ = *sp++;
363 }
364 if (dp < endp) {
365 *dp++ = ':';
366 }
367 for (sp = ndmntp->ndm_path; *sp && dp < endp;) {
368 *dp++ = *sp++;
369 }
370 *dp = '\0';
371 return 0;
372 }
373
374
375 /*
376 * Get an mbuf with the given length, and
377 * initialize the pkthdr length field.
378 */
379 static int
mbuf_get_with_len(size_t msg_len,mbuf_t * m)380 mbuf_get_with_len(size_t msg_len, mbuf_t *m)
381 {
382 int error;
383 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, m);
384 if (error) {
385 return error;
386 }
387 if (msg_len > mbuf_maxlen(*m)) {
388 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, m);
389 if (error) {
390 mbuf_freem(*m);
391 return error;
392 }
393 if (msg_len > mbuf_maxlen(*m)) {
394 panic("nfs_boot: msg_len > MCLBYTES");
395 }
396 }
397 mbuf_setlen(*m, msg_len);
398 mbuf_pkthdr_setlen(*m, msg_len);
399 return 0;
400 }
401
402
403 /*
404 * String representation for RPC.
405 */
406 struct rpc_string {
407 size_t len; /* length without null or padding */
408 u_char data[4]; /* data (longer, of course) */
409 /* data is padded to a long-word boundary */
410 };
411 /* Compute space used given string length. */
412 #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
413
414 /*
415 * Inet address in RPC messages
416 * (Note, really four 32-bit ints, NOT chars. Blech.)
417 */
418 struct bp_inaddr {
419 u_int32_t atype;
420 int32_t addr[4];
421 };
422
423
424 /*
425 * RPC: bootparam/whoami
426 * Given client IP address, get:
427 * client name (hostname)
428 * domain name (domainname)
429 * gateway address
430 *
431 * The hostname and domainname are set here for convenience.
432 *
433 * Note - bpsin is initialized to the broadcast address,
434 * and will be replaced with the bootparam server address
435 * after this call is complete. Have to use PMAP_PROC_CALL
436 * to make sure we get responses only from a servers that
437 * know about us (don't want to broadcast a getport call).
438 */
439 static int
bp_whoami(struct sockaddr_in * bpsin,struct in_addr * my_ip,struct in_addr * gw_ip)440 bp_whoami(struct sockaddr_in *bpsin,
441 struct in_addr *my_ip,
442 struct in_addr *gw_ip)
443 {
444 /* RPC structures for PMAPPROC_CALLIT */
445 struct whoami_call {
446 u_int32_t call_prog;
447 u_int32_t call_vers;
448 u_int32_t call_proc;
449 u_int32_t call_arglen;
450 struct bp_inaddr call_ia;
451 } *call;
452
453 struct rpc_string *str;
454 struct bp_inaddr *bia;
455 mbuf_t m;
456 struct sockaddr_in sin;
457 int error;
458 size_t msg_len, cn_len, dn_len;
459 u_char *p;
460 int32_t *lp;
461 size_t encapsulated_size;
462
463 /*
464 * Get message buffer of sufficient size.
465 */
466 msg_len = sizeof(*call);
467 error = mbuf_get_with_len(msg_len, &m);
468 if (error) {
469 return error;
470 }
471
472 /*
473 * Build request message for PMAPPROC_CALLIT.
474 */
475 call = mbuf_data(m);
476 call->call_prog = htonl(BOOTPARAM_PROG);
477 call->call_vers = htonl(BOOTPARAM_VERS);
478 call->call_proc = htonl(BOOTPARAM_WHOAMI);
479 call->call_arglen = htonl(sizeof(struct bp_inaddr));
480
481 /* client IP address */
482 call->call_ia.atype = htonl(1);
483 p = (u_char*)my_ip;
484 lp = call->call_ia.addr;
485 *lp++ = htonl(*p); p++;
486 *lp++ = htonl(*p); p++;
487 *lp++ = htonl(*p); p++;
488 *lp++ = htonl(*p); p++;
489
490 /* RPC: portmap/callit */
491 bpsin->sin_port = htons(PMAPPORT);
492
493 error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin);
494 if (error) {
495 return error;
496 }
497
498 /*
499 * Parse result message.
500 */
501 msg_len = mbuf_len(m);
502 lp = mbuf_data(m);
503
504 /* bootparam server port (also grab from address). */
505 if (msg_len < sizeof(*lp)) {
506 goto bad;
507 }
508 msg_len -= sizeof(*lp);
509 bpsin->sin_port = htons((short)ntohl(*lp++));
510 bpsin->sin_addr.s_addr = sin.sin_addr.s_addr;
511
512 /* length of encapsulated results */
513 if (os_add_overflow((size_t) ntohl(*lp), sizeof(*lp), &encapsulated_size)
514 || msg_len < encapsulated_size) {
515 goto bad;
516 }
517 msg_len = ntohl(*lp++);
518 p = (u_char*)lp;
519
520 /* client name */
521 if (msg_len < sizeof(*str)) {
522 goto bad;
523 }
524 str = (struct rpc_string *)p;
525 cn_len = ntohll(str->len);
526 if ((msg_len - 4) < cn_len) {
527 goto bad;
528 }
529 if (cn_len >= MAXHOSTNAMELEN) {
530 goto bad;
531 }
532 lck_mtx_lock(&hostname_lock);
533 bcopy(str->data, hostname, cn_len);
534 hostname[cn_len] = '\0';
535 lck_mtx_unlock(&hostname_lock);
536 p += RPC_STR_SIZE(cn_len);
537 msg_len -= RPC_STR_SIZE(cn_len);
538
539 /* domain name */
540 if (msg_len < sizeof(*str)) {
541 goto bad;
542 }
543 str = (struct rpc_string *)p;
544 dn_len = ntohll(str->len);
545 if ((msg_len - 4) < dn_len) {
546 goto bad;
547 }
548 if (dn_len >= MAXHOSTNAMELEN) {
549 goto bad;
550 }
551 lck_mtx_lock(&domainname_lock);
552 bcopy(str->data, domainname, dn_len);
553 domainname[dn_len] = '\0';
554 lck_mtx_unlock(&domainname_lock);
555 p += RPC_STR_SIZE(dn_len);
556 msg_len -= RPC_STR_SIZE(dn_len);
557
558 /* gateway address */
559 if (msg_len < sizeof(*bia)) {
560 goto bad;
561 }
562 bia = (struct bp_inaddr *)p;
563 if (bia->atype != htonl(1)) {
564 goto bad;
565 }
566 p = (u_char*)gw_ip;
567 *p++ = ntohl(bia->addr[0]) & 0xff;
568 *p++ = ntohl(bia->addr[1]) & 0xff;
569 *p++ = ntohl(bia->addr[2]) & 0xff;
570 *p++ = ntohl(bia->addr[3]) & 0xff;
571 goto out;
572
573 bad:
574 printf("nfs_boot: bootparam_whoami: bad reply\n");
575 error = EBADRPC;
576
577 out:
578 mbuf_freem(m);
579 return error;
580 }
581
582
583 /*
584 * RPC: bootparam/getfile
585 * Given client name and file "key", get:
586 * server name
587 * server IP address
588 * server pathname
589 */
590 static int
bp_getfile(struct sockaddr_in * bpsin,const char * key,struct sockaddr_in * md_sin,char * serv_name,char * pathname)591 bp_getfile(struct sockaddr_in *bpsin,
592 const char *key,
593 struct sockaddr_in *md_sin,
594 char *serv_name,
595 char *pathname)
596 {
597 struct rpc_string *str;
598 mbuf_t m;
599 struct bp_inaddr *bia;
600 struct sockaddr_in *sin;
601 u_char *p, *q;
602 int error;
603 size_t msg_len, cn_len, key_len, sn_len, path_len;
604
605 /*
606 * Get message buffer of sufficient size.
607 */
608 lck_mtx_lock(&hostname_lock);
609 cn_len = strlen(hostname);
610 lck_mtx_unlock(&hostname_lock);
611 key_len = strlen(key);
612 msg_len = 0;
613 msg_len += RPC_STR_SIZE(cn_len);
614 msg_len += RPC_STR_SIZE(key_len);
615 error = mbuf_get_with_len(msg_len, &m);
616 if (error) {
617 return error;
618 }
619
620 /*
621 * Build request message.
622 */
623 p = mbuf_data(m);
624 bzero(p, msg_len);
625 /* client name (hostname) */
626 str = (struct rpc_string *)p;
627 str->len = htonll(cn_len);
628 lck_mtx_lock(&hostname_lock);
629 bcopy(hostname, str->data, cn_len);
630 lck_mtx_unlock(&hostname_lock);
631 p += RPC_STR_SIZE(cn_len);
632 /* key name (root or swap) */
633 str = (struct rpc_string *)p;
634 str->len = htonll(key_len);
635 bcopy(key, str->data, key_len);
636
637 /* RPC: bootparam/getfile */
638 error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS,
639 BOOTPARAM_GETFILE, &m, NULL);
640 if (error) {
641 return error;
642 }
643
644 /*
645 * Parse result message.
646 */
647 p = mbuf_data(m);
648 msg_len = mbuf_len(m);
649
650 /* server name */
651 if (msg_len < sizeof(*str)) {
652 goto bad;
653 }
654 str = (struct rpc_string *)p;
655 sn_len = ntohll(str->len);
656 if ((msg_len - 4) < sn_len) {
657 goto bad;
658 }
659 if (sn_len >= MAXHOSTNAMELEN) {
660 goto bad;
661 }
662 bcopy(str->data, serv_name, sn_len);
663 serv_name[sn_len] = '\0';
664 p += RPC_STR_SIZE(sn_len);
665 msg_len -= RPC_STR_SIZE(sn_len);
666
667 /* server IP address (mountd) */
668 if (msg_len < sizeof(*bia)) {
669 goto bad;
670 }
671 bia = (struct bp_inaddr *)p;
672 if (bia->atype != htonl(1)) {
673 goto bad;
674 }
675 sin = md_sin;
676 bzero((caddr_t)sin, sizeof(*sin));
677 sin->sin_len = sizeof(*sin);
678 sin->sin_family = AF_INET;
679 q = (u_char*) &sin->sin_addr;
680 *q++ = ntohl(bia->addr[0]) & 0xff;
681 *q++ = ntohl(bia->addr[1]) & 0xff;
682 *q++ = ntohl(bia->addr[2]) & 0xff;
683 *q++ = ntohl(bia->addr[3]) & 0xff;
684 p += sizeof(*bia);
685 msg_len -= sizeof(*bia);
686
687 /* server pathname */
688 if (msg_len < sizeof(*str)) {
689 goto bad;
690 }
691 str = (struct rpc_string *)p;
692 path_len = ntohll(str->len);
693 if ((msg_len - 4) < path_len) {
694 goto bad;
695 }
696 if (path_len >= MAXPATHLEN) {
697 goto bad;
698 }
699 bcopy(str->data, pathname, path_len);
700 pathname[path_len] = '\0';
701 goto out;
702
703 bad:
704 printf("nfs_boot: bootparam_getfile: bad reply\n");
705 error = EBADRPC;
706
707 out:
708 mbuf_freem(m);
709 return 0;
710 }
711
712
713 /*
714 * RPC: mountd/mount
715 * Given a server pathname, get an NFS file handle.
716 * Also, sets sin->sin_port to the NFS service port.
717 */
718 static int
md_mount(struct sockaddr_in * mdsin,char * path,int v3,int sotype,u_char * fhp,u_int32_t * fhlenp)719 md_mount(struct sockaddr_in *mdsin, /* mountd server address */
720 char *path,
721 int v3,
722 int sotype,
723 u_char *fhp,
724 u_int32_t *fhlenp)
725 {
726 /* The RPC structures */
727 struct rpc_string *str;
728 struct rdata {
729 u_int32_t errno;
730 u_char data[NFSX_V3FHMAX + sizeof(u_int32_t)];
731 } *rdata;
732 mbuf_t m;
733 size_t mlen, slen;
734 int error;
735 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1;
736 int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP;
737 in_port_t mntport, nfsport;
738
739 /* Get port number for MOUNTD. */
740 error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion, proto, &mntport);
741 if (error) {
742 return error;
743 }
744
745 /* Get port number for NFS use. */
746 /* (If NFS/proto unavailable, don't bother with the mount call) */
747 error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2, proto, &nfsport);
748 if (error) {
749 return error;
750 }
751
752 /* Set port number for MOUNTD */
753 mdsin->sin_port = mntport;
754
755 slen = strlen(path);
756 mlen = RPC_STR_SIZE(slen);
757
758 error = mbuf_get_with_len(mlen, &m);
759 if (error) {
760 return error;
761 }
762 str = mbuf_data(m);
763 str->len = htonll(slen);
764 bcopy(path, str->data, slen);
765
766 /* Do RPC to mountd. */
767 error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL);
768 if (error) {
769 return error; /* message already freed */
770 }
771 /*
772 * the reply must be long enough to hold the errno plus either of:
773 * + a v2 filehandle
774 * + a v3 filehandle length + a v3 filehandle
775 */
776 mlen = mbuf_len(m);
777 if (mlen < sizeof(u_int32_t)) {
778 goto bad;
779 }
780 rdata = mbuf_data(m);
781 error = ntohl(rdata->errno);
782 if (error) {
783 goto out;
784 }
785 if (v3) {
786 u_int32_t fhlen;
787 u_char *fh;
788 if (mlen < sizeof(u_int32_t) * 2) {
789 goto bad;
790 }
791 fhlen = ntohl(*(u_int32_t*)rdata->data);
792 fh = rdata->data + sizeof(u_int32_t);
793 if (mlen < (sizeof(u_int32_t) * 2 + fhlen)
794 || fhlen >= (NFSX_V3FHMAX + sizeof(u_int32_t))) {
795 goto bad;
796 }
797 bcopy(fh, fhp, fhlen);
798 *fhlenp = fhlen;
799 } else {
800 if (mlen < (sizeof(u_int32_t) + NFSX_V2FH)) {
801 goto bad;
802 }
803 bcopy(rdata->data, fhp, NFSX_V2FH);
804 *fhlenp = NFSX_V2FH;
805 }
806
807 /* Set port number for NFS use. */
808 mdsin->sin_port = nfsport;
809 goto out;
810
811 bad:
812 error = EBADRPC;
813
814 out:
815 mbuf_freem(m);
816 return error;
817 }
818
819 #endif /* NETHER */
820
821 /*
822 * Mount a remote root fs via. nfs. This depends on the info in the
823 * nfs_diskless structure that has been filled in properly by some primary
824 * bootstrap.
825 * It goes something like this:
826 * - do enough of "ifconfig" by calling ifioctl() so that the system
827 * can talk to the server
828 * - If nfs_diskless.mygateway is filled in, use that address as
829 * a default gateway.
830 * - hand craft the swap nfs vnode hanging off a fake mount point
831 * if swdevt[0].sw_dev == NODEV
832 * - build the rootfs mount point and call mountnfs() to do the rest.
833 */
834 #if CONFIG_NETBOOT
835 int
nfs_mountroot(void)836 nfs_mountroot(void)
837 {
838 struct nfs_diskless nd;
839 mount_t mp = NULL;
840 vnode_t vp = NULL;
841 vfs_context_t ctx;
842 int error;
843 #if !defined(NO_MOUNT_PRIVATE)
844 mount_t mppriv = NULL;
845 vnode_t vppriv = NULL;
846 #endif /* NO_MOUNT_PRIVATE */
847 int v3, sotype;
848
849 /*
850 * Call nfs_boot_init() to fill in the nfs_diskless struct.
851 * Note: networking must already have been configured before
852 * we're called.
853 */
854 bzero((caddr_t) &nd, sizeof(nd));
855 error = nfs_boot_init(&nd);
856 if (error) {
857 panic("nfs_boot_init: unable to initialize NFS root system information, "
858 "error %d, check configuration: %s\n", error, PE_boot_args());
859 }
860
861 /*
862 * Try NFSv3 first, then fallback to NFSv2.
863 * Likewise, try TCP first, then fall back to UDP.
864 */
865 v3 = 1;
866 sotype = SOCK_STREAM;
867
868 tryagain:
869 error = nfs_boot_getfh(&nd, v3, sotype);
870 if (error) {
871 if (error == EHOSTDOWN || error == EHOSTUNREACH) {
872 if (nd.nd_root.ndm_mntfrom) {
873 NFS_ZFREE(ZV_NAMEI, nd.nd_root.ndm_mntfrom);
874 }
875 if (nd.nd_root.ndm_path) {
876 NFS_ZFREE(ZV_NAMEI, nd.nd_root.ndm_path);
877 }
878 if (nd.nd_private.ndm_mntfrom) {
879 NFS_ZFREE(ZV_NAMEI, nd.nd_private.ndm_mntfrom);
880 }
881 if (nd.nd_private.ndm_path) {
882 NFS_ZFREE(ZV_NAMEI, nd.nd_private.ndm_path);
883 }
884 return error;
885 }
886 if (v3) {
887 if (sotype == SOCK_STREAM) {
888 printf("NFS mount (v3,TCP) failed with error %d, trying UDP...\n", error);
889 sotype = SOCK_DGRAM;
890 goto tryagain;
891 }
892 printf("NFS mount (v3,UDP) failed with error %d, trying v2...\n", error);
893 v3 = 0;
894 sotype = SOCK_STREAM;
895 goto tryagain;
896 } else if (sotype == SOCK_STREAM) {
897 printf("NFS mount (v2,TCP) failed with error %d, trying UDP...\n", error);
898 sotype = SOCK_DGRAM;
899 goto tryagain;
900 } else {
901 printf("NFS mount (v2,UDP) failed with error %d, giving up...\n", error);
902 }
903 switch (error) {
904 case EPROGUNAVAIL:
905 panic("NFS mount failed: NFS server mountd not responding, check server configuration: %s", PE_boot_args());
906 case EACCES:
907 case EPERM:
908 panic("NFS mount failed: NFS server refused mount, check server configuration: %s", PE_boot_args());
909 default:
910 panic("NFS mount failed with error %d, check configuration: %s", error, PE_boot_args());
911 }
912 }
913
914 ctx = vfs_context_kernel();
915
916 /*
917 * Create the root mount point.
918 */
919 #if !defined(NO_MOUNT_PRIVATE)
920 {
921 //PWC hack until we have a real "mount" tool to remount root rw
922 int rw_root = 0;
923 int flags = MNT_ROOTFS | MNT_RDONLY;
924 PE_parse_boot_argn("-rwroot_hack", &rw_root, sizeof(rw_root));
925 if (rw_root) {
926 flags = MNT_ROOTFS;
927 kprintf("-rwroot_hack in effect: mounting root fs read/write\n");
928 }
929
930 if ((error = nfs_mount_diskless(&nd.nd_root, "/", flags, &vp, &mp, ctx)))
931 #else
932 if ((error = nfs_mount_diskless(&nd.nd_root, "/", MNT_ROOTFS, &vp, &mp, ctx)))
933 #endif /* NO_MOUNT_PRIVATE */
934 {
935 if (v3) {
936 if (sotype == SOCK_STREAM) {
937 printf("NFS root mount (v3,TCP) failed with %d, trying UDP...\n", error);
938 sotype = SOCK_DGRAM;
939 goto tryagain;
940 }
941 printf("NFS root mount (v3,UDP) failed with %d, trying v2...\n", error);
942 v3 = 0;
943 sotype = SOCK_STREAM;
944 goto tryagain;
945 } else if (sotype == SOCK_STREAM) {
946 printf("NFS root mount (v2,TCP) failed with %d, trying UDP...\n", error);
947 sotype = SOCK_DGRAM;
948 goto tryagain;
949 } else {
950 printf("NFS root mount (v2,UDP) failed with error %d, giving up...\n", error);
951 }
952 panic("NFS root mount failed with error %d, check configuration: %s", error, PE_boot_args());
953 }
954 }
955 printf("root on %s\n", nd.nd_root.ndm_mntfrom);
956
957 vfs_unbusy(mp);
958 mount_list_add(mp);
959 rootvp = vp;
960
961 #if !defined(NO_MOUNT_PRIVATE)
962 if (nd.nd_private.ndm_saddr.sin_addr.s_addr) {
963 error = nfs_mount_diskless_private(&nd.nd_private, "/private",
964 0, &vppriv, &mppriv, ctx);
965 if (error) {
966 panic("NFS /private mount failed with error %d, check configuration: %s", error, PE_boot_args());
967 }
968 printf("private on %s\n", nd.nd_private.ndm_mntfrom);
969
970 vfs_unbusy(mppriv);
971 mount_list_add(mppriv);
972 }
973
974 #endif /* NO_MOUNT_PRIVATE */
975
976 if (nd.nd_root.ndm_mntfrom) {
977 NFS_ZFREE(ZV_NAMEI, nd.nd_root.ndm_mntfrom);
978 }
979 if (nd.nd_root.ndm_path) {
980 NFS_ZFREE(ZV_NAMEI, nd.nd_root.ndm_path);
981 }
982 if (nd.nd_private.ndm_mntfrom) {
983 NFS_ZFREE(ZV_NAMEI, nd.nd_private.ndm_mntfrom);
984 }
985 if (nd.nd_private.ndm_path) {
986 NFS_ZFREE(ZV_NAMEI, nd.nd_private.ndm_path);
987 }
988
989 return 0;
990 }
991
992 /*
993 * Internal version of mount system call for diskless setup.
994 */
995 static int
nfs_mount_diskless(struct nfs_dlmount * ndmntp,const char * mntname,int mntflag,vnode_t * vpp,mount_t * mpp,vfs_context_t ctx)996 nfs_mount_diskless(
997 struct nfs_dlmount *ndmntp,
998 const char *mntname,
999 int mntflag,
1000 vnode_t *vpp,
1001 mount_t *mpp,
1002 vfs_context_t ctx)
1003 {
1004 mount_t mp;
1005 vnode_t vp = NULLVP;
1006 int error, numcomps;
1007 char *xdrbuf, *p, *cp, *frompath, *endserverp;
1008 char uaddr[MAX_IPv4_STR_LEN];
1009 struct xdrbuf xb;
1010 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
1011 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN];
1012 uint32_t mflags[NFS_MFLAG_BITMAP_LEN];
1013 uint64_t argslength_offset, attrslength_offset, end_offset;
1014
1015 if ((error = vfs_rootmountalloc("nfs", ndmntp->ndm_mntfrom, &mp))) {
1016 printf("nfs_mount_diskless: NFS not configured\n");
1017 return error;
1018 }
1019
1020 mp->mnt_kern_flag |= MNTK_KERNEL_MOUNT; /* mark as kernel mount */
1021 vfs_setflags(mp, mntflag);
1022 if (!vfs_isrdonly(mp)) {
1023 vfs_clearflags(mp, MNT_RDONLY);
1024 }
1025
1026 /* find the server-side path being mounted */
1027 frompath = ndmntp->ndm_mntfrom;
1028 if (*frompath == '[') { /* skip IPv6 literal address */
1029 while (*frompath && (*frompath != ']')) {
1030 frompath++;
1031 }
1032 if (*frompath == ']') {
1033 frompath++;
1034 }
1035 }
1036 while (*frompath && (*frompath != ':')) {
1037 frompath++;
1038 }
1039 endserverp = frompath;
1040 while (*frompath && (*frompath == ':')) {
1041 frompath++;
1042 }
1043 /* count fs location path components */
1044 p = frompath;
1045 while (*p && (*p == '/')) {
1046 p++;
1047 }
1048 numcomps = 0;
1049 while (*p) {
1050 numcomps++;
1051 while (*p && (*p != '/')) {
1052 p++;
1053 }
1054 while (*p && (*p == '/')) {
1055 p++;
1056 }
1057 }
1058
1059 /* convert address to universal address string */
1060 if (inet_ntop(AF_INET, &ndmntp->ndm_saddr.sin_addr, uaddr, sizeof(uaddr)) != uaddr) {
1061 printf("nfs_mount_diskless: bad address\n");
1062 return EINVAL;
1063 }
1064
1065 /* prepare mount attributes */
1066 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
1067 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
1068 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
1069 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
1070 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
1071 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
1072 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
1073
1074 /* prepare mount flags */
1075 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
1076 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
1077 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
1078 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
1079
1080 /* build xdr buffer */
1081 xb_init_buffer(&xb, NULL, 0);
1082 xb_add_32(error, &xb, NFS_ARGSVERSION_XDR);
1083 argslength_offset = xb_offset(&xb);
1084 xb_add_32(error, &xb, 0); // args length
1085 xb_add_32(error, &xb, NFS_XDRARGS_VERSION_0);
1086 xb_add_bitmap(error, &xb, mattrs, NFS_MATTR_BITMAP_LEN);
1087 attrslength_offset = xb_offset(&xb);
1088 xb_add_32(error, &xb, 0); // attrs length
1089 xb_add_32(error, &xb, ndmntp->ndm_nfsv3 ? 3 : 2); // NFS version
1090 xb_add_string(error, &xb, ((ndmntp->ndm_sotype == SOCK_DGRAM) ? "udp" : "tcp"), 3);
1091 xb_add_32(error, &xb, ntohs(ndmntp->ndm_saddr.sin_port)); // NFS port
1092 xb_add_fh(error, &xb, &ndmntp->ndm_fh[0], ndmntp->ndm_fhlen);
1093 /* fs location */
1094 xb_add_32(error, &xb, 1); /* fs location count */
1095 xb_add_32(error, &xb, 1); /* server count */
1096 xb_add_string(error, &xb, ndmntp->ndm_mntfrom, (endserverp - ndmntp->ndm_mntfrom)); /* server name */
1097 xb_add_32(error, &xb, 1); /* address count */
1098 xb_add_string(error, &xb, uaddr, strlen(uaddr)); /* address */
1099 xb_add_32(error, &xb, 0); /* empty server info */
1100 xb_add_32(error, &xb, numcomps); /* pathname component count */
1101 p = frompath;
1102 while (*p && (*p == '/')) {
1103 p++;
1104 }
1105 while (*p) {
1106 cp = p;
1107 while (*p && (*p != '/')) {
1108 p++;
1109 }
1110 xb_add_string(error, &xb, cp, (p - cp)); /* component */
1111 if (error) {
1112 break;
1113 }
1114 while (*p && (*p == '/')) {
1115 p++;
1116 }
1117 }
1118 xb_add_32(error, &xb, 0); /* empty fsl info */
1119 xb_add_32(error, &xb, mntflag); /* MNT flags */
1120 xb_build_done(error, &xb);
1121
1122 /* update opaque counts */
1123 end_offset = xb_offset(&xb);
1124 if (!error) {
1125 error = xb_seek(&xb, argslength_offset);
1126 xb_add_32(error, &xb, end_offset - argslength_offset + XDRWORD /*version*/);
1127 }
1128 if (!error) {
1129 error = xb_seek(&xb, attrslength_offset);
1130 xb_add_32(error, &xb, end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
1131 }
1132 if (error) {
1133 printf("nfs_mount_diskless: error %d assembling mount args\n", error);
1134 xb_cleanup(&xb);
1135 return error;
1136 }
1137 /* grab the assembled buffer */
1138 xdrbuf = xb_buffer_base(&xb);
1139
1140 /* do the mount */
1141 if ((error = VFS_MOUNT(mp, vp, CAST_USER_ADDR_T(xdrbuf), ctx))) {
1142 printf("nfs_mountroot: mount %s failed: %d\n", mntname, error);
1143 // XXX vfs_rootmountfailed(mp);
1144 mount_list_lock();
1145 mp->mnt_vtable->vfc_refcount--;
1146 mount_list_unlock();
1147 vfs_unbusy(mp);
1148 mount_lock_destroy(mp);
1149 #if CONFIG_MACF
1150 mac_mount_label_destroy(mp);
1151 #endif
1152 NFS_ZFREE(mount_zone, mp);
1153 } else {
1154 *mpp = mp;
1155 error = VFS_ROOT(mp, vpp, ctx);
1156 }
1157 xb_cleanup(&xb);
1158 return error;
1159 }
1160
1161 #if !defined(NO_MOUNT_PRIVATE)
1162 /*
1163 * Internal version of mount system call to mount "/private"
1164 * separately in diskless setup
1165 */
1166 static int
nfs_mount_diskless_private(struct nfs_dlmount * ndmntp,const char * mntname,int mntflag,vnode_t * vpp,mount_t * mpp,vfs_context_t ctx)1167 nfs_mount_diskless_private(
1168 struct nfs_dlmount *ndmntp,
1169 const char *mntname,
1170 int mntflag,
1171 vnode_t *vpp,
1172 mount_t *mpp,
1173 vfs_context_t ctx)
1174 {
1175 mount_t mp;
1176 vnode_t vp = NULLVP;
1177 int error, numcomps;
1178 proc_t procp;
1179 struct vfstable *vfsp;
1180 struct nameidata nd;
1181 char *xdrbuf = NULL, *p, *cp, *frompath, *endserverp;
1182 char uaddr[MAX_IPv4_STR_LEN];
1183 struct xdrbuf xb;
1184 uint32_t mattrs[NFS_MATTR_BITMAP_LEN];
1185 uint32_t mflags_mask[NFS_MFLAG_BITMAP_LEN], mflags[NFS_MFLAG_BITMAP_LEN];
1186 uint64_t argslength_offset, attrslength_offset, end_offset;
1187 struct vfsioattr ioattr;
1188
1189 procp = current_proc(); /* XXX */
1190 xb_init(&xb, XDRBUF_NONE);
1191
1192 {
1193 /*
1194 * mimic main()!. Temporarily set up rootvnode and other stuff so
1195 * that namei works. Need to undo this because main() does it, too
1196 */
1197 struct filedesc *fdp = &procp->p_fd;
1198 vfs_setflags(mountlist.tqh_first, MNT_ROOTFS);
1199
1200 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
1201 if (VFS_ROOT(mountlist.tqh_first, &rootvnode, NULL)) {
1202 panic("cannot find root vnode");
1203 }
1204 error = vnode_ref(rootvnode);
1205 if (error) {
1206 printf("nfs_mountroot: vnode_ref() failed on root vnode!\n");
1207 goto out;
1208 }
1209 fdp->fd_cdir = rootvnode;
1210 fdp->fd_rdir = NULL;
1211 }
1212
1213 /*
1214 * Get vnode to be covered
1215 */
1216 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
1217 CAST_USER_ADDR_T(mntname), ctx);
1218 error = namei(&nd);
1219 {
1220 /* undo vnode_ref() in mimic main()! */
1221 vnode_rele(rootvnode);
1222 }
1223 if (error) {
1224 printf("nfs_mountroot: private namei failed!\n");
1225 goto out;
1226 }
1227 nameidone(&nd);
1228 vp = nd.ni_vp;
1229
1230 if ((error = VNOP_FSYNC(vp, MNT_WAIT, ctx)) ||
1231 (error = buf_invalidateblks(vp, BUF_WRITE_DATA, 0, 0))) {
1232 vnode_put(vp);
1233 goto out;
1234 }
1235 if (vnode_vtype(vp) != VDIR) {
1236 vnode_put(vp);
1237 error = ENOTDIR;
1238 goto out;
1239 }
1240 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
1241 if (!strncmp(vfsp->vfc_name, "nfs", sizeof(vfsp->vfc_name))) {
1242 break;
1243 }
1244 }
1245 if (vfsp == NULL) {
1246 printf("nfs_mountroot: private NFS not configured\n");
1247 vnode_put(vp);
1248 error = ENODEV;
1249 goto out;
1250 }
1251 if (vnode_mountedhere(vp) != NULL) {
1252 vnode_put(vp);
1253 error = EBUSY;
1254 goto out;
1255 }
1256
1257 /*
1258 * Allocate and initialize the filesystem.
1259 */
1260 mp = zalloc_flags(mount_zone, Z_WAITOK | Z_ZERO);
1261 /* Initialize the default IO constraints */
1262 bzero(&ioattr, sizeof(ioattr));
1263 ioattr.io_maxreadcnt = ioattr.io_maxwritecnt = MAXPHYS;
1264 ioattr.io_segreadcnt = ioattr.io_segwritecnt = 32;
1265 vfs_setioattr(mp, &ioattr);
1266 mp->mnt_realrootvp = NULLVP;
1267 vfs_setauthcache_ttl(mp, 0); /* Allways go to our lookup */
1268 mp->mnt_kern_flag |= MNTK_KERNEL_MOUNT; /* mark as kernel mount */
1269
1270 mount_lock_init(mp);
1271 TAILQ_INIT(&mp->mnt_vnodelist);
1272 TAILQ_INIT(&mp->mnt_workerqueue);
1273 TAILQ_INIT(&mp->mnt_newvnodes);
1274 (void)vfs_busy(mp, LK_NOWAIT);
1275 TAILQ_INIT(&mp->mnt_vnodelist);
1276 mount_list_lock();
1277 vfsp->vfc_refcount++;
1278 mount_list_unlock();
1279 mp->mnt_vtable = vfsp;
1280 mp->mnt_op = vfsp->vfc_vfsops;
1281 vfs_setflags(mp, mntflag);
1282 vfs_setflags(mp, vfsp->vfc_flags);
1283 strncpy(vfs_statfs(mp)->f_fstypename, vfsp->vfc_name, MFSNAMELEN - 1);
1284 vp->v_mountedhere = mp;
1285 mp->mnt_vnodecovered = vp;
1286 vp = NULLVP;
1287 vfs_statfs(mp)->f_owner = kauth_cred_getuid(kauth_cred_get());
1288 (void) copystr(mntname, vfs_statfs(mp)->f_mntonname, MAXPATHLEN - 1, 0);
1289 (void) copystr(ndmntp->ndm_mntfrom, vfs_statfs(mp)->f_mntfromname, MAXPATHLEN - 1, 0);
1290 #if CONFIG_MACF
1291 mac_mount_label_init(mp);
1292 mac_mount_label_associate(ctx, mp);
1293 #endif
1294
1295 /* find the server-side path being mounted */
1296 frompath = ndmntp->ndm_mntfrom;
1297 if (*frompath == '[') { /* skip IPv6 literal address */
1298 while (*frompath && (*frompath != ']')) {
1299 frompath++;
1300 }
1301 if (*frompath == ']') {
1302 frompath++;
1303 }
1304 }
1305 while (*frompath && (*frompath != ':')) {
1306 frompath++;
1307 }
1308 endserverp = frompath;
1309 while (*frompath && (*frompath == ':')) {
1310 frompath++;
1311 }
1312 /* count fs location path components */
1313 p = frompath;
1314 while (*p && (*p == '/')) {
1315 p++;
1316 }
1317 numcomps = 0;
1318 while (*p) {
1319 numcomps++;
1320 while (*p && (*p != '/')) {
1321 p++;
1322 }
1323 while (*p && (*p == '/')) {
1324 p++;
1325 }
1326 }
1327
1328 /* convert address to universal address string */
1329 if (inet_ntop(AF_INET, &ndmntp->ndm_saddr.sin_addr, uaddr, sizeof(uaddr)) != uaddr) {
1330 printf("nfs_mountroot: bad address\n");
1331 error = EINVAL;
1332 goto out;
1333 }
1334
1335 /* prepare mount attributes */
1336 NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
1337 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
1338 NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
1339 NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
1340 NFS_BITMAP_SET(mattrs, NFS_MATTR_FH);
1341 NFS_BITMAP_SET(mattrs, NFS_MATTR_FS_LOCATIONS);
1342 NFS_BITMAP_SET(mattrs, NFS_MATTR_MNTFLAGS);
1343
1344 /* prepare mount flags */
1345 NFS_BITMAP_ZERO(mflags_mask, NFS_MFLAG_BITMAP_LEN);
1346 NFS_BITMAP_ZERO(mflags, NFS_MFLAG_BITMAP_LEN);
1347 NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_RESVPORT);
1348 NFS_BITMAP_SET(mflags, NFS_MFLAG_RESVPORT);
1349
1350 /* build xdr buffer */
1351 xb_init_buffer(&xb, NULL, 0);
1352 xb_add_32(error, &xb, NFS_ARGSVERSION_XDR);
1353 argslength_offset = xb_offset(&xb);
1354 xb_add_32(error, &xb, 0); // args length
1355 xb_add_32(error, &xb, NFS_XDRARGS_VERSION_0);
1356 xb_add_bitmap(error, &xb, mattrs, NFS_MATTR_BITMAP_LEN);
1357 attrslength_offset = xb_offset(&xb);
1358 xb_add_32(error, &xb, 0); // attrs length
1359 xb_add_32(error, &xb, ndmntp->ndm_nfsv3 ? 3 : 2); // NFS version
1360 xb_add_string(error, &xb, ((ndmntp->ndm_sotype == SOCK_DGRAM) ? "udp" : "tcp"), 3);
1361 xb_add_32(error, &xb, ntohs(ndmntp->ndm_saddr.sin_port)); // NFS port
1362 xb_add_fh(error, &xb, &ndmntp->ndm_fh[0], ndmntp->ndm_fhlen);
1363 /* fs location */
1364 xb_add_32(error, &xb, 1); /* fs location count */
1365 xb_add_32(error, &xb, 1); /* server count */
1366 xb_add_string(error, &xb, ndmntp->ndm_mntfrom, (endserverp - ndmntp->ndm_mntfrom)); /* server name */
1367 xb_add_32(error, &xb, 1); /* address count */
1368 xb_add_string(error, &xb, uaddr, strlen(uaddr)); /* address */
1369 xb_add_32(error, &xb, 0); /* empty server info */
1370 xb_add_32(error, &xb, numcomps); /* pathname component count */
1371 p = frompath;
1372 while (*p && (*p == '/')) {
1373 p++;
1374 }
1375 while (*p) {
1376 cp = p;
1377 while (*p && (*p != '/')) {
1378 p++;
1379 }
1380 xb_add_string(error, &xb, cp, (p - cp)); /* component */
1381 if (error) {
1382 break;
1383 }
1384 while (*p && (*p == '/')) {
1385 p++;
1386 }
1387 }
1388 xb_add_32(error, &xb, 0); /* empty fsl info */
1389 xb_add_32(error, &xb, mntflag); /* MNT flags */
1390 xb_build_done(error, &xb);
1391
1392 /* update opaque counts */
1393 end_offset = xb_offset(&xb);
1394 if (!error) {
1395 error = xb_seek(&xb, argslength_offset);
1396 xb_add_32(error, &xb, end_offset - argslength_offset + XDRWORD /*version*/);
1397 }
1398 if (!error) {
1399 error = xb_seek(&xb, attrslength_offset);
1400 xb_add_32(error, &xb, end_offset - attrslength_offset - XDRWORD /*don't include length field*/);
1401 }
1402 if (error) {
1403 printf("nfs_mountroot: error %d assembling mount args\n", error);
1404 goto out;
1405 }
1406 /* grab the assembled buffer */
1407 xdrbuf = xb_buffer_base(&xb);
1408
1409 /* do the mount */
1410 if ((error = VFS_MOUNT(mp, vp, CAST_USER_ADDR_T(xdrbuf), ctx))) {
1411 printf("nfs_mountroot: mount %s failed: %d\n", mntname, error);
1412 vnode_put(mp->mnt_vnodecovered);
1413 mount_list_lock();
1414 vfsp->vfc_refcount--;
1415 mount_list_unlock();
1416 vfs_unbusy(mp);
1417 mount_lock_destroy(mp);
1418 #if CONFIG_MACF
1419 mac_mount_label_destroy(mp);
1420 #endif
1421 NFS_ZFREE(mount_zone, mp);
1422 goto out;
1423 } else {
1424 *mpp = mp;
1425 error = VFS_ROOT(mp, vpp, ctx);
1426 }
1427 out:
1428 xb_cleanup(&xb);
1429 return error;
1430 }
1431 #endif /* NO_MOUNT_PRIVATE */
1432
1433 #endif /* CONFIG_NETBOOT */
1434
1435 #endif /* CONFIG_NFS_CLIENT */
1436