The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_boot.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_boot.c,v 1.77 2008/10/27 13:24:01 cegger Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Adam Glass and Gordon W. Ross.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Support for NFS diskless booting, specifically getting information
   34  * about where to mount root from, what pathnames, etc.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.77 2008/10/27 13:24:01 cegger Exp $");
   39 
   40 #include "opt_nfs.h"
   41 #include "opt_tftproot.h"
   42 #include "opt_nfs_boot.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/device.h>
   48 #include <sys/ioctl.h>
   49 #include <sys/proc.h>
   50 #include <sys/mount.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/reboot.h>
   53 #include <sys/socket.h>
   54 #include <sys/socketvar.h>
   55 
   56 #include <net/if.h>
   57 #include <net/route.h>
   58 #include <net/if_ether.h>
   59 #include <net/if_types.h>
   60 
   61 #include <netinet/in.h>
   62 #include <netinet/if_inarp.h>
   63 
   64 #include <nfs/rpcv2.h>
   65 #include <nfs/krpc.h>
   66 #include <nfs/xdr_subs.h>
   67 
   68 #include <nfs/nfsproto.h>
   69 #include <nfs/nfs.h>
   70 #include <nfs/nfsmount.h>
   71 #include <nfs/nfsdiskless.h>
   72 
   73 /*
   74  * There are two implementations of NFS diskless boot.
   75  * One implementation uses BOOTP (RFC951, RFC1048),
   76  * the other uses Sun RPC/bootparams.  See the files:
   77  *    nfs_bootp.c:   BOOTP (RFC951, RFC1048)
   78  *    nfs_bootsun.c: Sun RPC/bootparams
   79  */
   80 #if defined(NFS_BOOT_BOOTP) || defined(NFS_BOOT_DHCP)
   81 int nfs_boot_rfc951 = 1; /* BOOTP enabled (default) */
   82 #endif
   83 #ifdef NFS_BOOT_BOOTPARAM
   84 int nfs_boot_bootparam = 1; /* BOOTPARAM enabled (default) */
   85 #endif
   86 #ifdef NFS_BOOT_BOOTSTATIC
   87 int nfs_boot_bootstatic = 1; /* BOOTSTATIC enabled (default) */
   88 #endif
   89 
   90 /* mountd RPC */
   91 static int md_mount(struct sockaddr_in *mdsin, char *path,
   92         struct nfs_args *argp, struct lwp *l);
   93 
   94 static int nfs_boot_delroute(struct rtentry *, void *);
   95 static void nfs_boot_defrt(struct in_addr *);
   96 static  int nfs_boot_getfh(struct nfs_dlmount *ndm, struct lwp *);
   97 
   98 
   99 /*
  100  * Called with an empty nfs_diskless struct to be filled in.
  101  * Find an interface, determine its ip address (etc.) and
  102  * save all the boot parameters in the nfs_diskless struct.
  103  */
  104 int
  105 nfs_boot_init(struct nfs_diskless *nd, struct lwp *lwp)
  106 {
  107         struct ifnet *ifp;
  108         int error = 0;
  109         int flags;
  110 
  111         /* Explicitly necessary or build fails
  112          * due to unused variable, otherwise.
  113          */
  114         flags = 0;
  115 
  116         /*
  117          * Find the network interface.
  118          */
  119         ifp = ifunit(device_xname(root_device));
  120         if (ifp == NULL) {
  121                 printf("nfs_boot: '%s' not found\n",
  122                        device_xname(root_device));
  123                 return (ENXIO);
  124         }
  125         nd->nd_ifp = ifp;
  126 
  127         error = EADDRNOTAVAIL; /* ??? */
  128 #if defined(NFS_BOOT_BOOTSTATIC)
  129         if (error && nfs_boot_bootstatic) {
  130                 printf("nfs_boot: trying static\n");
  131                 error = nfs_bootstatic(nd, lwp, &flags);
  132         }
  133 #endif
  134 #if defined(NFS_BOOT_BOOTP) || defined(NFS_BOOT_DHCP)
  135         if (error && nfs_boot_rfc951) {
  136 #if defined(NFS_BOOT_DHCP)
  137                 printf("nfs_boot: trying DHCP/BOOTP\n");
  138 #else
  139                 printf("nfs_boot: trying BOOTP\n");
  140 #endif
  141                 error = nfs_bootdhcp(nd, lwp, &flags);
  142         }
  143 #endif
  144 #ifdef NFS_BOOT_BOOTPARAM
  145         if (error && nfs_boot_bootparam) {
  146                 printf("nfs_boot: trying RARP (and RPC/bootparam)\n");
  147                 error = nfs_bootparam(nd, lwp, &flags);
  148         }
  149 #endif
  150         if (error)
  151                 return (error);
  152 
  153         /*
  154          * If the gateway address is set, add a default route.
  155          * (The mountd RPCs may go across a gateway.)
  156          */
  157         if (nd->nd_gwip.s_addr)
  158                 nfs_boot_defrt(&nd->nd_gwip);
  159 
  160 #ifdef TFTPROOT
  161         if (nd->nd_nomount)
  162                 goto out;
  163 #endif
  164         /*
  165          * Now fetch the NFS file handles as appropriate.
  166          */
  167         error = nfs_boot_getfh(&nd->nd_root, lwp);
  168 
  169         if (error)
  170                 nfs_boot_cleanup(nd, lwp);
  171 
  172 #ifdef TFTPROOT
  173 out:
  174 #endif
  175         return (error);
  176 }
  177 
  178 void
  179 nfs_boot_cleanup(struct nfs_diskless *nd, struct lwp *lwp)
  180 {
  181 
  182         nfs_boot_deladdress(nd->nd_ifp, lwp, nd->nd_myip.s_addr);
  183         nfs_boot_ifupdown(nd->nd_ifp, lwp, 0);
  184         nfs_boot_flushrt(nd->nd_ifp);
  185 }
  186 
  187 int
  188 nfs_boot_ifupdown(struct ifnet *ifp, struct lwp *lwp, int up)
  189 {
  190         struct socket *so;
  191         struct ifreq ireq;
  192         int error;
  193 
  194         memset(&ireq, 0, sizeof(ireq));
  195         memcpy(ireq.ifr_name, ifp->if_xname, IFNAMSIZ);
  196 
  197         /*
  198          * Get a socket to use for various things in here.
  199          * After this, use "goto out" to cleanup and return.
  200          */
  201         error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL);
  202         if (error) {
  203                 printf("ifupdown: socreate, error=%d\n", error);
  204                 return (error);
  205         }
  206 
  207         /*
  208          * Bring up the interface. (just set the "up" flag)
  209          * Get the old interface flags and or IFF_UP into them so
  210          * things like media selection flags are not clobbered.
  211          */
  212         error = ifioctl(so, SIOCGIFFLAGS, (void *)&ireq, lwp);
  213         if (error) {
  214                 printf("ifupdown: GIFFLAGS, error=%d\n", error);
  215                 goto out;
  216         }
  217         if (up)
  218                 ireq.ifr_flags |= IFF_UP;
  219         else
  220                 ireq.ifr_flags &= ~IFF_UP;
  221         error = ifioctl(so, SIOCSIFFLAGS, &ireq, lwp);
  222         if (error) {
  223                 printf("ifupdown: SIFFLAGS, error=%d\n", error);
  224                 goto out;
  225         }
  226 
  227         if (up)
  228                 /* give the link some time to get up */
  229                 tsleep(nfs_boot_ifupdown, PZERO, "nfsbif", 3 * hz);
  230 out:
  231         soclose(so);
  232         return (error);
  233 }
  234 
  235 int
  236 nfs_boot_setaddress(struct ifnet *ifp, struct lwp *lwp,
  237                 uint32_t addr, uint32_t netmask, uint32_t braddr)
  238 {
  239         struct socket *so;
  240         struct ifaliasreq iareq;
  241         struct sockaddr_in *sin;
  242         int error;
  243 
  244         /*
  245          * Get a socket to use for various things in here.
  246          * After this, use "goto out" to cleanup and return.
  247          */
  248         error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL);
  249         if (error) {
  250                 printf("setaddress: socreate, error=%d\n", error);
  251                 return (error);
  252         }
  253 
  254         memset(&iareq, 0, sizeof(iareq));
  255         memcpy(iareq.ifra_name, ifp->if_xname, IFNAMSIZ);
  256 
  257         /* Set the I/F address */
  258         sin = (struct sockaddr_in *)&iareq.ifra_addr;
  259         sin->sin_len = sizeof(*sin);
  260         sin->sin_family = AF_INET;
  261         sin->sin_addr.s_addr = addr;
  262 
  263         /* Set the netmask */
  264         if (netmask != INADDR_ANY) {
  265                 sin = (struct sockaddr_in *)&iareq.ifra_mask;
  266                 sin->sin_len = sizeof(*sin);
  267                 sin->sin_family = AF_INET;
  268                 sin->sin_addr.s_addr = netmask;
  269         } /* else leave subnetmask unspecified (len=0) */
  270 
  271         /* Set the broadcast addr. */
  272         if (braddr != INADDR_ANY) {
  273                 sin = (struct sockaddr_in *)&iareq.ifra_broadaddr;
  274                 sin->sin_len = sizeof(*sin);
  275                 sin->sin_family = AF_INET;
  276                 sin->sin_addr.s_addr = braddr;
  277         } /* else leave broadcast addr unspecified (len=0) */
  278 
  279         error = ifioctl(so, SIOCAIFADDR, (void *)&iareq, lwp);
  280         if (error) {
  281                 printf("setaddress, error=%d\n", error);
  282                 goto out;
  283         }
  284 
  285         /* give the link some time to get up */
  286         tsleep(nfs_boot_setaddress, PZERO, "nfsbtd", 3 * hz);
  287 out:
  288         soclose(so);
  289         return (error);
  290 }
  291 
  292 int
  293 nfs_boot_deladdress(struct ifnet *ifp, struct lwp *lwp, uint32_t addr)
  294 {
  295         struct socket *so;
  296         struct ifreq ifr;
  297         struct sockaddr_in sin;
  298         struct in_addr ia = {.s_addr = addr};
  299         int error;
  300 
  301         /*
  302          * Get a socket to use for various things in here.
  303          * After this, use "goto out" to cleanup and return.
  304          */
  305         error = socreate(AF_INET, &so, SOCK_DGRAM, 0, lwp, NULL);
  306         if (error) {
  307                 printf("deladdress: socreate, error=%d\n", error);
  308                 return (error);
  309         }
  310 
  311         memset(&ifr, 0, sizeof(ifr));
  312         memcpy(ifr.ifr_name, ifp->if_xname, IFNAMSIZ);
  313 
  314         sockaddr_in_init(&sin, &ia, 0);
  315         ifreq_setaddr(SIOCDIFADDR, &ifr, sintocsa(&sin)); 
  316 
  317         error = ifioctl(so, SIOCDIFADDR, &ifr, lwp);
  318         if (error) {
  319                 printf("deladdress, error=%d\n", error);
  320                 goto out;
  321         }
  322 
  323 out:
  324         soclose(so);
  325         return (error);
  326 }
  327 
  328 int
  329 nfs_boot_setrecvtimo(struct socket *so)
  330 {
  331         struct timeval tv;
  332 
  333         tv.tv_sec = 1;
  334         tv.tv_usec = 0;
  335 
  336         return (so_setsockopt(NULL, so, SOL_SOCKET, SO_RCVTIMEO, &tv,
  337             sizeof(tv)));
  338 }
  339 
  340 int
  341 nfs_boot_enbroadcast(struct socket *so)
  342 {
  343         int32_t on;
  344 
  345         on = 1;
  346         return (so_setsockopt(NULL, so, SOL_SOCKET, SO_BROADCAST, &on,
  347             sizeof(on)));
  348 }
  349 
  350 int
  351 nfs_boot_sobind_ipport(struct socket *so, uint16_t port, struct lwp *l)
  352 {
  353         struct mbuf *m;
  354         struct sockaddr_in *sin;
  355         int error;
  356 
  357         m = m_getclr(M_WAIT, MT_SONAME);
  358         sin = mtod(m, struct sockaddr_in *);
  359         sin->sin_len = m->m_len = sizeof(*sin);
  360         sin->sin_family = AF_INET;
  361         sin->sin_addr.s_addr = INADDR_ANY;
  362         sin->sin_port = htons(port);
  363         error = sobind(so, m, l);
  364         m_freem(m);
  365         return (error);
  366 }
  367 
  368 /*
  369  * What is the longest we will wait before re-sending a request?
  370  * Note this is also the frequency of "timeout" messages.
  371  * The re-send loop counts up linearly to this maximum, so the
  372  * first complaint will happen after (1+2+3+4+5)=15 seconds.
  373  */
  374 #define MAX_RESEND_DELAY 5      /* seconds */
  375 #define TOTAL_TIMEOUT   30      /* seconds */
  376 
  377 int
  378 nfs_boot_sendrecv(struct socket *so, struct mbuf *nam,
  379                 int (*sndproc)(struct mbuf *, void *, int),
  380                 struct mbuf *snd,
  381                 int (*rcvproc)(struct mbuf *, void *),
  382                 struct mbuf **rcv, struct mbuf **from_p,
  383                 void *context, struct lwp *lwp)
  384 {
  385         int error, rcvflg, timo, secs, waited;
  386         struct mbuf *m, *from;
  387         struct uio uio;
  388 
  389         /* Free at end if not null. */
  390         from = NULL;
  391 
  392         /*
  393          * Send it, repeatedly, until a reply is received,
  394          * but delay each re-send by an increasing amount.
  395          * If the delay hits the maximum, start complaining.
  396          */
  397         waited = timo = 0;
  398 send_again:
  399         waited += timo;
  400         if (waited >= TOTAL_TIMEOUT)
  401                 return (ETIMEDOUT);
  402 
  403         /* Determine new timeout. */
  404         if (timo < MAX_RESEND_DELAY)
  405                 timo++;
  406         else
  407                 printf("nfs_boot: timeout...\n");
  408 
  409         if (sndproc) {
  410                 error = (*sndproc)(snd, context, waited);
  411                 if (error)
  412                         goto out;
  413         }
  414 
  415         /* Send request (or re-send). */
  416         m = m_copypacket(snd, M_WAIT);
  417         if (m == NULL) {
  418                 error = ENOBUFS;
  419                 goto out;
  420         }
  421         error = (*so->so_send)(so, nam, NULL, m, NULL, 0, lwp);
  422         if (error) {
  423                 printf("nfs_boot: sosend: %d\n", error);
  424                 goto out;
  425         }
  426         m = NULL;
  427 
  428         /*
  429          * Wait for up to timo seconds for a reply.
  430          * The socket receive timeout was set to 1 second.
  431          */
  432 
  433         secs = timo;
  434         for (;;) {
  435                 if (from) {
  436                         m_freem(from);
  437                         from = NULL;
  438                 }
  439                 if (m) {
  440                         m_freem(m);
  441                         m = NULL;
  442                 }
  443                 uio.uio_resid = 1 << 16; /* ??? */
  444                 rcvflg = 0;
  445                 error = (*so->so_receive)(so, &from, &uio, &m, NULL, &rcvflg);
  446                 if (error == EWOULDBLOCK) {
  447                         if (--secs <= 0)
  448                                 goto send_again;
  449                         continue;
  450                 }
  451                 if (error)
  452                         goto out;
  453 #ifdef DIAGNOSTIC
  454                 if (!m || !(m->m_flags & M_PKTHDR)
  455                     || (1 << 16) - uio.uio_resid != m->m_pkthdr.len)
  456                         panic("nfs_boot_sendrecv: return size");
  457 #endif
  458 
  459                 if ((*rcvproc)(m, context))
  460                         continue;
  461 
  462                 if (rcv)
  463                         *rcv = m;
  464                 else
  465                         m_freem(m);
  466                 if (from_p) {
  467                         *from_p = from;
  468                         from = NULL;
  469                 }
  470                 break;
  471         }
  472 out:
  473         if (from) m_freem(from);
  474         return (error);
  475 }
  476 
  477 /*
  478  * Install a default route to the passed IP address.
  479  */
  480 static void
  481 nfs_boot_defrt(struct in_addr *gw_ip)
  482 {
  483         struct sockaddr dst, gw, mask;
  484         struct sockaddr_in *sin;
  485         int error;
  486 
  487         /* Destination: (default) */
  488         memset((void *)&dst, 0, sizeof(dst));
  489         dst.sa_len = sizeof(dst);
  490         dst.sa_family = AF_INET;
  491         /* Gateway: */
  492         memset((void *)&gw, 0, sizeof(gw));
  493         sin = (struct sockaddr_in *)&gw;
  494         sin->sin_len = sizeof(*sin);
  495         sin->sin_family = AF_INET;
  496         sin->sin_addr.s_addr = gw_ip->s_addr;
  497         /* Mask: (zero length) */
  498         /* XXX - Just pass a null pointer? */
  499         memset(&mask, 0, sizeof(mask));
  500 
  501         /* add, dest, gw, mask, flags, 0 */
  502         error = rtrequest(RTM_ADD, &dst, &gw, &mask,
  503                           (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
  504         if (error) {
  505                 printf("nfs_boot: add route, error=%d\n", error);
  506                 error = 0;
  507         }
  508 }
  509 
  510 static int
  511 nfs_boot_delroute(struct rtentry *rt, void *w)
  512 {
  513         int error;
  514 
  515         if ((void *)rt->rt_ifp != w)
  516                 return 0;
  517 
  518         error = rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0,
  519             NULL);
  520         if (error != 0)
  521                 printf("%s: del route, error=%d\n", __func__, error);
  522 
  523         return 0;
  524 }
  525 
  526 void
  527 nfs_boot_flushrt(struct ifnet *ifp)
  528 {
  529 
  530         rt_walktree(AF_INET, nfs_boot_delroute, ifp);
  531 }
  532 
  533 /*
  534  * Get an initial NFS file handle using Sun RPC/mountd.
  535  * Separate function because we used to call it twice.
  536  * (once for root and once for swap)
  537  *
  538  * ndm  output
  539  */
  540 static int
  541 nfs_boot_getfh(struct nfs_dlmount *ndm, struct lwp *l)
  542 {
  543         struct nfs_args *args;
  544         struct sockaddr_in *sin;
  545         char *pathname;
  546         int error;
  547         u_int16_t port;
  548 
  549         args = &ndm->ndm_args;
  550 
  551         /* Initialize mount args. */
  552         memset((void *) args, 0, sizeof(*args));
  553         args->addr     = &ndm->ndm_saddr;
  554         args->addrlen  = args->addr->sa_len;
  555 #ifdef NFS_BOOT_TCP
  556         args->sotype   = SOCK_STREAM;
  557 #else
  558         args->sotype   = SOCK_DGRAM;
  559 #endif
  560         args->fh       = ndm->ndm_fh;
  561         args->hostname = ndm->ndm_host;
  562         args->flags    = NFSMNT_NOCONN | NFSMNT_RESVPORT;
  563 
  564 #ifndef NFS_V2_ONLY
  565         args->flags    |= NFSMNT_NFSV3;
  566 #endif
  567 #ifdef  NFS_BOOT_OPTIONS
  568         args->flags    |= NFS_BOOT_OPTIONS;
  569 #endif
  570 #ifdef  NFS_BOOT_RWSIZE
  571         /*
  572          * Reduce rsize,wsize for interfaces that consistently
  573          * drop fragments of long UDP messages.  (i.e. wd8003).
  574          * You can always change these later via remount.
  575          */
  576         args->flags   |= NFSMNT_WSIZE | NFSMNT_RSIZE;
  577         args->wsize    = NFS_BOOT_RWSIZE;
  578         args->rsize    = NFS_BOOT_RWSIZE;
  579 #endif
  580 
  581         /*
  582          * Find the pathname part of the "server:pathname"
  583          * string left in ndm->ndm_host by nfs_boot_init.
  584          */
  585         pathname = strchr(ndm->ndm_host, ':');
  586         if (pathname == 0) {
  587                 printf("nfs_boot: getfh - no pathname\n");
  588                 return (EIO);
  589         }
  590         pathname++;
  591 
  592         /*
  593          * Get file handle using RPC to mountd/mount
  594          */
  595         sin = (struct sockaddr_in *)&ndm->ndm_saddr;
  596         error = md_mount(sin, pathname, args, l);
  597         if (error) {
  598                 printf("nfs_boot: mountd `%s', error=%d\n",
  599                        ndm->ndm_host, error);
  600                 return (error);
  601         }
  602 
  603         /* Set port number for NFS use. */
  604         /* XXX: NFS port is always 2049, right? */
  605 #ifdef NFS_BOOT_TCP
  606 retry:
  607 #endif
  608         error = krpc_portmap(sin, NFS_PROG,
  609                     (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
  610                     (args->sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP,
  611                     &port, l);
  612         if (port == htons(0))
  613                 error = EIO;
  614         if (error) {
  615 #ifdef NFS_BOOT_TCP
  616                 if (args->sotype == SOCK_STREAM) {
  617                         args->sotype = SOCK_DGRAM;
  618                         goto retry;
  619                 }
  620 #endif
  621                 printf("nfs_boot: portmap NFS, error=%d\n", error);
  622                 return (error);
  623         }
  624         sin->sin_port = port;
  625         return (0);
  626 }
  627 
  628 
  629 /*
  630  * RPC: mountd/mount
  631  * Given a server pathname, get an NFS file handle.
  632  * Also, sets sin->sin_port to the NFS service port.
  633  *
  634  * mdsin   mountd server address
  635  */
  636 static int
  637 md_mount(struct sockaddr_in *mdsin, char *path,
  638          struct nfs_args *argp, struct lwp *lwp)
  639 {
  640         /* The RPC structures */
  641         struct rdata {
  642                 u_int32_t errno;
  643                 union {
  644                         u_int8_t  v2fh[NFSX_V2FH];
  645                         struct {
  646                                 u_int32_t fhlen;
  647                                 u_int8_t  fh[1];
  648                         } v3fh;
  649                 } fh;
  650         } *rdata;
  651         struct mbuf *m;
  652         u_int8_t *fh;
  653         int minlen, error;
  654         int mntver;
  655 
  656         mntver = (argp->flags & NFSMNT_NFSV3) ? 3 : 2;
  657         do {
  658                 /*
  659                  * Get port number for MOUNTD.
  660                  */
  661                 error = krpc_portmap(mdsin, RPCPROG_MNT, mntver,
  662                                     IPPROTO_UDP, &mdsin->sin_port, lwp);
  663                 if (error)
  664                         continue;
  665 
  666                 /* This mbuf is consumed by krpc_call. */
  667                 m = xdr_string_encode(path, strlen(path));
  668                 if (m == NULL)
  669                         return ENOMEM;
  670 
  671                 /* Do RPC to mountd. */
  672                 error = krpc_call(mdsin, RPCPROG_MNT, mntver,
  673                                   RPCMNT_MOUNT, &m, NULL, lwp);
  674                 if (error != EPROGMISMATCH)
  675                         break;
  676                 /* Try lower version of mountd. */
  677         } while (--mntver >= 1);
  678         if (error) {
  679                 printf("nfs_boot: mountd error=%d\n", error);
  680                 return error;
  681         }
  682         if (mntver != 3)
  683                 argp->flags &= ~NFSMNT_NFSV3;
  684 
  685         /* The reply might have only the errno. */
  686         if (m->m_len < 4)
  687                 goto bad;
  688         /* Have at least errno, so check that. */
  689         rdata = mtod(m, struct rdata *);
  690         error = fxdr_unsigned(u_int32_t, rdata->errno);
  691         if (error)
  692                 goto out;
  693 
  694         /* Have errno==0, so the fh must be there. */
  695         if (mntver == 3) {
  696                 argp->fhsize   = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen);
  697                 if (argp->fhsize > NFSX_V3FHMAX)
  698                         goto bad;
  699                 minlen = 2 * sizeof(u_int32_t) + argp->fhsize;
  700         } else {
  701                 argp->fhsize   = NFSX_V2FH;
  702                 minlen = sizeof(u_int32_t) + argp->fhsize;
  703         }
  704 
  705         if (m->m_len < minlen) {
  706                 m = m_pullup(m, minlen);
  707                 if (m == NULL)
  708                         return(EBADRPC);
  709                 rdata = mtod(m, struct rdata *);
  710         }
  711 
  712         fh = (mntver == 3) ?
  713                 rdata->fh.v3fh.fh : rdata->fh.v2fh;
  714         memcpy(argp->fh, fh, argp->fhsize);
  715 
  716         goto out;
  717 
  718 bad:
  719         error = EBADRPC;
  720 
  721 out:
  722         m_freem(m);
  723         return error;
  724 }

Cache object: b67bbc3f28a19aa3f7f3a8b0586fc778


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.