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_socket.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_socket.c,v 1.189 2011/03/23 17:42:11 tls Exp $     */
    2 
    3 /*
    4  * Copyright (c) 1989, 1991, 1993, 1995
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    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. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)nfs_socket.c        8.5 (Berkeley) 3/30/95
   35  */
   36 
   37 /*
   38  * Socket operations for use by nfs
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.189 2011/03/23 17:42:11 tls Exp $");
   43 
   44 #ifdef _KERNEL_OPT
   45 #include "opt_nfs.h"
   46 #include "opt_mbuftrace.h"
   47 #endif
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/evcnt.h>
   52 #include <sys/callout.h>
   53 #include <sys/proc.h>
   54 #include <sys/mount.h>
   55 #include <sys/kernel.h>
   56 #include <sys/kmem.h>
   57 #include <sys/mbuf.h>
   58 #include <sys/vnode.h>
   59 #include <sys/domain.h>
   60 #include <sys/protosw.h>
   61 #include <sys/socket.h>
   62 #include <sys/socketvar.h>
   63 #include <sys/syslog.h>
   64 #include <sys/tprintf.h>
   65 #include <sys/namei.h>
   66 #include <sys/signal.h>
   67 #include <sys/signalvar.h>
   68 #include <sys/kauth.h>
   69 
   70 #include <netinet/in.h>
   71 #include <netinet/tcp.h>
   72 
   73 #include <nfs/rpcv2.h>
   74 #include <nfs/nfsproto.h>
   75 #include <nfs/nfs.h>
   76 #include <nfs/xdr_subs.h>
   77 #include <nfs/nfsm_subs.h>
   78 #include <nfs/nfsmount.h>
   79 #include <nfs/nfsnode.h>
   80 #include <nfs/nfsrtt.h>
   81 #include <nfs/nfs_var.h>
   82 
   83 #ifdef MBUFTRACE
   84 struct mowner nfs_mowner = MOWNER_INIT("nfs","");
   85 #endif
   86 
   87 /*
   88  * Estimate rto for an nfs rpc sent via. an unreliable datagram.
   89  * Use the mean and mean deviation of rtt for the appropriate type of rpc
   90  * for the frequent rpcs and a default for the others.
   91  * The justification for doing "other" this way is that these rpcs
   92  * happen so infrequently that timer est. would probably be stale.
   93  * Also, since many of these rpcs are
   94  * non-idempotent, a conservative timeout is desired.
   95  * getattr, lookup - A+2D
   96  * read, write     - A+4D
   97  * other           - nm_timeo
   98  */
   99 #define NFS_RTO(n, t) \
  100         ((t) == 0 ? (n)->nm_timeo : \
  101          ((t) < 3 ? \
  102           (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \
  103           ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1)))
  104 #define NFS_SRTT(r)     (r)->r_nmp->nm_srtt[nfs_proct[(r)->r_procnum] - 1]
  105 #define NFS_SDRTT(r)    (r)->r_nmp->nm_sdrtt[nfs_proct[(r)->r_procnum] - 1]
  106 
  107 /*
  108  * Defines which timer to use for the procnum.
  109  * 0 - default
  110  * 1 - getattr
  111  * 2 - lookup
  112  * 3 - read
  113  * 4 - write
  114  */
  115 const int nfs_proct[NFS_NPROCS] = {
  116         [NFSPROC_NULL] = 0,
  117         [NFSPROC_GETATTR] = 1,
  118         [NFSPROC_SETATTR] = 0,
  119         [NFSPROC_LOOKUP] = 2,
  120         [NFSPROC_ACCESS] = 1,
  121         [NFSPROC_READLINK] = 3,
  122         [NFSPROC_READ] = 3,
  123         [NFSPROC_WRITE] = 4,
  124         [NFSPROC_CREATE] = 0,
  125         [NFSPROC_MKDIR] = 0,
  126         [NFSPROC_SYMLINK] = 0,
  127         [NFSPROC_MKNOD] = 0,
  128         [NFSPROC_REMOVE] = 0,
  129         [NFSPROC_RMDIR] = 0,
  130         [NFSPROC_RENAME] = 0,
  131         [NFSPROC_LINK] = 0,
  132         [NFSPROC_READDIR] = 3,
  133         [NFSPROC_READDIRPLUS] = 3,
  134         [NFSPROC_FSSTAT] = 0,
  135         [NFSPROC_FSINFO] = 0,
  136         [NFSPROC_PATHCONF] = 0,
  137         [NFSPROC_COMMIT] = 0,
  138         [NFSPROC_NOOP] = 0,
  139 };
  140 
  141 #ifdef DEBUG
  142 /*
  143  * Avoid spamming the console with debugging messages.  We only print
  144  * the nfs timer and reply error debugs every 10 seconds.
  145  */
  146 const struct timeval nfs_err_interval = { 10, 0 };
  147 struct timeval nfs_reply_last_err_time;
  148 struct timeval nfs_timer_last_err_time;
  149 #endif
  150 
  151 /*
  152  * There is a congestion window for outstanding rpcs maintained per mount
  153  * point. The cwnd size is adjusted in roughly the way that:
  154  * Van Jacobson, Congestion avoidance and Control, In "Proceedings of
  155  * SIGCOMM '88". ACM, August 1988.
  156  * describes for TCP. The cwnd size is chopped in half on a retransmit timeout
  157  * and incremented by 1/cwnd when each rpc reply is received and a full cwnd
  158  * of rpcs is in progress.
  159  * (The sent count and cwnd are scaled for integer arith.)
  160  * Variants of "slow start" were tried and were found to be too much of a
  161  * performance hit (ave. rtt 3 times larger),
  162  * I suspect due to the large rtt that nfs rpcs have.
  163  */
  164 int nfsrtton = 0;  
  165 struct nfsrtt nfsrtt;
  166 static const int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };
  167 struct nfsreqhead nfs_reqq;
  168 static callout_t nfs_timer_ch;
  169 static struct evcnt nfs_timer_ev;
  170 static struct evcnt nfs_timer_start_ev;
  171 static struct evcnt nfs_timer_stop_ev;
  172 static kmutex_t nfs_timer_lock;
  173 static bool (*nfs_timer_srvvec)(void);
  174 
  175 /*
  176  * Initialize sockets and congestion for a new NFS connection.
  177  * We do not free the sockaddr if error.
  178  */
  179 int
  180 nfs_connect(struct nfsmount *nmp, struct nfsreq *rep, struct lwp *l)
  181 {
  182         struct socket *so;
  183         int error, rcvreserve, sndreserve;
  184         struct sockaddr *saddr;
  185         struct sockaddr_in *sin;
  186         struct sockaddr_in6 *sin6;
  187         struct mbuf *m;
  188         int val;
  189 
  190         nmp->nm_so = NULL;
  191         saddr = mtod(nmp->nm_nam, struct sockaddr *);
  192         error = socreate(saddr->sa_family, &nmp->nm_so,
  193                 nmp->nm_sotype, nmp->nm_soproto, l, NULL);
  194         if (error)
  195                 goto bad;
  196         so = nmp->nm_so;
  197 #ifdef MBUFTRACE
  198         so->so_mowner = &nfs_mowner;
  199         so->so_rcv.sb_mowner = &nfs_mowner;
  200         so->so_snd.sb_mowner = &nfs_mowner;
  201 #endif
  202         nmp->nm_soflags = so->so_proto->pr_flags;
  203 
  204         /*
  205          * Some servers require that the client port be a reserved port number.
  206          */
  207         if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
  208                 val = IP_PORTRANGE_LOW;
  209 
  210                 if ((error = so_setsockopt(NULL, so, IPPROTO_IP, IP_PORTRANGE,
  211                     &val, sizeof(val))))
  212                         goto bad;
  213                 m = m_get(M_WAIT, MT_SONAME);
  214                 MCLAIM(m, so->so_mowner);
  215                 sin = mtod(m, struct sockaddr_in *);
  216                 sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
  217                 sin->sin_family = AF_INET;
  218                 sin->sin_addr.s_addr = INADDR_ANY;
  219                 sin->sin_port = 0;
  220                 error = sobind(so, m, &lwp0);
  221                 m_freem(m);
  222                 if (error)
  223                         goto bad;
  224         }
  225         if (saddr->sa_family == AF_INET6 && (nmp->nm_flag & NFSMNT_RESVPORT)) {
  226                 val = IPV6_PORTRANGE_LOW;
  227 
  228                 if ((error = so_setsockopt(NULL, so, IPPROTO_IPV6,
  229                     IPV6_PORTRANGE, &val, sizeof(val))))
  230                         goto bad;
  231                 m = m_get(M_WAIT, MT_SONAME);
  232                 MCLAIM(m, so->so_mowner);
  233                 sin6 = mtod(m, struct sockaddr_in6 *);
  234                 memset(sin6, 0, sizeof(*sin6));
  235                 sin6->sin6_len = m->m_len = sizeof (struct sockaddr_in6);
  236                 sin6->sin6_family = AF_INET6;
  237                 error = sobind(so, m, &lwp0);
  238                 m_freem(m);
  239                 if (error)
  240                         goto bad;
  241         }
  242 
  243         /*
  244          * Protocols that do not require connections may be optionally left
  245          * unconnected for servers that reply from a port other than NFS_PORT.
  246          */
  247         solock(so);
  248         if (nmp->nm_flag & NFSMNT_NOCONN) {
  249                 if (nmp->nm_soflags & PR_CONNREQUIRED) {
  250                         sounlock(so);
  251                         error = ENOTCONN;
  252                         goto bad;
  253                 }
  254         } else {
  255                 error = soconnect(so, nmp->nm_nam, l);
  256                 if (error) {
  257                         sounlock(so);
  258                         goto bad;
  259                 }
  260 
  261                 /*
  262                  * Wait for the connection to complete. Cribbed from the
  263                  * connect system call but with the wait timing out so
  264                  * that interruptible mounts don't hang here for a long time.
  265                  */
  266                 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
  267                         (void)sowait(so, false, 2 * hz);
  268                         if ((so->so_state & SS_ISCONNECTING) &&
  269                             so->so_error == 0 && rep &&
  270                             (error = nfs_sigintr(nmp, rep, rep->r_lwp)) != 0){
  271                                 so->so_state &= ~SS_ISCONNECTING;
  272                                 sounlock(so);
  273                                 goto bad;
  274                         }
  275                 }
  276                 if (so->so_error) {
  277                         error = so->so_error;
  278                         so->so_error = 0;
  279                         sounlock(so);
  280                         goto bad;
  281                 }
  282         }
  283         if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
  284                 so->so_rcv.sb_timeo = (5 * hz);
  285                 so->so_snd.sb_timeo = (5 * hz);
  286         } else {
  287                 /*
  288                  * enable receive timeout to detect server crash and reconnect.
  289                  * otherwise, we can be stuck in soreceive forever.
  290                  */
  291                 so->so_rcv.sb_timeo = (5 * hz);
  292                 so->so_snd.sb_timeo = 0;
  293         }
  294         if (nmp->nm_sotype == SOCK_DGRAM) {
  295                 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 3;
  296                 rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
  297                     NFS_MAXPKTHDR) * 2;
  298         } else if (nmp->nm_sotype == SOCK_SEQPACKET) {
  299                 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 3;
  300                 rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
  301                     NFS_MAXPKTHDR) * 3;
  302         } else {
  303                 sounlock(so);
  304                 if (nmp->nm_sotype != SOCK_STREAM)
  305                         panic("nfscon sotype");
  306                 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
  307                         val = 1;
  308                         so_setsockopt(NULL, so, SOL_SOCKET, SO_KEEPALIVE, &val,
  309                             sizeof(val));
  310                 }
  311                 if (so->so_proto->pr_protocol == IPPROTO_TCP) {
  312                         val = 1;
  313                         so_setsockopt(NULL, so, IPPROTO_TCP, TCP_NODELAY, &val,
  314                             sizeof(val));
  315                 }
  316                 sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
  317                     sizeof (u_int32_t)) * 3;
  318                 rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
  319                     sizeof (u_int32_t)) * 3;
  320                 solock(so);
  321         }
  322         error = soreserve(so, sndreserve, rcvreserve);
  323         if (error) {
  324                 sounlock(so);
  325                 goto bad;
  326         }
  327         so->so_rcv.sb_flags |= SB_NOINTR;
  328         so->so_snd.sb_flags |= SB_NOINTR;
  329         sounlock(so);
  330 
  331         /* Initialize other non-zero congestion variables */
  332         nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] =
  333                 NFS_TIMEO << 3;
  334         nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] =
  335                 nmp->nm_sdrtt[3] = 0;
  336         nmp->nm_cwnd = NFS_MAXCWND / 2;     /* Initial send window */
  337         nmp->nm_sent = 0;
  338         nmp->nm_timeouts = 0;
  339         return (0);
  340 
  341 bad:
  342         nfs_disconnect(nmp);
  343         return (error);
  344 }
  345 
  346 /*
  347  * Reconnect routine:
  348  * Called when a connection is broken on a reliable protocol.
  349  * - clean up the old socket
  350  * - nfs_connect() again
  351  * - set R_MUSTRESEND for all outstanding requests on mount point
  352  * If this fails the mount point is DEAD!
  353  * nb: Must be called with the nfs_sndlock() set on the mount point.
  354  */
  355 int
  356 nfs_reconnect(struct nfsreq *rep)
  357 {
  358         struct nfsreq *rp;
  359         struct nfsmount *nmp = rep->r_nmp;
  360         int error;
  361 
  362         nfs_disconnect(nmp);
  363         while ((error = nfs_connect(nmp, rep, &lwp0)) != 0) {
  364                 if (error == EINTR || error == ERESTART)
  365                         return (EINTR);
  366                 kpause("nfscn2", false, hz, NULL);
  367         }
  368 
  369         /*
  370          * Loop through outstanding request list and fix up all requests
  371          * on old socket.
  372          */
  373         TAILQ_FOREACH(rp, &nfs_reqq, r_chain) {
  374                 if (rp->r_nmp == nmp) {
  375                         if ((rp->r_flags & R_MUSTRESEND) == 0)
  376                                 rp->r_flags |= R_MUSTRESEND | R_REXMITTED;
  377                         rp->r_rexmit = 0;
  378                 }
  379         }
  380         return (0);
  381 }
  382 
  383 /*
  384  * NFS disconnect. Clean up and unlink.
  385  */
  386 void
  387 nfs_disconnect(struct nfsmount *nmp)
  388 {
  389         struct socket *so;
  390         int drain = 0;
  391 
  392         if (nmp->nm_so) {
  393                 so = nmp->nm_so;
  394                 nmp->nm_so = NULL;
  395                 solock(so);
  396                 soshutdown(so, SHUT_RDWR);
  397                 sounlock(so);
  398                 drain = (nmp->nm_iflag & NFSMNT_DISMNT) != 0;
  399                 if (drain) {
  400                         /*
  401                          * soshutdown() above should wake up the current
  402                          * listener.
  403                          * Now wake up those waiting for the receive lock, and
  404                          * wait for them to go away unhappy, to prevent *nmp
  405                          * from evaporating while they're sleeping.
  406                          */
  407                         mutex_enter(&nmp->nm_lock);
  408                         while (nmp->nm_waiters > 0) {
  409                                 cv_broadcast(&nmp->nm_rcvcv);
  410                                 cv_broadcast(&nmp->nm_sndcv);
  411                                 cv_wait(&nmp->nm_disconcv, &nmp->nm_lock);
  412                         }
  413                         mutex_exit(&nmp->nm_lock);
  414                 }
  415                 soclose(so);
  416         }
  417 #ifdef DIAGNOSTIC
  418         if (drain && (nmp->nm_waiters > 0))
  419                 panic("nfs_disconnect: waiters left after drain?");
  420 #endif
  421 }
  422 
  423 void
  424 nfs_safedisconnect(struct nfsmount *nmp)
  425 {
  426         struct nfsreq dummyreq;
  427 
  428         memset(&dummyreq, 0, sizeof(dummyreq));
  429         dummyreq.r_nmp = nmp;
  430         nfs_rcvlock(nmp, &dummyreq); /* XXX ignored error return */
  431         nfs_disconnect(nmp);
  432         nfs_rcvunlock(nmp);
  433 }
  434 
  435 /*
  436  * This is the nfs send routine. For connection based socket types, it
  437  * must be called with an nfs_sndlock() on the socket.
  438  * "rep == NULL" indicates that it has been called from a server.
  439  * For the client side:
  440  * - return EINTR if the RPC is terminated, 0 otherwise
  441  * - set R_MUSTRESEND if the send fails for any reason
  442  * - do any cleanup required by recoverable socket errors (? ? ?)
  443  * For the server side:
  444  * - return EINTR or ERESTART if interrupted by a signal
  445  * - return EPIPE if a connection is lost for connection based sockets (TCP...)
  446  * - do any cleanup required by recoverable socket errors (? ? ?)
  447  */
  448 int
  449 nfs_send(struct socket *so, struct mbuf *nam, struct mbuf *top, struct nfsreq *rep, struct lwp *l)
  450 {
  451         struct mbuf *sendnam;
  452         int error, soflags, flags;
  453 
  454         /* XXX nfs_doio()/nfs_request() calls with  rep->r_lwp == NULL */
  455         if (l == NULL && rep->r_lwp == NULL)
  456                 l = curlwp;
  457 
  458         if (rep) {
  459                 if (rep->r_flags & R_SOFTTERM) {
  460                         m_freem(top);
  461                         return (EINTR);
  462                 }
  463                 if ((so = rep->r_nmp->nm_so) == NULL) {
  464                         rep->r_flags |= R_MUSTRESEND;
  465                         m_freem(top);
  466                         return (0);
  467                 }
  468                 rep->r_flags &= ~R_MUSTRESEND;
  469                 soflags = rep->r_nmp->nm_soflags;
  470         } else
  471                 soflags = so->so_proto->pr_flags;
  472         if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
  473                 sendnam = NULL;
  474         else
  475                 sendnam = nam;
  476         if (so->so_type == SOCK_SEQPACKET)
  477                 flags = MSG_EOR;
  478         else
  479                 flags = 0;
  480 
  481         error = (*so->so_send)(so, sendnam, NULL, top, NULL, flags,  l);
  482         if (error) {
  483                 if (rep) {
  484                         if (error == ENOBUFS && so->so_type == SOCK_DGRAM) {
  485                                 /*
  486                                  * We're too fast for the network/driver,
  487                                  * and UDP isn't flowcontrolled.
  488                                  * We need to resend. This is not fatal,
  489                                  * just try again.
  490                                  *
  491                                  * Could be smarter here by doing some sort
  492                                  * of a backoff, but this is rare.
  493                                  */
  494                                 rep->r_flags |= R_MUSTRESEND;
  495                         } else {
  496                                 if (error != EPIPE)
  497                                         log(LOG_INFO,
  498                                             "nfs send error %d for %s\n",
  499                                             error,
  500                                             rep->r_nmp->nm_mountp->
  501                                                     mnt_stat.f_mntfromname);
  502                                 /*
  503                                  * Deal with errors for the client side.
  504                                  */
  505                                 if (rep->r_flags & R_SOFTTERM)
  506                                         error = EINTR;
  507                                 else if (error != EMSGSIZE)
  508                                         rep->r_flags |= R_MUSTRESEND;
  509                         }
  510                 } else {
  511                         /*
  512                          * See above. This error can happen under normal
  513                          * circumstances and the log is too noisy.
  514                          * The error will still show up in nfsstat.
  515                          */
  516                         if (error != ENOBUFS || so->so_type != SOCK_DGRAM)
  517                                 log(LOG_INFO, "nfsd send error %d\n", error);
  518                 }
  519 
  520                 /*
  521                  * Handle any recoverable (soft) socket errors here. (? ? ?)
  522                  */
  523                 if (error != EINTR && error != ERESTART &&
  524                     error != EWOULDBLOCK && error != EPIPE &&
  525                     error != EMSGSIZE)
  526                         error = 0;
  527         }
  528         return (error);
  529 }
  530 
  531 /*
  532  * Generate the rpc reply header
  533  * siz arg. is used to decide if adding a cluster is worthwhile
  534  */
  535 int
  536 nfs_rephead(int siz, struct nfsrv_descript *nd, struct nfssvc_sock *slp, int err, int cache, u_quad_t *frev, struct mbuf **mrq, struct mbuf **mbp, char **bposp)
  537 {
  538         u_int32_t *tl;
  539         struct mbuf *mreq;
  540         char *bpos;
  541         struct mbuf *mb;
  542 
  543         mreq = m_gethdr(M_WAIT, MT_DATA);
  544         MCLAIM(mreq, &nfs_mowner);
  545         mb = mreq;
  546         /*
  547          * If this is a big reply, use a cluster else
  548          * try and leave leading space for the lower level headers.
  549          */
  550         siz += RPC_REPLYSIZ;
  551         if (siz >= max_datalen) {
  552                 m_clget(mreq, M_WAIT);
  553         } else
  554                 mreq->m_data += max_hdr;
  555         tl = mtod(mreq, u_int32_t *);
  556         mreq->m_len = 6 * NFSX_UNSIGNED;
  557         bpos = ((char *)tl) + mreq->m_len;
  558         *tl++ = txdr_unsigned(nd->nd_retxid);
  559         *tl++ = rpc_reply;
  560         if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
  561                 *tl++ = rpc_msgdenied;
  562                 if (err & NFSERR_AUTHERR) {
  563                         *tl++ = rpc_autherr;
  564                         *tl = txdr_unsigned(err & ~NFSERR_AUTHERR);
  565                         mreq->m_len -= NFSX_UNSIGNED;
  566                         bpos -= NFSX_UNSIGNED;
  567                 } else {
  568                         *tl++ = rpc_mismatch;
  569                         *tl++ = txdr_unsigned(RPC_VER2);
  570                         *tl = txdr_unsigned(RPC_VER2);
  571                 }
  572         } else {
  573                 *tl++ = rpc_msgaccepted;
  574 
  575                 /*
  576                  * For Kerberos authentication, we must send the nickname
  577                  * verifier back, otherwise just RPCAUTH_NULL.
  578                  */
  579                 if (nd->nd_flag & ND_KERBFULL) {
  580                         struct nfsuid *nuidp;
  581                         struct timeval ktvin, ktvout;
  582 
  583                         memset(&ktvout, 0, sizeof ktvout);      /* XXX gcc */
  584 
  585                         LIST_FOREACH(nuidp,
  586                             NUIDHASH(slp, kauth_cred_geteuid(nd->nd_cr)),
  587                             nu_hash) {
  588                                 if (kauth_cred_geteuid(nuidp->nu_cr) ==
  589                                 kauth_cred_geteuid(nd->nd_cr) &&
  590                                     (!nd->nd_nam2 || netaddr_match(
  591                                     NU_NETFAM(nuidp), &nuidp->nu_haddr,
  592                                     nd->nd_nam2)))
  593                                         break;
  594                         }
  595                         if (nuidp) {
  596                                 ktvin.tv_sec =
  597                                     txdr_unsigned(nuidp->nu_timestamp.tv_sec
  598                                         - 1);
  599                                 ktvin.tv_usec =
  600                                     txdr_unsigned(nuidp->nu_timestamp.tv_usec);
  601 
  602                                 /*
  603                                  * Encrypt the timestamp in ecb mode using the
  604                                  * session key.
  605                                  */
  606 #ifdef NFSKERB
  607                                 XXX
  608 #endif
  609 
  610                                 *tl++ = rpc_auth_kerb;
  611                                 *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED);
  612                                 *tl = ktvout.tv_sec;
  613                                 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  614                                 *tl++ = ktvout.tv_usec;
  615                                 *tl++ = txdr_unsigned(
  616                                     kauth_cred_geteuid(nuidp->nu_cr));
  617                         } else {
  618                                 *tl++ = 0;
  619                                 *tl++ = 0;
  620                         }
  621                 } else {
  622                         *tl++ = 0;
  623                         *tl++ = 0;
  624                 }
  625                 switch (err) {
  626                 case EPROGUNAVAIL:
  627                         *tl = txdr_unsigned(RPC_PROGUNAVAIL);
  628                         break;
  629                 case EPROGMISMATCH:
  630                         *tl = txdr_unsigned(RPC_PROGMISMATCH);
  631                         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  632                         *tl++ = txdr_unsigned(2);
  633                         *tl = txdr_unsigned(3);
  634                         break;
  635                 case EPROCUNAVAIL:
  636                         *tl = txdr_unsigned(RPC_PROCUNAVAIL);
  637                         break;
  638                 case EBADRPC:
  639                         *tl = txdr_unsigned(RPC_GARBAGE);
  640                         break;
  641                 default:
  642                         *tl = 0;
  643                         if (err != NFSERR_RETVOID) {
  644                                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
  645                                 if (err)
  646                                     *tl = txdr_unsigned(nfsrv_errmap(nd, err));
  647                                 else
  648                                     *tl = 0;
  649                         }
  650                         break;
  651                 };
  652         }
  653 
  654         if (mrq != NULL)
  655                 *mrq = mreq;
  656         *mbp = mb;
  657         *bposp = bpos;
  658         if (err != 0 && err != NFSERR_RETVOID)
  659                 nfsstats.srvrpc_errs++;
  660         return (0);
  661 }
  662 
  663 static void
  664 nfs_timer_schedule(void)
  665 {
  666 
  667         callout_schedule(&nfs_timer_ch, nfs_ticks);
  668 }
  669 
  670 void
  671 nfs_timer_start(void)
  672 {
  673 
  674         if (callout_pending(&nfs_timer_ch))
  675                 return;
  676 
  677         nfs_timer_start_ev.ev_count++;
  678         nfs_timer_schedule();
  679 }
  680 
  681 void
  682 nfs_timer_init(void)
  683 {
  684 
  685         mutex_init(&nfs_timer_lock, MUTEX_DEFAULT, IPL_NONE);
  686         callout_init(&nfs_timer_ch, 0);
  687         callout_setfunc(&nfs_timer_ch, nfs_timer, NULL);
  688         evcnt_attach_dynamic(&nfs_timer_ev, EVCNT_TYPE_MISC, NULL,
  689             "nfs", "timer");
  690         evcnt_attach_dynamic(&nfs_timer_start_ev, EVCNT_TYPE_MISC, NULL,
  691             "nfs", "timer start");
  692         evcnt_attach_dynamic(&nfs_timer_stop_ev, EVCNT_TYPE_MISC, NULL,
  693             "nfs", "timer stop");
  694 }
  695 
  696 void
  697 nfs_timer_fini(void)
  698 {
  699 
  700         callout_halt(&nfs_timer_ch, NULL);
  701         callout_destroy(&nfs_timer_ch);
  702         mutex_destroy(&nfs_timer_lock);
  703         evcnt_detach(&nfs_timer_ev);
  704         evcnt_detach(&nfs_timer_start_ev);
  705         evcnt_detach(&nfs_timer_stop_ev);
  706 }
  707 
  708 void
  709 nfs_timer_srvinit(bool (*func)(void))
  710 {
  711 
  712         nfs_timer_srvvec = func;
  713 }
  714 
  715 void
  716 nfs_timer_srvfini(void)
  717 {
  718 
  719         mutex_enter(&nfs_timer_lock);
  720         nfs_timer_srvvec = NULL;
  721         mutex_exit(&nfs_timer_lock);
  722 }
  723 
  724 
  725 /*
  726  * Nfs timer routine
  727  * Scan the nfsreq list and retranmit any requests that have timed out
  728  * To avoid retransmission attempts on STREAM sockets (in the future) make
  729  * sure to set the r_retry field to 0 (implies nm_retry == 0).
  730  */
  731 void
  732 nfs_timer(void *arg)
  733 {
  734         struct nfsreq *rep;
  735         struct mbuf *m;
  736         struct socket *so;
  737         struct nfsmount *nmp;
  738         int timeo;
  739         int error;
  740         bool more = false;
  741 
  742         nfs_timer_ev.ev_count++;
  743 
  744         mutex_enter(softnet_lock);      /* XXX PR 40491 */
  745         TAILQ_FOREACH(rep, &nfs_reqq, r_chain) {
  746                 more = true;
  747                 nmp = rep->r_nmp;
  748                 if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
  749                         continue;
  750                 if (nfs_sigintr(nmp, rep, rep->r_lwp)) {
  751                         rep->r_flags |= R_SOFTTERM;
  752                         continue;
  753                 }
  754                 if (rep->r_rtt >= 0) {
  755                         rep->r_rtt++;
  756                         if (nmp->nm_flag & NFSMNT_DUMBTIMR)
  757                                 timeo = nmp->nm_timeo;
  758                         else
  759                                 timeo = NFS_RTO(nmp, nfs_proct[rep->r_procnum]);
  760                         if (nmp->nm_timeouts > 0)
  761                                 timeo *= nfs_backoff[nmp->nm_timeouts - 1];
  762                         if (timeo > NFS_MAXTIMEO)
  763                                 timeo = NFS_MAXTIMEO;
  764                         if (rep->r_rtt <= timeo)
  765                                 continue;
  766                         if (nmp->nm_timeouts <
  767                             (sizeof(nfs_backoff) / sizeof(nfs_backoff[0])))
  768                                 nmp->nm_timeouts++;
  769                 }
  770                 /*
  771                  * Check for server not responding
  772                  */
  773                 if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
  774                      rep->r_rexmit > nmp->nm_deadthresh) {
  775                         nfs_msg(rep->r_lwp,
  776                             nmp->nm_mountp->mnt_stat.f_mntfromname,
  777                             "not responding");
  778                         rep->r_flags |= R_TPRINTFMSG;
  779                 }
  780                 if (rep->r_rexmit >= rep->r_retry) {    /* too many */
  781                         nfsstats.rpctimeouts++;
  782                         rep->r_flags |= R_SOFTTERM;
  783                         continue;
  784                 }
  785                 if (nmp->nm_sotype != SOCK_DGRAM) {
  786                         if (++rep->r_rexmit > NFS_MAXREXMIT)
  787                                 rep->r_rexmit = NFS_MAXREXMIT;
  788                         continue;
  789                 }
  790                 if ((so = nmp->nm_so) == NULL)
  791                         continue;
  792 
  793                 /*
  794                  * If there is enough space and the window allows..
  795                  *      Resend it
  796                  * Set r_rtt to -1 in case we fail to send it now.
  797                  */
  798                 /* solock(so);          XXX PR 40491 */
  799                 rep->r_rtt = -1;
  800                 if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
  801                    ((nmp->nm_flag & NFSMNT_DUMBTIMR) ||
  802                     (rep->r_flags & R_SENT) ||
  803                     nmp->nm_sent < nmp->nm_cwnd) &&
  804                    (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
  805                         if (so->so_state & SS_ISCONNECTED)
  806                             error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
  807                             NULL, NULL, NULL);
  808                         else
  809                             error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
  810                             nmp->nm_nam, NULL, NULL);
  811                         if (error) {
  812                                 if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
  813 #ifdef DEBUG
  814                                         if (ratecheck(&nfs_timer_last_err_time,
  815                                             &nfs_err_interval))
  816                                                 printf("%s: ignoring error "
  817                                                        "%d\n", __func__, error);
  818 #endif
  819                                         so->so_error = 0;
  820                                 }
  821                         } else {
  822                                 /*
  823                                  * Iff first send, start timing
  824                                  * else turn timing off, backoff timer
  825                                  * and divide congestion window by 2.
  826                                  */
  827                                 if (rep->r_flags & R_SENT) {
  828                                         rep->r_flags &= ~R_TIMING;
  829                                         if (++rep->r_rexmit > NFS_MAXREXMIT)
  830                                                 rep->r_rexmit = NFS_MAXREXMIT;
  831                                         nmp->nm_cwnd >>= 1;
  832                                         if (nmp->nm_cwnd < NFS_CWNDSCALE)
  833                                                 nmp->nm_cwnd = NFS_CWNDSCALE;
  834                                         nfsstats.rpcretries++;
  835                                 } else {
  836                                         rep->r_flags |= R_SENT;
  837                                         nmp->nm_sent += NFS_CWNDSCALE;
  838                                 }
  839                                 rep->r_rtt = 0;
  840                         }
  841                 }
  842                 /* sounlock(so);        XXX PR 40491 */
  843         }
  844         mutex_exit(softnet_lock);       /* XXX PR 40491 */
  845 
  846         mutex_enter(&nfs_timer_lock);
  847         if (nfs_timer_srvvec != NULL) {
  848                 more |= (*nfs_timer_srvvec)();
  849         }
  850         mutex_exit(&nfs_timer_lock);
  851 
  852         if (more) {
  853                 nfs_timer_schedule();
  854         } else {
  855                 nfs_timer_stop_ev.ev_count++;
  856         }
  857 }
  858 
  859 /*
  860  * Test for a termination condition pending on the process.
  861  * This is used for NFSMNT_INT mounts.
  862  */
  863 int
  864 nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct lwp *l)
  865 {
  866         sigset_t ss;
  867 
  868         if (rep && (rep->r_flags & R_SOFTTERM))
  869                 return (EINTR);
  870         if (!(nmp->nm_flag & NFSMNT_INT))
  871                 return (0);
  872         if (l) {
  873                 sigpending1(l, &ss);
  874 #if 0
  875                 sigminusset(&l->l_proc->p_sigctx.ps_sigignore, &ss);
  876 #endif
  877                 if (sigismember(&ss, SIGINT) || sigismember(&ss, SIGTERM) ||
  878                     sigismember(&ss, SIGKILL) || sigismember(&ss, SIGHUP) ||
  879                     sigismember(&ss, SIGQUIT))
  880                         return (EINTR);
  881         }
  882         return (0);
  883 }
  884 
  885 int
  886 nfs_rcvlock(struct nfsmount *nmp, struct nfsreq *rep)
  887 {
  888         int *flagp = &nmp->nm_iflag;
  889         int slptimeo = 0;
  890         bool catch;
  891         int error = 0;
  892 
  893         KASSERT(nmp == rep->r_nmp);
  894 
  895         catch = (nmp->nm_flag & NFSMNT_INT) != 0;
  896         mutex_enter(&nmp->nm_lock);
  897         while (/* CONSTCOND */ true) {
  898                 if (*flagp & NFSMNT_DISMNT) {
  899                         cv_signal(&nmp->nm_disconcv);
  900                         error = EIO;
  901                         break;
  902                 }
  903                 /* If our reply was received while we were sleeping,
  904                  * then just return without taking the lock to avoid a
  905                  * situation where a single iod could 'capture' the
  906                  * receive lock.
  907                  */
  908                 if (rep->r_mrep != NULL) {
  909                         cv_signal(&nmp->nm_rcvcv);
  910                         error = EALREADY;
  911                         break;
  912                 }
  913                 if (nfs_sigintr(rep->r_nmp, rep, rep->r_lwp)) {
  914                         cv_signal(&nmp->nm_rcvcv);
  915                         error = EINTR;
  916                         break;
  917                 }
  918                 if ((*flagp & NFSMNT_RCVLOCK) == 0) {
  919                         *flagp |= NFSMNT_RCVLOCK;
  920                         break;
  921                 }
  922                 if (catch) {
  923                         cv_timedwait_sig(&nmp->nm_rcvcv, &nmp->nm_lock,
  924                             slptimeo);
  925                 } else {
  926                         cv_timedwait(&nmp->nm_rcvcv, &nmp->nm_lock,
  927                             slptimeo);
  928                 }
  929                 if (catch) {
  930                         catch = false;
  931                         slptimeo = 2 * hz;
  932                 }
  933         }
  934         mutex_exit(&nmp->nm_lock);
  935         return error;
  936 }
  937 
  938 /*
  939  * Unlock the stream socket for others.
  940  */
  941 void
  942 nfs_rcvunlock(struct nfsmount *nmp)
  943 {
  944 
  945         mutex_enter(&nmp->nm_lock);
  946         if ((nmp->nm_iflag & NFSMNT_RCVLOCK) == 0)
  947                 panic("nfs rcvunlock");
  948         nmp->nm_iflag &= ~NFSMNT_RCVLOCK;
  949         cv_signal(&nmp->nm_rcvcv);
  950         mutex_exit(&nmp->nm_lock);
  951 }
  952 
  953 /*
  954  * Parse an RPC request
  955  * - verify it
  956  * - allocate and fill in the cred.
  957  */
  958 int
  959 nfs_getreq(struct nfsrv_descript *nd, struct nfsd *nfsd, int has_header)
  960 {
  961         int len, i;
  962         u_int32_t *tl;
  963         int32_t t1;
  964         struct uio uio;
  965         struct iovec iov;
  966         char *dpos, *cp2, *cp;
  967         u_int32_t nfsvers, auth_type;
  968         uid_t nickuid;
  969         int error = 0, ticklen;
  970         struct mbuf *mrep, *md;
  971         struct nfsuid *nuidp;
  972         struct timeval tvin, tvout;
  973 
  974         memset(&tvout, 0, sizeof tvout);        /* XXX gcc */
  975 
  976         KASSERT(nd->nd_cr == NULL);
  977         mrep = nd->nd_mrep;
  978         md = nd->nd_md;
  979         dpos = nd->nd_dpos;
  980         if (has_header) {
  981                 nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
  982                 nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++);
  983                 if (*tl++ != rpc_call) {
  984                         m_freem(mrep);
  985                         return (EBADRPC);
  986                 }
  987         } else
  988                 nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
  989         nd->nd_repstat = 0;
  990         nd->nd_flag = 0;
  991         if (*tl++ != rpc_vers) {
  992                 nd->nd_repstat = ERPCMISMATCH;
  993                 nd->nd_procnum = NFSPROC_NOOP;
  994                 return (0);
  995         }
  996         if (*tl != nfs_prog) {
  997                 nd->nd_repstat = EPROGUNAVAIL;
  998                 nd->nd_procnum = NFSPROC_NOOP;
  999                 return (0);
 1000         }
 1001         tl++;
 1002         nfsvers = fxdr_unsigned(u_int32_t, *tl++);
 1003         if (nfsvers < NFS_VER2 || nfsvers > NFS_VER3) {
 1004                 nd->nd_repstat = EPROGMISMATCH;
 1005                 nd->nd_procnum = NFSPROC_NOOP;
 1006                 return (0);
 1007         }
 1008         if (nfsvers == NFS_VER3)
 1009                 nd->nd_flag = ND_NFSV3;
 1010         nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++);
 1011         if (nd->nd_procnum == NFSPROC_NULL)
 1012                 return (0);
 1013         if (nd->nd_procnum > NFSPROC_COMMIT ||
 1014             (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) {
 1015                 nd->nd_repstat = EPROCUNAVAIL;
 1016                 nd->nd_procnum = NFSPROC_NOOP;
 1017                 return (0);
 1018         }
 1019         if ((nd->nd_flag & ND_NFSV3) == 0)
 1020                 nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
 1021         auth_type = *tl++;
 1022         len = fxdr_unsigned(int, *tl++);
 1023         if (len < 0 || len > RPCAUTH_MAXSIZ) {
 1024                 m_freem(mrep);
 1025                 return (EBADRPC);
 1026         }
 1027 
 1028         nd->nd_flag &= ~ND_KERBAUTH;
 1029         /*
 1030          * Handle auth_unix or auth_kerb.
 1031          */
 1032         if (auth_type == rpc_auth_unix) {
 1033                 uid_t uid;
 1034                 gid_t gid;
 1035 
 1036                 nd->nd_cr = kauth_cred_alloc();
 1037                 len = fxdr_unsigned(int, *++tl);
 1038                 if (len < 0 || len > NFS_MAXNAMLEN) {
 1039                         m_freem(mrep);
 1040                         error = EBADRPC;
 1041                         goto errout;
 1042                 }
 1043                 nfsm_adv(nfsm_rndup(len));
 1044                 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1045 
 1046                 uid = fxdr_unsigned(uid_t, *tl++);
 1047                 gid = fxdr_unsigned(gid_t, *tl++);
 1048                 kauth_cred_setuid(nd->nd_cr, uid);
 1049                 kauth_cred_seteuid(nd->nd_cr, uid);
 1050                 kauth_cred_setsvuid(nd->nd_cr, uid);
 1051                 kauth_cred_setgid(nd->nd_cr, gid);
 1052                 kauth_cred_setegid(nd->nd_cr, gid);
 1053                 kauth_cred_setsvgid(nd->nd_cr, gid);
 1054 
 1055                 len = fxdr_unsigned(int, *tl);
 1056                 if (len < 0 || len > RPCAUTH_UNIXGIDS) {
 1057                         m_freem(mrep);
 1058                         error = EBADRPC;
 1059                         goto errout;
 1060                 }
 1061                 nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED);
 1062 
 1063                 if (len > 0) {
 1064                         size_t grbuf_size = min(len, NGROUPS) * sizeof(gid_t);
 1065                         gid_t *grbuf = kmem_alloc(grbuf_size, KM_SLEEP);
 1066 
 1067                         for (i = 0; i < len; i++) {
 1068                                 if (i < NGROUPS) /* XXX elad */
 1069                                         grbuf[i] = fxdr_unsigned(gid_t, *tl++);
 1070                                 else
 1071                                         tl++;
 1072                         }
 1073                         kauth_cred_setgroups(nd->nd_cr, grbuf,
 1074                             min(len, NGROUPS), -1, UIO_SYSSPACE);
 1075                         kmem_free(grbuf, grbuf_size);
 1076                 }
 1077 
 1078                 len = fxdr_unsigned(int, *++tl);
 1079                 if (len < 0 || len > RPCAUTH_MAXSIZ) {
 1080                         m_freem(mrep);
 1081                         error = EBADRPC;
 1082                         goto errout;
 1083                 }
 1084                 if (len > 0)
 1085                         nfsm_adv(nfsm_rndup(len));
 1086         } else if (auth_type == rpc_auth_kerb) {
 1087                 switch (fxdr_unsigned(int, *tl++)) {
 1088                 case RPCAKN_FULLNAME:
 1089                         ticklen = fxdr_unsigned(int, *tl);
 1090                         *((u_int32_t *)nfsd->nfsd_authstr) = *tl;
 1091                         uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED;
 1092                         nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED;
 1093                         if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
 1094                                 m_freem(mrep);
 1095                                 error = EBADRPC;
 1096                                 goto errout;
 1097                         }
 1098                         uio.uio_offset = 0;
 1099                         uio.uio_iov = &iov;
 1100                         uio.uio_iovcnt = 1;
 1101                         UIO_SETUP_SYSSPACE(&uio);
 1102                         iov.iov_base = (void *)&nfsd->nfsd_authstr[4];
 1103                         iov.iov_len = RPCAUTH_MAXSIZ - 4;
 1104                         nfsm_mtouio(&uio, uio.uio_resid);
 1105                         nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1106                         if (*tl++ != rpc_auth_kerb ||
 1107                                 fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) {
 1108                                 printf("Bad kerb verifier\n");
 1109                                 nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
 1110                                 nd->nd_procnum = NFSPROC_NOOP;
 1111                                 return (0);
 1112                         }
 1113                         nfsm_dissect(cp, void *, 4 * NFSX_UNSIGNED);
 1114                         tl = (u_int32_t *)cp;
 1115                         if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) {
 1116                                 printf("Not fullname kerb verifier\n");
 1117                                 nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
 1118                                 nd->nd_procnum = NFSPROC_NOOP;
 1119                                 return (0);
 1120                         }
 1121                         cp += NFSX_UNSIGNED;
 1122                         memcpy(nfsd->nfsd_verfstr, cp, 3 * NFSX_UNSIGNED);
 1123                         nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED;
 1124                         nd->nd_flag |= ND_KERBFULL;
 1125                         nfsd->nfsd_flag |= NFSD_NEEDAUTH;
 1126                         break;
 1127                 case RPCAKN_NICKNAME:
 1128                         if (len != 2 * NFSX_UNSIGNED) {
 1129                                 printf("Kerb nickname short\n");
 1130                                 nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED);
 1131                                 nd->nd_procnum = NFSPROC_NOOP;
 1132                                 return (0);
 1133                         }
 1134                         nickuid = fxdr_unsigned(uid_t, *tl);
 1135                         nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1136                         if (*tl++ != rpc_auth_kerb ||
 1137                                 fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) {
 1138                                 printf("Kerb nick verifier bad\n");
 1139                                 nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
 1140                                 nd->nd_procnum = NFSPROC_NOOP;
 1141                                 return (0);
 1142                         }
 1143                         nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1144                         tvin.tv_sec = *tl++;
 1145                         tvin.tv_usec = *tl;
 1146 
 1147                         LIST_FOREACH(nuidp, NUIDHASH(nfsd->nfsd_slp, nickuid),
 1148                             nu_hash) {
 1149                                 if (kauth_cred_geteuid(nuidp->nu_cr) == nickuid &&
 1150                                     (!nd->nd_nam2 ||
 1151                                      netaddr_match(NU_NETFAM(nuidp),
 1152                                       &nuidp->nu_haddr, nd->nd_nam2)))
 1153                                         break;
 1154                         }
 1155                         if (!nuidp) {
 1156                                 nd->nd_repstat =
 1157                                         (NFSERR_AUTHERR|AUTH_REJECTCRED);
 1158                                 nd->nd_procnum = NFSPROC_NOOP;
 1159                                 return (0);
 1160                         }
 1161 
 1162                         /*
 1163                          * Now, decrypt the timestamp using the session key
 1164                          * and validate it.
 1165                          */
 1166 #ifdef NFSKERB
 1167                         XXX
 1168 #endif
 1169 
 1170                         tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec);
 1171                         tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec);
 1172                         if (nuidp->nu_expire < time_second ||
 1173                             nuidp->nu_timestamp.tv_sec > tvout.tv_sec ||
 1174                             (nuidp->nu_timestamp.tv_sec == tvout.tv_sec &&
 1175                              nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) {
 1176                                 nuidp->nu_expire = 0;
 1177                                 nd->nd_repstat =
 1178                                     (NFSERR_AUTHERR|AUTH_REJECTVERF);
 1179                                 nd->nd_procnum = NFSPROC_NOOP;
 1180                                 return (0);
 1181                         }
 1182                         kauth_cred_hold(nuidp->nu_cr);
 1183                         nd->nd_cr = nuidp->nu_cr;
 1184                         nd->nd_flag |= ND_KERBNICK;
 1185                 }
 1186         } else {
 1187                 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
 1188                 nd->nd_procnum = NFSPROC_NOOP;
 1189                 return (0);
 1190         }
 1191 
 1192         nd->nd_md = md;
 1193         nd->nd_dpos = dpos;
 1194         KASSERT((nd->nd_cr == NULL && (nfsd->nfsd_flag & NFSD_NEEDAUTH) != 0)
 1195              || (nd->nd_cr != NULL && (nfsd->nfsd_flag & NFSD_NEEDAUTH) == 0));
 1196         return (0);
 1197 nfsmout:
 1198 errout:
 1199         KASSERT(error != 0);
 1200         if (nd->nd_cr != NULL) {
 1201                 kauth_cred_free(nd->nd_cr);
 1202                 nd->nd_cr = NULL;
 1203         }
 1204         return (error);
 1205 }
 1206 
 1207 int
 1208 nfs_msg(struct lwp *l, const char *server, const char *msg)
 1209 {
 1210         tpr_t tpr;
 1211 
 1212 #if 0 /* XXX nfs_timer can't block on proc_lock */
 1213         if (l)
 1214                 tpr = tprintf_open(l->l_proc);
 1215         else
 1216 #endif
 1217                 tpr = NULL;
 1218         tprintf(tpr, "nfs server %s: %s\n", server, msg);
 1219         tprintf_close(tpr);
 1220         return (0);
 1221 }
 1222 
 1223 static struct pool nfs_srvdesc_pool;
 1224 
 1225 void
 1226 nfsdreq_init(void)
 1227 {
 1228 
 1229         pool_init(&nfs_srvdesc_pool, sizeof(struct nfsrv_descript),
 1230             0, 0, 0, "nfsrvdescpl", &pool_allocator_nointr, IPL_NONE);
 1231 }
 1232 
 1233 void
 1234 nfsdreq_fini(void)
 1235 {
 1236 
 1237         pool_destroy(&nfs_srvdesc_pool);
 1238 }
 1239 
 1240 struct nfsrv_descript *
 1241 nfsdreq_alloc(void)
 1242 {
 1243         struct nfsrv_descript *nd;
 1244 
 1245         nd = pool_get(&nfs_srvdesc_pool, PR_WAITOK);
 1246         nd->nd_cr = NULL;
 1247         return nd;
 1248 }
 1249 
 1250 void
 1251 nfsdreq_free(struct nfsrv_descript *nd)
 1252 {
 1253         kauth_cred_t cr;
 1254 
 1255         cr = nd->nd_cr;
 1256         if (cr != NULL) {
 1257                 kauth_cred_free(cr);
 1258         }
 1259         pool_put(&nfs_srvdesc_pool, nd);
 1260 }

Cache object: af09cea7fbb98fbe18cb493b81952d09


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