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

Cache object: aa53bb2f914b2a3b9aafe3a6cd2c0c48


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