1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 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 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 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> 101#include <sys/mount_internal.h> 102#include <sys/kpi_mbuf.h> 103 104#include <sys/malloc.h> 105#include <sys/socket.h> 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 127 128#if NETHER == 0 129 130int nfs_boot_init(__unused struct nfs_diskless *nd) 131{ 132 panic("nfs_boot_init: no ether"); 133} 134 135int nfs_boot_getfh(__unused struct nfs_diskless *nd, __unused int v3, __unused int sotype) 136{ 137 panic("nfs_boot_getfh: no ether"); 138} 139 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 162/* bootparam RPC */ 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); 167 168/* mountd RPC */ 169static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype, 170 u_char *fhp, u_int32_t *fhlenp); 171 172/* other helpers */ 173static int get_file_handle(struct nfs_dlmount *ndmntp); 174 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] 179 180#include <sys/netboot.h> 181 182/* 183 * Called with an empty nfs_diskless struct to be filled in. 184 */ 185int 186nfs_boot_init(struct nfs_diskless *nd) 187{ 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; 193 struct sockaddr_in * sin_p; 194 195 /* make sure mbuf constants are set up */ 196 if (!nfs_mbuf_mhlen) 197 nfs_mbuf_init(); 198 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; 203 goto failed; 204 } 205 206 /* get the root path information */ 207 MALLOC_ZONE(nd->nd_root.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 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 } 213 MALLOC_ZONE(nd->nd_root.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 214 if (!nd->nd_root.ndm_mntfrom) { 215 printf("nfs_boot: can't allocate root mntfrom buffer\n"); 216 error = ENOMEM; 217 goto failed; 218 } 219 sin_p = &nd->nd_root.ndm_saddr; 220 bzero((caddr_t)sin_p, sizeof(*sin_p)); 221 sin_p->sin_len = sizeof(*sin_p); 222 sin_p->sin_family = AF_INET; 223 if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host, 224 sizeof(nd->nd_root.ndm_host), 225 nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) { 226 do_bpgetfile = FALSE; 227 do_bpwhoami = FALSE; 228 } 229 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; 230 231 if (do_bpwhoami) { 232 struct in_addr router; 233 /* 234 * Get client name and gateway address. 235 * RPC: bootparam/whoami 236 * Use the old broadcast address for the WHOAMI 237 * call because we do not yet know our netmask. 238 * The server address returned by the WHOAMI call 239 * is used for all subsequent booptaram RPCs. 240 */ 241 bzero((caddr_t)&bp_sin, sizeof(bp_sin)); 242 bp_sin.sin_len = sizeof(bp_sin); 243 bp_sin.sin_family = AF_INET; 244 bp_sin.sin_addr.s_addr = INADDR_BROADCAST; 245 hostnamelen = MAXHOSTNAMELEN; 246 router.s_addr = 0; 247 error = bp_whoami(&bp_sin, &my_ip, &router); 248 if (error) { 249 printf("nfs_boot: bootparam whoami, error=%d", error); 250 goto failed; 251 } 252 printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n", 253 IP_LIST(&bp_sin.sin_addr)); 254 printf("nfs_boot: hostname %s\n", hostname); 255 } 256 if (do_bpgetfile) { 257 error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, 258 nd->nd_root.ndm_host, nd->nd_root.ndm_path); 259 if (error) { 260 printf("nfs_boot: bootparam get root: %d\n", error); 261 goto failed; 262 } 263 } 264 265#if !defined(NO_MOUNT_PRIVATE) 266 if (do_bpgetfile) { /* get private path */ 267 MALLOC_ZONE(nd->nd_private.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 268 if (!nd->nd_private.ndm_path) { 269 printf("nfs_boot: can't allocate private path buffer\n"); 270 error = ENOMEM; 271 goto failed; 272 } 273 MALLOC_ZONE(nd->nd_private.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 274 if (!nd->nd_private.ndm_mntfrom) { 275 printf("nfs_boot: can't allocate private host buffer\n"); 276 error = ENOMEM; 277 goto failed; 278 } 279 error = bp_getfile(&bp_sin, "private", 280 &nd->nd_private.ndm_saddr, 281 nd->nd_private.ndm_host, 282 nd->nd_private.ndm_path); 283 if (!error) { 284 char * check_path = NULL; 285 286 MALLOC_ZONE(check_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 287 if (!check_path) { 288 printf("nfs_boot: can't allocate check_path buffer\n"); 289 error = ENOMEM; 290 goto failed; 291 } 292 snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path); 293 if ((nd->nd_root.ndm_saddr.sin_addr.s_addr 294 == nd->nd_private.ndm_saddr.sin_addr.s_addr) 295 && (strncmp(check_path, nd->nd_private.ndm_path, MAXPATHLEN) == 0)) { 296 /* private path is prefix of root path, don't mount */ 297 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; 298 } 299 FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI); 300 } 301 else { 302 /* private key not defined, don't mount */ 303 nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; 304 } 305 } 306 else { 307 error = 0; 308 } 309#endif /* NO_MOUNT_PRIVATE */ 310failed: 311 return (error); 312} 313 314/* 315 * Called with a partially initialized nfs_diskless struct 316 * with file handles to be filled in. 317 */ 318int 319nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype) 320{ 321 int error = 0; 322 323 nd->nd_root.ndm_nfsv3 = v3; 324 nd->nd_root.ndm_sotype = sotype; 325 error = get_file_handle(&nd->nd_root); 326 if (error) { 327 printf("nfs_boot: get_file_handle(v%d) root failed, %d\n", 328 v3 ? 3 : 2, error); 329 goto failed; 330 } 331 332#if !defined(NO_MOUNT_PRIVATE) 333 if (nd->nd_private.ndm_saddr.sin_addr.s_addr) { 334 /* get private file handle */ 335 nd->nd_private.ndm_nfsv3 = v3; 336 nd->nd_private.ndm_sotype = sotype; 337 error = get_file_handle(&nd->nd_private); 338 if (error) { 339 printf("nfs_boot: get_file_handle(v%d) private failed, %d\n", 340 v3 ? 3 : 2, error); 341 goto failed; 342 } 343 } 344#endif /* NO_MOUNT_PRIVATE */ 345failed: 346 return (error); 347} 348 349static int 350get_file_handle(ndmntp) 351 struct nfs_dlmount *ndmntp; 352{ 353 char *sp, *dp, *endp; 354 int error; 355 356 /* 357 * Get file handle for "key" (root or swap) 358 * using RPC to mountd/mount 359 */ 360 error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3, 361 ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen); 362 if (error) 363 return (error); 364 365 /* Construct remote path (for getmntinfo(3)) */ 366 dp = ndmntp->ndm_mntfrom; 367 endp = dp + MAXPATHLEN - 1; 368 for (sp = ndmntp->ndm_host; *sp && dp < endp;) 369 *dp++ = *sp++; 370 if (dp < endp) 371 *dp++ = ':'; 372 for (sp = ndmntp->ndm_path; *sp && dp < endp;) 373 *dp++ = *sp++; 374 *dp = '\0'; 375 return (0); 376 377} 378 379 380/* 381 * Get an mbuf with the given length, and 382 * initialize the pkthdr length field. 383 */ 384static int 385mbuf_get_with_len(size_t msg_len, mbuf_t *m) 386{ 387 int error; 388 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, m); 389 if (error) 390 return (error); 391 if (msg_len > mbuf_maxlen(*m)) { 392 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, m); 393 if (error) { 394 mbuf_freem(*m); 395 return (error); 396 } 397 if (msg_len > mbuf_maxlen(*m)) 398 panic("nfs_boot: msg_len > MCLBYTES"); 399 } 400 mbuf_setlen(*m, msg_len); 401 mbuf_pkthdr_setlen(*m, msg_len); 402 return (0); 403} 404 405 406/* 407 * String representation for RPC. 408 */ 409struct rpc_string { 410 u_int32_t len; /* length without null or padding */ 411 u_char data[4]; /* data (longer, of course) */ 412 /* data is padded to a long-word boundary */ 413}; 414/* Compute space used given string length. */ 415#define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3)) 416 417/* 418 * Inet address in RPC messages 419 * (Note, really four 32-bit ints, NOT chars. Blech.) 420 */ 421struct bp_inaddr { 422 u_int32_t atype; 423 int32_t addr[4]; 424}; 425 426 427/* 428 * RPC: bootparam/whoami 429 * Given client IP address, get: 430 * client name (hostname) 431 * domain name (domainname) 432 * gateway address 433 * 434 * The hostname and domainname are set here for convenience. 435 * 436 * Note - bpsin is initialized to the broadcast address, 437 * and will be replaced with the bootparam server address 438 * after this call is complete. Have to use PMAP_PROC_CALL 439 * to make sure we get responses only from a servers that 440 * know about us (don't want to broadcast a getport call). 441 */ 442static int 443bp_whoami(bpsin, my_ip, gw_ip) 444 struct sockaddr_in *bpsin; 445 struct in_addr *my_ip; 446 struct in_addr *gw_ip; 447{ 448 /* RPC structures for PMAPPROC_CALLIT */ 449 struct whoami_call { 450 u_int32_t call_prog; 451 u_int32_t call_vers; 452 u_int32_t call_proc; 453 u_int32_t call_arglen; 454 struct bp_inaddr call_ia; 455 } *call; 456 457 struct rpc_string *str; 458 struct bp_inaddr *bia; 459 mbuf_t m; 460 struct sockaddr_in sin; 461 int error; 462 size_t msg_len, cn_len, dn_len; 463 u_char *p; 464 int32_t *lp; 465 466 /* 467 * Get message buffer of sufficient size. 468 */ 469 msg_len = sizeof(*call); 470 error = mbuf_get_with_len(msg_len, &m); 471 if (error) 472 return error; 473 474 /* 475 * Build request message for PMAPPROC_CALLIT. 476 */ 477 call = mbuf_data(m); 478 call->call_prog = htonl(BOOTPARAM_PROG); 479 call->call_vers = htonl(BOOTPARAM_VERS); 480 call->call_proc = htonl(BOOTPARAM_WHOAMI); 481 call->call_arglen = htonl(sizeof(struct bp_inaddr)); 482 483 /* client IP address */ 484 call->call_ia.atype = htonl(1); 485 p = (u_char*)my_ip; 486 lp = call->call_ia.addr; 487 *lp++ = htonl(*p); p++; 488 *lp++ = htonl(*p); p++; 489 *lp++ = htonl(*p); p++; 490 *lp++ = htonl(*p); p++; 491 492 /* RPC: portmap/callit */ 493 bpsin->sin_port = htons(PMAPPORT); 494 495 error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin); 496 if (error) 497 return error; 498 499 /* 500 * Parse result message. 501 */ 502 msg_len = mbuf_len(m); 503 lp = mbuf_data(m); 504 505 /* bootparam server port (also grab from address). */ 506 if (msg_len < sizeof(*lp)) 507 goto bad; 508 msg_len -= sizeof(*lp); 509 bpsin->sin_port = htons((short)ntohl(*lp++)); 510 bpsin->sin_addr.s_addr = sin.sin_addr.s_addr; 511 512 /* length of encapsulated results */ 513 if (msg_len < (ntohl(*lp) + sizeof(*lp))) 514 goto bad; 515 msg_len = ntohl(*lp++); 516 p = (u_char*)lp; 517 518 /* client name */ 519 if (msg_len < sizeof(*str)) 520 goto bad; 521 str = (struct rpc_string *)p; 522 cn_len = ntohl(str->len); 523 if (msg_len < cn_len) 524 goto bad; 525 if (cn_len >= MAXHOSTNAMELEN) 526 goto bad; 527 bcopy(str->data, hostname, cn_len); 528 hostname[cn_len] = '\0'; 529 hostnamelen = cn_len; 530 p += RPC_STR_SIZE(cn_len); 531 msg_len -= RPC_STR_SIZE(cn_len); 532 533 /* domain name */ 534 if (msg_len < sizeof(*str)) 535 goto bad; 536 str = (struct rpc_string *)p; 537 dn_len = ntohl(str->len); 538 if (msg_len < dn_len) 539 goto bad; 540 if (dn_len >= MAXHOSTNAMELEN) 541 goto bad; 542 bcopy(str->data, domainname, dn_len); 543 domainname[dn_len] = '\0'; 544 domainnamelen = dn_len; 545 p += RPC_STR_SIZE(dn_len); 546 msg_len -= RPC_STR_SIZE(dn_len); 547 548 /* gateway address */ 549 if (msg_len < sizeof(*bia)) 550 goto bad; 551 bia = (struct bp_inaddr *)p; 552 if (bia->atype != htonl(1)) 553 goto bad; 554 p = (u_char*)gw_ip; 555 *p++ = ntohl(bia->addr[0]); 556 *p++ = ntohl(bia->addr[1]); 557 *p++ = ntohl(bia->addr[2]); 558 *p++ = ntohl(bia->addr[3]); 559 goto out; 560 561bad: 562 printf("nfs_boot: bootparam_whoami: bad reply\n"); 563 error = EBADRPC; 564 565out: 566 mbuf_freem(m); 567 return(error); 568} 569 570 571/* 572 * RPC: bootparam/getfile 573 * Given client name and file "key", get: 574 * server name 575 * server IP address 576 * server pathname 577 */ 578static int 579bp_getfile(bpsin, key, md_sin, serv_name, pathname) 580 struct sockaddr_in *bpsin; 581 const char *key; 582 struct sockaddr_in *md_sin; 583 char *serv_name; 584 char *pathname; 585{ 586 struct rpc_string *str; 587 mbuf_t m; 588 struct bp_inaddr *bia; 589 struct sockaddr_in *sin; 590 u_char *p, *q; 591 int error, msg_len; 592 int cn_len, key_len, sn_len, path_len; 593 594 /* 595 * Get message buffer of sufficient size. 596 */ 597 cn_len = hostnamelen; 598 key_len = strlen(key); 599 msg_len = 0; 600 msg_len += RPC_STR_SIZE(cn_len); 601 msg_len += RPC_STR_SIZE(key_len); 602 error = mbuf_get_with_len(msg_len, &m); 603 if (error) 604 return error; 605 606 /* 607 * Build request message. 608 */ 609 p = mbuf_data(m); 610 bzero(p, msg_len); 611 /* client name (hostname) */ 612 str = (struct rpc_string *)p; 613 str->len = htonl(cn_len); 614 bcopy(hostname, str->data, cn_len); 615 p += RPC_STR_SIZE(cn_len); 616 /* key name (root or swap) */ 617 str = (struct rpc_string *)p; 618 str->len = htonl(key_len); 619 bcopy(key, str->data, key_len); 620 621 /* RPC: bootparam/getfile */ 622 error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS, 623 BOOTPARAM_GETFILE, &m, NULL); 624 if (error) 625 return error; 626 627 /* 628 * Parse result message. 629 */ 630 p = mbuf_data(m); 631 msg_len = mbuf_len(m); 632 633 /* server name */ 634 if (msg_len < (int)sizeof(*str)) 635 goto bad; 636 str = (struct rpc_string *)p; 637 sn_len = ntohl(str->len); 638 if (msg_len < sn_len) 639 goto bad; 640 if (sn_len >= MAXHOSTNAMELEN) 641 goto bad; 642 bcopy(str->data, serv_name, sn_len); 643 serv_name[sn_len] = '\0'; 644 p += RPC_STR_SIZE(sn_len); 645 msg_len -= RPC_STR_SIZE(sn_len); 646 647 /* server IP address (mountd) */ 648 if (msg_len < (int)sizeof(*bia)) 649 goto bad; 650 bia = (struct bp_inaddr *)p; 651 if (bia->atype != htonl(1)) 652 goto bad; 653 sin = md_sin; 654 bzero((caddr_t)sin, sizeof(*sin)); 655 sin->sin_len = sizeof(*sin); 656 sin->sin_family = AF_INET; 657 q = (u_char*) &sin->sin_addr; 658 *q++ = ntohl(bia->addr[0]); 659 *q++ = ntohl(bia->addr[1]); 660 *q++ = ntohl(bia->addr[2]); 661 *q++ = ntohl(bia->addr[3]); 662 p += sizeof(*bia); 663 msg_len -= sizeof(*bia); 664 665 /* server pathname */ 666 if (msg_len < (int)sizeof(*str)) 667 goto bad; 668 str = (struct rpc_string *)p; 669 path_len = ntohl(str->len); 670 if (msg_len < path_len) 671 goto bad; 672 if (path_len >= MAXPATHLEN) 673 goto bad; 674 bcopy(str->data, pathname, path_len); 675 pathname[path_len] = '\0'; 676 goto out; 677 678bad: 679 printf("nfs_boot: bootparam_getfile: bad reply\n"); 680 error = EBADRPC; 681 682out: 683 mbuf_freem(m); 684 return(0); 685} 686 687 688/* 689 * RPC: mountd/mount 690 * Given a server pathname, get an NFS file handle. 691 * Also, sets sin->sin_port to the NFS service port. 692 */ 693static int 694md_mount(mdsin, path, v3, sotype, fhp, fhlenp) 695 struct sockaddr_in *mdsin; /* mountd server address */ 696 char *path; 697 int v3; 698 int sotype; 699 u_char *fhp; 700 u_int32_t *fhlenp; 701{ 702 /* The RPC structures */ 703 struct rpc_string *str; 704 struct rdata { 705 u_int32_t errno; 706 u_char data[NFSX_V3FHMAX + sizeof(u_int32_t)]; 707 } *rdata; 708 mbuf_t m; 709 int error, mlen, slen; 710 int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1; 711 int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP; 712 in_port_t mntport, nfsport; 713 714 /* Get port number for MOUNTD. */ 715 error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion, proto, &mntport); 716 if (error) 717 return error; 718 719 /* Get port number for NFS use. */ 720 /* (If NFS/proto unavailable, don't bother with the mount call) */ 721 error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2, proto, &nfsport); 722 if (error) 723 return error; 724 725 /* Set port number for MOUNTD */ 726 mdsin->sin_port = mntport; 727 728 slen = strlen(path); 729 mlen = RPC_STR_SIZE(slen); 730 731 error = mbuf_get_with_len(mlen, &m); 732 if (error) 733 return error; 734 str = mbuf_data(m); 735 str->len = htonl(slen); 736 bcopy(path, str->data, slen); 737 738 /* Do RPC to mountd. */ 739 error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL); 740 if (error) 741 return error; /* message already freed */ 742 743 /* 744 * the reply must be long enough to hold the errno plus either of: 745 * + a v2 filehandle 746 * + a v3 filehandle length + a v3 filehandle 747 */ 748 mlen = mbuf_len(m); 749 if (mlen < (int)sizeof(u_int32_t)) 750 goto bad; 751 rdata = mbuf_data(m); 752 error = ntohl(rdata->errno); 753 if (error) 754 goto out; 755 if (v3) { 756 u_int32_t fhlen; 757 u_char *fh; 758 if (mlen < (int)sizeof(u_int32_t)*2) 759 goto bad; 760 fhlen = ntohl(*(u_int32_t*)rdata->data); 761 fh = rdata->data + sizeof(u_int32_t); 762 if (mlen < (int)(sizeof(u_int32_t)*2 + fhlen)) 763 goto bad; 764 bcopy(fh, fhp, fhlen); 765 *fhlenp = fhlen; 766 } else { 767 if (mlen < ((int)sizeof(u_int32_t) + NFSX_V2FH)) 768 goto bad; 769 bcopy(rdata->data, fhp, NFSX_V2FH); 770 *fhlenp = NFSX_V2FH; 771 } 772 773 /* Set port number for NFS use. */ 774 mdsin->sin_port = nfsport; 775 goto out; 776 777bad: 778 error = EBADRPC; 779 780out: 781 mbuf_freem(m); 782 return error; 783} 784 785#endif /* NETHER */ 786