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