home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / nfs / nfs_socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  34.8 KB  |  1,414 lines

  1. /*
  2.  * Copyright (c) 1989, 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Rick Macklem at The University of Guelph.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  *    @(#)nfs_socket.c    7.23 (Berkeley) 4/20/91
  37.  */
  38.  
  39. /*
  40.  * Socket operations for use by nfs
  41.  */
  42.  
  43. #include "param.h"
  44. #include "proc.h"
  45. #include "mount.h"
  46. #include "kernel.h"
  47. #include "malloc.h"
  48. #include "mbuf.h"
  49. #include "namei.h"
  50. #include "vnode.h"
  51. #include "domain.h"
  52. #include "protosw.h"
  53. #include "socket.h"
  54. #include "socketvar.h"
  55. #include "syslog.h"
  56. #include "tprintf.h"
  57. #include "../netinet/in.h"
  58. #include "../netinet/tcp.h"
  59.  
  60. #include "rpcv2.h"
  61. #include "nfsv2.h"
  62. #include "nfs.h"
  63. #include "xdr_subs.h"
  64. #include "nfsm_subs.h"
  65. #include "nfsmount.h"
  66.  
  67. #define    TRUE    1
  68. #define    FALSE    0
  69.  
  70. /*
  71.  * External data, mostly RPC constants in XDR form
  72.  */
  73. extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
  74.     rpc_msgaccepted, rpc_call;
  75. extern u_long nfs_prog, nfs_vers;
  76. /* Maybe these should be bits in a u_long ?? */
  77. extern int nonidempotent[NFS_NPROCS];
  78. static int compressrequest[NFS_NPROCS] = {
  79.     FALSE,
  80.     TRUE,
  81.     TRUE,
  82.     FALSE,
  83.     TRUE,
  84.     TRUE,
  85.     TRUE,
  86.     FALSE,
  87.     FALSE,
  88.     TRUE,
  89.     TRUE,
  90.     TRUE,
  91.     TRUE,
  92.     TRUE,
  93.     TRUE,
  94.     TRUE,
  95.     TRUE,
  96.     TRUE,
  97. };
  98. int    nfs_sbwait();
  99. void    nfs_disconnect();
  100. struct mbuf *nfs_compress(), *nfs_uncompress();
  101.  
  102. int    nfsrv_null(),
  103.     nfsrv_getattr(),
  104.     nfsrv_setattr(),
  105.     nfsrv_lookup(),
  106.     nfsrv_readlink(),
  107.     nfsrv_read(),
  108.     nfsrv_write(),
  109.     nfsrv_create(),
  110.     nfsrv_remove(),
  111.     nfsrv_rename(),
  112.     nfsrv_link(),
  113.     nfsrv_symlink(),
  114.     nfsrv_mkdir(),
  115.     nfsrv_rmdir(),
  116.     nfsrv_readdir(),
  117.     nfsrv_statfs(),
  118.     nfsrv_noop();
  119.  
  120. int (*nfsrv_procs[NFS_NPROCS])() = {
  121.     nfsrv_null,
  122.     nfsrv_getattr,
  123.     nfsrv_setattr,
  124.     nfsrv_noop,
  125.     nfsrv_lookup,
  126.     nfsrv_readlink,
  127.     nfsrv_read,
  128.     nfsrv_noop,
  129.     nfsrv_write,
  130.     nfsrv_create,
  131.     nfsrv_remove,
  132.     nfsrv_rename,
  133.     nfsrv_link,
  134.     nfsrv_symlink,
  135.     nfsrv_mkdir,
  136.     nfsrv_rmdir,
  137.     nfsrv_readdir,
  138.     nfsrv_statfs,
  139. };
  140.  
  141. struct nfsreq nfsreqh;
  142. int nfsrexmtthresh = NFS_FISHY;
  143. int nfs_tcpnodelay = 1;
  144.  
  145. /*
  146.  * Initialize sockets and congestion for a new NFS connection.
  147.  * We do not free the sockaddr if error.
  148.  */
  149. nfs_connect(nmp)
  150.     register struct nfsmount *nmp;
  151. {
  152.     register struct socket *so;
  153.     int s, error, bufsize;
  154.     struct mbuf *m;
  155.  
  156.     nmp->nm_so = (struct socket *)0;
  157.     if (error = socreate(mtod(nmp->nm_nam, struct sockaddr *)->sa_family,
  158.         &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto))
  159.         goto bad;
  160.     so = nmp->nm_so;
  161.     nmp->nm_soflags = so->so_proto->pr_flags;
  162.  
  163.     if (nmp->nm_sotype == SOCK_DGRAM)
  164.         bufsize = min(4 * (nmp->nm_wsize + NFS_MAXPKTHDR),
  165.             NFS_MAXPACKET);
  166.     else
  167.         bufsize = min(4 * (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof(u_long)),
  168.             NFS_MAXPACKET + sizeof(u_long));
  169.     if (error = soreserve(so, bufsize, bufsize))
  170.         goto bad;
  171.  
  172.     /*
  173.      * Protocols that do not require connections may be optionally left
  174.      * unconnected for servers that reply from a port other than NFS_PORT.
  175.      */
  176.     if (nmp->nm_flag & NFSMNT_NOCONN) {
  177.         if (nmp->nm_soflags & PR_CONNREQUIRED) {
  178.             error = ENOTCONN;
  179.             goto bad;
  180.         }
  181.     } else {
  182.         if (error = soconnect(so, nmp->nm_nam))
  183.             goto bad;
  184.  
  185.         /*
  186.          * Wait for the connection to complete. Cribbed from the
  187.          * connect system call but with the wait at negative prio.
  188.          */
  189.         s = splnet();
  190.         while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
  191.             (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "nfscon", 0);
  192.         splx(s);
  193.         if (so->so_error) {
  194.             error = so->so_error;
  195.             goto bad;
  196.         }
  197.     }
  198.     if (nmp->nm_sotype == SOCK_DGRAM) {
  199.         if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) {
  200.             so->so_rcv.sb_timeo = (5 * hz);
  201.             so->so_snd.sb_timeo = (5 * hz);
  202.         } else {
  203.             so->so_rcv.sb_timeo = 0;
  204.             so->so_snd.sb_timeo = 0;
  205.         }
  206.         nmp->nm_rto = NFS_TIMEO;
  207.     } else {
  208.         if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) {
  209.             so->so_rcv.sb_timeo = (5 * hz);
  210.             so->so_snd.sb_timeo = (5 * hz);
  211.         } else {
  212.             so->so_rcv.sb_timeo = 0;
  213.             so->so_snd.sb_timeo = 0;
  214.         }
  215.         if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
  216.             MGET(m, M_WAIT, MT_SOOPTS);
  217.             *mtod(m, int *) = 1;
  218.             m->m_len = sizeof(int);
  219.             sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
  220.         }
  221.         if (so->so_proto->pr_domain->dom_family == AF_INET &&
  222.             so->so_proto->pr_protocol == IPPROTO_TCP &&
  223.             nfs_tcpnodelay) {
  224.             MGET(m, M_WAIT, MT_SOOPTS);
  225.             *mtod(m, int *) = 1;
  226.             m->m_len = sizeof(int);
  227.             sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
  228.         }
  229.         nmp->nm_rto = 10 * NFS_TIMEO;        /* XXX */
  230.     }
  231.     so->so_rcv.sb_flags |= SB_NOINTR;
  232.     so->so_snd.sb_flags |= SB_NOINTR;
  233.  
  234.     /* Initialize other non-zero congestion variables */
  235.     nmp->nm_window = 2;            /* Initial send window */
  236.     nmp->nm_ssthresh = NFS_MAXWINDOW;    /* Slowstart threshold */
  237.     nmp->nm_rttvar = nmp->nm_rto << 1;
  238.     nmp->nm_sent = 0;
  239.     nmp->nm_currexmit = 0;
  240.     return (0);
  241.  
  242. bad:
  243.     nfs_disconnect(nmp);
  244.     return (error);
  245. }
  246.  
  247. /*
  248.  * Reconnect routine:
  249.  * Called when a connection is broken on a reliable protocol.
  250.  * - clean up the old socket
  251.  * - nfs_connect() again
  252.  * - set R_MUSTRESEND for all outstanding requests on mount point
  253.  * If this fails the mount point is DEAD!
  254.  * nb: Must be called with the nfs_solock() set on the mount point.
  255.  */
  256. nfs_reconnect(rep, nmp)
  257.     register struct nfsreq *rep;
  258.     register struct nfsmount *nmp;
  259. {
  260.     register struct nfsreq *rp;
  261.     int error;
  262.  
  263.     nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
  264.         "trying reconnect");
  265.     while (error = nfs_connect(nmp)) {
  266. #ifdef lint
  267.         error = error;
  268. #endif /* lint */
  269.         if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp))
  270.             return (EINTR);
  271.         (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
  272.     }
  273.     nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
  274.         "reconnected");
  275.  
  276.     /*
  277.      * Loop through outstanding request list and fix up all requests
  278.      * on old socket.
  279.      */
  280.     rp = nfsreqh.r_next;
  281.     while (rp != &nfsreqh) {
  282.         if (rp->r_nmp == nmp)
  283.             rp->r_flags |= R_MUSTRESEND;
  284.         rp = rp->r_next;
  285.     }
  286.     return (0);
  287. }
  288.  
  289. /*
  290.  * NFS disconnect. Clean up and unlink.
  291.  */
  292. void
  293. nfs_disconnect(nmp)
  294.     register struct nfsmount *nmp;
  295. {
  296.     register struct socket *so;
  297.  
  298.     if (nmp->nm_so) {
  299.         so = nmp->nm_so;
  300.         nmp->nm_so = (struct socket *)0;
  301.         soshutdown(so, 2);
  302.         soclose(so);
  303.     }
  304. }
  305.  
  306. /*
  307.  * This is the nfs send routine. For connection based socket types, it
  308.  * must be called with an nfs_solock() on the socket.
  309.  * "rep == NULL" indicates that it has been called from a server.
  310.  */
  311. nfs_send(so, nam, top, rep)
  312.     register struct socket *so;
  313.     struct mbuf *nam;
  314.     register struct mbuf *top;
  315.     struct nfsreq *rep;
  316. {
  317.     struct mbuf *sendnam;
  318.     int error, soflags;
  319.  
  320.     if (rep) {
  321.         if (rep->r_flags & R_SOFTTERM) {
  322.             m_freem(top);
  323.             return (EINTR);
  324.         }
  325.         if (rep->r_nmp->nm_so == NULL &&
  326.             (error = nfs_reconnect(rep, rep->r_nmp)))
  327.             return (error);
  328.         rep->r_flags &= ~R_MUSTRESEND;
  329.         so = rep->r_nmp->nm_so;
  330.         soflags = rep->r_nmp->nm_soflags;
  331.     } else
  332.         soflags = so->so_proto->pr_flags;
  333.     if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
  334.         sendnam = (struct mbuf *)0;
  335.     else
  336.         sendnam = nam;
  337.  
  338.     error = sosend(so, sendnam, (struct uio *)0, top,
  339.         (struct mbuf *)0, 0);
  340.     if (error == EWOULDBLOCK && rep) {
  341.         if (rep->r_flags & R_SOFTTERM)
  342.             error = EINTR;
  343.         else {
  344.             rep->r_flags |= R_MUSTRESEND;
  345.             error = 0;
  346.         }
  347.     }
  348.     /*
  349.      * Ignore socket errors??
  350.      */
  351.     if (error && error != EINTR && error != ERESTART)
  352.         error = 0;
  353.     return (error);
  354. }
  355.  
  356. /*
  357.  * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
  358.  * done by soreceive(), but for SOCK_STREAM we must deal with the Record
  359.  * Mark and consolidate the data into a new mbuf list.
  360.  * nb: Sometimes TCP passes the data up to soreceive() in long lists of
  361.  *     small mbufs.
  362.  * For SOCK_STREAM we must be very careful to read an entire record once
  363.  * we have read any of it, even if the system call has been interrupted.
  364.  */
  365. nfs_receive(so, aname, mp, rep)
  366.     register struct socket *so;
  367.     struct mbuf **aname;
  368.     struct mbuf **mp;
  369.     register struct nfsreq *rep;
  370. {
  371.     struct uio auio;
  372.     struct iovec aio;
  373.     register struct mbuf *m;
  374.     struct mbuf *m2, *mnew, **mbp;
  375.     caddr_t fcp, tcp;
  376.     u_long len;
  377.     struct mbuf **getnam;
  378.     int error, siz, mlen, soflags, rcvflg;
  379.  
  380.     /*
  381.      * Set up arguments for soreceive()
  382.      */
  383.     *mp = (struct mbuf *)0;
  384.     *aname = (struct mbuf *)0;
  385.     if (rep)
  386.         soflags = rep->r_nmp->nm_soflags;
  387.     else
  388.         soflags = so->so_proto->pr_flags;
  389.  
  390.     /*
  391.      * For reliable protocols, lock against other senders/receivers
  392.      * in case a reconnect is necessary.
  393.      * For SOCK_STREAM, first get the Record Mark to find out how much
  394.      * more there is to get.
  395.      * We must lock the socket against other receivers
  396.      * until we have an entire rpc request/reply.
  397.      */
  398.     if (soflags & PR_CONNREQUIRED) {
  399. tryagain:
  400.         /*
  401.          * Check for fatal errors and resending request.
  402.          */
  403.         if (rep) {
  404.             /*
  405.              * Ugh: If a reconnect attempt just happened, nm_so
  406.              * would have changed. NULL indicates a failed
  407.              * attempt that has essentially shut down this
  408.              * mount point.
  409.              */
  410.             if (rep->r_mrep || (so = rep->r_nmp->nm_so) == NULL ||
  411.                 (rep->r_flags & R_SOFTTERM))
  412.                 return (EINTR);
  413.             while (rep->r_flags & R_MUSTRESEND) {
  414.                 m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
  415.                 nfsstats.rpcretries++;
  416.                 if (error = nfs_send(so, rep->r_nmp->nm_nam, m,
  417.                     rep))
  418.                     goto errout;
  419.             }
  420.         }
  421.         if ((soflags & PR_ATOMIC) == 0) {
  422.             aio.iov_base = (caddr_t) &len;
  423.             aio.iov_len = sizeof(u_long);
  424.             auio.uio_iov = &aio;
  425.             auio.uio_iovcnt = 1;
  426.             auio.uio_segflg = UIO_SYSSPACE;
  427.             auio.uio_rw = UIO_READ;
  428.             auio.uio_procp = (struct proc *)0;
  429.             auio.uio_offset = 0;
  430.             auio.uio_resid = sizeof(u_long);
  431.             do {
  432.                 rcvflg = MSG_WAITALL;
  433.                 error = soreceive(so, (struct mbuf **)0, &auio,
  434.                 (struct mbuf **)0, (struct mbuf **)0, &rcvflg);
  435.                 if (error == EWOULDBLOCK && rep) {
  436.                 if (rep->r_flags & R_SOFTTERM)
  437.                     return (EINTR);
  438.                 if (rep->r_flags & R_MUSTRESEND)
  439.                     goto tryagain;
  440.                 }
  441.             } while (error == EWOULDBLOCK);
  442.             if (!error && auio.uio_resid > 0) {
  443.                 if (rep)
  444.                 log(LOG_INFO,
  445.                    "short receive (%d/%d) from nfs server %s\n",
  446.                    sizeof(u_long) - auio.uio_resid,
  447.                    sizeof(u_long),
  448.                  rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
  449.                 error = EPIPE;
  450.             }
  451.             if (error)
  452.                 goto errout;
  453.             len = ntohl(len) & ~0x80000000;
  454.             /*
  455.              * This is SERIOUS! We are out of sync with the sender
  456.              * and forcing a disconnect/reconnect is all I can do.
  457.              */
  458.             if (len > NFS_MAXPACKET) {
  459.                 if (rep)
  460.                 log(LOG_ERR, "%s (%d) from nfs server %s\n",
  461.                     "impossible packet length",
  462.                     len,
  463.                  rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
  464.                 error = EFBIG;
  465.                 goto errout;
  466.             }
  467.             auio.uio_resid = len;
  468.             do {
  469.                 rcvflg = MSG_WAITALL;
  470.                 error =  soreceive(so, (struct mbuf **)0,
  471.                 &auio, mp, (struct mbuf **)0, &rcvflg);
  472.             } while (error == EWOULDBLOCK || error == EINTR ||
  473.                  error == ERESTART);
  474.             if (!error && auio.uio_resid > 0) {
  475.                 if (rep)
  476.                 log(LOG_INFO,
  477.                    "short receive (%d/%d) from nfs server %s\n",
  478.                    len - auio.uio_resid, len,
  479.                  rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
  480.                 error = EPIPE;
  481.             }
  482.         } else {
  483.             auio.uio_resid = len = 1000000;    /* Anything Big */
  484.             do {
  485.                 rcvflg = 0;
  486.                 error =  soreceive(so, (struct mbuf **)0,
  487.                 &auio, mp, (struct mbuf **)0, &rcvflg);
  488.                 if (error == EWOULDBLOCK && rep) {
  489.                 if (rep->r_flags & R_SOFTTERM)
  490.                     return (EINTR);
  491.                 if (rep->r_flags & R_MUSTRESEND)
  492.                     goto tryagain;
  493.                 }
  494.             } while (error == EWOULDBLOCK);
  495.             if (!error && *mp == NULL)
  496.                 error = EPIPE;
  497.             len -= auio.uio_resid;
  498.         }
  499. errout:
  500.         if (error && rep && error != EINTR && error != ERESTART) {
  501.             m_freem(*mp);
  502.             *mp = (struct mbuf *)0;
  503.             if (error != EPIPE && rep)
  504.                 log(LOG_INFO,
  505.                     "receive error %d from nfs server %s\n",
  506.                     error,
  507.                  rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
  508.             nfs_disconnect(rep->r_nmp);
  509.             error = nfs_reconnect(rep, rep->r_nmp);
  510.             if (!error)
  511.                 goto tryagain;
  512.         }
  513.     } else {
  514.         if (so->so_state & SS_ISCONNECTED)
  515.             getnam = (struct mbuf **)0;
  516.         else
  517.             getnam = aname;
  518.         auio.uio_resid = len = 1000000;
  519.         do {
  520.             rcvflg = 0;
  521.             error =  soreceive(so, getnam, &auio, mp,
  522.                 (struct mbuf **)0, &rcvflg);
  523.             if (error == EWOULDBLOCK && rep &&
  524.                 (rep->r_flags & R_SOFTTERM))
  525.                 return (EINTR);
  526.         } while (error == EWOULDBLOCK);
  527.         len -= auio.uio_resid;
  528.     }
  529.     if (error) {
  530.         m_freem(*mp);
  531.         *mp = (struct mbuf *)0;
  532.     }
  533.     /*
  534.      * Search for any mbufs that are not a multiple of 4 bytes long.
  535.      * These could cause pointer alignment problems, so copy them to
  536.      * well aligned mbufs.
  537.      */
  538.     m = *mp;
  539.     mbp = mp;
  540.     while (m) {
  541.         /*
  542.          * All this for something that may never happen.
  543.          */
  544.         if (m->m_next && (m->m_len & 0x3)) {
  545.             printf("nfs_rcv odd length!\n");
  546.             mlen = 0;
  547.             while (m) {
  548.                 fcp = mtod(m, caddr_t);
  549.                 while (m->m_len > 0) {
  550.                     if (mlen == 0) {
  551.                         MGET(m2, M_WAIT, MT_DATA);
  552.                         if (len >= MINCLSIZE)
  553.                             MCLGET(m2, M_WAIT);
  554.                         m2->m_len = 0;
  555.                         mlen = M_TRAILINGSPACE(m2);
  556.                         tcp = mtod(m2, caddr_t);
  557.                         *mbp = m2;
  558.                         mbp = &m2->m_next;
  559.                     }
  560.                     siz = MIN(mlen, m->m_len);
  561.                     bcopy(fcp, tcp, siz);
  562.                     m2->m_len += siz;
  563.                     mlen -= siz;
  564.                     len -= siz;
  565.                     tcp += siz;
  566.                     m->m_len -= siz;
  567.                     fcp += siz;
  568.                 }
  569.                 MFREE(m, mnew);
  570.                 m = mnew;
  571.             }
  572.             break;
  573.         }
  574.         len -= m->m_len;
  575.         mbp = &m->m_next;
  576.         m = m->m_next;
  577.     }
  578.     return (error);
  579. }
  580.  
  581. /*
  582.  * Implement receipt of reply on a socket.
  583.  * We must search through the list of received datagrams matching them
  584.  * with outstanding requests using the xid, until ours is found.
  585.  */
  586. /* ARGSUSED */
  587. nfs_reply(nmp, myrep)
  588.     struct nfsmount *nmp;
  589.     struct nfsreq *myrep;
  590. {
  591.     register struct mbuf *m;
  592.     register struct nfsreq *rep;
  593.     register int error = 0;
  594.     u_long rxid;
  595.     struct mbuf *mp, *nam;
  596.     char *cp;
  597.     int cnt, xfer;
  598.  
  599.     /*
  600.      * Loop around until we get our own reply
  601.      */
  602.     for (;;) {
  603.         /*
  604.          * Lock against other receivers so that I don't get stuck in
  605.          * sbwait() after someone else has received my reply for me.
  606.          * Also necessary for connection based protocols to avoid
  607.          * race conditions during a reconnect.
  608.          */
  609.         nfs_solock(&nmp->nm_flag);
  610.         /* Already received, bye bye */
  611.         if (myrep->r_mrep != NULL) {
  612.             nfs_sounlock(&nmp->nm_flag);
  613.             return (0);
  614.         }
  615.         /*
  616.          * Get the next Rpc reply off the socket
  617.          */
  618.         if (error = nfs_receive(nmp->nm_so, &nam, &mp, myrep)) {
  619.             nfs_sounlock(&nmp->nm_flag);
  620.  
  621.             /*
  622.              * Ignore routing errors on connectionless protocols??
  623.              */
  624.             if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
  625.                 nmp->nm_so->so_error = 0;
  626.                 continue;
  627.             }
  628.  
  629.             /*
  630.              * Otherwise cleanup and return a fatal error.
  631.              */
  632.             if (myrep->r_flags & R_TIMING) {
  633.                 myrep->r_flags &= ~R_TIMING;
  634.                 nmp->nm_rtt = -1;
  635.             }
  636.             if (myrep->r_flags & R_SENT) {
  637.                 myrep->r_flags &= ~R_SENT;
  638.                 nmp->nm_sent--;
  639.             }
  640.             return (error);
  641.         }
  642.     
  643.         /*
  644.          * Get the xid and check that it is an rpc reply
  645.          */
  646.         m = mp;
  647.         while (m && m->m_len == 0)
  648.             m = m->m_next;
  649.         if (m == NULL) {
  650.             nfsstats.rpcinvalid++;
  651.             m_freem(mp);
  652.             nfs_sounlock(&nmp->nm_flag);
  653.             continue;
  654.         }
  655.         bcopy(mtod(m, caddr_t), (caddr_t)&rxid, NFSX_UNSIGNED);
  656.         /*
  657.          * Loop through the request list to match up the reply
  658.          * Iff no match, just drop the datagram
  659.          */
  660.         m = mp;
  661.         rep = nfsreqh.r_next;
  662.         while (rep != &nfsreqh) {
  663.             if (rep->r_mrep == NULL && rxid == rep->r_xid) {
  664.                 /* Found it.. */
  665.                 rep->r_mrep = m;
  666.                 /*
  667.                  * Update timing
  668.                  */
  669.                 if (rep->r_flags & R_TIMING) {
  670.                     nfs_updatetimer(rep->r_nmp);
  671.                     rep->r_flags &= ~R_TIMING;
  672.                     rep->r_nmp->nm_rtt = -1;
  673.                 }
  674.                 if (rep->r_flags & R_SENT) {
  675.                     rep->r_flags &= ~R_SENT;
  676.                     rep->r_nmp->nm_sent--;
  677.                 }
  678.                 break;
  679.             }
  680.             rep = rep->r_next;
  681.         }
  682.         nfs_sounlock(&nmp->nm_flag);
  683.         if (nam)
  684.             m_freem(nam);
  685.         /*
  686.          * If not matched to a request, drop it.
  687.          * If it's mine, get out.
  688.          */
  689.         if (rep == &nfsreqh) {
  690.             nfsstats.rpcunexpected++;
  691.             m_freem(m);
  692.         } else if (rep == myrep)
  693.             return (0);
  694.     }
  695. }
  696.  
  697. /*
  698.  * nfs_request - goes something like this
  699.  *    - fill in request struct
  700.  *    - links it into list
  701.  *    - calls nfs_send() for first transmit
  702.  *    - calls nfs_receive() to get reply
  703.  *    - break down rpc header and return with nfs reply pointed to
  704.  *      by mrep or error
  705.  * nb: always frees up mreq mbuf list
  706.  */
  707. nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
  708.     struct vnode *vp;
  709.     struct mbuf *mreq;
  710.     u_long xid;
  711.     int procnum;
  712.     struct proc *procp;
  713.     int tryhard;
  714.     struct mount *mp;
  715.     struct mbuf **mrp;
  716.     struct mbuf **mdp;
  717.     caddr_t *dposp;
  718. {
  719.     register struct mbuf *m, *mrep;
  720.     register struct nfsreq *rep;
  721.     register u_long *tl;
  722.     register int len;
  723.     struct nfsmount *nmp;
  724.     struct mbuf *md;
  725.     struct nfsreq *reph;
  726.     caddr_t dpos;
  727.     char *cp2;
  728.     int t1;
  729.     int s, compressed;
  730.     int error = 0;
  731.  
  732.     nmp = VFSTONFS(mp);
  733.     m = mreq;
  734.     MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
  735.     rep->r_xid = xid;
  736.     rep->r_nmp = nmp;
  737.     rep->r_vp = vp;
  738.     rep->r_procp = procp;
  739.     if ((nmp->nm_flag & NFSMNT_SOFT) ||
  740.         ((nmp->nm_flag & NFSMNT_SPONGY) && !tryhard))
  741.         rep->r_retry = nmp->nm_retry;
  742.     else
  743.         rep->r_retry = NFS_MAXREXMIT + 1;    /* past clip limit */
  744.     rep->r_flags = rep->r_rexmit = 0;
  745.     /*
  746.      * Three cases:
  747.      * - non-idempotent requests on SOCK_DGRAM use NFS_MINIDEMTIMEO
  748.      * - idempotent requests on SOCK_DGRAM use 0
  749.      * - Reliable transports, NFS_RELIABLETIMEO
  750.      *   Timeouts are still done on reliable transports to ensure detection
  751.      *   of excessive connection delay.
  752.      */
  753.     if (nmp->nm_sotype != SOCK_DGRAM)
  754.         rep->r_timerinit = -NFS_RELIABLETIMEO;
  755.     else if (nonidempotent[procnum])
  756.         rep->r_timerinit = -NFS_MINIDEMTIMEO;
  757.     else
  758.         rep->r_timerinit = 0;
  759.     rep->r_timer = rep->r_timerinit;
  760.     rep->r_mrep = NULL;
  761.     len = 0;
  762.     while (m) {
  763.         len += m->m_len;
  764.         m = m->m_next;
  765.     }
  766.     mreq->m_pkthdr.len = len;
  767.     mreq->m_pkthdr.rcvif = (struct ifnet *)0;
  768.     compressed = 0;
  769.     m = mreq;
  770.     if ((nmp->nm_flag & NFSMNT_COMPRESS) && compressrequest[procnum]) {
  771.         mreq = nfs_compress(mreq);
  772.         if (mreq != m) {
  773.             len = mreq->m_pkthdr.len;
  774.             compressed++;
  775.         }
  776.     }
  777.     /*
  778.      * For non-atomic protocols, insert a Sun RPC Record Mark.
  779.      */
  780.     if ((nmp->nm_soflags & PR_ATOMIC) == 0) {
  781.         M_PREPEND(mreq, sizeof(u_long), M_WAIT);
  782.         *mtod(mreq, u_long *) = htonl(0x80000000 | len);
  783.     }
  784.     rep->r_mreq = mreq;
  785.  
  786.     /*
  787.      * Do the client side RPC.
  788.      */
  789.     nfsstats.rpcrequests++;
  790.     /*
  791.      * Chain request into list of outstanding requests. Be sure
  792.      * to put it LAST so timer finds oldest requests first.
  793.      */
  794.     s = splnet();
  795.     reph = &nfsreqh;
  796.     reph->r_prev->r_next = rep;
  797.     rep->r_prev = reph->r_prev;
  798.     reph->r_prev = rep;
  799.     rep->r_next = reph;
  800.     /*
  801.      * If backing off another request or avoiding congestion, don't
  802.      * send this one now but let timer do it. If not timing a request,
  803.      * do it now.
  804.      */
  805.     if (nmp->nm_sent <= 0 || nmp->nm_sotype != SOCK_DGRAM ||
  806.         (nmp->nm_currexmit == 0 && nmp->nm_sent < nmp->nm_window)) {
  807.         nmp->nm_sent++;
  808.         rep->r_flags |= R_SENT;
  809.         if (nmp->nm_rtt == -1) {
  810.             nmp->nm_rtt = 0;
  811.             rep->r_flags |= R_TIMING;
  812.         }
  813.         splx(s);
  814.         m = m_copym(mreq, 0, M_COPYALL, M_WAIT);
  815.         if (nmp->nm_soflags & PR_CONNREQUIRED)
  816.             nfs_solock(&nmp->nm_flag);
  817.         error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
  818.         if (nmp->nm_soflags & PR_CONNREQUIRED)
  819.             nfs_sounlock(&nmp->nm_flag);
  820.         if (error && NFSIGNORE_SOERROR(nmp->nm_soflags, error))
  821.             nmp->nm_so->so_error = error = 0;
  822.     } else
  823.         splx(s);
  824.  
  825.     /*
  826.      * Wait for the reply from our send or the timer's.
  827.      */
  828.     if (!error)
  829.         error = nfs_reply(nmp, rep);
  830.  
  831.     /*
  832.      * RPC done, unlink the request.
  833.      */
  834.     s = splnet();
  835.     rep->r_prev->r_next = rep->r_next;
  836.     rep->r_next->r_prev = rep->r_prev;
  837.     splx(s);
  838.  
  839.     /*
  840.      * If there was a successful reply and a tprintf msg.
  841.      * tprintf a response.
  842.      */
  843.     if (!error && (rep->r_flags & R_TPRINTFMSG))
  844.         nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
  845.             "is alive again");
  846.     m_freem(rep->r_mreq);
  847.     mrep = rep->r_mrep;
  848.     FREE((caddr_t)rep, M_NFSREQ);
  849.     if (error)
  850.         return (error);
  851.  
  852.     if (compressed)
  853.         mrep = nfs_uncompress(mrep);
  854.     md = mrep;
  855.     /*
  856.      * break down the rpc header and check if ok
  857.      */
  858.     dpos = mtod(md, caddr_t);
  859.     nfsm_disect(tl, u_long *, 5*NFSX_UNSIGNED);
  860.     tl += 2;
  861.     if (*tl++ == rpc_msgdenied) {
  862.         if (*tl == rpc_mismatch)
  863.             error = EOPNOTSUPP;
  864.         else
  865.             error = EACCES;
  866.         m_freem(mrep);
  867.         return (error);
  868.     }
  869.     /*
  870.      * skip over the auth_verf, someday we may want to cache auth_short's
  871.      * for nfs_reqhead(), but for now just dump it
  872.      */
  873.     if (*++tl != 0) {
  874.         len = nfsm_rndup(fxdr_unsigned(long, *tl));
  875.         nfsm_adv(len);
  876.     }
  877.     nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
  878.     /* 0 == ok */
  879.     if (*tl == 0) {
  880.         nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
  881.         if (*tl != 0) {
  882.             error = fxdr_unsigned(int, *tl);
  883.             m_freem(mrep);
  884.             return (error);
  885.         }
  886.         *mrp = mrep;
  887.         *mdp = md;
  888.         *dposp = dpos;
  889.         return (0);
  890.     }
  891.     m_freem(mrep);
  892.     return (EPROTONOSUPPORT);
  893. nfsmout:
  894.     return (error);
  895. }
  896.  
  897. /*
  898.  * Get a request for the server main loop
  899.  * - receive a request via. nfs_soreceive()
  900.  * - verify it
  901.  * - fill in the cred struct.
  902.  */
  903. nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
  904.     msk, mtch, wascomp)
  905.     struct socket *so;
  906.     u_long prog;
  907.     u_long vers;
  908.     int maxproc;
  909.     struct mbuf **nam;
  910.     struct mbuf **mrp;
  911.     struct mbuf **mdp;
  912.     caddr_t *dposp;
  913.     u_long *retxid;
  914.     u_long *procnum;
  915.     register struct ucred *cr;
  916.     struct mbuf *msk, *mtch;
  917.     int *wascomp;
  918. {
  919.     register int i;
  920.     register u_long *tl;
  921.     register long t1;
  922.     caddr_t dpos, cp2;
  923.     int error = 0;
  924.     struct mbuf *mrep, *md;
  925.     int len;
  926.  
  927.     if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
  928.         error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
  929.     } else {
  930.         mrep = (struct mbuf *)0;
  931.         do {
  932.             if (mrep) {
  933.                 m_freem(*nam);
  934.                 m_freem(mrep);
  935.             }
  936.             error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
  937.         } while (!error && nfs_badnam(*nam, msk, mtch));
  938.     }
  939.     if (error)
  940.         return (error);
  941.     md = mrep;
  942.     mrep = nfs_uncompress(mrep);
  943.     if (mrep != md) {
  944.         *wascomp = 1;
  945.         md = mrep;
  946.     } else
  947.         *wascomp = 0;
  948.     dpos = mtod(mrep, caddr_t);
  949.     nfsm_disect(tl, u_long *, 10*NFSX_UNSIGNED);
  950.     *retxid = *tl++;
  951.     if (*tl++ != rpc_call) {
  952.         m_freem(mrep);
  953.         return (ERPCMISMATCH);
  954.     }
  955.     if (*tl++ != rpc_vers) {
  956.         m_freem(mrep);
  957.         return (ERPCMISMATCH);
  958.     }
  959.     if (*tl++ != prog) {
  960.         m_freem(mrep);
  961.         return (EPROGUNAVAIL);
  962.     }
  963.     if (*tl++ != vers) {
  964.         m_freem(mrep);
  965.         return (EPROGMISMATCH);
  966.     }
  967.     *procnum = fxdr_unsigned(u_long, *tl++);
  968.     if (*procnum == NFSPROC_NULL) {
  969.         *mrp = mrep;
  970.         return (0);
  971.     }
  972.     if (*procnum > maxproc || *tl++ != rpc_auth_unix) {
  973.         m_freem(mrep);
  974.         return (EPROCUNAVAIL);
  975.     }
  976.     len = fxdr_unsigned(int, *tl++);
  977.     if (len < 0 || len > RPCAUTH_MAXSIZ) {
  978.         m_freem(mrep);
  979.         return (EBADRPC);
  980.     }
  981.     len = fxdr_unsigned(int, *++tl);
  982.     if (len < 0 || len > NFS_MAXNAMLEN) {
  983.         m_freem(mrep);
  984.         return (EBADRPC);
  985.     }
  986.     nfsm_adv(nfsm_rndup(len));
  987.     nfsm_disect(tl, u_long *, 3*NFSX_UNSIGNED);
  988.     cr->cr_uid = fxdr_unsigned(uid_t, *tl++);
  989.     cr->cr_gid = fxdr_unsigned(gid_t, *tl++);
  990.     len = fxdr_unsigned(int, *tl);
  991.     if (len < 0 || len > RPCAUTH_UNIXGIDS) {
  992.         m_freem(mrep);
  993.         return (EBADRPC);
  994.     }
  995.     nfsm_disect(tl, u_long *, (len + 2)*NFSX_UNSIGNED);
  996.     for (i = 1; i <= len; i++)
  997.         if (i < NGROUPS)
  998.             cr->cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
  999.         else
  1000.             tl++;
  1001.     cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
  1002.     /*
  1003.      * Do we have any use for the verifier.
  1004.      * According to the "Remote Procedure Call Protocol Spec." it
  1005.      * should be AUTH_NULL, but some clients make it AUTH_UNIX?
  1006.      * For now, just skip over it
  1007.      */
  1008.     len = fxdr_unsigned(int, *++tl);
  1009.     if (len < 0 || len > RPCAUTH_MAXSIZ) {
  1010.         m_freem(mrep);
  1011.         return (EBADRPC);
  1012.     }
  1013.     if (len > 0)
  1014.         nfsm_adv(nfsm_rndup(len));
  1015.     *mrp = mrep;
  1016.     *mdp = md;
  1017.     *dposp = dpos;
  1018.     return (0);
  1019. nfsmout:
  1020.     return (error);
  1021. }
  1022.  
  1023. /*
  1024.  * Generate the rpc reply header
  1025.  * siz arg. is used to decide if adding a cluster is worthwhile
  1026.  */
  1027. nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
  1028.     int siz;
  1029.     u_long retxid;
  1030.     int err;
  1031.     struct mbuf **mrq;
  1032.     struct mbuf **mbp;
  1033.     caddr_t *bposp;
  1034. {
  1035.     register u_long *tl;
  1036.     register long t1;
  1037.     caddr_t bpos;
  1038.     struct mbuf *mreq, *mb, *mb2;
  1039.  
  1040.     NFSMGETHDR(mreq);
  1041.     mb = mreq;
  1042.     if ((siz+RPC_REPLYSIZ) > MHLEN)
  1043.         MCLGET(mreq, M_WAIT);
  1044.     tl = mtod(mreq, u_long *);
  1045.     mreq->m_len = 6*NFSX_UNSIGNED;
  1046.     bpos = ((caddr_t)tl)+mreq->m_len;
  1047.     *tl++ = retxid;
  1048.     *tl++ = rpc_reply;
  1049.     if (err == ERPCMISMATCH) {
  1050.         *tl++ = rpc_msgdenied;
  1051.         *tl++ = rpc_mismatch;
  1052.         *tl++ = txdr_unsigned(2);
  1053.         *tl = txdr_unsigned(2);
  1054.     } else {
  1055.         *tl++ = rpc_msgaccepted;
  1056.         *tl++ = 0;
  1057.         *tl++ = 0;
  1058.         switch (err) {
  1059.         case EPROGUNAVAIL:
  1060.             *tl = txdr_unsigned(RPC_PROGUNAVAIL);
  1061.             break;
  1062.         case EPROGMISMATCH:
  1063.             *tl = txdr_unsigned(RPC_PROGMISMATCH);
  1064.             nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
  1065.             *tl++ = txdr_unsigned(2);
  1066.             *tl = txdr_unsigned(2);    /* someday 3 */
  1067.             break;
  1068.         case EPROCUNAVAIL:
  1069.             *tl = txdr_unsigned(RPC_PROCUNAVAIL);
  1070.             break;
  1071.         default:
  1072.             *tl = 0;
  1073.             if (err != VNOVAL) {
  1074.                 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
  1075.                 *tl = txdr_unsigned(err);
  1076.             }
  1077.             break;
  1078.         };
  1079.     }
  1080.     *mrq = mreq;
  1081.     *mbp = mb;
  1082.     *bposp = bpos;
  1083.     if (err != 0 && err != VNOVAL)
  1084.         nfsstats.srvrpc_errs++;
  1085.     return (0);
  1086. }
  1087.  
  1088. /*
  1089.  * Nfs timer routine
  1090.  * Scan the nfsreq list and retranmit any requests that have timed out
  1091.  * To avoid retransmission attempts on STREAM sockets (in the future) make
  1092.  * sure to set the r_retry field to 0 (implies nm_retry == 0).
  1093.  */
  1094. nfs_timer()
  1095. {
  1096.     register struct nfsreq *rep;
  1097.     register struct mbuf *m;
  1098.     register struct socket *so;
  1099.     register struct nfsmount *nmp;
  1100.     int s, error;
  1101.  
  1102.     s = splnet();
  1103.     for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) {
  1104.         nmp = rep->r_nmp;
  1105.         if (rep->r_mrep || (rep->r_flags & R_SOFTTERM) ||
  1106.             (so = nmp->nm_so) == NULL)
  1107.             continue;
  1108.         if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp)) {
  1109.             rep->r_flags |= R_SOFTTERM;
  1110.             continue;
  1111.         }
  1112.         if (rep->r_flags & R_TIMING)    /* update rtt in mount */
  1113.             nmp->nm_rtt++;
  1114.         /* If not timed out */
  1115.         if (++rep->r_timer < nmp->nm_rto)
  1116.             continue;
  1117.         /* Do backoff and save new timeout in mount */
  1118.         if (rep->r_flags & R_TIMING) {
  1119.             nfs_backofftimer(nmp);
  1120.             rep->r_flags &= ~R_TIMING;
  1121.             nmp->nm_rtt = -1;
  1122.         }
  1123.         if (rep->r_flags & R_SENT) {
  1124.             rep->r_flags &= ~R_SENT;
  1125.             nmp->nm_sent--;
  1126.         }
  1127.  
  1128.         /*
  1129.          * Check for too many retries on soft mount.
  1130.          * nb: For hard mounts, r_retry == NFS_MAXREXMIT+1
  1131.          */
  1132.         if (++rep->r_rexmit > NFS_MAXREXMIT)
  1133.             rep->r_rexmit = NFS_MAXREXMIT;
  1134.  
  1135.         /*
  1136.          * Check for server not responding
  1137.          */
  1138.         if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
  1139.              rep->r_rexmit > NFS_FISHY) {
  1140.             nfs_msg(rep->r_procp,
  1141.                 nmp->nm_mountp->mnt_stat.f_mntfromname,
  1142.                 "not responding");
  1143.             rep->r_flags |= R_TPRINTFMSG;
  1144.         }
  1145.         if (rep->r_rexmit >= rep->r_retry) {    /* too many */
  1146.             nfsstats.rpctimeouts++;
  1147.             rep->r_flags |= R_SOFTTERM;
  1148.             continue;
  1149.         }
  1150.         if (nmp->nm_sotype != SOCK_DGRAM)
  1151.             continue;
  1152.  
  1153.         /*
  1154.          * If there is enough space and the window allows..
  1155.          *    Resend it
  1156.          */
  1157.         if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
  1158.                nmp->nm_sent < nmp->nm_window &&
  1159.                (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
  1160.             nfsstats.rpcretries++;
  1161.             if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
  1162.                 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
  1163.                 (caddr_t)0, (struct mbuf *)0, (struct mbuf *)0);
  1164.             else
  1165.                 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
  1166.                 nmp->nm_nam, (struct mbuf *)0, (struct mbuf *)0);
  1167.             if (error) {
  1168.                 if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
  1169.                     so->so_error = 0;
  1170.             } else {
  1171.                 /*
  1172.                  * We need to time the request even though we
  1173.                  * are retransmitting.
  1174.                  */
  1175.                 nmp->nm_rtt = 0;
  1176.                 nmp->nm_sent++;
  1177.                 rep->r_flags |= (R_SENT|R_TIMING);
  1178.                 rep->r_timer = rep->r_timerinit;
  1179.             }
  1180.         }
  1181.     }
  1182.     splx(s);
  1183.     timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ);
  1184. }
  1185.  
  1186. /*
  1187.  * NFS timer update and backoff. The "Jacobson/Karels/Karn" scheme is
  1188.  * used here. The timer state is held in the nfsmount structure and
  1189.  * a single request is used to clock the response. When successful
  1190.  * the rtt smoothing in nfs_updatetimer is used, when failed the backoff
  1191.  * is done by nfs_backofftimer. We also log failure messages in these
  1192.  * routines.
  1193.  *
  1194.  * Congestion variables are held in the nfshost structure which
  1195.  * is referenced by nfsmounts and shared per-server. This separation
  1196.  * makes it possible to do per-mount timing which allows varying disk
  1197.  * access times to be dealt with, while preserving a network oriented
  1198.  * congestion control scheme.
  1199.  *
  1200.  * The windowing implements the Jacobson/Karels slowstart algorithm
  1201.  * with adjusted scaling factors. We start with one request, then send
  1202.  * 4 more after each success until the ssthresh limit is reached, then
  1203.  * we increment at a rate proportional to the window. On failure, we
  1204.  * remember 3/4 the current window and clamp the send limit to 1. Note
  1205.  * ICMP source quench is not reflected in so->so_error so we ignore that
  1206.  * for now.
  1207.  *
  1208.  * NFS behaves much more like a transport protocol with these changes,
  1209.  * shedding the teenage pedal-to-the-metal tendencies of "other"
  1210.  * implementations.
  1211.  *
  1212.  * Timers and congestion avoidance by Tom Talpey, Open Software Foundation.
  1213.  */
  1214.  
  1215. /*
  1216.  * The TCP algorithm was not forgiving enough. Because the NFS server
  1217.  * responds only after performing lookups/diskio/etc, we have to be
  1218.  * more prepared to accept a spiky variance. The TCP algorithm is:
  1219.  * TCP_RTO(nmp) ((((nmp)->nm_srtt >> 2) + (nmp)->nm_rttvar) >> 1)
  1220.  */
  1221. #define NFS_RTO(nmp)    (((nmp)->nm_srtt >> 3) + (nmp)->nm_rttvar)
  1222.  
  1223. nfs_updatetimer(nmp)
  1224.     register struct nfsmount *nmp;
  1225. {
  1226.  
  1227.     /* If retransmitted, clear and return */
  1228.     if (nmp->nm_rexmit || nmp->nm_currexmit) {
  1229.         nmp->nm_rexmit = nmp->nm_currexmit = 0;
  1230.         return;
  1231.     }
  1232.     /* If have a measurement, do smoothing */
  1233.     if (nmp->nm_srtt) {
  1234.         register short delta;
  1235.         delta = nmp->nm_rtt - (nmp->nm_srtt >> 3);
  1236.         if ((nmp->nm_srtt += delta) <= 0)
  1237.             nmp->nm_srtt = 1;
  1238.         if (delta < 0)
  1239.             delta = -delta;
  1240.         delta -= (nmp->nm_rttvar >> 2);
  1241.         if ((nmp->nm_rttvar += delta) <= 0)
  1242.             nmp->nm_rttvar = 1;
  1243.     /* Else initialize */
  1244.     } else {
  1245.         nmp->nm_rttvar = nmp->nm_rtt << 1;
  1246.         if (nmp->nm_rttvar == 0) nmp->nm_rttvar = 2;
  1247.         nmp->nm_srtt = nmp->nm_rttvar << 2;
  1248.     }
  1249.     /* Compute new Retransmission TimeOut and clip */
  1250.     nmp->nm_rto = NFS_RTO(nmp);
  1251.     if (nmp->nm_rto < NFS_MINTIMEO)
  1252.         nmp->nm_rto = NFS_MINTIMEO;
  1253.     else if (nmp->nm_rto > NFS_MAXTIMEO)
  1254.         nmp->nm_rto = NFS_MAXTIMEO;
  1255.  
  1256.     /* Update window estimate */
  1257.     if (nmp->nm_window < nmp->nm_ssthresh)    /* quickly */
  1258.         nmp->nm_window += 4;
  1259.     else {                        /* slowly */
  1260.         register long incr = ++nmp->nm_winext;
  1261.         incr = (incr * incr) / nmp->nm_window;
  1262.         if (incr > 0) {
  1263.             nmp->nm_winext = 0;
  1264.             ++nmp->nm_window;
  1265.         }
  1266.     }
  1267.     if (nmp->nm_window > NFS_MAXWINDOW)
  1268.         nmp->nm_window = NFS_MAXWINDOW;
  1269. }
  1270.  
  1271. nfs_backofftimer(nmp)
  1272.     register struct nfsmount *nmp;
  1273. {
  1274.     register unsigned long newrto;
  1275.  
  1276.     /* Clip shift count */
  1277.     if (++nmp->nm_rexmit > 8 * sizeof nmp->nm_rto)
  1278.         nmp->nm_rexmit = 8 * sizeof nmp->nm_rto;
  1279.     /* Back off RTO exponentially */
  1280.     newrto = NFS_RTO(nmp);
  1281.     newrto <<= (nmp->nm_rexmit - 1);
  1282.     if (newrto == 0 || newrto > NFS_MAXTIMEO)
  1283.         newrto = NFS_MAXTIMEO;
  1284.     nmp->nm_rto = newrto;
  1285.  
  1286.     /* If too many retries, message, assume a bogus RTT and re-measure */
  1287.     if (nmp->nm_currexmit < nmp->nm_rexmit) {
  1288.         nmp->nm_currexmit = nmp->nm_rexmit;
  1289.         if (nmp->nm_currexmit >= nfsrexmtthresh) {
  1290.             if (nmp->nm_currexmit == nfsrexmtthresh) {
  1291.                 nmp->nm_rttvar += (nmp->nm_srtt >> 2);
  1292.                 nmp->nm_srtt = 0;
  1293.             }
  1294.         }
  1295.     }
  1296.     /* Close down window but remember this point (3/4 current) for later */
  1297.     nmp->nm_ssthresh = ((nmp->nm_window << 1) + nmp->nm_window) >> 2;
  1298.     nmp->nm_window = 1;
  1299.     nmp->nm_winext = 0;
  1300. }
  1301.  
  1302. /*
  1303.  * Test for a termination signal pending on procp.
  1304.  * This is used for NFSMNT_INT mounts.
  1305.  */
  1306. nfs_sigintr(p)
  1307.     register struct proc *p;
  1308. {
  1309.     if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) &
  1310.         NFSINT_SIGMASK))
  1311.         return (1);
  1312.     else
  1313.         return (0);
  1314. }
  1315.  
  1316. nfs_msg(p, server, msg)
  1317.     struct proc *p;
  1318.     char *server, *msg;
  1319. {
  1320.     tpr_t tpr;
  1321.  
  1322.     if (p)
  1323.         tpr = tprintf_open(p);
  1324.     else
  1325.         tpr = NULL;
  1326.     tprintf(tpr, "nfs server %s: %s\n", server, msg);
  1327.     tprintf_close(tpr);
  1328. }
  1329.  
  1330. /*
  1331.  * Lock a socket against others.
  1332.  * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
  1333.  * and also to avoid race conditions between the processes with nfs requests
  1334.  * in progress when a reconnect is necessary.
  1335.  */
  1336. nfs_solock(flagp)
  1337.     register int *flagp;
  1338. {
  1339.  
  1340.     while (*flagp & NFSMNT_SCKLOCK) {
  1341.         *flagp |= NFSMNT_WANTSCK;
  1342.         (void) tsleep((caddr_t)flagp, PZERO-1, "nfsolck", 0);
  1343.     }
  1344.     *flagp |= NFSMNT_SCKLOCK;
  1345. }
  1346.  
  1347. /*
  1348.  * Unlock the stream socket for others.
  1349.  */
  1350. nfs_sounlock(flagp)
  1351.     register int *flagp;
  1352. {
  1353.  
  1354.     if ((*flagp & NFSMNT_SCKLOCK) == 0)
  1355.         panic("nfs sounlock");
  1356.     *flagp &= ~NFSMNT_SCKLOCK;
  1357.     if (*flagp & NFSMNT_WANTSCK) {
  1358.         *flagp &= ~NFSMNT_WANTSCK;
  1359.         wakeup((caddr_t)flagp);
  1360.     }
  1361. }
  1362.  
  1363. /*
  1364.  * This function compares two net addresses by family and returns TRUE
  1365.  * if they are the same.
  1366.  * If there is any doubt, return FALSE.
  1367.  */
  1368. nfs_netaddr_match(nam1, nam2)
  1369.     struct mbuf *nam1, *nam2;
  1370. {
  1371.     register struct sockaddr *saddr1, *saddr2;
  1372.  
  1373.     saddr1 = mtod(nam1, struct sockaddr *);
  1374.     saddr2 = mtod(nam2, struct sockaddr *);
  1375.     if (saddr1->sa_family != saddr2->sa_family)
  1376.         return (0);
  1377.  
  1378.     /*
  1379.      * Must do each address family separately since unused fields
  1380.      * are undefined values and not always zeroed.
  1381.      */
  1382.     switch (saddr1->sa_family) {
  1383.     case AF_INET:
  1384.         if (((struct sockaddr_in *)saddr1)->sin_addr.s_addr ==
  1385.             ((struct sockaddr_in *)saddr2)->sin_addr.s_addr)
  1386.             return (1);
  1387.         break;
  1388.     default:
  1389.         break;
  1390.     };
  1391.     return (0);
  1392. }
  1393.  
  1394. /*
  1395.  * Check the hostname fields for nfsd's mask and match fields.
  1396.  * By address family:
  1397.  * - Bitwise AND the mask with the host address field
  1398.  * - Compare for == with match
  1399.  * return TRUE if not equal
  1400.  */
  1401. nfs_badnam(nam, msk, mtch)
  1402.     register struct mbuf *nam, *msk, *mtch;
  1403. {
  1404.     switch (mtod(nam, struct sockaddr *)->sa_family) {
  1405.     case AF_INET:
  1406.         return ((mtod(nam, struct sockaddr_in *)->sin_addr.s_addr &
  1407.              mtod(msk, struct sockaddr_in *)->sin_addr.s_addr) !=
  1408.              mtod(mtch, struct sockaddr_in *)->sin_addr.s_addr);
  1409.     default:
  1410.         printf("nfs_badmatch, unknown sa_family\n");
  1411.         return (0);
  1412.     };
  1413. }
  1414.