Annotation of XNU/bsd/nfs/nfs_boot.c, revision 1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.