Annotation of XNU/bsd/nfs/nfs_boot.c, revision 1.1.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.