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