LCOV - code coverage report
Current view: top level - nfs - nfs_boot.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 199 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: nfs_boot.c,v 1.45 2018/07/30 12:22:14 mpi 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/mount.h>
      37             : #include <sys/mbuf.h>
      38             : #include <sys/reboot.h>
      39             : #include <sys/socket.h>
      40             : #include <sys/socketvar.h>
      41             : #include <sys/queue.h>
      42             : 
      43             : #include <net/if.h>
      44             : #include <net/if_var.h>
      45             : 
      46             : #include <netinet/in.h>
      47             : #include <netinet/in_var.h>
      48             : #include <netinet/if_ether.h>
      49             : 
      50             : #include <nfs/rpcv2.h>
      51             : #include <nfs/nfsproto.h>
      52             : #include <nfs/nfs.h>
      53             : #include <nfs/nfsdiskless.h>
      54             : #include <nfs/krpc.h>
      55             : #include <nfs/xdr_subs.h>
      56             : #include <nfs/nfs_var.h>
      57             : 
      58             : #include "ether.h"
      59             : 
      60             : #if !defined(NFSCLIENT) || (NETHER == 0 && NFDDI == 0)
      61             : 
      62             : int
      63             : nfs_boot_init(struct nfs_diskless *nd, struct proc *procp)
      64             : {
      65             :         panic("nfs_boot_init: NFSCLIENT not enabled in kernel");
      66             : }
      67             : 
      68             : int
      69             : nfs_boot_getfh(struct sockaddr_in *bpsin, char *key,
      70             :     struct nfs_dlmount *ndmntp, int retries)
      71             : {
      72             :         /* can not get here */
      73             :         return (EOPNOTSUPP);
      74             : }
      75             : 
      76             : #else
      77             : 
      78             : /*
      79             :  * Support for NFS diskless booting, specifically getting information
      80             :  * about where to boot from, what pathnames, etc.
      81             :  *
      82             :  * This implementation uses RARP and the bootparam RPC.
      83             :  * We are forced to implement RPC anyway (to get file handles)
      84             :  * so we might as well take advantage of it for bootparam too.
      85             :  *
      86             :  * The diskless boot sequence goes as follows:
      87             :  * (1) Use RARP to get our interface address
      88             :  * (2) Use RPC/bootparam/whoami to get our hostname,
      89             :  *     our IP address, and the server's IP address.
      90             :  * (3) Use RPC/bootparam/getfile to get the root path
      91             :  * (4) Use RPC/mountd to get the root file handle
      92             :  * (5) Use RPC/bootparam/getfile to get the swap path
      93             :  * (6) Use RPC/mountd to get the swap file handle
      94             :  *
      95             :  * (This happens to be the way Sun does it too.)
      96             :  */
      97             : 
      98             : /* bootparam RPC */
      99             : static int bp_whoami(struct sockaddr_in *bpsin,
     100             :         struct in_addr *my_ip, struct in_addr *gw_ip);
     101             : static int bp_getfile(struct sockaddr_in *bpsin, char *key,
     102             :         struct sockaddr_in *mdsin, char *servname, char *path, int retries);
     103             : 
     104             : /* mountd RPC */
     105             : static int md_mount(struct sockaddr_in *mdsin, char *path,
     106             :         struct nfs_args *argp);
     107             : 
     108             : char    *nfsbootdevname;
     109             : 
     110             : /*
     111             :  * Called with an empty nfs_diskless struct to be filled in.
     112             :  */
     113             : int
     114           0 : nfs_boot_init(struct nfs_diskless *nd, struct proc *procp)
     115             : {
     116           0 :         struct ifreq ireq;
     117           0 :         struct in_aliasreq ifra;
     118           0 :         struct in_addr my_ip, gw_ip;
     119           0 :         struct sockaddr_in bp_sin;
     120             :         struct sockaddr_in *sin;
     121             :         struct ifnet *ifp;
     122           0 :         struct socket *so;
     123             :         struct ifaddr *ifa;
     124           0 :         char addr[INET_ADDRSTRLEN];
     125             :         int error;
     126             : 
     127             :         /*
     128             :          * Find an interface, rarp for its ip address, stuff it, the
     129             :          * implied broadcast addr, and netmask into a nfs_diskless struct.
     130             :          *
     131             :          * This was moved here from nfs_vfsops.c because this procedure
     132             :          * would be quite different if someone decides to write (i.e.) a
     133             :          * BOOTP version of this file (might not use RARP, etc.)
     134             :          */
     135             : 
     136             :         /*
     137             :          * Find a network interface.
     138             :          */
     139           0 :         if (nfsbootdevname)
     140           0 :                 ifp = ifunit(nfsbootdevname);
     141             :         else {
     142           0 :                 TAILQ_FOREACH(ifp, &ifnet, if_list) {
     143           0 :                         if ((ifp->if_flags &
     144           0 :                              (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
     145             :                                 break;
     146             :                 }
     147             :         }
     148           0 :         if (ifp == NULL)
     149           0 :                 panic("nfs_boot: no suitable interface");
     150           0 :         bcopy(ifp->if_xname, ireq.ifr_name, IFNAMSIZ);
     151           0 :         printf("nfs_boot: using interface %s, with revarp & bootparams\n",
     152             :             ireq.ifr_name);
     153             : 
     154             :         /*
     155             :          * Bring up the interface.
     156             :          *
     157             :          * Get the old interface flags and or IFF_UP into them; if
     158             :          * IFF_UP set blindly, interface selection can be clobbered.
     159             :          */
     160           0 :         if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
     161           0 :                 panic("nfs_boot: socreate, error=%d", error);
     162           0 :         error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
     163           0 :         if (error)
     164           0 :                 panic("nfs_boot: GIFFLAGS, error=%d", error);
     165           0 :         ireq.ifr_flags |= IFF_UP;
     166           0 :         error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
     167           0 :         if (error)
     168           0 :                 panic("nfs_boot: SIFFLAGS, error=%d", error);
     169             : 
     170             :         /*
     171             :          * Do RARP for the interface address.
     172             :          */
     173           0 :         if ((error = revarpwhoami(&my_ip, ifp)) != 0)
     174           0 :                 panic("reverse arp not answered by rarpd(8) or dhcpd(8)");
     175           0 :         inet_ntop(AF_INET, &my_ip, addr, sizeof(addr));
     176           0 :         printf("nfs_boot: client_addr=%s\n", addr);
     177             : 
     178             :         /*
     179             :          * Do enough of ifconfig(8) so that the chosen interface
     180             :          * can talk to the servers.  (just set the address)
     181             :          */
     182           0 :         memset(&ifra, 0, sizeof(ifra));
     183           0 :         bcopy(ifp->if_xname, ifra.ifra_name, sizeof(ifra.ifra_name));
     184             : 
     185           0 :         sin = &ifra.ifra_addr;
     186           0 :         sin->sin_len = sizeof(*sin);
     187           0 :         sin->sin_family = AF_INET;
     188           0 :         sin->sin_addr.s_addr = my_ip.s_addr;
     189           0 :         error = ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, procp);
     190           0 :         if (error)
     191           0 :                 panic("nfs_boot: set if addr, error=%d", error);
     192             : 
     193           0 :         soclose(so, 0);
     194             : 
     195           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
     196           0 :                 if (ifa->ifa_addr->sa_family == AF_INET)
     197             :                         break;
     198             :         }
     199           0 :         if (ifa == NULL)
     200           0 :                 panic("nfs_boot: address not configured on %s", ifp->if_xname);
     201             : 
     202             :         /*
     203             :          * Get client name and gateway address.
     204             :          * RPC: bootparam/whoami
     205             :          * The server address returned by the WHOAMI call
     206             :          * is used for all subsequent bootparam RPCs.
     207             :          */
     208           0 :         memset(&bp_sin, 0, sizeof(bp_sin));
     209           0 :         bp_sin.sin_len = sizeof(bp_sin);
     210           0 :         bp_sin.sin_family = AF_INET;
     211           0 :         bp_sin.sin_addr.s_addr = ifatoia(ifa)->ia_broadaddr.sin_addr.s_addr;
     212           0 :         hostnamelen = MAXHOSTNAMELEN;
     213             : 
     214             :         /* this returns gateway IP address */
     215           0 :         error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
     216           0 :         if (error)
     217           0 :                 panic("nfs_boot: bootparam whoami, error=%d", error);
     218           0 :         inet_ntop(AF_INET, &bp_sin.sin_addr, addr, sizeof(addr));
     219           0 :         printf("nfs_boot: server_addr=%s hostname=%s\n", addr, hostname);
     220             : 
     221           0 :         bcopy(&bp_sin, &nd->nd_boot, sizeof(bp_sin));
     222             : 
     223           0 :         return (0);
     224           0 : }
     225             : 
     226             : /*
     227             :  * bpsin:       bootparam server
     228             :  * key:         root or swap
     229             :  * ndmntp:      output
     230             :  */
     231             : int
     232           0 : nfs_boot_getfh(struct sockaddr_in *bpsin, char *key,
     233             :     struct nfs_dlmount *ndmntp, int retries)
     234             : {
     235             :         struct nfs_args *args;
     236           0 :         char pathname[MAXPATHLEN];
     237             :         char *sp, *dp, *endp;
     238             :         struct sockaddr_in *sin;
     239             :         int error;
     240             : 
     241           0 :         args = &ndmntp->ndm_args;
     242             : 
     243             :         /* Initialize mount args. */
     244           0 :         memset(args, 0, sizeof(*args));
     245           0 :         args->addr     = sintosa(&ndmntp->ndm_saddr);
     246           0 :         args->addrlen  = args->addr->sa_len;
     247           0 :         args->sotype   = SOCK_DGRAM;
     248           0 :         args->fh       = ndmntp->ndm_fh;
     249           0 :         args->hostname = ndmntp->ndm_host;
     250           0 :         args->flags    = NFSMNT_NFSV3;
     251             : #ifdef  NFS_BOOT_OPTIONS
     252             :         args->flags    |= NFS_BOOT_OPTIONS;
     253             : #endif
     254             : #ifdef  NFS_BOOT_RWSIZE
     255             :         /*
     256             :          * Reduce rsize,wsize for interfaces that consistently
     257             :          * drop fragments of long UDP messages.  (i.e. wd8003).
     258             :          * You can always change these later via remount.
     259             :          */
     260             :         args->flags   |= NFSMNT_WSIZE | NFSMNT_RSIZE;
     261             :         args->wsize    = NFS_BOOT_RWSIZE;
     262             :         args->rsize    = NFS_BOOT_RWSIZE;
     263             : #endif
     264             : 
     265             :         sin = &ndmntp->ndm_saddr;
     266             : 
     267             :         /*
     268             :          * Get server:pathname for "key" (root or swap)
     269             :          * using RPC to bootparam/getfile
     270             :          */
     271           0 :         error = bp_getfile(bpsin, key, sin, ndmntp->ndm_host, pathname,
     272             :             retries);
     273           0 :         if (error) {
     274           0 :                 printf("nfs_boot: bootparam get %s: %d\n", key, error);
     275           0 :                 return (error);
     276             :         }
     277             : 
     278             :         /*
     279             :          * Get file handle for "key" (root or swap)
     280             :          * using RPC to mountd/mount
     281             :          */
     282           0 :         error = md_mount(sin, pathname, args);
     283           0 :         if (error) {
     284           0 :                 printf("nfs_boot: mountd %s, error=%d\n", key, error);
     285           0 :                 return (error);
     286             :         }
     287             : 
     288             :         /* Set port number for NFS use. */
     289             :         /* XXX: NFS port is always 2049, right? */
     290           0 :         error = krpc_portmap(sin, NFS_PROG,
     291           0 :             (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
     292           0 :             &sin->sin_port);
     293           0 :         if (error) {
     294           0 :                 printf("nfs_boot: portmap NFS, error=%d\n", error);
     295           0 :                 return (error);
     296             :         }
     297             : 
     298             :         /* Construct remote path (for getmntinfo(3)) */
     299             :         dp = ndmntp->ndm_host;
     300           0 :         endp = dp + MNAMELEN - 1;
     301           0 :         dp += strlen(dp);
     302           0 :         *dp++ = ':';
     303           0 :         for (sp = pathname; *sp && dp < endp;)
     304           0 :                 *dp++ = *sp++;
     305           0 :         *dp = '\0';
     306             : 
     307           0 :         return (0);
     308           0 : }
     309             : 
     310             : 
     311             : /*
     312             :  * RPC: bootparam/whoami
     313             :  * Given client IP address, get:
     314             :  *      client name     (hostname)
     315             :  *      domain name (domainname)
     316             :  *      gateway address
     317             :  *
     318             :  * The hostname and domainname are set here for convenience.
     319             :  *
     320             :  * Note - bpsin is initialized to the broadcast address,
     321             :  * and will be replaced with the bootparam server address
     322             :  * after this call is complete.  Have to use PMAP_PROC_CALL
     323             :  * to make sure we get responses only from a servers that
     324             :  * know about us (don't want to broadcast a getport call).
     325             :  */
     326             : static int
     327           0 : bp_whoami(struct sockaddr_in *bpsin, struct in_addr *my_ip,
     328             :     struct in_addr *gw_ip)
     329             : {
     330             :         /* RPC structures for PMAPPROC_CALLIT */
     331             :         struct whoami_call {
     332             :                 u_int32_t call_prog;
     333             :                 u_int32_t call_vers;
     334             :                 u_int32_t call_proc;
     335             :                 u_int32_t call_arglen;
     336             :         } *call;
     337             :         struct callit_reply {
     338             :                 u_int32_t port;
     339             :                 u_int32_t encap_len;
     340             :                 /* encapsulated data here */
     341             :         } *reply;
     342             : 
     343           0 :         struct mbuf *m, *from;
     344             :         struct sockaddr_in *sin;
     345             :         int error, msg_len;
     346             :         int16_t port;
     347             : 
     348             :         /*
     349             :          * Build request message for PMAPPROC_CALLIT.
     350             :          */
     351           0 :         m = m_get(M_WAIT, MT_DATA);
     352           0 :         call = mtod(m, struct whoami_call *);
     353           0 :         m->m_len = sizeof(*call);
     354           0 :         call->call_prog = txdr_unsigned(BOOTPARAM_PROG);
     355           0 :         call->call_vers = txdr_unsigned(BOOTPARAM_VERS);
     356           0 :         call->call_proc = txdr_unsigned(BOOTPARAM_WHOAMI);
     357             : 
     358             :         /*
     359             :          * append encapsulated data (client IP address)
     360             :          */
     361           0 :         m->m_next = xdr_inaddr_encode(my_ip);
     362           0 :         call->call_arglen = txdr_unsigned(m->m_next->m_len);
     363             : 
     364             :         /* RPC: portmap/callit */
     365           0 :         bpsin->sin_port = htons(PMAPPORT);
     366           0 :         from = NULL;
     367           0 :         error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
     368             :                         PMAPPROC_CALLIT, &m, &from, -1);
     369           0 :         if (error)
     370           0 :                 return error;
     371             : 
     372             :         /*
     373             :          * Parse result message.
     374             :          */
     375           0 :         if (m->m_len < sizeof(*reply)) {
     376           0 :                 m = m_pullup(m, sizeof(*reply));
     377           0 :                 if (m == NULL)
     378             :                         goto bad;
     379             :         }
     380           0 :         reply = mtod(m, struct callit_reply *);
     381           0 :         port = fxdr_unsigned(u_int32_t, reply->port);
     382           0 :         msg_len = fxdr_unsigned(u_int32_t, reply->encap_len);
     383           0 :         m_adj(m, sizeof(*reply));
     384             : 
     385             :         /*
     386             :          * Save bootparam server address
     387             :          */
     388           0 :         sin = mtod(from, struct sockaddr_in *);
     389           0 :         bpsin->sin_port = htons(port);
     390           0 :         bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
     391             : 
     392             :         /* client name */
     393           0 :         hostnamelen = MAXHOSTNAMELEN-1;
     394           0 :         m = xdr_string_decode(m, hostname, &hostnamelen);
     395           0 :         if (m == NULL)
     396             :                 goto bad;
     397             : 
     398             :         /* domain name */
     399           0 :         domainnamelen = MAXHOSTNAMELEN-1;
     400           0 :         m = xdr_string_decode(m, domainname, &domainnamelen);
     401           0 :         if (m == NULL)
     402             :                 goto bad;
     403             : 
     404             :         /* gateway address */
     405           0 :         m = xdr_inaddr_decode(m, gw_ip);
     406           0 :         if (m == NULL)
     407             :                 goto bad;
     408             : 
     409             :         /* success */
     410             :         goto out;
     411             : 
     412             : bad:
     413           0 :         printf("nfs_boot: bootparam_whoami: bad reply\n");
     414           0 :         error = EBADRPC;
     415             : 
     416             : out:
     417           0 :         m_freem(from);
     418           0 :         m_freem(m);
     419           0 :         return(error);
     420           0 : }
     421             : 
     422             : 
     423             : /*
     424             :  * RPC: bootparam/getfile
     425             :  * Given client name and file "key", get:
     426             :  *      server name
     427             :  *      server IP address
     428             :  *      server pathname
     429             :  */
     430             : static int
     431           0 : bp_getfile(struct sockaddr_in *bpsin, char *key, struct sockaddr_in *md_sin,
     432             :     char *serv_name, char *pathname, int retries)
     433             : {
     434           0 :         struct mbuf *m;
     435             :         struct sockaddr_in *sin;
     436           0 :         struct in_addr inaddr;
     437           0 :         int error, sn_len, path_len;
     438             : 
     439             :         /*
     440             :          * Build request message.
     441             :          */
     442             : 
     443             :         /* client name (hostname) */
     444           0 :         m  = xdr_string_encode(hostname, hostnamelen);
     445           0 :         if (m == NULL)
     446           0 :                 return (ENOMEM);
     447             : 
     448             :         /* key name (root or swap) */
     449           0 :         m->m_next = xdr_string_encode(key, strlen(key));
     450           0 :         if (m->m_next == NULL) {
     451           0 :                 m_freem(m);
     452           0 :                 return (ENOMEM);
     453             :         }
     454             : 
     455             :         /* RPC: bootparam/getfile */
     456           0 :         error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
     457             :                         BOOTPARAM_GETFILE, &m, NULL, retries);
     458           0 :         if (error)
     459           0 :                 return error;
     460             : 
     461             :         /*
     462             :          * Parse result message.
     463             :          */
     464             : 
     465             :         /* server name */
     466           0 :         sn_len = MNAMELEN-1;
     467           0 :         m = xdr_string_decode(m, serv_name, &sn_len);
     468           0 :         if (m == NULL)
     469             :                 goto bad;
     470             : 
     471             :         /* server IP address (mountd/NFS) */
     472           0 :         m = xdr_inaddr_decode(m, &inaddr);
     473           0 :         if (m == NULL)
     474             :                 goto bad;
     475             : 
     476             :         /* server pathname */
     477           0 :         path_len = MAXPATHLEN-1;
     478           0 :         m = xdr_string_decode(m, pathname, &path_len);
     479           0 :         if (m == NULL)
     480             :                 goto bad;
     481             : 
     482             :         /* setup server socket address */
     483             :         sin = md_sin;
     484           0 :         memset(sin, 0, sizeof(*sin));
     485           0 :         sin->sin_len = sizeof(*sin);
     486           0 :         sin->sin_family = AF_INET;
     487           0 :         sin->sin_addr = inaddr;
     488             : 
     489             :         /* success */
     490           0 :         goto out;
     491             : 
     492             : bad:
     493           0 :         printf("nfs_boot: bootparam_getfile: bad reply\n");
     494           0 :         error = EBADRPC;
     495             : 
     496             : out:
     497           0 :         m_freem(m);
     498           0 :         return(error);
     499           0 : }
     500             : 
     501             : 
     502             : /*
     503             :  * RPC: mountd/mount
     504             :  * Given a server pathname, get an NFS file handle.
     505             :  * Also, sets sin->sin_port to the NFS service port.
     506             :  * mdsin:       mountd server address
     507             :  */
     508             : static int
     509           0 : md_mount(struct sockaddr_in *mdsin, char *path, struct nfs_args *argp)
     510             : {
     511             :         /* The RPC structures */
     512             :         struct rdata {
     513             :                 u_int32_t errno;
     514             :                 union {
     515             :                         u_int8_t v2fh[NFSX_V2FH];
     516             :                         struct {
     517             :                                 u_int32_t fhlen;
     518             :                                 u_int8_t fh[1];
     519             :                         } v3fh;
     520             :                 } fh;
     521             :         } *rdata;
     522           0 :         struct mbuf *m;
     523             :         u_int8_t *fh;
     524             :         int minlen, error;
     525             :         int mntver;
     526             : 
     527           0 :         mntver = (argp->flags & NFSMNT_NFSV3) ? 3 : 2;
     528           0 :         do {
     529           0 :                 error = krpc_portmap(mdsin, RPCPROG_MNT, mntver,
     530           0 :                     &mdsin->sin_port);
     531           0 :                 if (error)
     532             :                         continue;
     533             : 
     534           0 :                 m = xdr_string_encode(path, strlen(path));
     535           0 :                 if (m == NULL)
     536           0 :                         return ENOMEM;
     537             : 
     538             :                 /* Do RPC to mountd. */
     539           0 :                 error = krpc_call(mdsin, RPCPROG_MNT, mntver,
     540             :                     RPCMNT_MOUNT, &m, NULL, -1);
     541             : 
     542           0 :                 if (error != EPROGMISMATCH)
     543             :                         break;
     544             :                 /* Try lower version of mountd. */
     545           0 :         } while (--mntver >= 1);
     546           0 :         if (error)
     547           0 :                 return error;   /* message already freed */
     548             : 
     549           0 :         if (mntver != 3)
     550           0 :                 argp->flags &= ~NFSMNT_NFSV3;
     551             : 
     552             :         /* The reply might have only the errno. */
     553           0 :         if (m->m_len < 4)
     554             :                 goto bad;
     555             :         /* Have at least errno, so check that. */
     556           0 :         rdata = mtod(m, struct rdata *);
     557           0 :         error = fxdr_unsigned(u_int32_t, rdata->errno);
     558           0 :         if (error)
     559             :                 goto out;
     560             : 
     561             :          /* Have errno==0, so the fh must be there. */
     562           0 :         if (mntver == 3) {
     563           0 :                 argp->fhsize = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen);
     564           0 :                 if (argp->fhsize > NFSX_V3FHMAX)
     565             :                         goto bad;
     566           0 :                 minlen = 2 * sizeof(u_int32_t) + argp->fhsize;
     567           0 :         } else {
     568           0 :                 argp->fhsize = NFSX_V2FH;
     569             :                 minlen = sizeof(u_int32_t) + argp->fhsize;
     570             :         }
     571             : 
     572           0 :         if (m->m_len < minlen) {
     573           0 :                 m = m_pullup(m, minlen);
     574           0 :                 if (m == NULL)
     575           0 :                         return (EBADRPC);
     576           0 :                 rdata = mtod(m, struct rdata *);
     577           0 :         }
     578             : 
     579           0 :         fh = (mntver == 3) ? rdata->fh.v3fh.fh : rdata->fh.v2fh;
     580           0 :         bcopy(fh, argp->fh, argp->fhsize);
     581             : 
     582           0 :         goto out;
     583             : 
     584             : bad:
     585           0 :         error = EBADRPC;
     586             : 
     587             : out:
     588           0 :         m_freem(m);
     589           0 :         return error;
     590           0 : }
     591             : 
     592             : #endif /* ifdef NFSCLIENT */

Generated by: LCOV version 1.13