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