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