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