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.61 2004/05/22 22:52:15 jonathan 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.61 2004/05/22 22:52:15 jonathan 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, struct proc *procp));
   99 
  100 static void nfs_boot_defrt __P((struct in_addr *));
  101 static  int nfs_boot_getfh __P((struct nfs_dlmount *ndm, struct proc *));
  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, procp);
  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, procp);
  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, procp);
  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, procp);
  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, procp)
  364         struct socket *so;
  365         u_int16_t port;
  366         struct proc *procp;
  367 {
  368         struct mbuf *m;
  369         struct sockaddr_in *sin;
  370         int error;
  371 
  372         m = m_getclr(M_WAIT, MT_SONAME);
  373         sin = mtod(m, struct sockaddr_in *);
  374         sin->sin_len = m->m_len = sizeof(*sin);
  375         sin->sin_family = AF_INET;
  376         sin->sin_addr.s_addr = INADDR_ANY;
  377         sin->sin_port = htons(port);
  378         error = sobind(so, m, procp);
  379         m_freem(m);
  380         return (error);
  381 }
  382 
  383 /*
  384  * What is the longest we will wait before re-sending a request?
  385  * Note this is also the frequency of "timeout" messages.
  386  * The re-send loop counts up linearly to this maximum, so the
  387  * first complaint will happen after (1+2+3+4+5)=15 seconds.
  388  */
  389 #define MAX_RESEND_DELAY 5      /* seconds */
  390 #define TOTAL_TIMEOUT   30      /* seconds */
  391 
  392 int
  393 nfs_boot_sendrecv(so, nam, sndproc, snd, rcvproc, rcv, from_p, context, procp)
  394         struct socket *so;
  395         struct mbuf *nam;
  396         int (*sndproc) __P((struct mbuf*, void*, int));
  397         struct mbuf *snd;
  398         int (*rcvproc) __P((struct mbuf*, void*));
  399         struct mbuf **rcv, **from_p;
  400         void *context;
  401         struct proc *procp;
  402 {
  403         int error, rcvflg, timo, secs, waited;
  404         struct mbuf *m, *from;
  405         struct uio uio;
  406 
  407         /* Free at end if not null. */
  408         from = NULL;
  409 
  410         /*
  411          * Send it, repeatedly, until a reply is received,
  412          * but delay each re-send by an increasing amount.
  413          * If the delay hits the maximum, start complaining.
  414          */
  415         waited = timo = 0;
  416 send_again:
  417         waited += timo;
  418         if (waited >= TOTAL_TIMEOUT)
  419                 return (ETIMEDOUT);
  420 
  421         /* Determine new timeout. */
  422         if (timo < MAX_RESEND_DELAY)
  423                 timo++;
  424         else
  425                 printf("nfs_boot: timeout...\n");
  426 
  427         if (sndproc) {
  428                 error = (*sndproc)(snd, context, waited);
  429                 if (error)
  430                         goto out;
  431         }
  432 
  433         /* Send request (or re-send). */
  434         m = m_copypacket(snd, M_WAIT);
  435         if (m == NULL) {
  436                 error = ENOBUFS;
  437                 goto out;
  438         }
  439         error = (*so->so_send)(so, nam, NULL, m, NULL, 0, procp);
  440         if (error) {
  441                 printf("nfs_boot: sosend: %d\n", error);
  442                 goto out;
  443         }
  444         m = NULL;
  445 
  446         /*
  447          * Wait for up to timo seconds for a reply.
  448          * The socket receive timeout was set to 1 second.
  449          */
  450 
  451         secs = timo;
  452         for (;;) {
  453                 if (from) {
  454                         m_freem(from);
  455                         from = NULL;
  456                 }
  457                 if (m) {
  458                         m_freem(m);
  459                         m = NULL;
  460                 }
  461                 uio.uio_resid = 1 << 16; /* ??? */
  462                 uio.uio_procp = procp;
  463                 rcvflg = 0;
  464                 error = (*so->so_receive)(so, &from, &uio, &m, NULL, &rcvflg);
  465                 if (error == EWOULDBLOCK) {
  466                         if (--secs <= 0)
  467                                 goto send_again;
  468                         continue;
  469                 }
  470                 if (error)
  471                         goto out;
  472 #ifdef DIAGNOSTIC
  473                 if (!m || !(m->m_flags & M_PKTHDR)
  474                     || (1 << 16) - uio.uio_resid != m->m_pkthdr.len)
  475                         panic("nfs_boot_sendrecv: return size");
  476 #endif
  477 
  478                 if ((*rcvproc)(m, context))
  479                         continue;
  480 
  481                 if (rcv)
  482                         *rcv = m;
  483                 else
  484                         m_freem(m);
  485                 if (from_p) {
  486                         *from_p = from;
  487                         from = NULL;
  488                 }
  489                 break;
  490         }
  491 out:
  492         if (from) m_freem(from);
  493         return (error);
  494 }
  495 
  496 /*
  497  * Install a default route to the passed IP address.
  498  */
  499 static void
  500 nfs_boot_defrt(gw_ip)
  501         struct in_addr *gw_ip;
  502 {
  503         struct sockaddr dst, gw, mask;
  504         struct sockaddr_in *sin;
  505         int error;
  506 
  507         /* Destination: (default) */
  508         memset((caddr_t)&dst, 0, sizeof(dst));
  509         dst.sa_len = sizeof(dst);
  510         dst.sa_family = AF_INET;
  511         /* Gateway: */
  512         memset((caddr_t)&gw, 0, sizeof(gw));
  513         sin = (struct sockaddr_in *)&gw;
  514         sin->sin_len = sizeof(*sin);
  515         sin->sin_family = AF_INET;
  516         sin->sin_addr.s_addr = gw_ip->s_addr;
  517         /* Mask: (zero length) */
  518         /* XXX - Just pass a null pointer? */
  519         memset(&mask, 0, sizeof(mask));
  520 
  521         /* add, dest, gw, mask, flags, 0 */
  522         error = rtrequest(RTM_ADD, &dst, &gw, &mask,
  523                           (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
  524         if (error) {
  525                 printf("nfs_boot: add route, error=%d\n", error);
  526                 error = 0;
  527         }
  528 }
  529 
  530 static int nfs_boot_delroute __P((struct radix_node *, void *));
  531 static int
  532 nfs_boot_delroute(rn, w)
  533         struct radix_node *rn;
  534         void *w;
  535 {
  536         struct rtentry *rt = (struct rtentry *)rn;
  537         int error;
  538 
  539         if (rt->rt_ifp != (struct ifnet *)w)
  540                 return (0);
  541 
  542         error = rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL);
  543         if (error)
  544                 printf("nfs_boot: del route, error=%d\n", error);
  545 
  546         return (0);
  547 }
  548 
  549 void
  550 nfs_boot_flushrt(ifp)
  551         struct ifnet *ifp;
  552 {
  553 
  554         rn_walktree(rt_tables[AF_INET], nfs_boot_delroute, ifp);
  555 }
  556 
  557 /*
  558  * Get an initial NFS file handle using Sun RPC/mountd.
  559  * Separate function because we used to call it twice.
  560  * (once for root and once for swap)
  561  */
  562 static int
  563 nfs_boot_getfh(ndm, p)
  564         struct nfs_dlmount *ndm;        /* output */
  565         struct proc *p;
  566 {
  567         struct nfs_args *args;
  568         struct sockaddr_in *sin;
  569         char *pathname;
  570         int error;
  571         u_int16_t port;
  572 
  573         args = &ndm->ndm_args;
  574 
  575         /* Initialize mount args. */
  576         memset((caddr_t) args, 0, sizeof(*args));
  577         args->addr     = &ndm->ndm_saddr;
  578         args->addrlen  = args->addr->sa_len;
  579 #ifdef NFS_BOOT_TCP
  580         args->sotype   = SOCK_STREAM;
  581 #else
  582         args->sotype   = SOCK_DGRAM;
  583 #endif
  584         args->fh       = ndm->ndm_fh;
  585         args->hostname = ndm->ndm_host;
  586         args->flags    = NFSMNT_NOCONN | NFSMNT_RESVPORT;
  587 
  588 #ifndef NFS_V2_ONLY
  589         args->flags    |= NFSMNT_NFSV3;
  590 #endif
  591 #ifdef  NFS_BOOT_OPTIONS
  592         args->flags    |= NFS_BOOT_OPTIONS;
  593 #endif
  594 #ifdef  NFS_BOOT_RWSIZE
  595         /*
  596          * Reduce rsize,wsize for interfaces that consistently
  597          * drop fragments of long UDP messages.  (i.e. wd8003).
  598          * You can always change these later via remount.
  599          */
  600         args->flags   |= NFSMNT_WSIZE | NFSMNT_RSIZE;
  601         args->wsize    = NFS_BOOT_RWSIZE;
  602         args->rsize    = NFS_BOOT_RWSIZE;
  603 #endif
  604 
  605         /*
  606          * Find the pathname part of the "server:pathname"
  607          * string left in ndm->ndm_host by nfs_boot_init.
  608          */
  609         pathname = strchr(ndm->ndm_host, ':');
  610         if (pathname == 0) {
  611                 printf("nfs_boot: getfh - no pathname\n");
  612                 return (EIO);
  613         }
  614         pathname++;
  615 
  616         /*
  617          * Get file handle using RPC to mountd/mount
  618          */
  619         sin = (struct sockaddr_in *)&ndm->ndm_saddr;
  620         error = md_mount(sin, pathname, args, p);
  621         if (error) {
  622                 printf("nfs_boot: mountd `%s', error=%d\n",
  623                        ndm->ndm_host, error);
  624                 return (error);
  625         }
  626 
  627         /* Set port number for NFS use. */
  628         /* XXX: NFS port is always 2049, right? */
  629 #ifdef NFS_BOOT_TCP
  630 retry:
  631 #endif
  632         error = krpc_portmap(sin, NFS_PROG,
  633                     (args->flags & NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
  634                     (args->sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP,
  635                     &port, p);
  636         if (port == htons(0))
  637                 error = EIO;
  638         if (error) {
  639 #ifdef NFS_BOOT_TCP
  640                 if (args->sotype == SOCK_STREAM) {
  641                         args->sotype = SOCK_DGRAM;
  642                         goto retry;
  643                 }
  644 #endif
  645                 printf("nfs_boot: portmap NFS, error=%d\n", error);
  646                 return (error);
  647         }
  648         sin->sin_port = port;
  649         return (0);
  650 }
  651 
  652 
  653 /*
  654  * RPC: mountd/mount
  655  * Given a server pathname, get an NFS file handle.
  656  * Also, sets sin->sin_port to the NFS service port.
  657  */
  658 static int
  659 md_mount(mdsin, path, argp, procp)
  660         struct sockaddr_in *mdsin;              /* mountd server address */
  661         char *path;
  662         struct nfs_args *argp;
  663         struct proc *procp;
  664 {
  665         /* The RPC structures */
  666         struct rdata {
  667                 u_int32_t errno;
  668                 union {
  669                         u_int8_t  v2fh[NFSX_V2FH];
  670                         struct {
  671                                 u_int32_t fhlen;
  672                                 u_int8_t  fh[1];
  673                         } v3fh;
  674                 } fh;
  675         } *rdata;
  676         struct mbuf *m;
  677         u_int8_t *fh;
  678         int minlen, error;
  679         int mntver;
  680 
  681         mntver = (argp->flags & NFSMNT_NFSV3) ? 3 : 2;
  682         do {
  683                 /*
  684                  * Get port number for MOUNTD.
  685                  */
  686                 error = krpc_portmap(mdsin, RPCPROG_MNT, mntver,
  687                                     IPPROTO_UDP, &mdsin->sin_port, procp);
  688                 if (error)
  689                         continue;
  690 
  691                 /* This mbuf is consumed by krpc_call. */
  692                 m = xdr_string_encode(path, strlen(path));
  693                 if (m == NULL)
  694                         return ENOMEM;
  695 
  696                 /* Do RPC to mountd. */
  697                 error = krpc_call(mdsin, RPCPROG_MNT, mntver,
  698                                   RPCMNT_MOUNT, &m, NULL, procp);
  699                 if (error != EPROGMISMATCH)
  700                         break;
  701                 /* Try lower version of mountd. */
  702         } while (--mntver >= 1);
  703         if (error) {
  704                 printf("nfs_boot: mountd error=%d\n", error);
  705                 return error;
  706         }
  707         if (mntver != 3)
  708                 argp->flags &= ~NFSMNT_NFSV3;
  709 
  710         /* The reply might have only the errno. */
  711         if (m->m_len < 4)
  712                 goto bad;
  713         /* Have at least errno, so check that. */
  714         rdata = mtod(m, struct rdata *);
  715         error = fxdr_unsigned(u_int32_t, rdata->errno);
  716         if (error)
  717                 goto out;
  718 
  719         /* Have errno==0, so the fh must be there. */
  720         if (mntver == 3) {
  721                 argp->fhsize   = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen);
  722                 if (argp->fhsize > NFSX_V3FHMAX)
  723                         goto bad;
  724                 minlen = 2 * sizeof(u_int32_t) + argp->fhsize;
  725         } else {
  726                 argp->fhsize   = NFSX_V2FH;
  727                 minlen = sizeof(u_int32_t) + argp->fhsize;
  728         }
  729 
  730         if (m->m_len < minlen) {
  731                 m = m_pullup(m, minlen);
  732                 if (m == NULL)
  733                         return(EBADRPC);
  734                 rdata = mtod(m, struct rdata *);
  735         }
  736 
  737         fh = (mntver == 3) ?
  738                 rdata->fh.v3fh.fh : rdata->fh.v2fh;
  739         memcpy(argp->fh, fh, argp->fhsize);
  740 
  741         goto out;
  742 
  743 bad:
  744         error = EBADRPC;
  745 
  746 out:
  747         m_freem(m);
  748         return error;
  749 }

Cache object: 8dd98c78c41912486fede7e46aae5789


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