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