|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 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. ! 11: * ! 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 ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1994 Adam Glass, Gordon Ross ! 25: * All rights reserved. ! 26: * ! 27: * This software was developed by the Computer Systems Engineering group ! 28: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and ! 29: * contributed to Berkeley. ! 30: * ! 31: * Redistribution and use in source and binary forms, with or without ! 32: * modification, are permitted provided that the following conditions ! 33: * are met: ! 34: * 1. Redistributions of source code must retain the above copyright ! 35: * notice, this list of conditions and the following disclaimer. ! 36: * 2. Redistributions in binary form must reproduce the above copyright ! 37: * notice, this list of conditions and the following disclaimer in the ! 38: * documentation and/or other materials provided with the distribution. ! 39: * 3. All advertising materials mentioning features or use of this software ! 40: * must display the following acknowledgement: ! 41: * This product includes software developed by the University of ! 42: * California, Lawrence Berkeley Laboratory and its contributors. ! 43: * 4. Neither the name of the University nor the names of its contributors ! 44: * may be used to endorse or promote products derived from this software ! 45: * without specific prior written permission. ! 46: * ! 47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 57: * SUCH DAMAGE. ! 58: * ! 59: * History: ! 60: * 14-March-97 Dieter Siegmund ([email protected]) ! 61: * - Use BOOTP instead of RARP to get the IP address at boot time ! 62: * ! 63: * 23-May-97 Umesh Vaishampayan ([email protected]) ! 64: * - Added the ability to mount "/private" separately. ! 65: * ! 66: * 30-May-97 Dieter Siegmund ([email protected]) ! 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 ([email protected]) ! 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 ([email protected]) ! 75: * - use the default route from the bpwhoami call, enabled autonetmask ! 76: * again ! 77: * 19-Feb-1999 Dieter Siegmund ([email protected]) ! 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 ([email protected]) ! 86: * - replaced big automatic arrays with MALLOC'd data ! 87: */ ! 88: ! 89: #include <sys/param.h> ! 90: #include <sys/systm.h> ! 91: #include <sys/kernel.h> ! 92: #include <sys/conf.h> ! 93: #include <sys/ioctl.h> ! 94: #include <sys/proc.h> ! 95: #include <sys/mount.h> ! 96: #include <sys/mbuf.h> ! 97: ! 98: #include <sys/malloc.h> ! 99: #include <sys/socket.h> ! 100: #include <sys/reboot.h> ! 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: ! 122: extern char *strchr(const char *str, int ch); ! 123: ! 124: #if NETHER == 0 ! 125: ! 126: int nfs_boot_init(nd, procp) ! 127: struct nfs_diskless *nd; ! 128: struct proc *procp; ! 129: { ! 130: panic("nfs_boot_init: no ether"); ! 131: } ! 132: ! 133: #else /* NETHER */ ! 134: ! 135: /* ! 136: * Support for NFS diskless booting, specifically getting information ! 137: * about where to boot from, what pathnames, etc. ! 138: * ! 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. ! 142: * ! 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 ! 151: * ! 152: * (This happens to be the way Sun does it too.) ! 153: */ ! 154: ! 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); ! 158: ! 159: /* bootparam RPC */ ! 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)); ! 164: ! 165: static boolean_t path_getfile __P((char * image_path, ! 166: struct sockaddr_in * sin_p, ! 167: char * serv_name, char * pathname)); ! 168: ! 169: static __inline__ ! 170: u_long iptohl(struct in_addr ip) ! 171: { ! 172: return (ntohl(ip.s_addr)); ! 173: } ! 174: ! 175: static __inline__ boolean_t ! 176: same_subnet(struct in_addr addr1, struct in_addr addr2, struct in_addr mask) ! 177: { ! 178: u_long m = iptohl(mask); ! 179: if ((iptohl(addr1) & m) != (iptohl(addr2) & m)) ! 180: return (FALSE); ! 181: return (TRUE); ! 182: } ! 183: ! 184: /* mountd RPC */ ! 185: static int md_mount __P((struct sockaddr_in *mdsin, char *path, ! 186: u_char *fh)); ! 187: ! 188: /* other helpers */ ! 189: static void get_file_handle __P((char *pathname, struct nfs_dlmount *ndmntp)); ! 190: ! 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] ! 194: /* ! 195: * Called with an empty nfs_diskless struct to be filled in. ! 196: */ ! 197: int ! 198: nfs_boot_init(nd, procp) ! 199: struct nfs_diskless *nd; ! 200: struct proc *procp; ! 201: { ! 202: char * booter_path = NULL; ! 203: boolean_t do_bpwhoami = TRUE; ! 204: boolean_t do_bpgetfile = TRUE; ! 205: struct ifreq ireq; ! 206: struct in_addr my_ip; ! 207: struct sockaddr_in bp_sin; ! 208: struct sockaddr_in *sin; ! 209: struct ifnet *ifp; ! 210: struct in_addr gw_ip; ! 211: struct socket *so; ! 212: struct in_addr my_netmask; ! 213: int error; ! 214: char * root_path = NULL; ! 215: ! 216: MALLOC(booter_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); ! 217: MALLOC(root_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); ! 218: ! 219: /* booter-supplied path */ ! 220: if (!PE_parse_boot_arg("rp", booter_path) ! 221: && !PE_parse_boot_arg("rootpath", booter_path)) { ! 222: booter_path[0] = 0; ! 223: } ! 224: ! 225: root_path[0] = 0; ! 226: ! 227: gw_ip.s_addr = 0; ! 228: ! 229: /* clear out the request structure */ ! 230: bzero(&ireq, sizeof(ireq)); ! 231: ! 232: /* ! 233: * Find an interface, rarp for its ip address, stuff it, the ! 234: * implied broadcast addr, and netmask into a nfs_diskless struct. ! 235: * ! 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.) ! 239: */ ! 240: ! 241: /* ! 242: * Find a network interface. ! 243: */ ! 244: ifp = NULL; ! 245: { /* if the root device is set, use it */ ! 246: extern char rootdevice[]; ! 247: if (rootdevice[0]) ! 248: ifp = ifunit(rootdevice); ! 249: } ! 250: if (ifp == NULL) { /* search for network device */ ! 251: /* for (ifp = ifnet; ifp; ifp = ifp->if_next)*/ ! 252: TAILQ_FOREACH(ifp, &ifnet, if_link) ! 253: if ((ifp->if_flags & ! 254: (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) ! 255: break; ! 256: } ! 257: if (ifp == NULL) ! 258: panic("nfs_boot: no suitable interface"); ! 259: sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); ! 260: printf("nfs_boot: using network interface '%s'\n", ireq.ifr_name); ! 261: ! 262: /* ! 263: * Bring up the interface. ! 264: */ ! 265: if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) ! 266: panic("nfs_boot: socreate, error=%d", error); ! 267: ireq.ifr_flags = ifp->if_flags | IFF_UP; ! 268: error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp); ! 269: if (error) ! 270: panic("nfs_boot: SIFFLAGS, error=%d", error); ! 271: ! 272: #define DO_BOOTP ! 273: #ifdef DO_BOOTP ! 274: { /* use BOOTP to retrieve IP address, netmask and router */ ! 275: struct sockaddr_in sockin; ! 276: struct in_addr router; ! 277: struct in_addr netmask; ! 278: ! 279: my_ip.s_addr = 0; ! 280: netmask.s_addr = 0; ! 281: router.s_addr = 0; ! 282: sockin.sin_family = AF_INET; ! 283: sockin.sin_len = sizeof(sockin); ! 284: sockin.sin_addr.s_addr = 0; ! 285: #define RETRY_COUNT 32 ! 286: while ((error = bootp(ifp, &my_ip, RETRY_COUNT, ! 287: &netmask, &router, procp))) { ! 288: if (error == ETIMEDOUT) ! 289: printf("nfs_boot: BOOTP timed out, retrying...\n"); ! 290: ! 291: else { ! 292: printf("nfs_boot: bootp() failed, error = %d\n", error); ! 293: panic("nfs_boot"); ! 294: } ! 295: } ! 296: /* clear the netmask */ ! 297: ((struct sockaddr_in *)&ireq.ifr_addr)->sin_addr.s_addr = 0; ! 298: error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp); ! 299: if (error) ! 300: printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error); ! 301: ! 302: if (netmask.s_addr) { ! 303: /* set our new subnet mask */ ! 304: sockin.sin_addr = netmask; ! 305: *((struct sockaddr_in *)&ireq.ifr_addr) = sockin; ! 306: error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp); ! 307: if (error) ! 308: printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error); ! 309: } ! 310: ! 311: /* set our address */ ! 312: sockin.sin_addr = my_ip; ! 313: *((struct sockaddr_in *)&ireq.ifr_addr) = sockin; ! 314: error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp); ! 315: if (error) { ! 316: printf("SIOCSIFADDR failed: %d\n", error); ! 317: panic("nfs_boot.c"); ! 318: } ! 319: printf("nfs_boot: IP address " IP_FORMAT, IP_LIST(&my_ip)); ! 320: if (netmask.s_addr) ! 321: printf(" netmask " IP_FORMAT, IP_LIST(&netmask)); ! 322: if (router.s_addr) { ! 323: gw_ip = router; ! 324: printf(" router " IP_FORMAT, IP_LIST(&router)); ! 325: } ! 326: printf("\n"); ! 327: } ! 328: #else ! 329: /* ! 330: * Do RARP for the interface address. ! 331: */ ! 332: if ((error = revarpwhoami(&my_ip, ifp)) != 0) ! 333: panic("revarp failed, error=%d", error); ! 334: printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr)); ! 335: ! 336: /* ! 337: * Do enough of ifconfig(8) so that the chosen interface ! 338: * can talk to the servers. (just set the address) ! 339: */ ! 340: sin = (struct sockaddr_in *)&ireq.ifr_addr; ! 341: bzero((caddr_t)sin, sizeof(*sin)); ! 342: sin->sin_len = sizeof(*sin); ! 343: sin->sin_family = AF_INET; ! 344: sin->sin_addr.s_addr = my_ip.s_addr; ! 345: error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp); ! 346: if (error) ! 347: panic("nfs_boot: set if addr, error=%d", error); ! 348: #endif DO_BOOTP ! 349: ! 350: /* need netmask to determine whether NFS server local */ ! 351: sin = (struct sockaddr_in *)&ireq.ifr_addr; ! 352: bzero((caddr_t)sin, sizeof(*sin)); ! 353: sin->sin_len = sizeof(*sin); ! 354: sin->sin_family = AF_INET; ! 355: error = ifioctl(so, SIOCGIFNETMASK, (caddr_t)&ireq, procp); ! 356: if (error) ! 357: panic("nfs_boot: SIOCGIFNETMASK error=%d", error); ! 358: my_netmask = sin->sin_addr; ! 359: ! 360: soclose(so); ! 361: ! 362: /* check for a booter-specified path */ ! 363: if (booter_path[0]) { ! 364: nd->nd_root.ndm_saddr.sin_addr.s_addr = 0; ! 365: nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; ! 366: if (path_getfile(booter_path, &nd->nd_root.ndm_saddr, ! 367: nd->nd_root.ndm_host, root_path)) { ! 368: do_bpgetfile = FALSE; ! 369: printf("nfs_boot: using booter-supplied path '%s'\n", ! 370: booter_path); ! 371: if (same_subnet(nd->nd_root.ndm_saddr.sin_addr, ! 372: my_ip, my_netmask) ! 373: || gw_ip.s_addr) { ! 374: do_bpwhoami = FALSE; ! 375: } ! 376: else { ! 377: /* do bpwhoami to attempt to get the router */ ! 378: } ! 379: } ! 380: else { ! 381: printf("nfs_boot: ignoring badly formed bootpath '%s'\n", ! 382: booter_path); ! 383: } ! 384: } ! 385: ! 386: if (do_bpwhoami) { ! 387: /* ! 388: * Get client name and gateway address. ! 389: * RPC: bootparam/whoami ! 390: * Use the old broadcast address for the WHOAMI ! 391: * call because we do not yet know our netmask. ! 392: * The server address returned by the WHOAMI call ! 393: * is used for all subsequent booptaram RPCs. ! 394: */ ! 395: bzero((caddr_t)&bp_sin, sizeof(bp_sin)); ! 396: bp_sin.sin_len = sizeof(bp_sin); ! 397: bp_sin.sin_family = AF_INET; ! 398: bp_sin.sin_addr.s_addr = INADDR_BROADCAST; ! 399: hostnamelen = MAXHOSTNAMELEN; ! 400: ! 401: { /* bpwhoami also returns gateway IP address */ ! 402: ! 403: struct in_addr router; ! 404: ! 405: router.s_addr = 0; ! 406: error = bp_whoami(&bp_sin, &my_ip, &router); ! 407: if (error) { ! 408: printf("nfs_boot: bootparam whoami, error=%d", error); ! 409: panic("nfs_boot: bootparam whoami\n"); ! 410: } ! 411: /* if not already set by BOOTP, use the one from BPWHOAMI */ ! 412: if (gw_ip.s_addr == 0) ! 413: gw_ip = router; ! 414: } ! 415: printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n", ! 416: IP_LIST(&bp_sin.sin_addr)); ! 417: printf("nfs_boot: hostname %s\n", hostname); ! 418: } ! 419: #define NFS_BOOT_GATEWAY 1 ! 420: #ifdef NFS_BOOT_GATEWAY ! 421: /* ! 422: * DWS 2/18/1999 ! 423: * The comment below does not apply to gw_ip discovered ! 424: * via BOOTP (see DO_BOOTP loop above) since BOOTP servers ! 425: * are supposed to be more trustworthy. ! 426: */ ! 427: /* ! 428: * XXX - This code is conditionally compiled only because ! 429: * many bootparam servers (in particular, SunOS 4.1.3) ! 430: * always set the gateway address to their own address. ! 431: * The bootparam server is not necessarily the gateway. ! 432: * We could just believe the server, and at worst you would ! 433: * need to delete the incorrect default route before adding ! 434: * the correct one, but for simplicity, ignore the gateway. ! 435: * If your server is OK, you can turn on this option. ! 436: * ! 437: * If the gateway address is set, add a default route. ! 438: * (The mountd RPCs may go across a gateway.) ! 439: */ ! 440: if (gw_ip.s_addr) { ! 441: struct sockaddr dst, gw, mask; ! 442: /* Destination: (default) */ ! 443: bzero((caddr_t)&dst, sizeof(dst)); ! 444: dst.sa_len = sizeof(dst); ! 445: dst.sa_family = AF_INET; ! 446: /* Gateway: */ ! 447: bzero((caddr_t)&gw, sizeof(gw)); ! 448: sin = (struct sockaddr_in *)&gw; ! 449: sin->sin_len = sizeof(gw); ! 450: sin->sin_family = AF_INET; ! 451: sin->sin_addr.s_addr = gw_ip.s_addr; ! 452: /* Mask: (zero length) */ ! 453: bzero(&mask, sizeof(mask)); ! 454: printf("nfs_boot: adding default route " IP_FORMAT "\n", ! 455: IP_LIST(&gw_ip)); ! 456: /* add, dest, gw, mask, flags, 0 */ ! 457: error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw, ! 458: &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); ! 459: if (error) ! 460: printf("nfs_boot: add route, error=%d\n", error); ! 461: } ! 462: #endif ! 463: if (do_bpgetfile) { ! 464: error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, ! 465: nd->nd_root.ndm_host, root_path); ! 466: if (error) { ! 467: printf("nfs_boot: bootparam get root: %d\n", error); ! 468: panic("nfs_boot: bootparam get root"); ! 469: } ! 470: } ! 471: ! 472: get_file_handle(root_path, &nd->nd_root); ! 473: ! 474: #if !defined(NO_MOUNT_PRIVATE) ! 475: if (do_bpgetfile) { /* get private path */ ! 476: char * private_path = NULL; ! 477: ! 478: MALLOC(private_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); ! 479: error = bp_getfile(&bp_sin, "private", ! 480: &nd->nd_private.ndm_saddr, ! 481: nd->nd_private.ndm_host, private_path); ! 482: if (!error) { ! 483: char * check_path = NULL; ! 484: ! 485: MALLOC(check_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); ! 486: sprintf(check_path, "%s/private", root_path); ! 487: if ((nd->nd_root.ndm_saddr.sin_addr.s_addr ! 488: == nd->nd_private.ndm_saddr.sin_addr.s_addr) ! 489: && (strcmp(check_path, private_path) == 0)) { ! 490: /* private path is prefix of root path, don't mount */ ! 491: nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; ! 492: } ! 493: else { ! 494: get_file_handle(private_path, &nd->nd_private); ! 495: } ! 496: _FREE(check_path, M_TEMP); ! 497: } ! 498: else { ! 499: /* private key not defined, don't mount */ ! 500: nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; ! 501: } ! 502: _FREE(private_path, M_TEMP); ! 503: } ! 504: #endif NO_MOUNT_PRIVATE ! 505: _FREE(booter_path, M_TEMP); ! 506: _FREE(root_path, M_TEMP); ! 507: return (0); ! 508: } ! 509: ! 510: int ! 511: inet_aton(char * cp, struct in_addr * pin) ! 512: { ! 513: u_char * b = (char *)pin; ! 514: int i; ! 515: char * p; ! 516: ! 517: for (p = cp, i = 0; i < 4; i++) { ! 518: u_long l = strtoul(p, 0, 0); ! 519: if (l > 255) ! 520: return (FALSE); ! 521: b[i] = l; ! 522: p = strchr(p, '.'); ! 523: if (i < 3 && p == NULL) ! 524: return (FALSE); ! 525: p++; ! 526: } ! 527: return (TRUE); ! 528: } ! 529: ! 530: /* ! 531: * Function: parse_image_path ! 532: * Purpose: ! 533: * Parse a string of the form "<IP>:<host>:<path>" into ! 534: * the given ip address and host and pathnames. ! 535: * Example: ! 536: * "17.202.16.17:seaport:/release/.images/Image9/CurrentHera" ! 537: */ ! 538: static __inline__ boolean_t ! 539: parse_image_path(char * c, struct in_addr * iaddr_p, char * hostname, ! 540: char * pathname) ! 541: { ! 542: char * d; ! 543: char * p; ! 544: #define TMP_SIZE 128 ! 545: char tmp[TMP_SIZE]; ! 546: ! 547: p = strchr(c, ':'); ! 548: if (p == NULL) ! 549: return (FALSE); ! 550: if ((p - c) >= TMP_SIZE) ! 551: return (FALSE); ! 552: strncpy(tmp, c, p - c); ! 553: tmp[p - c] = 0; ! 554: if (inet_aton(tmp, iaddr_p) != 1) ! 555: return (FALSE); ! 556: p++; ! 557: d = strchr(p, ':'); ! 558: if (d == NULL) ! 559: return (FALSE); ! 560: strncpy(hostname, p, d - p); ! 561: hostname[d - p] = 0; ! 562: d++; ! 563: strcpy(pathname, d); ! 564: return (TRUE); ! 565: } ! 566: ! 567: static boolean_t ! 568: path_getfile(char * image_path, struct sockaddr_in * sin_p, ! 569: char * serv_name, char * pathname) ! 570: { ! 571: bzero((caddr_t)sin_p, sizeof(*sin_p)); ! 572: sin_p->sin_len = sizeof(*sin_p); ! 573: sin_p->sin_family = AF_INET; ! 574: if (parse_image_path(image_path, &sin_p->sin_addr, serv_name, pathname) ! 575: == FALSE) ! 576: return (FALSE); ! 577: return (TRUE); ! 578: } ! 579: ! 580: static void ! 581: get_file_handle(pathname, ndmntp) ! 582: char *pathname; /* path on server */ ! 583: struct nfs_dlmount *ndmntp; /* output */ ! 584: { ! 585: char *sp, *dp, *endp; ! 586: int error; ! 587: ! 588: /* ! 589: * Get file handle for "key" (root or swap) ! 590: * using RPC to mountd/mount ! 591: */ ! 592: error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh); ! 593: if (error) ! 594: panic("nfs_boot: mountd, error=%d", error); ! 595: ! 596: /* Construct remote path (for getmntinfo(3)) */ ! 597: dp = ndmntp->ndm_host; ! 598: endp = dp + MNAMELEN - 1; ! 599: dp += strlen(dp); ! 600: *dp++ = ':'; ! 601: for (sp = pathname; *sp && dp < endp;) ! 602: *dp++ = *sp++; ! 603: *dp = '\0'; ! 604: ! 605: } ! 606: ! 607: ! 608: /* ! 609: * Get an mbuf with the given length, and ! 610: * initialize the pkthdr length field. ! 611: */ ! 612: static struct mbuf * ! 613: m_get_len(int msg_len) ! 614: { ! 615: struct mbuf *m; ! 616: m = m_gethdr(M_WAIT, MT_DATA); ! 617: if (m == NULL) ! 618: return NULL; ! 619: if (msg_len > MHLEN) { ! 620: if (msg_len > MCLBYTES) ! 621: panic("nfs_boot: msg_len > MCLBYTES"); ! 622: MCLGET(m, M_WAIT); ! 623: if (m == NULL) ! 624: return NULL; ! 625: } ! 626: m->m_len = msg_len; ! 627: m->m_pkthdr.len = m->m_len; ! 628: return (m); ! 629: } ! 630: ! 631: ! 632: /* ! 633: * String representation for RPC. ! 634: */ ! 635: struct rpc_string { ! 636: u_long len; /* length without null or padding */ ! 637: u_char data[4]; /* data (longer, of course) */ ! 638: /* data is padded to a long-word boundary */ ! 639: }; ! 640: /* Compute space used given string length. */ ! 641: #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3)) ! 642: ! 643: /* ! 644: * Inet address in RPC messages ! 645: * (Note, really four longs, NOT chars. Blech.) ! 646: */ ! 647: struct bp_inaddr { ! 648: u_long atype; ! 649: long addr[4]; ! 650: }; ! 651: ! 652: ! 653: /* ! 654: * RPC: bootparam/whoami ! 655: * Given client IP address, get: ! 656: * client name (hostname) ! 657: * domain name (domainname) ! 658: * gateway address ! 659: * ! 660: * The hostname and domainname are set here for convenience. ! 661: * ! 662: * Note - bpsin is initialized to the broadcast address, ! 663: * and will be replaced with the bootparam server address ! 664: * after this call is complete. Have to use PMAP_PROC_CALL ! 665: * to make sure we get responses only from a servers that ! 666: * know about us (don't want to broadcast a getport call). ! 667: */ ! 668: static int ! 669: bp_whoami(bpsin, my_ip, gw_ip) ! 670: struct sockaddr_in *bpsin; ! 671: struct in_addr *my_ip; ! 672: struct in_addr *gw_ip; ! 673: { ! 674: /* RPC structures for PMAPPROC_CALLIT */ ! 675: struct whoami_call { ! 676: u_long call_prog; ! 677: u_long call_vers; ! 678: u_long call_proc; ! 679: u_long call_arglen; ! 680: struct bp_inaddr call_ia; ! 681: } *call; ! 682: ! 683: struct rpc_string *str; ! 684: struct bp_inaddr *bia; ! 685: struct mbuf *m; ! 686: struct sockaddr_in *sin; ! 687: int error, msg_len; ! 688: int cn_len, dn_len; ! 689: u_char *p; ! 690: long *lp; ! 691: ! 692: /* ! 693: * Get message buffer of sufficient size. ! 694: */ ! 695: msg_len = sizeof(*call); ! 696: m = m_get_len(msg_len); ! 697: if (m == NULL) ! 698: return ENOBUFS; ! 699: ! 700: /* ! 701: * Build request message for PMAPPROC_CALLIT. ! 702: */ ! 703: call = mtod(m, struct whoami_call *); ! 704: call->call_prog = htonl(BOOTPARAM_PROG); ! 705: call->call_vers = htonl(BOOTPARAM_VERS); ! 706: call->call_proc = htonl(BOOTPARAM_WHOAMI); ! 707: call->call_arglen = htonl(sizeof(struct bp_inaddr)); ! 708: ! 709: /* client IP address */ ! 710: call->call_ia.atype = htonl(1); ! 711: p = (u_char*)my_ip; ! 712: lp = call->call_ia.addr; ! 713: *lp++ = htonl(*p); p++; ! 714: *lp++ = htonl(*p); p++; ! 715: *lp++ = htonl(*p); p++; ! 716: *lp++ = htonl(*p); p++; ! 717: ! 718: /* RPC: portmap/callit */ ! 719: bpsin->sin_port = htons(PMAPPORT); ! 720: ! 721: error = krpc_call(bpsin, PMAPPROG, PMAPVERS, ! 722: PMAPPROC_CALLIT, &m, &sin); ! 723: if (error) ! 724: return error; ! 725: ! 726: /* ! 727: * Parse result message. ! 728: */ ! 729: msg_len = m->m_len; ! 730: lp = mtod(m, long *); ! 731: ! 732: /* bootparam server port (also grab from address). */ ! 733: if (msg_len < sizeof(*lp)) ! 734: goto bad; ! 735: msg_len -= sizeof(*lp); ! 736: bpsin->sin_port = htons((short)ntohl(*lp++)); ! 737: bpsin->sin_addr.s_addr = sin->sin_addr.s_addr; ! 738: ! 739: /* length of encapsulated results */ ! 740: if (msg_len < (ntohl(*lp) + sizeof(*lp))) ! 741: goto bad; ! 742: msg_len = ntohl(*lp++); ! 743: p = (char*)lp; ! 744: ! 745: /* client name */ ! 746: if (msg_len < sizeof(*str)) ! 747: goto bad; ! 748: str = (struct rpc_string *)p; ! 749: cn_len = ntohl(str->len); ! 750: if (msg_len < cn_len) ! 751: goto bad; ! 752: if (cn_len >= MAXHOSTNAMELEN) ! 753: goto bad; ! 754: bcopy(str->data, hostname, cn_len); ! 755: hostname[cn_len] = '\0'; ! 756: hostnamelen = cn_len; ! 757: p += RPC_STR_SIZE(cn_len); ! 758: msg_len -= RPC_STR_SIZE(cn_len); ! 759: ! 760: /* domain name */ ! 761: if (msg_len < sizeof(*str)) ! 762: goto bad; ! 763: str = (struct rpc_string *)p; ! 764: dn_len = ntohl(str->len); ! 765: if (msg_len < dn_len) ! 766: goto bad; ! 767: if (dn_len >= MAXHOSTNAMELEN) ! 768: goto bad; ! 769: bcopy(str->data, domainname, dn_len); ! 770: domainname[dn_len] = '\0'; ! 771: domainnamelen = dn_len; ! 772: p += RPC_STR_SIZE(dn_len); ! 773: msg_len -= RPC_STR_SIZE(dn_len); ! 774: ! 775: /* gateway address */ ! 776: if (msg_len < sizeof(*bia)) ! 777: goto bad; ! 778: bia = (struct bp_inaddr *)p; ! 779: if (bia->atype != htonl(1)) ! 780: goto bad; ! 781: p = (u_char*)gw_ip; ! 782: *p++ = ntohl(bia->addr[0]); ! 783: *p++ = ntohl(bia->addr[1]); ! 784: *p++ = ntohl(bia->addr[2]); ! 785: *p++ = ntohl(bia->addr[3]); ! 786: goto out; ! 787: ! 788: bad: ! 789: printf("nfs_boot: bootparam_whoami: bad reply\n"); ! 790: error = EBADRPC; ! 791: ! 792: out: ! 793: if (sin) ! 794: FREE(sin, M_SONAME); ! 795: ! 796: m_freem(m); ! 797: return(error); ! 798: } ! 799: ! 800: ! 801: /* ! 802: * RPC: bootparam/getfile ! 803: * Given client name and file "key", get: ! 804: * server name ! 805: * server IP address ! 806: * server pathname ! 807: */ ! 808: static int ! 809: bp_getfile(bpsin, key, md_sin, serv_name, pathname) ! 810: struct sockaddr_in *bpsin; ! 811: char *key; ! 812: struct sockaddr_in *md_sin; ! 813: char *serv_name; ! 814: char *pathname; ! 815: { ! 816: struct rpc_string *str; ! 817: struct mbuf *m; ! 818: struct bp_inaddr *bia; ! 819: struct sockaddr_in *sin; ! 820: u_char *p, *q; ! 821: int error, msg_len; ! 822: int cn_len, key_len, sn_len, path_len; ! 823: ! 824: /* ! 825: * Get message buffer of sufficient size. ! 826: */ ! 827: cn_len = hostnamelen; ! 828: key_len = strlen(key); ! 829: msg_len = 0; ! 830: msg_len += RPC_STR_SIZE(cn_len); ! 831: msg_len += RPC_STR_SIZE(key_len); ! 832: m = m_get_len(msg_len); ! 833: if (m == NULL) ! 834: return ENOBUFS; ! 835: ! 836: /* ! 837: * Build request message. ! 838: */ ! 839: p = mtod(m, u_char *); ! 840: bzero(p, msg_len); ! 841: /* client name (hostname) */ ! 842: str = (struct rpc_string *)p; ! 843: str->len = htonl(cn_len); ! 844: bcopy(hostname, str->data, cn_len); ! 845: p += RPC_STR_SIZE(cn_len); ! 846: /* key name (root or swap) */ ! 847: str = (struct rpc_string *)p; ! 848: str->len = htonl(key_len); ! 849: bcopy(key, str->data, key_len); ! 850: ! 851: /* RPC: bootparam/getfile */ ! 852: error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS, ! 853: BOOTPARAM_GETFILE, &m, NULL); ! 854: if (error) ! 855: return error; ! 856: ! 857: /* ! 858: * Parse result message. ! 859: */ ! 860: p = mtod(m, u_char *); ! 861: msg_len = m->m_len; ! 862: ! 863: /* server name */ ! 864: if (msg_len < sizeof(*str)) ! 865: goto bad; ! 866: str = (struct rpc_string *)p; ! 867: sn_len = ntohl(str->len); ! 868: if (msg_len < sn_len) ! 869: goto bad; ! 870: if (sn_len >= MNAMELEN) ! 871: goto bad; ! 872: bcopy(str->data, serv_name, sn_len); ! 873: serv_name[sn_len] = '\0'; ! 874: p += RPC_STR_SIZE(sn_len); ! 875: msg_len -= RPC_STR_SIZE(sn_len); ! 876: ! 877: /* server IP address (mountd) */ ! 878: if (msg_len < sizeof(*bia)) ! 879: goto bad; ! 880: bia = (struct bp_inaddr *)p; ! 881: if (bia->atype != htonl(1)) ! 882: goto bad; ! 883: sin = md_sin; ! 884: bzero((caddr_t)sin, sizeof(*sin)); ! 885: sin->sin_len = sizeof(*sin); ! 886: sin->sin_family = AF_INET; ! 887: q = (u_char*) &sin->sin_addr; ! 888: *q++ = ntohl(bia->addr[0]); ! 889: *q++ = ntohl(bia->addr[1]); ! 890: *q++ = ntohl(bia->addr[2]); ! 891: *q++ = ntohl(bia->addr[3]); ! 892: p += sizeof(*bia); ! 893: msg_len -= sizeof(*bia); ! 894: ! 895: /* server pathname */ ! 896: if (msg_len < sizeof(*str)) ! 897: goto bad; ! 898: str = (struct rpc_string *)p; ! 899: path_len = ntohl(str->len); ! 900: if (msg_len < path_len) ! 901: goto bad; ! 902: if (path_len >= MAXPATHLEN) ! 903: goto bad; ! 904: bcopy(str->data, pathname, path_len); ! 905: pathname[path_len] = '\0'; ! 906: goto out; ! 907: ! 908: bad: ! 909: printf("nfs_boot: bootparam_getfile: bad reply\n"); ! 910: error = EBADRPC; ! 911: ! 912: out: ! 913: m_freem(m); ! 914: return(0); ! 915: } ! 916: ! 917: ! 918: /* ! 919: * RPC: mountd/mount ! 920: * Given a server pathname, get an NFS file handle. ! 921: * Also, sets sin->sin_port to the NFS service port. ! 922: */ ! 923: static int ! 924: md_mount(mdsin, path, fhp) ! 925: struct sockaddr_in *mdsin; /* mountd server address */ ! 926: char *path; ! 927: u_char *fhp; ! 928: { ! 929: /* The RPC structures */ ! 930: struct rpc_string *str; ! 931: struct rdata { ! 932: u_long errno; ! 933: u_char fh[NFSX_V2FH]; ! 934: } *rdata; ! 935: struct mbuf *m; ! 936: int error, mlen, slen; ! 937: ! 938: /* Get port number for MOUNTD. */ ! 939: error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, ! 940: &mdsin->sin_port); ! 941: if (error) return error; ! 942: ! 943: slen = strlen(path); ! 944: mlen = RPC_STR_SIZE(slen); ! 945: ! 946: m = m_get_len(mlen); ! 947: if (m == NULL) ! 948: return ENOBUFS; ! 949: str = mtod(m, struct rpc_string *); ! 950: str->len = htonl(slen); ! 951: bcopy(path, str->data, slen); ! 952: ! 953: /* Do RPC to mountd. */ ! 954: error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, ! 955: RPCMNT_MOUNT, &m, NULL); ! 956: if (error) ! 957: return error; /* message already freed */ ! 958: ! 959: mlen = m->m_len; ! 960: if (mlen < sizeof(*rdata)) ! 961: goto bad; ! 962: rdata = mtod(m, struct rdata *); ! 963: error = ntohl(rdata->errno); ! 964: if (error) ! 965: goto bad; ! 966: bcopy(rdata->fh, fhp, NFSX_V2FH); ! 967: ! 968: /* Set port number for NFS use. */ ! 969: error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2, ! 970: &mdsin->sin_port); ! 971: goto out; ! 972: ! 973: bad: ! 974: error = EBADRPC; ! 975: ! 976: out: ! 977: m_freem(m); ! 978: return error; ! 979: } ! 980: ! 981: #endif /* NETHER */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.