]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_boot.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_boot.c
CommitLineData
1c79356b 1/*
90556fb8 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
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
125extern char *strchr(const char *str, int ch);
126
127#if NETHER == 0
128
129int nfs_boot_init(nd, procp)
130 struct nfs_diskless *nd;
131 struct proc *procp;
132{
133 panic("nfs_boot_init: no ether");
134}
135
90556fb8
A
136int 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
1c79356b
A
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
1c79356b
A
166/* bootparam RPC */
167static int bp_whoami __P((struct sockaddr_in *bpsin,
168 struct in_addr *my_ip, struct in_addr *gw_ip));
169static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
170 struct sockaddr_in *mdsin, char *servname, char *path));
171
1c79356b 172/* mountd RPC */
90556fb8
A
173static int md_mount __P((struct sockaddr_in *mdsin, char *path, int v3,
174 u_char *fhp, u_long *fhlenp));
1c79356b
A
175
176/* other helpers */
90556fb8 177static int get_file_handle __P((struct nfs_dlmount *ndmntp));
9bccf70c 178
1c79356b
A
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]
9bccf70c
A
183
184extern boolean_t
185netboot_iaddr(struct in_addr * iaddr_p);
186
187extern boolean_t
188netboot_rootpath(struct in_addr * server_ip,
189 char * name, int name_len,
190 char * path, int path_len);
191
1c79356b
A
192/*
193 * Called with an empty nfs_diskless struct to be filled in.
194 */
195int
196nfs_boot_init(nd, procp)
197 struct nfs_diskless *nd;
198 struct proc *procp;
199{
9bccf70c
A
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;
9bccf70c
A
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;
de355530 211 goto failed;
9bccf70c 212 }
1c79356b 213
9bccf70c 214 /* get the root path information */
90556fb8 215 MALLOC_ZONE(nd->nd_root.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
9bccf70c
A
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),
90556fb8 222 nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) {
9bccf70c
A
223 do_bpgetfile = FALSE;
224 do_bpwhoami = FALSE;
1c79356b 225 }
9bccf70c 226 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
1c79356b
A
227
228 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
229
1c79356b 230 if (do_bpwhoami) {
1c79356b 231 struct in_addr router;
9bccf70c
A
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;
1c79356b
A
245 router.s_addr = 0;
246 error = bp_whoami(&bp_sin, &my_ip, &router);
247 if (error) {
9bccf70c
A
248 printf("nfs_boot: bootparam whoami, error=%d", error);
249 goto failed;
1c79356b 250 }
9bccf70c
A
251 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
252 IP_LIST(&bp_sin.sin_addr));
253 printf("nfs_boot: hostname %s\n", hostname);
1c79356b 254 }
1c79356b 255 if (do_bpgetfile) {
9bccf70c 256 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
90556fb8 257 nd->nd_root.ndm_host, nd->nd_root.ndm_path);
9bccf70c
A
258 if (error) {
259 printf("nfs_boot: bootparam get root: %d\n", error);
260 goto failed;
261 }
262 }
1c79356b
A
263
264#if !defined(NO_MOUNT_PRIVATE)
265 if (do_bpgetfile) { /* get private path */
90556fb8 266 MALLOC_ZONE(nd->nd_private.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
9bccf70c
A
267 error = bp_getfile(&bp_sin, "private",
268 &nd->nd_private.ndm_saddr,
90556fb8
A
269 nd->nd_private.ndm_host,
270 nd->nd_private.ndm_path);
9bccf70c
A
271 if (!error) {
272 char * check_path = NULL;
273
90556fb8
A
274 MALLOC_ZONE(check_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
275 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path);
9bccf70c
A
276 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
277 == nd->nd_private.ndm_saddr.sin_addr.s_addr)
90556fb8 278 && (strcmp(check_path, nd->nd_private.ndm_path) == 0)) {
9bccf70c
A
279 /* private path is prefix of root path, don't mount */
280 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
281 }
90556fb8 282 FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI);
1c79356b 283 }
9bccf70c
A
284 else {
285 /* private key not defined, don't mount */
286 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
1c79356b 287 }
9bccf70c
A
288 }
289 else {
290 error = 0;
1c79356b
A
291 }
292#endif NO_MOUNT_PRIVATE
9bccf70c 293 failed:
1c79356b 294 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
90556fb8
A
295 return (error);
296}
297
298/*
299 * Called with a partially initialized nfs_diskless struct
300 * with file handles to be filled in.
301 */
302int
303nfs_boot_getfh(nd, procp, v3)
304 struct nfs_diskless *nd;
305 struct proc *procp;
306 int v3;
307{
308 int error = 0;
309
310 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
311
312 nd->nd_root.ndm_nfsv3 = v3;
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 error = get_file_handle(&nd->nd_private);
325 if (error) {
326 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n",
327 v3 ? 3 : 2, error);
328 goto failed;
329 }
330 }
331#endif NO_MOUNT_PRIVATE
332 failed:
333 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
9bccf70c 334 return (error);
1c79356b
A
335}
336
9bccf70c 337static int
90556fb8
A
338get_file_handle(ndmntp)
339 struct nfs_dlmount *ndmntp;
1c79356b
A
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 */
90556fb8
A
348 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3,
349 ndmntp->ndm_fh, &ndmntp->ndm_fhlen);
1c79356b 350 if (error)
9bccf70c 351 return (error);
1c79356b
A
352
353 /* Construct remote path (for getmntinfo(3)) */
354 dp = ndmntp->ndm_host;
355 endp = dp + MNAMELEN - 1;
356 dp += strlen(dp);
357 *dp++ = ':';
90556fb8 358 for (sp = ndmntp->ndm_path; *sp && dp < endp;)
1c79356b
A
359 *dp++ = *sp++;
360 *dp = '\0';
9bccf70c 361 return (0);
1c79356b
A
362
363}
364
365
366/*
367 * Get an mbuf with the given length, and
368 * initialize the pkthdr length field.
369 */
370static struct mbuf *
371m_get_len(int msg_len)
372{
373 struct mbuf *m;
374 m = m_gethdr(M_WAIT, MT_DATA);
375 if (m == NULL)
376 return NULL;
377 if (msg_len > MHLEN) {
378 if (msg_len > MCLBYTES)
379 panic("nfs_boot: msg_len > MCLBYTES");
380 MCLGET(m, M_WAIT);
381 if (m == NULL)
382 return NULL;
383 }
384 m->m_len = msg_len;
385 m->m_pkthdr.len = m->m_len;
386 return (m);
387}
388
389
390/*
391 * String representation for RPC.
392 */
393struct rpc_string {
394 u_long len; /* length without null or padding */
395 u_char data[4]; /* data (longer, of course) */
396 /* data is padded to a long-word boundary */
397};
398/* Compute space used given string length. */
399#define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
400
401/*
402 * Inet address in RPC messages
403 * (Note, really four longs, NOT chars. Blech.)
404 */
405struct bp_inaddr {
406 u_long atype;
407 long addr[4];
408};
409
410
411/*
412 * RPC: bootparam/whoami
413 * Given client IP address, get:
414 * client name (hostname)
415 * domain name (domainname)
416 * gateway address
417 *
418 * The hostname and domainname are set here for convenience.
419 *
420 * Note - bpsin is initialized to the broadcast address,
421 * and will be replaced with the bootparam server address
422 * after this call is complete. Have to use PMAP_PROC_CALL
423 * to make sure we get responses only from a servers that
424 * know about us (don't want to broadcast a getport call).
425 */
426static int
427bp_whoami(bpsin, my_ip, gw_ip)
428 struct sockaddr_in *bpsin;
429 struct in_addr *my_ip;
430 struct in_addr *gw_ip;
431{
432 /* RPC structures for PMAPPROC_CALLIT */
433 struct whoami_call {
434 u_long call_prog;
435 u_long call_vers;
436 u_long call_proc;
437 u_long call_arglen;
438 struct bp_inaddr call_ia;
439 } *call;
440
441 struct rpc_string *str;
442 struct bp_inaddr *bia;
443 struct mbuf *m;
444 struct sockaddr_in *sin;
445 int error, msg_len;
446 int cn_len, dn_len;
447 u_char *p;
448 long *lp;
449
450 /*
451 * Get message buffer of sufficient size.
452 */
453 msg_len = sizeof(*call);
454 m = m_get_len(msg_len);
455 if (m == NULL)
456 return ENOBUFS;
457
458 /*
459 * Build request message for PMAPPROC_CALLIT.
460 */
461 call = mtod(m, struct whoami_call *);
462 call->call_prog = htonl(BOOTPARAM_PROG);
463 call->call_vers = htonl(BOOTPARAM_VERS);
464 call->call_proc = htonl(BOOTPARAM_WHOAMI);
465 call->call_arglen = htonl(sizeof(struct bp_inaddr));
466
467 /* client IP address */
468 call->call_ia.atype = htonl(1);
469 p = (u_char*)my_ip;
470 lp = call->call_ia.addr;
471 *lp++ = htonl(*p); p++;
472 *lp++ = htonl(*p); p++;
473 *lp++ = htonl(*p); p++;
474 *lp++ = htonl(*p); p++;
475
476 /* RPC: portmap/callit */
477 bpsin->sin_port = htons(PMAPPORT);
478
479 error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
480 PMAPPROC_CALLIT, &m, &sin);
481 if (error)
482 return error;
483
484 /*
485 * Parse result message.
486 */
487 msg_len = m->m_len;
488 lp = mtod(m, long *);
489
490 /* bootparam server port (also grab from address). */
491 if (msg_len < sizeof(*lp))
492 goto bad;
493 msg_len -= sizeof(*lp);
494 bpsin->sin_port = htons((short)ntohl(*lp++));
495 bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
496
497 /* length of encapsulated results */
498 if (msg_len < (ntohl(*lp) + sizeof(*lp)))
499 goto bad;
500 msg_len = ntohl(*lp++);
501 p = (char*)lp;
502
503 /* client name */
504 if (msg_len < sizeof(*str))
505 goto bad;
506 str = (struct rpc_string *)p;
507 cn_len = ntohl(str->len);
508 if (msg_len < cn_len)
509 goto bad;
510 if (cn_len >= MAXHOSTNAMELEN)
511 goto bad;
512 bcopy(str->data, hostname, cn_len);
513 hostname[cn_len] = '\0';
514 hostnamelen = cn_len;
515 p += RPC_STR_SIZE(cn_len);
516 msg_len -= RPC_STR_SIZE(cn_len);
517
518 /* domain name */
519 if (msg_len < sizeof(*str))
520 goto bad;
521 str = (struct rpc_string *)p;
522 dn_len = ntohl(str->len);
523 if (msg_len < dn_len)
524 goto bad;
525 if (dn_len >= MAXHOSTNAMELEN)
526 goto bad;
527 bcopy(str->data, domainname, dn_len);
528 domainname[dn_len] = '\0';
529 domainnamelen = dn_len;
530 p += RPC_STR_SIZE(dn_len);
531 msg_len -= RPC_STR_SIZE(dn_len);
532
533 /* gateway address */
534 if (msg_len < sizeof(*bia))
535 goto bad;
536 bia = (struct bp_inaddr *)p;
537 if (bia->atype != htonl(1))
538 goto bad;
539 p = (u_char*)gw_ip;
540 *p++ = ntohl(bia->addr[0]);
541 *p++ = ntohl(bia->addr[1]);
542 *p++ = ntohl(bia->addr[2]);
543 *p++ = ntohl(bia->addr[3]);
544 goto out;
545
546bad:
547 printf("nfs_boot: bootparam_whoami: bad reply\n");
548 error = EBADRPC;
549
550out:
551 if (sin)
552 FREE(sin, M_SONAME);
553
554 m_freem(m);
555 return(error);
556}
557
558
559/*
560 * RPC: bootparam/getfile
561 * Given client name and file "key", get:
562 * server name
563 * server IP address
564 * server pathname
565 */
566static int
567bp_getfile(bpsin, key, md_sin, serv_name, pathname)
568 struct sockaddr_in *bpsin;
569 char *key;
570 struct sockaddr_in *md_sin;
571 char *serv_name;
572 char *pathname;
573{
574 struct rpc_string *str;
575 struct mbuf *m;
576 struct bp_inaddr *bia;
577 struct sockaddr_in *sin;
578 u_char *p, *q;
579 int error, msg_len;
580 int cn_len, key_len, sn_len, path_len;
581
582 /*
583 * Get message buffer of sufficient size.
584 */
585 cn_len = hostnamelen;
586 key_len = strlen(key);
587 msg_len = 0;
588 msg_len += RPC_STR_SIZE(cn_len);
589 msg_len += RPC_STR_SIZE(key_len);
590 m = m_get_len(msg_len);
591 if (m == NULL)
592 return ENOBUFS;
593
594 /*
595 * Build request message.
596 */
597 p = mtod(m, u_char *);
598 bzero(p, msg_len);
599 /* client name (hostname) */
600 str = (struct rpc_string *)p;
601 str->len = htonl(cn_len);
602 bcopy(hostname, str->data, cn_len);
603 p += RPC_STR_SIZE(cn_len);
604 /* key name (root or swap) */
605 str = (struct rpc_string *)p;
606 str->len = htonl(key_len);
607 bcopy(key, str->data, key_len);
608
609 /* RPC: bootparam/getfile */
610 error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
611 BOOTPARAM_GETFILE, &m, NULL);
612 if (error)
613 return error;
614
615 /*
616 * Parse result message.
617 */
618 p = mtod(m, u_char *);
619 msg_len = m->m_len;
620
621 /* server name */
622 if (msg_len < sizeof(*str))
623 goto bad;
624 str = (struct rpc_string *)p;
625 sn_len = ntohl(str->len);
626 if (msg_len < sn_len)
627 goto bad;
628 if (sn_len >= MNAMELEN)
629 goto bad;
630 bcopy(str->data, serv_name, sn_len);
631 serv_name[sn_len] = '\0';
632 p += RPC_STR_SIZE(sn_len);
633 msg_len -= RPC_STR_SIZE(sn_len);
634
635 /* server IP address (mountd) */
636 if (msg_len < sizeof(*bia))
637 goto bad;
638 bia = (struct bp_inaddr *)p;
639 if (bia->atype != htonl(1))
640 goto bad;
641 sin = md_sin;
642 bzero((caddr_t)sin, sizeof(*sin));
643 sin->sin_len = sizeof(*sin);
644 sin->sin_family = AF_INET;
645 q = (u_char*) &sin->sin_addr;
646 *q++ = ntohl(bia->addr[0]);
647 *q++ = ntohl(bia->addr[1]);
648 *q++ = ntohl(bia->addr[2]);
649 *q++ = ntohl(bia->addr[3]);
650 p += sizeof(*bia);
651 msg_len -= sizeof(*bia);
652
653 /* server pathname */
654 if (msg_len < sizeof(*str))
655 goto bad;
656 str = (struct rpc_string *)p;
657 path_len = ntohl(str->len);
658 if (msg_len < path_len)
659 goto bad;
660 if (path_len >= MAXPATHLEN)
661 goto bad;
662 bcopy(str->data, pathname, path_len);
663 pathname[path_len] = '\0';
664 goto out;
665
666bad:
667 printf("nfs_boot: bootparam_getfile: bad reply\n");
668 error = EBADRPC;
669
670out:
671 m_freem(m);
672 return(0);
673}
674
675
676/*
677 * RPC: mountd/mount
678 * Given a server pathname, get an NFS file handle.
679 * Also, sets sin->sin_port to the NFS service port.
680 */
681static int
90556fb8 682md_mount(mdsin, path, v3, fhp, fhlenp)
1c79356b
A
683 struct sockaddr_in *mdsin; /* mountd server address */
684 char *path;
90556fb8 685 int v3;
1c79356b 686 u_char *fhp;
90556fb8 687 u_long *fhlenp;
1c79356b
A
688{
689 /* The RPC structures */
690 struct rpc_string *str;
691 struct rdata {
692 u_long errno;
90556fb8 693 u_char data[NFSX_V3FHMAX + sizeof(u_long)];
1c79356b
A
694 } *rdata;
695 struct mbuf *m;
696 int error, mlen, slen;
90556fb8 697 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1;
1c79356b
A
698
699 /* Get port number for MOUNTD. */
90556fb8 700 error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion,
1c79356b
A
701 &mdsin->sin_port);
702 if (error) return error;
703
704 slen = strlen(path);
705 mlen = RPC_STR_SIZE(slen);
706
707 m = m_get_len(mlen);
708 if (m == NULL)
709 return ENOBUFS;
710 str = mtod(m, struct rpc_string *);
711 str->len = htonl(slen);
712 bcopy(path, str->data, slen);
713
714 /* Do RPC to mountd. */
90556fb8 715 error = krpc_call(mdsin, RPCPROG_MNT, mntversion,
1c79356b
A
716 RPCMNT_MOUNT, &m, NULL);
717 if (error)
718 return error; /* message already freed */
719
90556fb8
A
720 /*
721 * the reply must be long enough to hold the errno plus either of:
722 * + a v2 filehandle
723 * + a v3 filehandle length + a v3 filehandle
724 */
1c79356b 725 mlen = m->m_len;
90556fb8 726 if (mlen < sizeof(u_long))
1c79356b
A
727 goto bad;
728 rdata = mtod(m, struct rdata *);
729 error = ntohl(rdata->errno);
730 if (error)
90556fb8
A
731 goto out;
732 if (v3) {
733 u_long fhlen;
734 u_char *fh;
735 if (mlen < sizeof(u_long)*2)
736 goto bad;
737 fhlen = ntohl(*(u_long*)rdata->data);
738 fh = rdata->data + sizeof(u_long);
739 if (mlen < (sizeof(u_long)*2 + fhlen))
740 goto bad;
741 bcopy(fh, fhp, fhlen);
742 *fhlenp = fhlen;
743 } else {
744 if (mlen < (sizeof(u_long) + NFSX_V2FH))
745 goto bad;
746 bcopy(rdata->data, fhp, NFSX_V2FH);
747 *fhlenp = NFSX_V2FH;
748 }
1c79356b
A
749
750 /* Set port number for NFS use. */
90556fb8 751 error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2,
1c79356b
A
752 &mdsin->sin_port);
753 goto out;
754
755bad:
756 error = EBADRPC;
757
758out:
759 m_freem(m);
760 return error;
761}
762
763#endif /* NETHER */