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

Cache object: a3f591a0b6d755673fae0a2c53bd54c0


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