]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_boot.c
f7849b02d1a8eedf34368eda40ba3bce1fb48028
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1994 Adam Glass, Gordon Ross
25 * All rights reserved.
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.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
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.
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
60 * 14-March-97 Dieter Siegmund (dieter@next.com)
61 * - Use BOOTP instead of RARP to get the IP address at boot time
63 * 23-May-97 Umesh Vaishampayan (umeshv@apple.com)
64 * - Added the ability to mount "/private" separately.
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
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
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/kernel.h>
93 #include <sys/ioctl.h>
95 #include <sys/mount.h>
98 #include <sys/malloc.h>
99 #include <sys/socket.h>
100 #include <sys/reboot.h>
103 #include <net/if_dl.h>
104 #include <net/if_types.h>
105 #include <net/route.h>
107 #include <netinet/in.h>
108 #include <netinet/if_ether.h>
110 #include <nfs/rpcv2.h>
111 #include <nfs/nfsproto.h>
113 #include <nfs/nfsdiskless.h>
114 #include <nfs/krpc.h>
116 #include <pexpert/pexpert.h>
120 #include <libkern/libkern.h>
122 extern char *strchr(const char *str
, int ch
);
126 int nfs_boot_init(nd
, procp
)
127 struct nfs_diskless
*nd
;
130 panic("nfs_boot_init: no ether");
136 * Support for NFS diskless booting, specifically getting information
137 * about where to boot from, what pathnames, etc.
139 * This implememtation uses RARP and the bootparam RPC.
140 * We are forced to implement RPC anyway (to get file handles)
141 * so we might as well take advantage of it for bootparam too.
143 * The diskless boot sequence goes as follows:
144 * (1) Use RARP to get our interface address
145 * (2) Use RPC/bootparam/whoami to get our hostname,
146 * our IP address, and the server's IP address.
147 * (3) Use RPC/bootparam/getfile to get the root path
148 * (4) Use RPC/mountd to get the root file handle
149 * (5) Use RPC/bootparam/getfile to get the swap path
150 * (6) Use RPC/mountd to get the swap file handle
152 * (This happens to be the way Sun does it too.)
155 extern int bootp(struct ifnet
* ifp
, struct in_addr
* iaddr_p
, int max_retry
,
156 struct in_addr
* netmask_p
, struct in_addr
* router_p
,
157 struct proc
* procp
);
160 static int bp_whoami
__P((struct sockaddr_in
*bpsin
,
161 struct in_addr
*my_ip
, struct in_addr
*gw_ip
));
162 static int bp_getfile
__P((struct sockaddr_in
*bpsin
, char *key
,
163 struct sockaddr_in
*mdsin
, char *servname
, char *path
));
165 static boolean_t path_getfile
__P((char * image_path
,
166 struct sockaddr_in
* sin_p
,
167 char * serv_name
, char * pathname
));
170 u_long
iptohl(struct in_addr ip
)
172 return (ntohl(ip
.s_addr
));
175 static __inline__ boolean_t
176 same_subnet(struct in_addr addr1
, struct in_addr addr2
, struct in_addr mask
)
178 u_long m
= iptohl(mask
);
179 if ((iptohl(addr1
) & m
) != (iptohl(addr2
) & m
))
185 static int md_mount
__P((struct sockaddr_in
*mdsin
, char *path
,
189 static void get_file_handle
__P((char *pathname
, struct nfs_dlmount
*ndmntp
));
191 #define IP_FORMAT "%d.%d.%d.%d"
192 #define IP_CH(ip) ((u_char *)ip)
193 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
195 * Called with an empty nfs_diskless struct to be filled in.
198 nfs_boot_init(nd
, procp
)
199 struct nfs_diskless
*nd
;
202 char * booter_path
= NULL
;
203 boolean_t do_bpwhoami
= TRUE
;
204 boolean_t do_bpgetfile
= TRUE
;
206 struct in_addr my_ip
;
207 struct sockaddr_in bp_sin
;
208 struct sockaddr_in
*sin
;
210 struct in_addr gw_ip
;
212 struct in_addr my_netmask
;
214 char * root_path
= NULL
;
216 MALLOC(booter_path
, char *, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
217 MALLOC(root_path
, char *, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
219 /* booter-supplied path */
220 if (!PE_parse_boot_arg("rp", booter_path
)
221 && !PE_parse_boot_arg("rootpath", booter_path
)) {
229 /* clear out the request structure */
230 bzero(&ireq
, sizeof(ireq
));
233 * Find an interface, rarp for its ip address, stuff it, the
234 * implied broadcast addr, and netmask into a nfs_diskless struct.
236 * This was moved here from nfs_vfsops.c because this procedure
237 * would be quite different if someone decides to write (i.e.) a
238 * BOOTP version of this file (might not use RARP, etc.)
241 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
244 * Find a network interface.
247 { /* if the root device is set, use it */
248 extern char rootdevice
[];
250 ifp
= ifunit(rootdevice
);
252 if (ifp
== NULL
) { /* search for network device */
253 /* for (ifp = ifnet; ifp; ifp = ifp->if_next)*/
254 TAILQ_FOREACH(ifp
, &ifnet
, if_link
)
256 (IFF_LOOPBACK
|IFF_POINTOPOINT
)) == 0)
260 panic("nfs_boot: no suitable interface");
261 sprintf(ireq
.ifr_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
262 printf("nfs_boot: using network interface '%s'\n", ireq
.ifr_name
);
265 * Bring up the interface.
267 if ((error
= socreate(AF_INET
, &so
, SOCK_DGRAM
, 0)) != 0)
268 panic("nfs_boot: socreate, error=%d", error
);
269 ireq
.ifr_flags
= ifp
->if_flags
| IFF_UP
;
270 error
= ifioctl(so
, SIOCSIFFLAGS
, (caddr_t
)&ireq
, procp
);
272 panic("nfs_boot: SIFFLAGS, error=%d", error
);
276 { /* use BOOTP to retrieve IP address, netmask and router */
277 struct sockaddr_in sockin
;
278 struct in_addr router
;
279 struct in_addr netmask
;
284 sockin
.sin_family
= AF_INET
;
285 sockin
.sin_len
= sizeof(sockin
);
286 sockin
.sin_addr
.s_addr
= 0;
287 #define RETRY_COUNT 32
288 while ((error
= bootp(ifp
, &my_ip
, RETRY_COUNT
,
289 &netmask
, &router
, procp
))) {
290 if (error
== ETIMEDOUT
)
291 printf("nfs_boot: BOOTP timed out, retrying...\n");
294 printf("nfs_boot: bootp() failed, error = %d\n", error
);
298 /* clear the netmask */
299 ((struct sockaddr_in
*)&ireq
.ifr_addr
)->sin_addr
.s_addr
= 0;
300 error
= ifioctl(so
, SIOCSIFNETMASK
, (caddr_t
)&ireq
, procp
);
302 printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error
);
304 if (netmask
.s_addr
) {
305 /* set our new subnet mask */
306 sockin
.sin_addr
= netmask
;
307 *((struct sockaddr_in
*)&ireq
.ifr_addr
) = sockin
;
308 error
= ifioctl(so
, SIOCSIFNETMASK
, (caddr_t
)&ireq
, procp
);
310 printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error
);
313 /* set our address */
314 sockin
.sin_addr
= my_ip
;
315 *((struct sockaddr_in
*)&ireq
.ifr_addr
) = sockin
;
316 error
= ifioctl(so
, SIOCSIFADDR
, (caddr_t
)&ireq
, procp
);
318 printf("SIOCSIFADDR failed: %d\n", error
);
321 printf("nfs_boot: IP address " IP_FORMAT
, IP_LIST(&my_ip
));
323 printf(" netmask " IP_FORMAT
, IP_LIST(&netmask
));
326 printf(" router " IP_FORMAT
, IP_LIST(&router
));
332 * Do RARP for the interface address.
334 if ((error
= revarpwhoami(&my_ip
, ifp
)) != 0)
335 panic("revarp failed, error=%d", error
);
336 printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip
.s_addr
));
339 * Do enough of ifconfig(8) so that the chosen interface
340 * can talk to the servers. (just set the address)
342 sin
= (struct sockaddr_in
*)&ireq
.ifr_addr
;
343 bzero((caddr_t
)sin
, sizeof(*sin
));
344 sin
->sin_len
= sizeof(*sin
);
345 sin
->sin_family
= AF_INET
;
346 sin
->sin_addr
.s_addr
= my_ip
.s_addr
;
347 error
= ifioctl(so
, SIOCSIFADDR
, (caddr_t
)&ireq
, procp
);
349 panic("nfs_boot: set if addr, error=%d", error
);
352 /* need netmask to determine whether NFS server local */
353 sin
= (struct sockaddr_in
*)&ireq
.ifr_addr
;
354 bzero((caddr_t
)sin
, sizeof(*sin
));
355 sin
->sin_len
= sizeof(*sin
);
356 sin
->sin_family
= AF_INET
;
357 error
= ifioctl(so
, SIOCGIFNETMASK
, (caddr_t
)&ireq
, procp
);
359 panic("nfs_boot: SIOCGIFNETMASK error=%d", error
);
360 my_netmask
= sin
->sin_addr
;
364 /* check for a booter-specified path */
365 if (booter_path
[0]) {
366 nd
->nd_root
.ndm_saddr
.sin_addr
.s_addr
= 0;
367 nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
= 0;
368 if (path_getfile(booter_path
, &nd
->nd_root
.ndm_saddr
,
369 nd
->nd_root
.ndm_host
, root_path
)) {
370 do_bpgetfile
= FALSE
;
371 printf("nfs_boot: using booter-supplied path '%s'\n",
373 if (same_subnet(nd
->nd_root
.ndm_saddr
.sin_addr
,
379 /* do bpwhoami to attempt to get the router */
383 printf("nfs_boot: ignoring badly formed bootpath '%s'\n",
390 * Get client name and gateway address.
391 * RPC: bootparam/whoami
392 * Use the old broadcast address for the WHOAMI
393 * call because we do not yet know our netmask.
394 * The server address returned by the WHOAMI call
395 * is used for all subsequent booptaram RPCs.
397 bzero((caddr_t
)&bp_sin
, sizeof(bp_sin
));
398 bp_sin
.sin_len
= sizeof(bp_sin
);
399 bp_sin
.sin_family
= AF_INET
;
400 bp_sin
.sin_addr
.s_addr
= INADDR_BROADCAST
;
401 hostnamelen
= MAXHOSTNAMELEN
;
403 { /* bpwhoami also returns gateway IP address */
405 struct in_addr router
;
408 error
= bp_whoami(&bp_sin
, &my_ip
, &router
);
410 printf("nfs_boot: bootparam whoami, error=%d", error
);
411 panic("nfs_boot: bootparam whoami\n");
413 /* if not already set by BOOTP, use the one from BPWHOAMI */
414 if (gw_ip
.s_addr
== 0)
417 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT
"\n",
418 IP_LIST(&bp_sin
.sin_addr
));
419 printf("nfs_boot: hostname %s\n", hostname
);
421 #define NFS_BOOT_GATEWAY 1
422 #ifdef NFS_BOOT_GATEWAY
425 * The comment below does not apply to gw_ip discovered
426 * via BOOTP (see DO_BOOTP loop above) since BOOTP servers
427 * are supposed to be more trustworthy.
430 * XXX - This code is conditionally compiled only because
431 * many bootparam servers (in particular, SunOS 4.1.3)
432 * always set the gateway address to their own address.
433 * The bootparam server is not necessarily the gateway.
434 * We could just believe the server, and at worst you would
435 * need to delete the incorrect default route before adding
436 * the correct one, but for simplicity, ignore the gateway.
437 * If your server is OK, you can turn on this option.
439 * If the gateway address is set, add a default route.
440 * (The mountd RPCs may go across a gateway.)
443 struct sockaddr dst
, gw
, mask
;
444 /* Destination: (default) */
445 bzero((caddr_t
)&dst
, sizeof(dst
));
446 dst
.sa_len
= sizeof(dst
);
447 dst
.sa_family
= AF_INET
;
449 bzero((caddr_t
)&gw
, sizeof(gw
));
450 sin
= (struct sockaddr_in
*)&gw
;
451 sin
->sin_len
= sizeof(gw
);
452 sin
->sin_family
= AF_INET
;
453 sin
->sin_addr
.s_addr
= gw_ip
.s_addr
;
454 /* Mask: (zero length) */
455 bzero(&mask
, sizeof(mask
));
456 printf("nfs_boot: adding default route " IP_FORMAT
"\n",
458 /* add, dest, gw, mask, flags, 0 */
459 error
= rtrequest(RTM_ADD
, &dst
, (struct sockaddr
*)&gw
,
460 &mask
, (RTF_UP
| RTF_GATEWAY
| RTF_STATIC
), NULL
);
462 printf("nfs_boot: add route, error=%d\n", error
);
466 error
= bp_getfile(&bp_sin
, "root", &nd
->nd_root
.ndm_saddr
,
467 nd
->nd_root
.ndm_host
, root_path
);
469 printf("nfs_boot: bootparam get root: %d\n", error
);
470 panic("nfs_boot: bootparam get root");
474 get_file_handle(root_path
, &nd
->nd_root
);
476 #if !defined(NO_MOUNT_PRIVATE)
477 if (do_bpgetfile
) { /* get private path */
478 char * private_path
= NULL
;
480 MALLOC(private_path
, char *, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
481 error
= bp_getfile(&bp_sin
, "private",
482 &nd
->nd_private
.ndm_saddr
,
483 nd
->nd_private
.ndm_host
, private_path
);
485 char * check_path
= NULL
;
487 MALLOC(check_path
, char *, MAXPATHLEN
, M_TEMP
, M_WAITOK
);
488 sprintf(check_path
, "%s/private", root_path
);
489 if ((nd
->nd_root
.ndm_saddr
.sin_addr
.s_addr
490 == nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
)
491 && (strcmp(check_path
, private_path
) == 0)) {
492 /* private path is prefix of root path, don't mount */
493 nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
= 0;
496 get_file_handle(private_path
, &nd
->nd_private
);
498 _FREE(check_path
, M_TEMP
);
501 /* private key not defined, don't mount */
502 nd
->nd_private
.ndm_saddr
.sin_addr
.s_addr
= 0;
504 _FREE(private_path
, M_TEMP
);
506 #endif NO_MOUNT_PRIVATE
507 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
508 _FREE(booter_path
, M_TEMP
);
509 _FREE(root_path
, M_TEMP
);
514 inet_aton(char * cp
, struct in_addr
* pin
)
516 u_char
* b
= (char *)pin
;
520 for (p
= cp
, i
= 0; i
< 4; i
++) {
521 u_long l
= strtoul(p
, 0, 0);
526 if (i
< 3 && p
== NULL
)
534 * Function: parse_image_path
536 * Parse a string of the form "<IP>:<host>:<path>" into
537 * the given ip address and host and pathnames.
539 * "17.202.16.17:seaport:/release/.images/Image9/CurrentHera"
541 static __inline__ boolean_t
542 parse_image_path(char * c
, struct in_addr
* iaddr_p
, char * hostname
,
553 if ((p
- c
) >= TMP_SIZE
)
555 strncpy(tmp
, c
, p
- c
);
557 if (inet_aton(tmp
, iaddr_p
) != 1)
563 strncpy(hostname
, p
, d
- p
);
571 path_getfile(char * image_path
, struct sockaddr_in
* sin_p
,
572 char * serv_name
, char * pathname
)
574 bzero((caddr_t
)sin_p
, sizeof(*sin_p
));
575 sin_p
->sin_len
= sizeof(*sin_p
);
576 sin_p
->sin_family
= AF_INET
;
577 if (parse_image_path(image_path
, &sin_p
->sin_addr
, serv_name
, pathname
)
584 get_file_handle(pathname
, ndmntp
)
585 char *pathname
; /* path on server */
586 struct nfs_dlmount
*ndmntp
; /* output */
588 char *sp
, *dp
, *endp
;
592 * Get file handle for "key" (root or swap)
593 * using RPC to mountd/mount
595 error
= md_mount(&ndmntp
->ndm_saddr
, pathname
, ndmntp
->ndm_fh
);
597 panic("nfs_boot: mountd, error=%d", error
);
599 /* Construct remote path (for getmntinfo(3)) */
600 dp
= ndmntp
->ndm_host
;
601 endp
= dp
+ MNAMELEN
- 1;
604 for (sp
= pathname
; *sp
&& dp
< endp
;)
612 * Get an mbuf with the given length, and
613 * initialize the pkthdr length field.
616 m_get_len(int msg_len
)
619 m
= m_gethdr(M_WAIT
, MT_DATA
);
622 if (msg_len
> MHLEN
) {
623 if (msg_len
> MCLBYTES
)
624 panic("nfs_boot: msg_len > MCLBYTES");
630 m
->m_pkthdr
.len
= m
->m_len
;
636 * String representation for RPC.
639 u_long len
; /* length without null or padding */
640 u_char data
[4]; /* data (longer, of course) */
641 /* data is padded to a long-word boundary */
643 /* Compute space used given string length. */
644 #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
647 * Inet address in RPC messages
648 * (Note, really four longs, NOT chars. Blech.)
657 * RPC: bootparam/whoami
658 * Given client IP address, get:
659 * client name (hostname)
660 * domain name (domainname)
663 * The hostname and domainname are set here for convenience.
665 * Note - bpsin is initialized to the broadcast address,
666 * and will be replaced with the bootparam server address
667 * after this call is complete. Have to use PMAP_PROC_CALL
668 * to make sure we get responses only from a servers that
669 * know about us (don't want to broadcast a getport call).
672 bp_whoami(bpsin
, my_ip
, gw_ip
)
673 struct sockaddr_in
*bpsin
;
674 struct in_addr
*my_ip
;
675 struct in_addr
*gw_ip
;
677 /* RPC structures for PMAPPROC_CALLIT */
683 struct bp_inaddr call_ia
;
686 struct rpc_string
*str
;
687 struct bp_inaddr
*bia
;
689 struct sockaddr_in
*sin
;
696 * Get message buffer of sufficient size.
698 msg_len
= sizeof(*call
);
699 m
= m_get_len(msg_len
);
704 * Build request message for PMAPPROC_CALLIT.
706 call
= mtod(m
, struct whoami_call
*);
707 call
->call_prog
= htonl(BOOTPARAM_PROG
);
708 call
->call_vers
= htonl(BOOTPARAM_VERS
);
709 call
->call_proc
= htonl(BOOTPARAM_WHOAMI
);
710 call
->call_arglen
= htonl(sizeof(struct bp_inaddr
));
712 /* client IP address */
713 call
->call_ia
.atype
= htonl(1);
715 lp
= call
->call_ia
.addr
;
716 *lp
++ = htonl(*p
); p
++;
717 *lp
++ = htonl(*p
); p
++;
718 *lp
++ = htonl(*p
); p
++;
719 *lp
++ = htonl(*p
); p
++;
721 /* RPC: portmap/callit */
722 bpsin
->sin_port
= htons(PMAPPORT
);
724 error
= krpc_call(bpsin
, PMAPPROG
, PMAPVERS
,
725 PMAPPROC_CALLIT
, &m
, &sin
);
730 * Parse result message.
733 lp
= mtod(m
, long *);
735 /* bootparam server port (also grab from address). */
736 if (msg_len
< sizeof(*lp
))
738 msg_len
-= sizeof(*lp
);
739 bpsin
->sin_port
= htons((short)ntohl(*lp
++));
740 bpsin
->sin_addr
.s_addr
= sin
->sin_addr
.s_addr
;
742 /* length of encapsulated results */
743 if (msg_len
< (ntohl(*lp
) + sizeof(*lp
)))
745 msg_len
= ntohl(*lp
++);
749 if (msg_len
< sizeof(*str
))
751 str
= (struct rpc_string
*)p
;
752 cn_len
= ntohl(str
->len
);
753 if (msg_len
< cn_len
)
755 if (cn_len
>= MAXHOSTNAMELEN
)
757 bcopy(str
->data
, hostname
, cn_len
);
758 hostname
[cn_len
] = '\0';
759 hostnamelen
= cn_len
;
760 p
+= RPC_STR_SIZE(cn_len
);
761 msg_len
-= RPC_STR_SIZE(cn_len
);
764 if (msg_len
< sizeof(*str
))
766 str
= (struct rpc_string
*)p
;
767 dn_len
= ntohl(str
->len
);
768 if (msg_len
< dn_len
)
770 if (dn_len
>= MAXHOSTNAMELEN
)
772 bcopy(str
->data
, domainname
, dn_len
);
773 domainname
[dn_len
] = '\0';
774 domainnamelen
= dn_len
;
775 p
+= RPC_STR_SIZE(dn_len
);
776 msg_len
-= RPC_STR_SIZE(dn_len
);
778 /* gateway address */
779 if (msg_len
< sizeof(*bia
))
781 bia
= (struct bp_inaddr
*)p
;
782 if (bia
->atype
!= htonl(1))
785 *p
++ = ntohl(bia
->addr
[0]);
786 *p
++ = ntohl(bia
->addr
[1]);
787 *p
++ = ntohl(bia
->addr
[2]);
788 *p
++ = ntohl(bia
->addr
[3]);
792 printf("nfs_boot: bootparam_whoami: bad reply\n");
805 * RPC: bootparam/getfile
806 * Given client name and file "key", get:
812 bp_getfile(bpsin
, key
, md_sin
, serv_name
, pathname
)
813 struct sockaddr_in
*bpsin
;
815 struct sockaddr_in
*md_sin
;
819 struct rpc_string
*str
;
821 struct bp_inaddr
*bia
;
822 struct sockaddr_in
*sin
;
825 int cn_len
, key_len
, sn_len
, path_len
;
828 * Get message buffer of sufficient size.
830 cn_len
= hostnamelen
;
831 key_len
= strlen(key
);
833 msg_len
+= RPC_STR_SIZE(cn_len
);
834 msg_len
+= RPC_STR_SIZE(key_len
);
835 m
= m_get_len(msg_len
);
840 * Build request message.
842 p
= mtod(m
, u_char
*);
844 /* client name (hostname) */
845 str
= (struct rpc_string
*)p
;
846 str
->len
= htonl(cn_len
);
847 bcopy(hostname
, str
->data
, cn_len
);
848 p
+= RPC_STR_SIZE(cn_len
);
849 /* key name (root or swap) */
850 str
= (struct rpc_string
*)p
;
851 str
->len
= htonl(key_len
);
852 bcopy(key
, str
->data
, key_len
);
854 /* RPC: bootparam/getfile */
855 error
= krpc_call(bpsin
, BOOTPARAM_PROG
, BOOTPARAM_VERS
,
856 BOOTPARAM_GETFILE
, &m
, NULL
);
861 * Parse result message.
863 p
= mtod(m
, u_char
*);
867 if (msg_len
< sizeof(*str
))
869 str
= (struct rpc_string
*)p
;
870 sn_len
= ntohl(str
->len
);
871 if (msg_len
< sn_len
)
873 if (sn_len
>= MNAMELEN
)
875 bcopy(str
->data
, serv_name
, sn_len
);
876 serv_name
[sn_len
] = '\0';
877 p
+= RPC_STR_SIZE(sn_len
);
878 msg_len
-= RPC_STR_SIZE(sn_len
);
880 /* server IP address (mountd) */
881 if (msg_len
< sizeof(*bia
))
883 bia
= (struct bp_inaddr
*)p
;
884 if (bia
->atype
!= htonl(1))
887 bzero((caddr_t
)sin
, sizeof(*sin
));
888 sin
->sin_len
= sizeof(*sin
);
889 sin
->sin_family
= AF_INET
;
890 q
= (u_char
*) &sin
->sin_addr
;
891 *q
++ = ntohl(bia
->addr
[0]);
892 *q
++ = ntohl(bia
->addr
[1]);
893 *q
++ = ntohl(bia
->addr
[2]);
894 *q
++ = ntohl(bia
->addr
[3]);
896 msg_len
-= sizeof(*bia
);
898 /* server pathname */
899 if (msg_len
< sizeof(*str
))
901 str
= (struct rpc_string
*)p
;
902 path_len
= ntohl(str
->len
);
903 if (msg_len
< path_len
)
905 if (path_len
>= MAXPATHLEN
)
907 bcopy(str
->data
, pathname
, path_len
);
908 pathname
[path_len
] = '\0';
912 printf("nfs_boot: bootparam_getfile: bad reply\n");
923 * Given a server pathname, get an NFS file handle.
924 * Also, sets sin->sin_port to the NFS service port.
927 md_mount(mdsin
, path
, fhp
)
928 struct sockaddr_in
*mdsin
; /* mountd server address */
932 /* The RPC structures */
933 struct rpc_string
*str
;
936 u_char fh
[NFSX_V2FH
];
939 int error
, mlen
, slen
;
941 /* Get port number for MOUNTD. */
942 error
= krpc_portmap(mdsin
, RPCPROG_MNT
, RPCMNT_VER1
,
944 if (error
) return error
;
947 mlen
= RPC_STR_SIZE(slen
);
952 str
= mtod(m
, struct rpc_string
*);
953 str
->len
= htonl(slen
);
954 bcopy(path
, str
->data
, slen
);
956 /* Do RPC to mountd. */
957 error
= krpc_call(mdsin
, RPCPROG_MNT
, RPCMNT_VER1
,
958 RPCMNT_MOUNT
, &m
, NULL
);
960 return error
; /* message already freed */
963 if (mlen
< sizeof(*rdata
))
965 rdata
= mtod(m
, struct rdata
*);
966 error
= ntohl(rdata
->errno
);
969 bcopy(rdata
->fh
, fhp
, NFSX_V2FH
);
971 /* Set port number for NFS use. */
972 error
= krpc_portmap(mdsin
, NFS_PROG
, NFS_VER2
,