Annotation of kernel/bsd/nfs/nfs_boot.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */
                     26: /*
                     27:  * Copyright (c) 1994 Adam Glass, Gordon Ross
                     28:  * All rights reserved.
                     29:  *
                     30:  * The NEXTSTEP Software License Agreement specifies the terms
                     31:  * and conditions for redistribution.
                     32:  *
                     33:  *  History:
                     34:  *
                     35:  *  14-March-97        Dieter Siegmund ([email protected])
                     36:  *     Use BOOTP instead of RARP to get the IP address at boot time
                     37:  *
                     38:  *  23-May-97  Umesh Vaishampayan  ([email protected])
                     39:  *     Added the ability to mount "/private" separately.
                     40:  *
                     41:  *  30-May-97  Dieter Siegmund ([email protected])
                     42:  *     - Clear out the ireq structure before using it to prevent
                     43:  *       our sending using a bogus source IP address, we should use
                     44:  *       an IP address of all zeroes
                     45:  *     - Right after BOOTP, get the correct netmask using AUTONETMASK
                     46:  *  18-Jul-97  Dieter Siegmund ([email protected])
                     47:  *     - we can't restrict the netmask until we have a default route,
                     48:  *       removed AUTONETMASK call (ifdef'd out)
                     49:  *  5-Aug-97   Dieter Siegmund ([email protected])
                     50:  *     - use the default route from the bpwhoami call, enabled autonetmask
                     51:  *       again
                     52:  */
                     53: 
                     54: #include <sys/param.h>
                     55: #include <sys/systm.h>
                     56: #include <sys/kernel.h>
                     57: #include <sys/conf.h>
                     58: #include <sys/ioctl.h>
                     59: #include <sys/proc.h>
                     60: #include <sys/mount.h>
                     61: #include <sys/mbuf.h>
                     62: #include <sys/socket.h>
                     63: #include <sys/reboot.h>
                     64: 
                     65: #include <net/if.h>
                     66: #include <net/route.h>
                     67: 
                     68: #include <netinet/in.h>
                     69: #include <netinet/if_ether.h>
                     70: 
                     71: #include <nfs/rpcv2.h>
                     72: #include <nfs/nfsproto.h>
                     73: #include <nfs/nfs.h>
                     74: #include <nfs/nfsdiskless.h>
                     75: #include <nfs/krpc.h>
                     76: 
                     77: #include "ether.h"
                     78: 
                     79: #if NETHER == 0
                     80: 
                     81: int nfs_boot_init(nd, procp)
                     82:        struct nfs_diskless *nd;
                     83:        struct proc *procp;
                     84: {
                     85:        panic("nfs_boot_init: no ether");
                     86: }
                     87: 
                     88: #else /* NETHER */
                     89: 
                     90: /*
                     91:  * Support for NFS diskless booting, specifically getting information
                     92:  * about where to boot from, what pathnames, etc.
                     93:  *
                     94:  * This implememtation uses RARP and the bootparam RPC.
                     95:  * We are forced to implement RPC anyway (to get file handles)
                     96:  * so we might as well take advantage of it for bootparam too.
                     97:  *
                     98:  * The diskless boot sequence goes as follows:
                     99:  * (1) Use RARP to get our interface address
                    100:  * (2) Use RPC/bootparam/whoami to get our hostname,
                    101:  *     our IP address, and the server's IP address.
                    102:  * (3) Use RPC/bootparam/getfile to get the root path
                    103:  * (4) Use RPC/mountd to get the root file handle
                    104:  * (5) Use RPC/bootparam/getfile to get the swap path
                    105:  * (6) Use RPC/mountd to get the swap file handle
                    106:  *
                    107:  * (This happens to be the way Sun does it too.)
                    108:  */
                    109: 
                    110: /* bootparam RPC */
                    111: static int bp_whoami __P((struct sockaddr_in *bpsin,
                    112:        struct in_addr *my_ip, struct in_addr *gw_ip));
                    113: static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
                    114:        struct sockaddr_in *mdsin, char *servname, char *path));
                    115: 
                    116: /* mountd RPC */
                    117: static int md_mount __P((struct sockaddr_in *mdsin, char *path,
                    118:        u_char *fh));
                    119: 
                    120: /* other helpers */
                    121: static void get_path_and_handle __P((struct sockaddr_in *bpsin,
                    122:        char *key, struct nfs_dlmount *ndmntp));
                    123: 
                    124: char   *nfsbootdevname;
                    125: 
                    126: /*
                    127:  * Called with an empty nfs_diskless struct to be filled in.
                    128:  */
                    129: int
                    130: nfs_boot_init(nd, procp)
                    131:        struct nfs_diskless *nd;
                    132:        struct proc *procp;
                    133: {
                    134:        struct ifreq ireq;
                    135:        struct in_addr my_ip, gw_ip;
                    136:        struct sockaddr_in bp_sin;
                    137:        struct sockaddr_in *sin;
                    138:        struct ifnet *ifp;
                    139:        struct socket *so;
                    140:        int error;
                    141: 
                    142:        /* clear out the request structure */
                    143:        bzero(&ireq, sizeof(ireq));
                    144: 
                    145:        /*
                    146:         * Find an interface, rarp for its ip address, stuff it, the
                    147:         * implied broadcast addr, and netmask into a nfs_diskless struct.
                    148:         *
                    149:         * This was moved here from nfs_vfsops.c because this procedure
                    150:         * would be quite different if someone decides to write (i.e.) a
                    151:         * BOOTP version of this file (might not use RARP, etc.)
                    152:         */
                    153: 
                    154:        /*
                    155:         * Find a network interface.
                    156:         */
                    157:        if (nfsbootdevname)
                    158:                ifp = ifunit(nfsbootdevname);
                    159:        else
                    160:                for (ifp = ifnet; ifp; ifp = ifp->if_next)
                    161:                        if ((ifp->if_flags &
                    162:                             (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
                    163:                                break;
                    164:        if (ifp == NULL)
                    165:                panic("nfs_boot: no suitable interface");
                    166:        sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
                    167:        printf("nfs_boot: using network interface '%s'\n", ireq.ifr_name);
                    168: 
                    169:        /*
                    170:         * Bring up the interface.
                    171:         */
                    172:        if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
                    173:                panic("nfs_boot: socreate, error=%d", error);
                    174:        ireq.ifr_flags = IFF_UP;
                    175:        error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
                    176:        if (error)
                    177:                panic("nfs_boot: SIFFLAGS, error=%d", error);
                    178: 
                    179: #if NeXT
                    180:        /*
                    181:         * Do BOOTP to get the interface address
                    182:         */
                    183:        {
                    184:            int message = 0;
                    185:            
                    186:            ireq.ifr_addr.sa_family = AF_INET;
                    187:            while ((error = ifioctl(so, SIOCAUTOADDR, (caddr_t)&ireq, procp))) {
                    188:                if (error == ETIMEDOUT) {
                    189:                    if (!message) {
                    190:                        printf("nfs_boot: BOOTP timed out, still trying...\n");
                    191:                        message++;
                    192:                    }
                    193:                } 
                    194:                else {
                    195:                    printf("nfs_boot: autoaddr failed, error = %d\n", error);
                    196:                    panic("nfs_boot: SIOCAUTOADDR failed");
                    197:                }
                    198:            }
                    199: 
                    200:            sin = (struct sockaddr_in *)&(ireq.ifr_addr);
                    201:            my_ip = sin->sin_addr;
                    202:        }
                    203:        printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
                    204: 
                    205:        /*
                    206:         * get the netmask
                    207:         * XXX - if BOOTP returns a netmask, we should use that instead
                    208:         *       of icmp (DWS)
                    209:         */
                    210:        if ((error = ifioctl(so, SIOCAUTONETMASK, (caddr_t)&ireq, procp))) {
                    211:            printf("nfs_boot: autonetmask failed, error = %d\n", error);
                    212:        }
                    213: 
                    214: #else NeXT
                    215:        /*
                    216:         * Do RARP for the interface address.
                    217:         */
                    218:        if ((error = revarpwhoami(&my_ip, ifp)) != 0)
                    219:                panic("revarp failed, error=%d", error);
                    220:        printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
                    221: 
                    222:        /*
                    223:         * Do enough of ifconfig(8) so that the chosen interface
                    224:         * can talk to the servers.  (just set the address)
                    225:         */
                    226:        sin = (struct sockaddr_in *)&ireq.ifr_addr;
                    227:        bzero((caddr_t)sin, sizeof(*sin));
                    228:        sin->sin_len = sizeof(*sin);
                    229:        sin->sin_family = AF_INET;
                    230:        sin->sin_addr.s_addr = my_ip.s_addr;
                    231:        error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
                    232:        if (error)
                    233:                panic("nfs_boot: set if addr, error=%d", error);
                    234: #endif NeXT
                    235: 
                    236:        soclose(so);
                    237: 
                    238:        /*
                    239:         * Get client name and gateway address.
                    240:         * RPC: bootparam/whoami
                    241:         * Use the old broadcast address for the WHOAMI
                    242:         * call because we do not yet know our netmask.
                    243:         * The server address returned by the WHOAMI call
                    244:         * is used for all subsequent booptaram RPCs.
                    245:         */
                    246:        bzero((caddr_t)&bp_sin, sizeof(bp_sin));
                    247:        bp_sin.sin_len = sizeof(bp_sin);
                    248:        bp_sin.sin_family = AF_INET;
                    249:        bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
                    250:        hostnamelen = MAXHOSTNAMELEN;
                    251: 
                    252:        /* this returns gateway IP address */
                    253:        error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
                    254:        if (error) {
                    255:            printf("nfs_boot: bootparam whoami, error=%d", error);
                    256:            panic("nfs_boot: bootparam whoami\n");
                    257:        }
                    258:        printf("nfs_boot: server_addr=0x%x\n",
                    259:                   ntohl(bp_sin.sin_addr.s_addr));
                    260:        printf("nfs_boot: hostname=%s\n", hostname);
                    261: #define NFS_BOOT_GATEWAY       1
                    262: #ifdef NFS_BOOT_GATEWAY
                    263:        /*
                    264:         * XXX - This code is conditionally compiled only because
                    265:         * many bootparam servers (in particular, SunOS 4.1.3)
                    266:         * always set the gateway address to their own address.
                    267:         * The bootparam server is not necessarily the gateway.
                    268:         * We could just believe the server, and at worst you would
                    269:         * need to delete the incorrect default route before adding
                    270:         * the correct one, but for simplicity, ignore the gateway.
                    271:         * If your server is OK, you can turn on this option.
                    272:         *
                    273:         * If the gateway address is set, add a default route.
                    274:         * (The mountd RPCs may go across a gateway.)
                    275:         */
                    276:        if (gw_ip.s_addr) {
                    277:                struct sockaddr dst, gw, mask;
                    278:                /* Destination: (default) */
                    279:                bzero((caddr_t)&dst, sizeof(dst));
                    280:                dst.sa_len = sizeof(dst);
                    281:                dst.sa_family = AF_INET;
                    282:                /* Gateway: */
                    283:                bzero((caddr_t)&gw, sizeof(gw));
                    284:                sin = (struct sockaddr_in *)&gw;
                    285:                sin->sin_len = sizeof(gw);
                    286:                sin->sin_family = AF_INET;
                    287:                sin->sin_addr.s_addr = gw_ip.s_addr;
                    288:                /* Mask: (zero length) */
                    289:                bzero(&mask, sizeof(mask));
                    290: 
                    291:                printf("nfs_boot: gateway=0x%x\n", ntohl(gw_ip.s_addr));
                    292:                /* add, dest, gw, mask, flags, 0 */
                    293:                error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw,
                    294:                    &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
                    295:                if (error)
                    296:                        printf("nfs_boot: add route, error=%d\n", error);
                    297:        }
                    298: #endif
                    299: 
                    300:        get_path_and_handle(&bp_sin, "root", &nd->nd_root);
                    301: #if !defined(NO_MOUNT_PRIVATE)
                    302:        get_path_and_handle(&bp_sin, "private", &nd->nd_private);
                    303: #endif /* NO_MOUNT_PRIVATE */
                    304: 
                    305:        return (0);
                    306: }
                    307: 
                    308: static void
                    309: get_path_and_handle(bpsin, key, ndmntp)
                    310:        struct sockaddr_in *bpsin;      /* bootparam server */
                    311:        char *key;                      /* root or swap */
                    312:        struct nfs_dlmount *ndmntp;     /* output */
                    313: {
                    314:        char pathname[MAXPATHLEN];
                    315:        char *sp, *dp, *endp;
                    316:        int error;
                    317: 
                    318:        /*
                    319:         * Get server:pathname for "key" (root or swap)
                    320:         * using RPC to bootparam/getfile
                    321:         */
                    322:        error = bp_getfile(bpsin, key, &ndmntp->ndm_saddr,
                    323:            ndmntp->ndm_host, pathname);
                    324:        if (error) {
                    325:                printf("nfs_boot: bootparam get %s: %d\n", key, error);
                    326:                panic("nfs_boot: bootparam get %s: %d", key, error);
                    327:        }
                    328:        /*
                    329:         * Get file handle for "key" (root or swap)
                    330:         * using RPC to mountd/mount
                    331:         */
                    332:        error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh);
                    333:        if (error)
                    334:                panic("nfs_boot: mountd %s, error=%d", key, error);
                    335: 
                    336:        /* Construct remote path (for getmntinfo(3)) */
                    337:        dp = ndmntp->ndm_host;
                    338:        endp = dp + MNAMELEN - 1;
                    339:        dp += strlen(dp);
                    340:        *dp++ = ':';
                    341:        for (sp = pathname; *sp && dp < endp;)
                    342:                *dp++ = *sp++;
                    343:        *dp = '\0';
                    344: 
                    345: }
                    346: 
                    347: 
                    348: /*
                    349:  * Get an mbuf with the given length, and
                    350:  * initialize the pkthdr length field.
                    351:  */
                    352: static struct mbuf *
                    353: m_get_len(int msg_len)
                    354: {
                    355:        struct mbuf *m;
                    356:        m = m_gethdr(M_WAIT, MT_DATA);
                    357:        if (m == NULL)
                    358:                return NULL;
                    359:        if (msg_len > MHLEN) {
                    360:                if (msg_len > MCLBYTES)
                    361:                        panic("nfs_boot: msg_len > MCLBYTES");
                    362:                MCLGET(m, M_WAIT);
                    363:                if (m == NULL)
                    364:                        return NULL;
                    365:        }
                    366:        m->m_len = msg_len;
                    367:        m->m_pkthdr.len = m->m_len;
                    368:        return (m);
                    369: }
                    370: 
                    371: 
                    372: /*
                    373:  * String representation for RPC.
                    374:  */
                    375: struct rpc_string {
                    376:        u_long len;             /* length without null or padding */
                    377:        u_char data[4]; /* data (longer, of course) */
                    378:     /* data is padded to a long-word boundary */
                    379: };
                    380: /* Compute space used given string length. */
                    381: #define        RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
                    382: 
                    383: /*
                    384:  * Inet address in RPC messages
                    385:  * (Note, really four longs, NOT chars.  Blech.)
                    386:  */
                    387: struct bp_inaddr {
                    388:        u_long  atype;
                    389:        long    addr[4];
                    390: };
                    391: 
                    392: 
                    393: /*
                    394:  * RPC: bootparam/whoami
                    395:  * Given client IP address, get:
                    396:  *     client name     (hostname)
                    397:  *     domain name (domainname)
                    398:  *     gateway address
                    399:  *
                    400:  * The hostname and domainname are set here for convenience.
                    401:  *
                    402:  * Note - bpsin is initialized to the broadcast address,
                    403:  * and will be replaced with the bootparam server address
                    404:  * after this call is complete.  Have to use PMAP_PROC_CALL
                    405:  * to make sure we get responses only from a servers that
                    406:  * know about us (don't want to broadcast a getport call).
                    407:  */
                    408: static int
                    409: bp_whoami(bpsin, my_ip, gw_ip)
                    410:        struct sockaddr_in *bpsin;
                    411:        struct in_addr *my_ip;
                    412:        struct in_addr *gw_ip;
                    413: {
                    414:        /* RPC structures for PMAPPROC_CALLIT */
                    415:        struct whoami_call {
                    416:                u_long call_prog;
                    417:                u_long call_vers;
                    418:                u_long call_proc;
                    419:                u_long call_arglen;
                    420:                struct bp_inaddr call_ia;
                    421:        } *call;
                    422: 
                    423:        struct rpc_string *str;
                    424:        struct bp_inaddr *bia;
                    425:        struct mbuf *m, *from;
                    426:        struct sockaddr_in *sin;
                    427:        int error, msg_len;
                    428:        int cn_len, dn_len;
                    429:        u_char *p;
                    430:        long *lp;
                    431: 
                    432:        /*
                    433:         * Get message buffer of sufficient size.
                    434:         */
                    435:        msg_len = sizeof(*call);
                    436:        m = m_get_len(msg_len);
                    437:        if (m == NULL)
                    438:                return ENOBUFS;
                    439: 
                    440:        /*
                    441:         * Build request message for PMAPPROC_CALLIT.
                    442:         */
                    443:        call = mtod(m, struct whoami_call *);
                    444:        call->call_prog = htonl(BOOTPARAM_PROG);
                    445:        call->call_vers = htonl(BOOTPARAM_VERS);
                    446:        call->call_proc = htonl(BOOTPARAM_WHOAMI);
                    447:        call->call_arglen = htonl(sizeof(struct bp_inaddr));
                    448: 
                    449:        /* client IP address */
                    450:        call->call_ia.atype = htonl(1);
                    451:        p = (u_char*)my_ip;
                    452:        lp = call->call_ia.addr;
                    453:        *lp++ = htonl(*p);      p++;
                    454:        *lp++ = htonl(*p);      p++;
                    455:        *lp++ = htonl(*p);      p++;
                    456:        *lp++ = htonl(*p);      p++;
                    457: 
                    458:        /* RPC: portmap/callit */
                    459:        bpsin->sin_port = htons(PMAPPORT);
                    460:        from = NULL;
                    461:        error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
                    462:                        PMAPPROC_CALLIT, &m, &from);
                    463:        if (error)
                    464:                return error;
                    465: 
                    466:        /*
                    467:         * Parse result message.
                    468:         */
                    469:        msg_len = m->m_len;
                    470:        lp = mtod(m, long *);
                    471: 
                    472:        /* bootparam server port (also grab from address). */
                    473:        if (msg_len < sizeof(*lp))
                    474:                goto bad;
                    475:        msg_len -= sizeof(*lp);
                    476:        bpsin->sin_port = htons((short)ntohl(*lp++));
                    477:        sin = mtod(from, struct sockaddr_in *);
                    478:        bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
                    479: 
                    480:        /* length of encapsulated results */
                    481:        if (msg_len < (ntohl(*lp) + sizeof(*lp)))
                    482:                goto bad;
                    483:        msg_len = ntohl(*lp++);
                    484:        p = (char*)lp;
                    485: 
                    486:        /* client name */
                    487:        if (msg_len < sizeof(*str))
                    488:                goto bad;
                    489:        str = (struct rpc_string *)p;
                    490:        cn_len = ntohl(str->len);
                    491:        if (msg_len < cn_len)
                    492:                goto bad;
                    493:        if (cn_len >= MAXHOSTNAMELEN)
                    494:                goto bad;
                    495:        bcopy(str->data, hostname, cn_len);
                    496:        hostname[cn_len] = '\0';
                    497:        hostnamelen = cn_len;
                    498:        p += RPC_STR_SIZE(cn_len);
                    499:        msg_len -= RPC_STR_SIZE(cn_len);
                    500: 
                    501:        /* domain name */
                    502:        if (msg_len < sizeof(*str))
                    503:                goto bad;
                    504:        str = (struct rpc_string *)p;
                    505:        dn_len = ntohl(str->len);
                    506:        if (msg_len < dn_len)
                    507:                goto bad;
                    508:        if (dn_len >= MAXHOSTNAMELEN)
                    509:                goto bad;
                    510:        bcopy(str->data, domainname, dn_len);
                    511:        domainname[dn_len] = '\0';
                    512:        domainnamelen = dn_len;
                    513:        p += RPC_STR_SIZE(dn_len);
                    514:        msg_len -= RPC_STR_SIZE(dn_len);
                    515: 
                    516:        /* gateway address */
                    517:        if (msg_len < sizeof(*bia))
                    518:                goto bad;
                    519:        bia = (struct bp_inaddr *)p;
                    520:        if (bia->atype != htonl(1))
                    521:                goto bad;
                    522:        p = (u_char*)gw_ip;
                    523:        *p++ = ntohl(bia->addr[0]);
                    524:        *p++ = ntohl(bia->addr[1]);
                    525:        *p++ = ntohl(bia->addr[2]);
                    526:        *p++ = ntohl(bia->addr[3]);
                    527:        goto out;
                    528: 
                    529: bad:
                    530:        printf("nfs_boot: bootparam_whoami: bad reply\n");
                    531:        error = EBADRPC;
                    532: 
                    533: out:
                    534:        if (from)
                    535:                m_freem(from);
                    536:        m_freem(m);
                    537:        return(error);
                    538: }
                    539: 
                    540: 
                    541: /*
                    542:  * RPC: bootparam/getfile
                    543:  * Given client name and file "key", get:
                    544:  *     server name
                    545:  *     server IP address
                    546:  *     server pathname
                    547:  */
                    548: static int
                    549: bp_getfile(bpsin, key, md_sin, serv_name, pathname)
                    550:        struct sockaddr_in *bpsin;
                    551:        char *key;
                    552:        struct sockaddr_in *md_sin;
                    553:        char *serv_name;
                    554:        char *pathname;
                    555: {
                    556:        struct rpc_string *str;
                    557:        struct mbuf *m;
                    558:        struct bp_inaddr *bia;
                    559:        struct sockaddr_in *sin;
                    560:        u_char *p, *q;
                    561:        int error, msg_len;
                    562:        int cn_len, key_len, sn_len, path_len;
                    563: 
                    564:        /*
                    565:         * Get message buffer of sufficient size.
                    566:         */
                    567:        cn_len = hostnamelen;
                    568:        key_len = strlen(key);
                    569:        msg_len = 0;
                    570:        msg_len += RPC_STR_SIZE(cn_len);
                    571:        msg_len += RPC_STR_SIZE(key_len);
                    572:        m = m_get_len(msg_len);
                    573:        if (m == NULL)
                    574:                return ENOBUFS;
                    575: 
                    576:        /*
                    577:         * Build request message.
                    578:         */
                    579:        p = mtod(m, u_char *);
                    580:        bzero(p, msg_len);
                    581:        /* client name (hostname) */
                    582:        str = (struct rpc_string *)p;
                    583:        str->len = htonl(cn_len);
                    584:        bcopy(hostname, str->data, cn_len);
                    585:        p += RPC_STR_SIZE(cn_len);
                    586:        /* key name (root or swap) */
                    587:        str = (struct rpc_string *)p;
                    588:        str->len = htonl(key_len);
                    589:        bcopy(key, str->data, key_len);
                    590: 
                    591:        /* RPC: bootparam/getfile */
                    592:        error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
                    593:                        BOOTPARAM_GETFILE, &m, NULL);
                    594:        if (error)
                    595:                return error;
                    596: 
                    597:        /*
                    598:         * Parse result message.
                    599:         */
                    600:        p = mtod(m, u_char *);
                    601:        msg_len = m->m_len;
                    602: 
                    603:        /* server name */
                    604:        if (msg_len < sizeof(*str))
                    605:                goto bad;
                    606:        str = (struct rpc_string *)p;
                    607:        sn_len = ntohl(str->len);
                    608:        if (msg_len < sn_len)
                    609:                goto bad;
                    610:        if (sn_len >= MNAMELEN)
                    611:                goto bad;
                    612:        bcopy(str->data, serv_name, sn_len);
                    613:        serv_name[sn_len] = '\0';
                    614:        p += RPC_STR_SIZE(sn_len);
                    615:        msg_len -= RPC_STR_SIZE(sn_len);
                    616: 
                    617:        /* server IP address (mountd) */
                    618:        if (msg_len < sizeof(*bia))
                    619:                goto bad;
                    620:        bia = (struct bp_inaddr *)p;
                    621:        if (bia->atype != htonl(1))
                    622:                goto bad;
                    623:        sin = md_sin;
                    624:        bzero((caddr_t)sin, sizeof(*sin));
                    625:        sin->sin_len = sizeof(*sin);
                    626:        sin->sin_family = AF_INET;
                    627:        q = (u_char*) &sin->sin_addr;
                    628:        *q++ = ntohl(bia->addr[0]);
                    629:        *q++ = ntohl(bia->addr[1]);
                    630:        *q++ = ntohl(bia->addr[2]);
                    631:        *q++ = ntohl(bia->addr[3]);
                    632:        p += sizeof(*bia);
                    633:        msg_len -= sizeof(*bia);
                    634: 
                    635:        /* server pathname */
                    636:        if (msg_len < sizeof(*str))
                    637:                goto bad;
                    638:        str = (struct rpc_string *)p;
                    639:        path_len = ntohl(str->len);
                    640:        if (msg_len < path_len)
                    641:                goto bad;
                    642:        if (path_len >= MAXPATHLEN)
                    643:                goto bad;
                    644:        bcopy(str->data, pathname, path_len);
                    645:        pathname[path_len] = '\0';
                    646:        goto out;
                    647: 
                    648: bad:
                    649:        printf("nfs_boot: bootparam_getfile: bad reply\n");
                    650:        error = EBADRPC;
                    651: 
                    652: out:
                    653:        m_freem(m);
                    654:        return(0);
                    655: }
                    656: 
                    657: 
                    658: /*
                    659:  * RPC: mountd/mount
                    660:  * Given a server pathname, get an NFS file handle.
                    661:  * Also, sets sin->sin_port to the NFS service port.
                    662:  */
                    663: static int
                    664: md_mount(mdsin, path, fhp)
                    665:        struct sockaddr_in *mdsin;              /* mountd server address */
                    666:        char *path;
                    667:        u_char *fhp;
                    668: {
                    669:        /* The RPC structures */
                    670:        struct rpc_string *str;
                    671:        struct rdata {
                    672:                u_long  errno;
                    673:                u_char  fh[NFSX_V2FH];
                    674:        } *rdata;
                    675:        struct mbuf *m;
                    676:        int error, mlen, slen;
                    677: 
                    678:        /* Get port number for MOUNTD. */
                    679:        error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
                    680:                                                 &mdsin->sin_port);
                    681:        if (error) return error;
                    682: 
                    683:        slen = strlen(path);
                    684:        mlen = RPC_STR_SIZE(slen);
                    685: 
                    686:        m = m_get_len(mlen);
                    687:        if (m == NULL)
                    688:                return ENOBUFS;
                    689:        str = mtod(m, struct rpc_string *);
                    690:        str->len = htonl(slen);
                    691:        bcopy(path, str->data, slen);
                    692: 
                    693:        /* Do RPC to mountd. */
                    694:        error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
                    695:                        RPCMNT_MOUNT, &m, NULL);
                    696:        if (error)
                    697:                return error;   /* message already freed */
                    698: 
                    699:        mlen = m->m_len;
                    700:        if (mlen < sizeof(*rdata))
                    701:                goto bad;
                    702:        rdata = mtod(m, struct rdata *);
                    703:        error = ntohl(rdata->errno);
                    704:        if (error)
                    705:                goto bad;
                    706:        bcopy(rdata->fh, fhp, NFSX_V2FH);
                    707: 
                    708:        /* Set port number for NFS use. */
                    709:        error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2,
                    710:                                                 &mdsin->sin_port);
                    711:        goto out;
                    712: 
                    713: bad:
                    714:        error = EBADRPC;
                    715: 
                    716: out:
                    717:        m_freem(m);
                    718:        return error;
                    719: }
                    720: 
                    721: #endif /* NETHER */

unix.superglobalmegacorp.com

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