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