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

Cache object: 241bc5a11c9daa0f8b516ec9754b5f8e


[ 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.