]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_boot.c
xnu-792.6.22.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_boot.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
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 *
e5568f75
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,
e5568f75
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>
91447636
A
95#include <sys/mount_internal.h>
96#include <sys/kpi_mbuf.h>
1c79356b
A
97
98#include <sys/malloc.h>
99#include <sys/socket.h>
1c79356b
A
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
1c79356b
A
121
122#if NETHER == 0
123
91447636 124int nfs_boot_init(struct nfs_diskless *nd, proc_t procp)
1c79356b
A
125{
126 panic("nfs_boot_init: no ether");
127}
128
91447636 129int nfs_boot_getfh(struct nfs_diskless *nd, proc_t procp, int v3, int sotype)
90556fb8
A
130{
131 panic("nfs_boot_getfh: no ether");
132}
133
1c79356b
A
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
1c79356b 156/* bootparam RPC */
91447636
A
157static int bp_whoami(struct sockaddr_in *bpsin,
158 struct in_addr *my_ip, struct in_addr *gw_ip);
159static int bp_getfile(struct sockaddr_in *bpsin, const char *key,
160 struct sockaddr_in *mdsin, char *servname, char *path);
1c79356b 161
1c79356b 162/* mountd RPC */
91447636
A
163static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype,
164 u_char *fhp, u_long *fhlenp);
1c79356b
A
165
166/* other helpers */
91447636 167static int get_file_handle(struct nfs_dlmount *ndmntp);
9bccf70c 168
1c79356b
A
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]
9bccf70c
A
173
174extern boolean_t
175netboot_iaddr(struct in_addr * iaddr_p);
176
177extern boolean_t
178netboot_rootpath(struct in_addr * server_ip,
179 char * name, int name_len,
180 char * path, int path_len);
181
1c79356b
A
182/*
183 * Called with an empty nfs_diskless struct to be filled in.
184 */
185int
91447636 186nfs_boot_init(struct nfs_diskless *nd, __unused proc_t procp)
1c79356b 187{
9bccf70c
A
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;
9bccf70c
A
193 struct sockaddr_in * sin_p;
194
91447636
A
195 /* make sure mbuf constants are set up */
196 if (!nfs_mbuf_mlen)
197 nfs_mbuf_init();
198
9bccf70c
A
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;
91447636 203 goto failed;
9bccf70c 204 }
1c79356b 205
9bccf70c 206 /* get the root path information */
90556fb8 207 MALLOC_ZONE(nd->nd_root.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636
A
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 }
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 224
1c79356b 225 if (do_bpwhoami) {
1c79356b 226 struct in_addr router;
9bccf70c
A
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;
1c79356b
A
240 router.s_addr = 0;
241 error = bp_whoami(&bp_sin, &my_ip, &router);
242 if (error) {
9bccf70c
A
243 printf("nfs_boot: bootparam whoami, error=%d", error);
244 goto failed;
1c79356b 245 }
9bccf70c
A
246 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
247 IP_LIST(&bp_sin.sin_addr));
248 printf("nfs_boot: hostname %s\n", hostname);
1c79356b 249 }
1c79356b 250 if (do_bpgetfile) {
9bccf70c 251 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
90556fb8 252 nd->nd_root.ndm_host, nd->nd_root.ndm_path);
9bccf70c
A
253 if (error) {
254 printf("nfs_boot: bootparam get root: %d\n", error);
255 goto failed;
256 }
257 }
1c79356b
A
258
259#if !defined(NO_MOUNT_PRIVATE)
260 if (do_bpgetfile) { /* get private path */
90556fb8 261 MALLOC_ZONE(nd->nd_private.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636
A
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 }
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 274 MALLOC_ZONE(check_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636
A
275 if (!check_path) {
276 printf("nfs_boot: can't allocate check_path buffer\n");
277 error = ENOMEM;
278 goto failed;
279 }
90556fb8 280 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path);
9bccf70c
A
281 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
282 == nd->nd_private.ndm_saddr.sin_addr.s_addr)
90556fb8 283 && (strcmp(check_path, nd->nd_private.ndm_path) == 0)) {
9bccf70c
A
284 /* private path is prefix of root path, don't mount */
285 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
286 }
90556fb8 287 FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI);
1c79356b 288 }
9bccf70c
A
289 else {
290 /* private key not defined, don't mount */
291 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
1c79356b 292 }
9bccf70c
A
293 }
294 else {
295 error = 0;
1c79356b 296 }
55e303ae
A
297#endif /* NO_MOUNT_PRIVATE */
298failed:
90556fb8
A
299 return (error);
300}
301
302/*
303 * Called with a partially initialized nfs_diskless struct
304 * with file handles to be filled in.
305 */
306int
91447636 307nfs_boot_getfh(struct nfs_diskless *nd, __unused proc_t procp, int v3, int sotype)
90556fb8
A
308{
309 int error = 0;
310
90556fb8 311 nd->nd_root.ndm_nfsv3 = v3;
91447636 312 nd->nd_root.ndm_sotype = sotype;
90556fb8
A
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;
91447636 324 nd->nd_private.ndm_sotype = sotype;
90556fb8
A
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 }
55e303ae 332#endif /* NO_MOUNT_PRIVATE */
91447636 333failed:
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 348 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3,
91447636 349 ndmntp->ndm_sotype, 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 */
91447636
A
370static int
371mbuf_get_with_len(int msg_len, mbuf_t *m)
1c79356b 372{
91447636
A
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))
1c79356b 384 panic("nfs_boot: msg_len > MCLBYTES");
1c79356b 385 }
91447636
A
386 mbuf_setlen(*m, msg_len);
387 mbuf_pkthdr_setlen(*m, msg_len);
388 return (0);
1c79356b
A
389}
390
391
392/*
393 * String representation for RPC.
394 */
395struct 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 */
407struct 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 */
428static int
429bp_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;
91447636
A
445 mbuf_t m;
446 struct sockaddr_in sin;
1c79356b
A
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);
91447636
A
456 error = mbuf_get_with_len(msg_len, &m);
457 if (error)
458 return error;
1c79356b
A
459
460 /*
461 * Build request message for PMAPPROC_CALLIT.
462 */
91447636 463 call = mbuf_data(m);
1c79356b
A
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
91447636 481 error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin);
1c79356b
A
482 if (error)
483 return error;
484
485 /*
486 * Parse result message.
487 */
91447636
A
488 msg_len = mbuf_len(m);
489 lp = mbuf_data(m);
1c79356b
A
490
491 /* bootparam server port (also grab from address). */
91447636 492 if (msg_len < (int)sizeof(*lp))
1c79356b
A
493 goto bad;
494 msg_len -= sizeof(*lp);
495 bpsin->sin_port = htons((short)ntohl(*lp++));
91447636 496 bpsin->sin_addr.s_addr = sin.sin_addr.s_addr;
1c79356b
A
497
498 /* length of encapsulated results */
91447636 499 if (msg_len < (ntohl(*lp) + (int)sizeof(*lp)))
1c79356b
A
500 goto bad;
501 msg_len = ntohl(*lp++);
502 p = (char*)lp;
503
504 /* client name */
91447636 505 if (msg_len < (int)sizeof(*str))
1c79356b
A
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 */
91447636 520 if (msg_len < (int)sizeof(*str))
1c79356b
A
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 */
91447636 535 if (msg_len < (int)sizeof(*bia))
1c79356b
A
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
547bad:
548 printf("nfs_boot: bootparam_whoami: bad reply\n");
549 error = EBADRPC;
550
551out:
91447636 552 mbuf_freem(m);
1c79356b
A
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 */
564static int
565bp_getfile(bpsin, key, md_sin, serv_name, pathname)
566 struct sockaddr_in *bpsin;
91447636 567 const char *key;
1c79356b
A
568 struct sockaddr_in *md_sin;
569 char *serv_name;
570 char *pathname;
571{
572 struct rpc_string *str;
91447636 573 mbuf_t m;
1c79356b
A
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);
91447636
A
588 error = mbuf_get_with_len(msg_len, &m);
589 if (error)
590 return error;
1c79356b
A
591
592 /*
593 * Build request message.
594 */
91447636 595 p = mbuf_data(m);
1c79356b
A
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 */
91447636 608 error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS,
1c79356b
A
609 BOOTPARAM_GETFILE, &m, NULL);
610 if (error)
611 return error;
612
613 /*
614 * Parse result message.
615 */
91447636
A
616 p = mbuf_data(m);
617 msg_len = mbuf_len(m);
1c79356b
A
618
619 /* server name */
91447636 620 if (msg_len < (int)sizeof(*str))
1c79356b
A
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) */
91447636 634 if (msg_len < (int)sizeof(*bia))
1c79356b
A
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 */
91447636 652 if (msg_len < (int)sizeof(*str))
1c79356b
A
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
664bad:
665 printf("nfs_boot: bootparam_getfile: bad reply\n");
666 error = EBADRPC;
667
668out:
91447636 669 mbuf_freem(m);
1c79356b
A
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 */
679static int
91447636 680md_mount(mdsin, path, v3, sotype, fhp, fhlenp)
1c79356b
A
681 struct sockaddr_in *mdsin; /* mountd server address */
682 char *path;
90556fb8 683 int v3;
91447636 684 int sotype;
1c79356b 685 u_char *fhp;
90556fb8 686 u_long *fhlenp;
1c79356b
A
687{
688 /* The RPC structures */
689 struct rpc_string *str;
690 struct rdata {
691 u_long errno;
90556fb8 692 u_char data[NFSX_V3FHMAX + sizeof(u_long)];
1c79356b 693 } *rdata;
91447636 694 mbuf_t m;
1c79356b 695 int error, mlen, slen;
90556fb8 696 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1;
91447636
A
697 int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP;
698 in_port_t mntport, nfsport;
1c79356b
A
699
700 /* Get port number for MOUNTD. */
91447636
A
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;
1c79356b
A
713
714 slen = strlen(path);
715 mlen = RPC_STR_SIZE(slen);
716
91447636
A
717 error = mbuf_get_with_len(mlen, &m);
718 if (error)
719 return error;
720 str = mbuf_data(m);
1c79356b
A
721 str->len = htonl(slen);
722 bcopy(path, str->data, slen);
723
724 /* Do RPC to mountd. */
91447636 725 error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL);
1c79356b
A
726 if (error)
727 return error; /* message already freed */
728
90556fb8
A
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 */
91447636
A
734 mlen = mbuf_len(m);
735 if (mlen < (int)sizeof(u_long))
1c79356b 736 goto bad;
91447636 737 rdata = mbuf_data(m);
1c79356b
A
738 error = ntohl(rdata->errno);
739 if (error)
90556fb8
A
740 goto out;
741 if (v3) {
742 u_long fhlen;
743 u_char *fh;
91447636 744 if (mlen < (int)sizeof(u_long)*2)
90556fb8
A
745 goto bad;
746 fhlen = ntohl(*(u_long*)rdata->data);
747 fh = rdata->data + sizeof(u_long);
91447636 748 if (mlen < (int)(sizeof(u_long)*2 + fhlen))
90556fb8
A
749 goto bad;
750 bcopy(fh, fhp, fhlen);
751 *fhlenp = fhlen;
752 } else {
91447636 753 if (mlen < ((int)sizeof(u_long) + NFSX_V2FH))
90556fb8
A
754 goto bad;
755 bcopy(rdata->data, fhp, NFSX_V2FH);
756 *fhlenp = NFSX_V2FH;
757 }
1c79356b
A
758
759 /* Set port number for NFS use. */
91447636 760 mdsin->sin_port = nfsport;
1c79356b
A
761 goto out;
762
763bad:
764 error = EBADRPC;
765
766out:
91447636 767 mbuf_freem(m);
1c79356b
A
768 return error;
769}
770
771#endif /* NETHER */