[BACK]Return to nfs_boot.c CVS log [TXT][DIR] Up to [local] / sys / nfs

Annotation of sys/nfs/nfs_boot.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: nfs_boot.c,v 1.18 2006/06/17 14:14:12 henning Exp $ */
        !             2: /*     $NetBSD: nfs_boot.c,v 1.26 1996/05/07 02:51:25 thorpej Exp $    */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1995 Adam Glass, Gordon Ross
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. The name of the authors may not be used to endorse or promote products
        !            17:  *    derived from this software without specific prior written permission.
        !            18:  *
        !            19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
        !            20:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            21:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            22:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            23:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            24:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            25:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            26:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            27:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            28:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            29:  */
        !            30:
        !            31: #include <sys/param.h>
        !            32: #include <sys/systm.h>
        !            33: #include <sys/kernel.h>
        !            34: #include <sys/conf.h>
        !            35: #include <sys/ioctl.h>
        !            36: #include <sys/proc.h>
        !            37: #include <sys/mount.h>
        !            38: #include <sys/mbuf.h>
        !            39: #include <sys/reboot.h>
        !            40: #include <sys/socket.h>
        !            41: #include <sys/socketvar.h>
        !            42:
        !            43: #include <net/if.h>
        !            44: #include <net/route.h>
        !            45:
        !            46: #include <netinet/in.h>
        !            47: #include <netinet/if_ether.h>
        !            48:
        !            49: #include <nfs/rpcv2.h>
        !            50: #include <nfs/nfsproto.h>
        !            51: #include <nfs/nfs.h>
        !            52: #include <nfs/nfsdiskless.h>
        !            53: #include <nfs/krpc.h>
        !            54: #include <nfs/xdr_subs.h>
        !            55: #include <nfs/nfs_var.h>
        !            56:
        !            57: #include "ether.h"
        !            58:
        !            59: #if !defined(NFSCLIENT) || (NETHER == 0 && NFDDI == 0)
        !            60:
        !            61: int
        !            62: nfs_boot_init(nd, procp)
        !            63:        struct nfs_diskless *nd;
        !            64:        struct proc *procp;
        !            65: {
        !            66:        panic("nfs_boot_init: NFSCLIENT not enabled in kernel");
        !            67: }
        !            68:
        !            69: int
        !            70: nfs_boot_getfh(bpsin, key, ndmntp, retries)
        !            71:        struct sockaddr_in *bpsin;
        !            72:        char *key;
        !            73:        struct nfs_dlmount *ndmntp;
        !            74:        int retries;
        !            75: {
        !            76:        /* can not get here */
        !            77:        return (EOPNOTSUPP);
        !            78: }
        !            79:
        !            80: #else
        !            81:
        !            82: /*
        !            83:  * Support for NFS diskless booting, specifically getting information
        !            84:  * about where to boot from, what pathnames, etc.
        !            85:  *
        !            86:  * This implementation uses RARP and the bootparam RPC.
        !            87:  * We are forced to implement RPC anyway (to get file handles)
        !            88:  * so we might as well take advantage of it for bootparam too.
        !            89:  *
        !            90:  * The diskless boot sequence goes as follows:
        !            91:  * (1) Use RARP to get our interface address
        !            92:  * (2) Use RPC/bootparam/whoami to get our hostname,
        !            93:  *     our IP address, and the server's IP address.
        !            94:  * (3) Use RPC/bootparam/getfile to get the root path
        !            95:  * (4) Use RPC/mountd to get the root file handle
        !            96:  * (5) Use RPC/bootparam/getfile to get the swap path
        !            97:  * (6) Use RPC/mountd to get the swap file handle
        !            98:  *
        !            99:  * (This happens to be the way Sun does it too.)
        !           100:  */
        !           101:
        !           102: /* bootparam RPC */
        !           103: static int bp_whoami(struct sockaddr_in *bpsin,
        !           104:        struct in_addr *my_ip, struct in_addr *gw_ip);
        !           105: static int bp_getfile(struct sockaddr_in *bpsin, char *key,
        !           106:        struct sockaddr_in *mdsin, char *servname, char *path, int retries);
        !           107:
        !           108: /* mountd RPC */
        !           109: static int md_mount(struct sockaddr_in *mdsin, char *path,
        !           110:        u_char *fh);
        !           111:
        !           112: char   *nfsbootdevname;
        !           113:
        !           114: /*
        !           115:  * Called with an empty nfs_diskless struct to be filled in.
        !           116:  */
        !           117: int
        !           118: nfs_boot_init(nd, procp)
        !           119:        struct nfs_diskless *nd;
        !           120:        struct proc *procp;
        !           121: {
        !           122:        struct ifreq ireq;
        !           123:        struct in_addr my_ip, gw_ip;
        !           124:        struct sockaddr_in bp_sin;
        !           125:        struct sockaddr_in *sin;
        !           126:        struct ifnet *ifp;
        !           127:        struct socket *so;
        !           128:        int error;
        !           129:
        !           130:        /*
        !           131:         * Find an interface, rarp for its ip address, stuff it, the
        !           132:         * implied broadcast addr, and netmask into a nfs_diskless struct.
        !           133:         *
        !           134:         * This was moved here from nfs_vfsops.c because this procedure
        !           135:         * would be quite different if someone decides to write (i.e.) a
        !           136:         * BOOTP version of this file (might not use RARP, etc.)
        !           137:         */
        !           138:
        !           139:        /*
        !           140:         * Find a network interface.
        !           141:         */
        !           142:        if (nfsbootdevname)
        !           143:                ifp = ifunit(nfsbootdevname);
        !           144:        else {
        !           145:                for (ifp = TAILQ_FIRST(&ifnet); ifp != NULL;
        !           146:                    ifp = TAILQ_NEXT(ifp, if_list)) {
        !           147:                        if ((ifp->if_flags &
        !           148:                             (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
        !           149:                                break;
        !           150:                }
        !           151:        }
        !           152:        if (ifp == NULL)
        !           153:                panic("nfs_boot: no suitable interface");
        !           154:        bcopy(ifp->if_xname, ireq.ifr_name, IFNAMSIZ);
        !           155:        printf("nfs_boot: using interface %s, with revarp & bootparams\n",
        !           156:            ireq.ifr_name);
        !           157:
        !           158:        /*
        !           159:         * Bring up the interface.
        !           160:         *
        !           161:         * Get the old interface flags and or IFF_UP into them; if
        !           162:         * IFF_UP set blindly, interface selection can be clobbered.
        !           163:         */
        !           164:        if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
        !           165:                panic("nfs_boot: socreate, error=%d", error);
        !           166:        error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
        !           167:        if (error)
        !           168:                panic("nfs_boot: GIFFLAGS, error=%d", error);
        !           169:        ireq.ifr_flags |= IFF_UP;
        !           170:        error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
        !           171:        if (error)
        !           172:                panic("nfs_boot: SIFFLAGS, error=%d", error);
        !           173:
        !           174:        /*
        !           175:         * Do RARP for the interface address.
        !           176:         */
        !           177:        if ((error = revarpwhoami(&my_ip, ifp)) != 0)
        !           178:                panic("revarp failed, error=%d", error);
        !           179:        printf("nfs_boot: client_addr=%s\n", inet_ntoa(my_ip));
        !           180:
        !           181:        /*
        !           182:         * Do enough of ifconfig(8) so that the chosen interface
        !           183:         * can talk to the servers.  (just set the address)
        !           184:         */
        !           185:        sin = (struct sockaddr_in *)&ireq.ifr_addr;
        !           186:        bzero((caddr_t)sin, sizeof(*sin));
        !           187:        sin->sin_len = sizeof(*sin);
        !           188:        sin->sin_family = AF_INET;
        !           189:        sin->sin_addr.s_addr = my_ip.s_addr;
        !           190:        error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
        !           191:        if (error)
        !           192:                panic("nfs_boot: set if addr, error=%d", error);
        !           193:
        !           194:        soclose(so);
        !           195:
        !           196:        /*
        !           197:         * Get client name and gateway address.
        !           198:         * RPC: bootparam/whoami
        !           199:         * Use the old broadcast address for the WHOAMI
        !           200:         * call because we do not yet know our netmask.
        !           201:         * The server address returned by the WHOAMI call
        !           202:         * is used for all subsequent booptaram RPCs.
        !           203:         */
        !           204:        bzero((caddr_t)&bp_sin, sizeof(bp_sin));
        !           205:        bp_sin.sin_len = sizeof(bp_sin);
        !           206:        bp_sin.sin_family = AF_INET;
        !           207:        bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
        !           208:        hostnamelen = MAXHOSTNAMELEN;
        !           209:
        !           210:        /* this returns gateway IP address */
        !           211:        error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
        !           212:        if (error)
        !           213:                panic("nfs_boot: bootparam whoami, error=%d", error);
        !           214:        printf("nfs_boot: server_addr=%s hostname=%s\n",
        !           215:            inet_ntoa(bp_sin.sin_addr), hostname);
        !           216:
        !           217: #ifdef NFS_BOOT_GATEWAY
        !           218:        /*
        !           219:         * XXX - This code is conditionally compiled only because
        !           220:         * many bootparam servers (in particular, SunOS 4.1.3)
        !           221:         * always set the gateway address to their own address.
        !           222:         * The bootparam server is not necessarily the gateway.
        !           223:         * We could just believe the server, and at worst you would
        !           224:         * need to delete the incorrect default route before adding
        !           225:         * the correct one, but for simplicity, ignore the gateway.
        !           226:         * If your server is OK, you can turn on this option.
        !           227:         *
        !           228:         * If the gateway address is set, add a default route.
        !           229:         * (The mountd RPCs may go across a gateway.)
        !           230:         */
        !           231:        if (gw_ip.s_addr) {
        !           232:                struct sockaddr dst, gw, mask;
        !           233:                /* Destination: (default) */
        !           234:                bzero((caddr_t)&dst, sizeof(dst));
        !           235:                dst.sa_len = sizeof(dst);
        !           236:                dst.sa_family = AF_INET;
        !           237:                /* Gateway: */
        !           238:                bzero((caddr_t)&gw, sizeof(gw));
        !           239:                sin = (struct sockaddr_in *)&gw;
        !           240:                sin->sin_len = sizeof(gw);
        !           241:                sin->sin_family = AF_INET;
        !           242:                sin->sin_addr.s_addr = gw_ip.s_addr;
        !           243:                /* Mask: (zero length) */
        !           244:                bzero(&mask, sizeof(mask));
        !           245:
        !           246:                printf("nfs_boot: gateway=%s\n", inet_ntoa(gw_ip));
        !           247:                /* add, dest, gw, mask, flags, 0 */
        !           248:                error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw,
        !           249:                    &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, 0);
        !           250:                if (error)
        !           251:                        printf("nfs_boot: add route, error=%d\n", error);
        !           252:        }
        !           253: #endif
        !           254:
        !           255:        bcopy(&bp_sin, &nd->nd_boot, sizeof(bp_sin));
        !           256:
        !           257:        return (0);
        !           258: }
        !           259:
        !           260: int
        !           261: nfs_boot_getfh(bpsin, key, ndmntp, retries)
        !           262:        struct sockaddr_in *bpsin;      /* bootparam server */
        !           263:        char *key;                      /* root or swap */
        !           264:        struct nfs_dlmount *ndmntp;     /* output */
        !           265:        int retries;
        !           266: {
        !           267:        char pathname[MAXPATHLEN];
        !           268:        char *sp, *dp, *endp;
        !           269:        struct sockaddr_in *sin;
        !           270:        int error;
        !           271:
        !           272:        sin = &ndmntp->ndm_saddr;
        !           273:
        !           274:        /*
        !           275:         * Get server:pathname for "key" (root or swap)
        !           276:         * using RPC to bootparam/getfile
        !           277:         */
        !           278:        error = bp_getfile(bpsin, key, sin, ndmntp->ndm_host, pathname,
        !           279:            retries);
        !           280:        if (error) {
        !           281:                printf("nfs_boot: bootparam get %s: %d\n", key, error);
        !           282:                return (error);
        !           283:        }
        !           284:
        !           285:        /*
        !           286:         * Get file handle for "key" (root or swap)
        !           287:         * using RPC to mountd/mount
        !           288:         */
        !           289:        error = md_mount(sin, pathname, ndmntp->ndm_fh);
        !           290:        if (error) {
        !           291:                printf("nfs_boot: mountd %s, error=%d\n", key, error);
        !           292:                return (error);
        !           293:        }
        !           294:
        !           295:        /* Set port number for NFS use. */
        !           296:        /* XXX: NFS port is always 2049, right? */
        !           297:        error = krpc_portmap(sin, NFS_PROG, NFS_VER2, &sin->sin_port);
        !           298:        if (error) {
        !           299:                printf("nfs_boot: portmap NFS/v2, error=%d\n", error);
        !           300:                return (error);
        !           301:        }
        !           302:
        !           303:        /* Construct remote path (for getmntinfo(3)) */
        !           304:        dp = ndmntp->ndm_host;
        !           305:        endp = dp + MNAMELEN - 1;
        !           306:        dp += strlen(dp);
        !           307:        *dp++ = ':';
        !           308:        for (sp = pathname; *sp && dp < endp;)
        !           309:                *dp++ = *sp++;
        !           310:        *dp = '\0';
        !           311:
        !           312:        return (0);
        !           313: }
        !           314:
        !           315:
        !           316: /*
        !           317:  * RPC: bootparam/whoami
        !           318:  * Given client IP address, get:
        !           319:  *     client name     (hostname)
        !           320:  *     domain name (domainname)
        !           321:  *     gateway address
        !           322:  *
        !           323:  * The hostname and domainname are set here for convenience.
        !           324:  *
        !           325:  * Note - bpsin is initialized to the broadcast address,
        !           326:  * and will be replaced with the bootparam server address
        !           327:  * after this call is complete.  Have to use PMAP_PROC_CALL
        !           328:  * to make sure we get responses only from a servers that
        !           329:  * know about us (don't want to broadcast a getport call).
        !           330:  */
        !           331: static int
        !           332: bp_whoami(bpsin, my_ip, gw_ip)
        !           333:        struct sockaddr_in *bpsin;
        !           334:        struct in_addr *my_ip;
        !           335:        struct in_addr *gw_ip;
        !           336: {
        !           337:        /* RPC structures for PMAPPROC_CALLIT */
        !           338:        struct whoami_call {
        !           339:                u_int32_t call_prog;
        !           340:                u_int32_t call_vers;
        !           341:                u_int32_t call_proc;
        !           342:                u_int32_t call_arglen;
        !           343:        } *call;
        !           344:        struct callit_reply {
        !           345:                u_int32_t port;
        !           346:                u_int32_t encap_len;
        !           347:                /* encapsulated data here */
        !           348:        } *reply;
        !           349:
        !           350:        struct mbuf *m, *from;
        !           351:        struct sockaddr_in *sin;
        !           352:        int error, msg_len;
        !           353:        int16_t port;
        !           354:
        !           355:        /*
        !           356:         * Build request message for PMAPPROC_CALLIT.
        !           357:         */
        !           358:        m = m_get(M_WAIT, MT_DATA);
        !           359:        call = mtod(m, struct whoami_call *);
        !           360:        m->m_len = sizeof(*call);
        !           361:        call->call_prog = txdr_unsigned(BOOTPARAM_PROG);
        !           362:        call->call_vers = txdr_unsigned(BOOTPARAM_VERS);
        !           363:        call->call_proc = txdr_unsigned(BOOTPARAM_WHOAMI);
        !           364:
        !           365:        /*
        !           366:         * append encapsulated data (client IP address)
        !           367:         */
        !           368:        m->m_next = xdr_inaddr_encode(my_ip);
        !           369:        call->call_arglen = txdr_unsigned(m->m_next->m_len);
        !           370:
        !           371:        /* RPC: portmap/callit */
        !           372:        bpsin->sin_port = htons(PMAPPORT);
        !           373:        from = NULL;
        !           374:        error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
        !           375:                        PMAPPROC_CALLIT, &m, &from, -1);
        !           376:        if (error)
        !           377:                return error;
        !           378:
        !           379:        /*
        !           380:         * Parse result message.
        !           381:         */
        !           382:        if (m->m_len < sizeof(*reply)) {
        !           383:                m = m_pullup(m, sizeof(*reply));
        !           384:                if (m == NULL)
        !           385:                        goto bad;
        !           386:        }
        !           387:        reply = mtod(m, struct callit_reply *);
        !           388:        port = fxdr_unsigned(u_int32_t, reply->port);
        !           389:        msg_len = fxdr_unsigned(u_int32_t, reply->encap_len);
        !           390:        m_adj(m, sizeof(*reply));
        !           391:
        !           392:        /*
        !           393:         * Save bootparam server address
        !           394:         */
        !           395:        sin = mtod(from, struct sockaddr_in *);
        !           396:        bpsin->sin_port = htons(port);
        !           397:        bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
        !           398:
        !           399:        /* client name */
        !           400:        hostnamelen = MAXHOSTNAMELEN-1;
        !           401:        m = xdr_string_decode(m, hostname, &hostnamelen);
        !           402:        if (m == NULL)
        !           403:                goto bad;
        !           404:
        !           405:        /* domain name */
        !           406:        domainnamelen = MAXHOSTNAMELEN-1;
        !           407:        m = xdr_string_decode(m, domainname, &domainnamelen);
        !           408:        if (m == NULL)
        !           409:                goto bad;
        !           410:
        !           411:        /* gateway address */
        !           412:        m = xdr_inaddr_decode(m, gw_ip);
        !           413:        if (m == NULL)
        !           414:                goto bad;
        !           415:
        !           416:        /* success */
        !           417:        goto out;
        !           418:
        !           419: bad:
        !           420:        printf("nfs_boot: bootparam_whoami: bad reply\n");
        !           421:        error = EBADRPC;
        !           422:
        !           423: out:
        !           424:        if (from)
        !           425:                m_freem(from);
        !           426:        if (m)
        !           427:                m_freem(m);
        !           428:        return(error);
        !           429: }
        !           430:
        !           431:
        !           432: /*
        !           433:  * RPC: bootparam/getfile
        !           434:  * Given client name and file "key", get:
        !           435:  *     server name
        !           436:  *     server IP address
        !           437:  *     server pathname
        !           438:  */
        !           439: static int
        !           440: bp_getfile(bpsin, key, md_sin, serv_name, pathname, retries)
        !           441:        struct sockaddr_in *bpsin;
        !           442:        char *key;
        !           443:        struct sockaddr_in *md_sin;
        !           444:        char *serv_name;
        !           445:        char *pathname;
        !           446:        int retries;
        !           447: {
        !           448:        struct mbuf *m;
        !           449:        struct sockaddr_in *sin;
        !           450:        struct in_addr inaddr;
        !           451:        int error, sn_len, path_len;
        !           452:
        !           453:        /*
        !           454:         * Build request message.
        !           455:         */
        !           456:
        !           457:        /* client name (hostname) */
        !           458:        m  = xdr_string_encode(hostname, hostnamelen);
        !           459:        if (m == NULL)
        !           460:                return (ENOMEM);
        !           461:
        !           462:        /* key name (root or swap) */
        !           463:        m->m_next = xdr_string_encode(key, strlen(key));
        !           464:        if (m->m_next == NULL)
        !           465:                return (ENOMEM);
        !           466:
        !           467:        /* RPC: bootparam/getfile */
        !           468:        error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
        !           469:                        BOOTPARAM_GETFILE, &m, NULL, retries);
        !           470:        if (error)
        !           471:                return error;
        !           472:
        !           473:        /*
        !           474:         * Parse result message.
        !           475:         */
        !           476:
        !           477:        /* server name */
        !           478:        sn_len = MNAMELEN-1;
        !           479:        m = xdr_string_decode(m, serv_name, &sn_len);
        !           480:        if (m == NULL)
        !           481:                goto bad;
        !           482:
        !           483:        /* server IP address (mountd/NFS) */
        !           484:        m = xdr_inaddr_decode(m, &inaddr);
        !           485:        if (m == NULL)
        !           486:                goto bad;
        !           487:
        !           488:        /* server pathname */
        !           489:        path_len = MAXPATHLEN-1;
        !           490:        m = xdr_string_decode(m, pathname, &path_len);
        !           491:        if (m == NULL)
        !           492:                goto bad;
        !           493:
        !           494:        /* setup server socket address */
        !           495:        sin = md_sin;
        !           496:        bzero((caddr_t)sin, sizeof(*sin));
        !           497:        sin->sin_len = sizeof(*sin);
        !           498:        sin->sin_family = AF_INET;
        !           499:        sin->sin_addr = inaddr;
        !           500:
        !           501:        /* success */
        !           502:        goto out;
        !           503:
        !           504: bad:
        !           505:        printf("nfs_boot: bootparam_getfile: bad reply\n");
        !           506:        error = EBADRPC;
        !           507:
        !           508: out:
        !           509:        m_freem(m);
        !           510:        return(0);
        !           511: }
        !           512:
        !           513:
        !           514: /*
        !           515:  * RPC: mountd/mount
        !           516:  * Given a server pathname, get an NFS file handle.
        !           517:  * Also, sets sin->sin_port to the NFS service port.
        !           518:  */
        !           519: static int
        !           520: md_mount(mdsin, path, fhp)
        !           521:        struct sockaddr_in *mdsin;              /* mountd server address */
        !           522:        char *path;
        !           523:        u_char *fhp;
        !           524: {
        !           525:        /* The RPC structures */
        !           526:        struct rdata {
        !           527:                u_int32_t errno;
        !           528:                u_int8_t  fh[NFSX_V2FH];
        !           529:        } *rdata;
        !           530:        struct mbuf *m;
        !           531:        int error;
        !           532:
        !           533:        /* Get port number for MOUNTD. */
        !           534:        error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
        !           535:                                                 &mdsin->sin_port);
        !           536:        if (error) return error;
        !           537:
        !           538:        m = xdr_string_encode(path, strlen(path));
        !           539:        if (m == NULL)
        !           540:                return ENOMEM;
        !           541:
        !           542:        /* Do RPC to mountd. */
        !           543:        error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
        !           544:                        RPCMNT_MOUNT, &m, NULL, -1);
        !           545:        if (error)
        !           546:                return error;   /* message already freed */
        !           547:
        !           548:        /* The reply might have only the errno. */
        !           549:        if (m->m_len < 4)
        !           550:                goto bad;
        !           551:        /* Have at least errno, so check that. */
        !           552:        rdata = mtod(m, struct rdata *);
        !           553:        error = fxdr_unsigned(u_int32_t, rdata->errno);
        !           554:        if (error)
        !           555:                goto out;
        !           556:
        !           557:         /* Have errno==0, so the fh must be there. */
        !           558:        if (m->m_len < sizeof(*rdata)) {
        !           559:                m = m_pullup(m, sizeof(*rdata));
        !           560:                if (m == NULL)
        !           561:                        goto bad;
        !           562:                rdata = mtod(m, struct rdata *);
        !           563:        }
        !           564:        bcopy(rdata->fh, fhp, NFSX_V2FH);
        !           565:        goto out;
        !           566:
        !           567: bad:
        !           568:        error = EBADRPC;
        !           569:
        !           570: out:
        !           571:        m_freem(m);
        !           572:        return error;
        !           573: }
        !           574:
        !           575: #endif /* ifdef NFSCLIENT */

CVSweb