|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1989, 1991, 1993, 1995 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * This code is derived from software contributed to Berkeley by ! 31: * Rick Macklem at The University of Guelph. ! 32: * ! 33: * Redistribution and use in source and binary forms, with or without ! 34: * modification, are permitted provided that the following conditions ! 35: * are met: ! 36: * 1. Redistributions of source code must retain the above copyright ! 37: * notice, this list of conditions and the following disclaimer. ! 38: * 2. Redistributions in binary form must reproduce the above copyright ! 39: * notice, this list of conditions and the following disclaimer in the ! 40: * documentation and/or other materials provided with the distribution. ! 41: * 3. All advertising materials mentioning features or use of this software ! 42: * must display the following acknowledgement: ! 43: * This product includes software developed by the University of ! 44: * California, Berkeley and its contributors. ! 45: * 4. Neither the name of the University nor the names of its contributors ! 46: * may be used to endorse or promote products derived from this software ! 47: * without specific prior written permission. ! 48: * ! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 59: * SUCH DAMAGE. ! 60: * ! 61: * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 ! 62: * FreeBSD-Id: nfs_socket.c,v 1.30 1997/10/28 15:59:07 bde Exp $ ! 63: */ ! 64: ! 65: /* ! 66: * Socket operations for use by nfs ! 67: */ ! 68: ! 69: #include <sys/param.h> ! 70: #include <sys/systm.h> ! 71: #include <sys/proc.h> ! 72: #include <sys/mount.h> ! 73: #include <sys/kernel.h> ! 74: #include <sys/mbuf.h> ! 75: #include <sys/malloc.h> ! 76: #include <sys/vnode.h> ! 77: #include <sys/domain.h> ! 78: #include <sys/protosw.h> ! 79: #include <sys/socket.h> ! 80: #include <sys/socketvar.h> ! 81: #include <sys/syslog.h> ! 82: #include <sys/tprintf.h> ! 83: #include <machine/spl.h> ! 84: ! 85: #include <netinet/in.h> ! 86: #include <netinet/tcp.h> ! 87: ! 88: #include <nfs/rpcv2.h> ! 89: #include <nfs/nfsproto.h> ! 90: #include <nfs/nfs.h> ! 91: #include <nfs/xdr_subs.h> ! 92: #include <nfs/nfsm_subs.h> ! 93: #include <nfs/nfsmount.h> ! 94: #include <nfs/nfsnode.h> ! 95: #include <nfs/nfsrtt.h> ! 96: #include <nfs/nqnfs.h> ! 97: ! 98: #define TRUE 1 ! 99: #define FALSE 0 ! 100: ! 101: /* ! 102: * Estimate rto for an nfs rpc sent via. an unreliable datagram. ! 103: * Use the mean and mean deviation of rtt for the appropriate type of rpc ! 104: * for the frequent rpcs and a default for the others. ! 105: * The justification for doing "other" this way is that these rpcs ! 106: * happen so infrequently that timer est. would probably be stale. ! 107: * Also, since many of these rpcs are ! 108: * non-idempotent, a conservative timeout is desired. ! 109: * getattr, lookup - A+2D ! 110: * read, write - A+4D ! 111: * other - nm_timeo ! 112: */ ! 113: #define NFS_RTO(n, t) \ ! 114: ((t) == 0 ? (n)->nm_timeo : \ ! 115: ((t) < 3 ? \ ! 116: (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \ ! 117: ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1))) ! 118: #define NFS_SRTT(r) (r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1] ! 119: #define NFS_SDRTT(r) (r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1] ! 120: /* ! 121: * External data, mostly RPC constants in XDR form ! 122: */ ! 123: extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, ! 124: rpc_msgaccepted, rpc_call, rpc_autherr, ! 125: rpc_auth_kerb; ! 126: extern u_long nfs_prog, nqnfs_prog; ! 127: extern time_t nqnfsstarttime; ! 128: extern struct nfsstats nfsstats; ! 129: extern int nfsv3_procid[NFS_NPROCS]; ! 130: extern int nfs_ticks; ! 131: ! 132: /* ! 133: * Defines which timer to use for the procnum. ! 134: * 0 - default ! 135: * 1 - getattr ! 136: * 2 - lookup ! 137: * 3 - read ! 138: * 4 - write ! 139: */ ! 140: static int proct[NFS_NPROCS] = { ! 141: 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, ! 142: 0, 0, 0, ! 143: }; ! 144: ! 145: /* ! 146: * There is a congestion window for outstanding rpcs maintained per mount ! 147: * point. The cwnd size is adjusted in roughly the way that: ! 148: * Van Jacobson, Congestion avoidance and Control, In "Proceedings of ! 149: * SIGCOMM '88". ACM, August 1988. ! 150: * describes for TCP. The cwnd size is chopped in half on a retransmit timeout ! 151: * and incremented by 1/cwnd when each rpc reply is received and a full cwnd ! 152: * of rpcs is in progress. ! 153: * (The sent count and cwnd are scaled for integer arith.) ! 154: * Variants of "slow start" were tried and were found to be too much of a ! 155: * performance hit (ave. rtt 3 times larger), ! 156: * I suspect due to the large rtt that nfs rpcs have. ! 157: */ ! 158: #define NFS_CWNDSCALE 256 ! 159: #define NFS_MAXCWND (NFS_CWNDSCALE * 32) ! 160: static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, }; ! 161: int nfsrtton = 0; ! 162: struct nfsrtt nfsrtt; ! 163: ! 164: static int nfs_msg __P((struct proc *,char *,char *)); ! 165: static int nfs_rcvlock __P((struct nfsreq *)); ! 166: static void nfs_rcvunlock __P((int *flagp)); ! 167: static int nfs_receive __P((struct nfsreq *rep, struct mbuf **aname, ! 168: struct mbuf **mp)); ! 169: static int nfs_reconnect __P((struct nfsreq *rep)); ! 170: #ifndef NFS_NOSERVER ! 171: static int nfsrv_getstream __P((struct nfssvc_sock *,int)); ! 172: ! 173: int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd, ! 174: struct nfssvc_sock *slp, ! 175: struct proc *procp, ! 176: struct mbuf **mreqp)) = { ! 177: nfsrv_null, ! 178: nfsrv_getattr, ! 179: nfsrv_setattr, ! 180: nfsrv_lookup, ! 181: nfsrv3_access, ! 182: nfsrv_readlink, ! 183: nfsrv_read, ! 184: nfsrv_write, ! 185: nfsrv_create, ! 186: nfsrv_mkdir, ! 187: nfsrv_symlink, ! 188: nfsrv_mknod, ! 189: nfsrv_remove, ! 190: nfsrv_rmdir, ! 191: nfsrv_rename, ! 192: nfsrv_link, ! 193: nfsrv_readdir, ! 194: nfsrv_readdirplus, ! 195: nfsrv_statfs, ! 196: nfsrv_fsinfo, ! 197: nfsrv_pathconf, ! 198: nfsrv_commit, ! 199: nqnfsrv_getlease, ! 200: nqnfsrv_vacated, ! 201: nfsrv_noop, ! 202: nfsrv_noop ! 203: }; ! 204: #endif /* NFS_NOSERVER */ ! 205: ! 206: /* ! 207: * Initialize sockets and congestion for a new NFS connection. ! 208: * We do not free the sockaddr if error. ! 209: */ ! 210: int ! 211: nfs_connect(nmp, rep) ! 212: register struct nfsmount *nmp; ! 213: struct nfsreq *rep; ! 214: { ! 215: register struct socket *so; ! 216: int s, error, rcvreserve, sndreserve; ! 217: struct sockaddr *saddr; ! 218: struct sockaddr_in *sin; ! 219: struct mbuf *m; ! 220: u_short tport; ! 221: ! 222: nmp->nm_so = (struct socket *)0; ! 223: saddr = mtod(nmp->nm_nam, struct sockaddr *); ! 224: error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, ! 225: nmp->nm_soproto); ! 226: if (error) ! 227: goto bad; ! 228: so = nmp->nm_so; ! 229: nmp->nm_soflags = so->so_proto->pr_flags; ! 230: ! 231: /* ! 232: * Some servers require that the client port be a reserved port number. ! 233: */ ! 234: if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) { ! 235: MGET(m, M_WAIT, MT_SONAME); ! 236: sin = mtod(m, struct sockaddr_in *); ! 237: sin->sin_len = m->m_len = sizeof (struct sockaddr_in); ! 238: sin->sin_family = AF_INET; ! 239: sin->sin_addr.s_addr = INADDR_ANY; ! 240: tport = IPPORT_RESERVED - 1; ! 241: sin->sin_port = htons(tport); ! 242: while ((error = sobind(so, m)) == EADDRINUSE && ! 243: --tport > IPPORT_RESERVED / 2) ! 244: sin->sin_port = htons(tport); ! 245: m_freem(m); ! 246: if (error) ! 247: goto bad; ! 248: } ! 249: ! 250: /* ! 251: * Protocols that do not require connections may be optionally left ! 252: * unconnected for servers that reply from a port other than NFS_PORT. ! 253: */ ! 254: if (nmp->nm_flag & NFSMNT_NOCONN) { ! 255: if (nmp->nm_soflags & PR_CONNREQUIRED) { ! 256: error = ENOTCONN; ! 257: goto bad; ! 258: } ! 259: } else { ! 260: error = soconnect(so, nmp->nm_nam); ! 261: if (error) ! 262: goto bad; ! 263: ! 264: /* ! 265: * Wait for the connection to complete. Cribbed from the ! 266: * connect system call but with the wait timing out so ! 267: * that interruptible mounts don't hang here for a long time. ! 268: */ ! 269: s = splnet(); ! 270: while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { ! 271: (void) tsleep((caddr_t)&so->so_timeo, PSOCK, ! 272: "nfscon", 2 * hz); ! 273: if ((so->so_state & SS_ISCONNECTING) && ! 274: so->so_error == 0 && rep && ! 275: (error = nfs_sigintr(nmp, rep, rep->r_procp))) { ! 276: so->so_state &= ~SS_ISCONNECTING; ! 277: splx(s); ! 278: goto bad; ! 279: } ! 280: } ! 281: if (so->so_error) { ! 282: error = so->so_error; ! 283: so->so_error = 0; ! 284: splx(s); ! 285: goto bad; ! 286: } ! 287: splx(s); ! 288: } ! 289: if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) { ! 290: so->so_rcv.sb_timeo = (5 * hz); ! 291: so->so_snd.sb_timeo = (5 * hz); ! 292: } else { ! 293: so->so_rcv.sb_timeo = 0; ! 294: so->so_snd.sb_timeo = 0; ! 295: } ! 296: if (nmp->nm_sotype == SOCK_DGRAM) { ! 297: sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2; ! 298: rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2; ! 299: } else if (nmp->nm_sotype == SOCK_SEQPACKET) { ! 300: sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2; ! 301: rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2; ! 302: } else { ! 303: if (nmp->nm_sotype != SOCK_STREAM) ! 304: panic("nfscon sotype"); ! 305: if (so->so_proto->pr_flags & PR_CONNREQUIRED) { ! 306: MGET(m, M_WAIT, MT_SOOPTS); ! 307: *mtod(m, int *) = 1; ! 308: m->m_len = sizeof(int); ! 309: sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); ! 310: } ! 311: if (so->so_proto->pr_protocol == IPPROTO_TCP) { ! 312: MGET(m, M_WAIT, MT_SOOPTS); ! 313: *mtod(m, int *) = 1; ! 314: m->m_len = sizeof(int); ! 315: sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); ! 316: } ! 317: sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof (u_long)) ! 318: * 2; ! 319: rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_long)) ! 320: * 2; ! 321: } ! 322: error = soreserve(so, sndreserve, rcvreserve); ! 323: if (error) ! 324: goto bad; ! 325: so->so_rcv.sb_flags |= SB_NOINTR; ! 326: so->so_snd.sb_flags |= SB_NOINTR; ! 327: ! 328: /* Initialize other non-zero congestion variables */ ! 329: nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] = ! 330: nmp->nm_srtt[4] = (NFS_TIMEO << 3); ! 331: nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] = ! 332: nmp->nm_sdrtt[3] = nmp->nm_sdrtt[4] = 0; ! 333: nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */ ! 334: nmp->nm_sent = 0; ! 335: nmp->nm_timeouts = 0; ! 336: return (0); ! 337: ! 338: bad: ! 339: nfs_disconnect(nmp); ! 340: return (error); ! 341: } ! 342: ! 343: /* ! 344: * Reconnect routine: ! 345: * Called when a connection is broken on a reliable protocol. ! 346: * - clean up the old socket ! 347: * - nfs_connect() again ! 348: * - set R_MUSTRESEND for all outstanding requests on mount point ! 349: * If this fails the mount point is DEAD! ! 350: * nb: Must be called with the nfs_sndlock() set on the mount point. ! 351: */ ! 352: static int ! 353: nfs_reconnect(rep) ! 354: register struct nfsreq *rep; ! 355: { ! 356: register struct nfsreq *rp; ! 357: register struct nfsmount *nmp = rep->r_nmp; ! 358: int error; ! 359: ! 360: nfs_disconnect(nmp); ! 361: while ((error = nfs_connect(nmp, rep))) { ! 362: if (error == EINTR || error == ERESTART) ! 363: return (EINTR); ! 364: (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0); ! 365: } ! 366: ! 367: /* ! 368: * Loop through outstanding request list and fix up all requests ! 369: * on old socket. ! 370: */ ! 371: for (rp = nfs_reqq.tqh_first; rp != 0; rp = rp->r_chain.tqe_next) { ! 372: if (rp->r_nmp == nmp) ! 373: rp->r_flags |= R_MUSTRESEND; ! 374: } ! 375: return (0); ! 376: } ! 377: ! 378: /* ! 379: * NFS disconnect. Clean up and unlink. ! 380: */ ! 381: void ! 382: nfs_disconnect(nmp) ! 383: register struct nfsmount *nmp; ! 384: { ! 385: register struct socket *so; ! 386: ! 387: if (nmp->nm_so) { ! 388: so = nmp->nm_so; ! 389: nmp->nm_so = (struct socket *)0; ! 390: soshutdown(so, 2); ! 391: soclose(so); ! 392: } ! 393: } ! 394: ! 395: /* ! 396: * This is the nfs send routine. For connection based socket types, it ! 397: * must be called with an nfs_sndlock() on the socket. ! 398: * "rep == NULL" indicates that it has been called from a server. ! 399: * For the client side: ! 400: * - return EINTR if the RPC is terminated, 0 otherwise ! 401: * - set R_MUSTRESEND if the send fails for any reason ! 402: * - do any cleanup required by recoverable socket errors (???) ! 403: * For the server side: ! 404: * - return EINTR or ERESTART if interrupted by a signal ! 405: * - return EPIPE if a connection is lost for connection based sockets (TCP...) ! 406: * - do any cleanup required by recoverable socket errors (???) ! 407: */ ! 408: int ! 409: nfs_send(so, nam, top, rep) ! 410: register struct socket *so; ! 411: struct mbuf *nam; ! 412: register struct mbuf *top; ! 413: struct nfsreq *rep; ! 414: { ! 415: struct mbuf *sendnam; ! 416: int error, soflags, flags; ! 417: ! 418: if (rep) { ! 419: if (rep->r_flags & R_SOFTTERM) { ! 420: m_freem(top); ! 421: return (EINTR); ! 422: } ! 423: if ((so = rep->r_nmp->nm_so) == NULL) { ! 424: rep->r_flags |= R_MUSTRESEND; ! 425: m_freem(top); ! 426: return (0); ! 427: } ! 428: rep->r_flags &= ~R_MUSTRESEND; ! 429: soflags = rep->r_nmp->nm_soflags; ! 430: } else ! 431: soflags = so->so_proto->pr_flags; ! 432: if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) ! 433: sendnam = (struct mbuf *)0; ! 434: else ! 435: sendnam = nam; ! 436: if (so->so_type == SOCK_SEQPACKET) ! 437: flags = MSG_EOR; ! 438: else ! 439: flags = 0; ! 440: ! 441: error = sosend(so, sendnam, (struct uio *)0, top, ! 442: (struct mbuf *)0, flags); ! 443: if (error) { ! 444: if (rep) { ! 445: log(LOG_INFO, "nfs send error %d for server %s\n", ! 446: error, ! 447: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 448: /* ! 449: * Deal with errors for the client side. ! 450: */ ! 451: if (rep->r_flags & R_SOFTTERM) ! 452: error = EINTR; ! 453: else ! 454: rep->r_flags |= R_MUSTRESEND; ! 455: } else ! 456: log(LOG_INFO, "nfsd send error %d\n", error); ! 457: ! 458: /* ! 459: * Handle any recoverable (soft) socket errors here. (???) ! 460: */ ! 461: if (error != EINTR && error != ERESTART && ! 462: error != EWOULDBLOCK && error != EPIPE) ! 463: error = 0; ! 464: } ! 465: return (error); ! 466: } ! 467: ! 468: /* ! 469: * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all ! 470: * done by soreceive(), but for SOCK_STREAM we must deal with the Record ! 471: * Mark and consolidate the data into a new mbuf list. ! 472: * nb: Sometimes TCP passes the data up to soreceive() in long lists of ! 473: * small mbufs. ! 474: * For SOCK_STREAM we must be very careful to read an entire record once ! 475: * we have read any of it, even if the system call has been interrupted. ! 476: */ ! 477: static int ! 478: nfs_receive(rep, aname, mp) ! 479: register struct nfsreq *rep; ! 480: struct mbuf **aname; ! 481: struct mbuf **mp; ! 482: { ! 483: register struct socket *so; ! 484: struct uio auio; ! 485: struct iovec aio; ! 486: register struct mbuf *m; ! 487: struct mbuf *control; ! 488: u_long len; ! 489: struct mbuf **getnam; ! 490: int error, sotype, rcvflg; ! 491: struct proc *p = current_proc(); /* XXX */ ! 492: ! 493: /* ! 494: * Set up arguments for soreceive() ! 495: */ ! 496: *mp = (struct mbuf *)0; ! 497: *aname = (struct mbuf *)0; ! 498: sotype = rep->r_nmp->nm_sotype; ! 499: ! 500: /* ! 501: * For reliable protocols, lock against other senders/receivers ! 502: * in case a reconnect is necessary. ! 503: * For SOCK_STREAM, first get the Record Mark to find out how much ! 504: * more there is to get. ! 505: * We must lock the socket against other receivers ! 506: * until we have an entire rpc request/reply. ! 507: */ ! 508: if (sotype != SOCK_DGRAM) { ! 509: error = nfs_sndlock(&rep->r_nmp->nm_flag, rep); ! 510: if (error) ! 511: return (error); ! 512: tryagain: ! 513: /* ! 514: * Check for fatal errors and resending request. ! 515: */ ! 516: /* ! 517: * Ugh: If a reconnect attempt just happened, nm_so ! 518: * would have changed. NULL indicates a failed ! 519: * attempt that has essentially shut down this ! 520: * mount point. ! 521: */ ! 522: if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) { ! 523: nfs_sndunlock(&rep->r_nmp->nm_flag); ! 524: return (EINTR); ! 525: } ! 526: so = rep->r_nmp->nm_so; ! 527: if (!so) { ! 528: error = nfs_reconnect(rep); ! 529: if (error) { ! 530: nfs_sndunlock(&rep->r_nmp->nm_flag); ! 531: return (error); ! 532: } ! 533: goto tryagain; ! 534: } ! 535: while (rep->r_flags & R_MUSTRESEND) { ! 536: m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT); ! 537: nfsstats.rpcretries++; ! 538: #if DIAGNOSTIC ! 539: kprintf("nfs_receive %s flg=0x%x\n", rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname, rep->r_nmp->nm_flag); ! 540: #endif ! 541: error = nfs_send(so, rep->r_nmp->nm_nam, m, rep); ! 542: if (error) { ! 543: if (error == EINTR || error == ERESTART || ! 544: (error = nfs_reconnect(rep))) { ! 545: nfs_sndunlock(&rep->r_nmp->nm_flag); ! 546: return (error); ! 547: } ! 548: goto tryagain; ! 549: } ! 550: } ! 551: nfs_sndunlock(&rep->r_nmp->nm_flag); ! 552: if (sotype == SOCK_STREAM) { ! 553: aio.iov_base = (caddr_t) &len; ! 554: aio.iov_len = sizeof(u_long); ! 555: auio.uio_iov = &aio; ! 556: auio.uio_iovcnt = 1; ! 557: auio.uio_segflg = UIO_SYSSPACE; ! 558: auio.uio_rw = UIO_READ; ! 559: auio.uio_offset = 0; ! 560: auio.uio_resid = sizeof(u_long); ! 561: auio.uio_procp = p; ! 562: do { ! 563: rcvflg = MSG_WAITALL; ! 564: error = soreceive(so, (struct mbuf **)0, &auio, ! 565: (struct mbuf **)0, (struct mbuf **)0, &rcvflg); ! 566: if (!rep->r_nmp) /* if unmounted then bailout */ ! 567: goto shutout; ! 568: if (error == EWOULDBLOCK && rep) { ! 569: if (rep->r_flags & R_SOFTTERM) ! 570: return (EINTR); ! 571: } ! 572: } while (error == EWOULDBLOCK); ! 573: if (!error && auio.uio_resid > 0) { ! 574: log(LOG_INFO, ! 575: "short receive (%d/%d) from nfs server %s\n", ! 576: sizeof(u_long) - auio.uio_resid, ! 577: sizeof(u_long), ! 578: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 579: error = EPIPE; ! 580: } ! 581: if (error) ! 582: goto errout; ! 583: len = ntohl(len) & ~0x80000000; ! 584: /* ! 585: * This is SERIOUS! We are out of sync with the sender ! 586: * and forcing a disconnect/reconnect is all I can do. ! 587: */ ! 588: if (len > NFS_MAXPACKET) { ! 589: log(LOG_ERR, "%s (%d) from nfs server %s\n", ! 590: "impossible packet length", ! 591: len, ! 592: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 593: error = EFBIG; ! 594: goto errout; ! 595: } ! 596: auio.uio_resid = len; ! 597: do { ! 598: rcvflg = MSG_WAITALL; ! 599: error = soreceive(so, (struct mbuf **)0, ! 600: &auio, mp, (struct mbuf **)0, &rcvflg); ! 601: if (!rep->r_nmp) /* if unmounted then bailout */ ! 602: goto shutout; ! 603: } while (error == EWOULDBLOCK || error == EINTR || ! 604: error == ERESTART); ! 605: if (!error && auio.uio_resid > 0) { ! 606: log(LOG_INFO, ! 607: "short receive (%d/%d) from nfs server %s\n", ! 608: len - auio.uio_resid, len, ! 609: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 610: error = EPIPE; ! 611: } ! 612: } else { ! 613: /* ! 614: * NB: Since uio_resid is big, MSG_WAITALL is ignored ! 615: * and soreceive() will return when it has either a ! 616: * control msg or a data msg. ! 617: * We have no use for control msg., but must grab them ! 618: * and then throw them away so we know what is going ! 619: * on. ! 620: */ ! 621: auio.uio_resid = len = 100000000; /* Anything Big */ ! 622: auio.uio_procp = p; ! 623: do { ! 624: rcvflg = 0; ! 625: error = soreceive(so, (struct mbuf **)0, ! 626: &auio, mp, &control, &rcvflg); ! 627: if (!rep->r_nmp) /* if unmounted then bailout */ ! 628: goto shutout; ! 629: if (control) ! 630: m_freem(control); ! 631: if (error == EWOULDBLOCK && rep) { ! 632: if (rep->r_flags & R_SOFTTERM) ! 633: return (EINTR); ! 634: } ! 635: } while (error == EWOULDBLOCK || ! 636: (!error && *mp == NULL && control)); ! 637: if ((rcvflg & MSG_EOR) == 0) ! 638: printf("Egad!!\n"); ! 639: if (!error && *mp == NULL) ! 640: error = EPIPE; ! 641: len -= auio.uio_resid; ! 642: } ! 643: errout: ! 644: if (error && error != EINTR && error != ERESTART) { ! 645: m_freem(*mp); ! 646: *mp = (struct mbuf *)0; ! 647: if (error != EPIPE) ! 648: log(LOG_INFO, ! 649: "receive error %d from nfs server %s\n", ! 650: error, ! 651: rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); ! 652: error = nfs_sndlock(&rep->r_nmp->nm_flag, rep); ! 653: if (!error) ! 654: error = nfs_reconnect(rep); ! 655: if (!error) ! 656: goto tryagain; ! 657: } ! 658: } else { ! 659: if ((so = rep->r_nmp->nm_so) == NULL) ! 660: return (EACCES); ! 661: if (so->so_state & SS_ISCONNECTED) ! 662: getnam = (struct mbuf **)0; ! 663: else ! 664: getnam = aname; ! 665: auio.uio_resid = len = 1000000; ! 666: auio.uio_procp = p; ! 667: do { ! 668: rcvflg = 0; ! 669: error = soreceive(so, getnam, &auio, mp, ! 670: (struct mbuf **)0, &rcvflg); ! 671: if (!rep->r_nmp) /* if unmounted then bailout */ ! 672: goto shutout; ! 673: if (error == EWOULDBLOCK && ! 674: (rep->r_flags & R_SOFTTERM)) ! 675: return (EINTR); ! 676: } while (error == EWOULDBLOCK); ! 677: len -= auio.uio_resid; ! 678: } ! 679: shutout: ! 680: if (error) { ! 681: m_freem(*mp); ! 682: *mp = (struct mbuf *)0; ! 683: } ! 684: return (error); ! 685: } ! 686: ! 687: /* ! 688: * Implement receipt of reply on a socket. ! 689: * We must search through the list of received datagrams matching them ! 690: * with outstanding requests using the xid, until ours is found. ! 691: */ ! 692: /* ARGSUSED */ ! 693: int ! 694: nfs_reply(myrep) ! 695: struct nfsreq *myrep; ! 696: { ! 697: register struct nfsreq *rep; ! 698: register struct nfsmount *nmp = myrep->r_nmp; ! 699: register long t1; ! 700: struct mbuf *mrep, *md; ! 701: struct mbuf *nam; ! 702: u_long rxid, *tl; ! 703: caddr_t dpos, cp2; ! 704: int error; ! 705: ! 706: /* ! 707: * Loop around until we get our own reply ! 708: */ ! 709: for (;;) { ! 710: /* ! 711: * Lock against other receivers so that I don't get stuck in ! 712: * sbwait() after someone else has received my reply for me. ! 713: * Also necessary for connection based protocols to avoid ! 714: * race conditions during a reconnect. ! 715: * If nfs_rcvlock() returns EALREADY, that means that ! 716: * the reply has already been recieved by another ! 717: * process and we can return immediately. In this ! 718: * case, the lock is not taken to avoid races with ! 719: * other processes. ! 720: */ ! 721: error = nfs_rcvlock(myrep); ! 722: if (error == EALREADY) ! 723: return (0); ! 724: if (error) ! 725: return (error); ! 726: /* ! 727: * Get the next Rpc reply off the socket ! 728: */ ! 729: error = nfs_receive(myrep, &nam, &mrep); ! 730: /* ! 731: * Bailout asap if nfsmount struct gone (unmounted) ! 732: */ ! 733: if (!myrep->r_nmp) ! 734: return(ECONNABORTED); ! 735: nfs_rcvunlock(&nmp->nm_flag); ! 736: if (error) { ! 737: ! 738: /* ! 739: * Ignore routing errors on connectionless protocols?? ! 740: */ ! 741: if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) { ! 742: nmp->nm_so->so_error = 0; ! 743: if (myrep->r_flags & R_GETONEREP) ! 744: return (0); ! 745: continue; ! 746: } ! 747: return (error); ! 748: } ! 749: if (nam) ! 750: m_freem(nam); ! 751: ! 752: /* ! 753: * Get the xid and check that it is an rpc reply ! 754: */ ! 755: md = mrep; ! 756: dpos = mtod(md, caddr_t); ! 757: nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); ! 758: rxid = *tl++; ! 759: if (*tl != rpc_reply) { ! 760: #ifndef NFS_NOSERVER ! 761: if (nmp->nm_flag & NFSMNT_NQNFS) { ! 762: if (nqnfs_callback(nmp, mrep, md, dpos)) ! 763: nfsstats.rpcinvalid++; ! 764: } else { ! 765: nfsstats.rpcinvalid++; ! 766: m_freem(mrep); ! 767: } ! 768: #else ! 769: nfsstats.rpcinvalid++; ! 770: m_freem(mrep); ! 771: #endif ! 772: nfsmout: ! 773: if (myrep->r_flags & R_GETONEREP) ! 774: return (0); ! 775: continue; ! 776: } ! 777: ! 778: /* ! 779: * Loop through the request list to match up the reply ! 780: * Iff no match, just drop the datagram ! 781: */ ! 782: for (rep = nfs_reqq.tqh_first; rep != 0; ! 783: rep = rep->r_chain.tqe_next) { ! 784: if (rep->r_mrep == NULL && rxid == rep->r_xid) { ! 785: /* Found it.. */ ! 786: rep->r_mrep = mrep; ! 787: rep->r_md = md; ! 788: rep->r_dpos = dpos; ! 789: if (nfsrtton) { ! 790: struct rttl *rt; ! 791: ! 792: rt = &nfsrtt.rttl[nfsrtt.pos]; ! 793: rt->proc = rep->r_procnum; ! 794: rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]); ! 795: rt->sent = nmp->nm_sent; ! 796: rt->cwnd = nmp->nm_cwnd; ! 797: rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1]; ! 798: rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1]; ! 799: rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid; ! 800: rt->tstamp = time; ! 801: if (rep->r_flags & R_TIMING) ! 802: rt->rtt = rep->r_rtt; ! 803: else ! 804: rt->rtt = 1000000; ! 805: nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ; ! 806: } ! 807: /* ! 808: * Update congestion window. ! 809: * Do the additive increase of ! 810: * one rpc/rtt. ! 811: */ ! 812: if (nmp->nm_cwnd <= nmp->nm_sent) { ! 813: nmp->nm_cwnd += ! 814: (NFS_CWNDSCALE * NFS_CWNDSCALE + ! 815: (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd; ! 816: if (nmp->nm_cwnd > NFS_MAXCWND) ! 817: nmp->nm_cwnd = NFS_MAXCWND; ! 818: } ! 819: rep->r_flags &= ~R_SENT; ! 820: nmp->nm_sent -= NFS_CWNDSCALE; ! 821: /* ! 822: * Update rtt using a gain of 0.125 on the mean ! 823: * and a gain of 0.25 on the deviation. ! 824: */ ! 825: if (rep->r_flags & R_TIMING) { ! 826: /* ! 827: * Since the timer resolution of ! 828: * NFS_HZ is so course, it can often ! 829: * result in r_rtt == 0. Since ! 830: * r_rtt == N means that the actual ! 831: * rtt is between N+dt and N+2-dt ticks, ! 832: * add 1. ! 833: */ ! 834: t1 = rep->r_rtt + 1; ! 835: t1 -= (NFS_SRTT(rep) >> 3); ! 836: NFS_SRTT(rep) += t1; ! 837: if (t1 < 0) ! 838: t1 = -t1; ! 839: t1 -= (NFS_SDRTT(rep) >> 2); ! 840: NFS_SDRTT(rep) += t1; ! 841: } ! 842: nmp->nm_timeouts = 0; ! 843: break; ! 844: } ! 845: } ! 846: /* ! 847: * If not matched to a request, drop it. ! 848: * If it's mine, get out. ! 849: */ ! 850: if (rep == 0) { ! 851: nfsstats.rpcunexpected++; ! 852: m_freem(mrep); ! 853: } else if (rep == myrep) { ! 854: if (rep->r_mrep == NULL) ! 855: panic("nfsreply nil"); ! 856: return (0); ! 857: } ! 858: if (myrep->r_flags & R_GETONEREP) ! 859: return (0); ! 860: } ! 861: } ! 862: ! 863: /* ! 864: * nfs_request - goes something like this ! 865: * - fill in request struct ! 866: * - links it into list ! 867: * - calls nfs_send() for first transmit ! 868: * - calls nfs_receive() to get reply ! 869: * - break down rpc header and return with nfs reply pointed to ! 870: * by mrep or error ! 871: * nb: always frees up mreq mbuf list ! 872: */ ! 873: int ! 874: nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) ! 875: struct vnode *vp; ! 876: struct mbuf *mrest; ! 877: int procnum; ! 878: struct proc *procp; ! 879: struct ucred *cred; ! 880: struct mbuf **mrp; ! 881: struct mbuf **mdp; ! 882: caddr_t *dposp; ! 883: { ! 884: register struct mbuf *m, *mrep; ! 885: register struct nfsreq *rep; ! 886: register u_long *tl; ! 887: register int i; ! 888: struct nfsmount *nmp; ! 889: struct mbuf *md, *mheadend; ! 890: struct nfsnode *np; ! 891: char nickv[RPCX_NICKVERF]; ! 892: time_t reqtime, waituntil; ! 893: caddr_t dpos, cp2; ! 894: int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; ! 895: int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; ! 896: int verf_len, verf_type; ! 897: u_long xid; ! 898: u_quad_t frev; ! 899: char *auth_str, *verf_str; ! 900: NFSKERBKEY_T key; /* save session key */ ! 901: ! 902: NFSTRACE4(NFSTRC_REQ, vp, procnum, 0, 0); ! 903: nmp = VFSTONFS(vp->v_mount); ! 904: MALLOC_ZONE(rep, struct nfsreq *, ! 905: sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); ! 906: rep->r_nmp = nmp; ! 907: rep->r_vp = vp; ! 908: rep->r_procp = procp; ! 909: rep->r_procnum = procnum; ! 910: i = 0; ! 911: m = mrest; ! 912: while (m) { ! 913: i += m->m_len; ! 914: m = m->m_next; ! 915: } ! 916: mrest_len = i; ! 917: ! 918: /* ! 919: * Get the RPC header with authorization. ! 920: */ ! 921: kerbauth: ! 922: verf_str = auth_str = (char *)0; ! 923: if (nmp->nm_flag & NFSMNT_KERB) { ! 924: verf_str = nickv; ! 925: verf_len = sizeof (nickv); ! 926: auth_type = RPCAUTH_KERB4; ! 927: bzero((caddr_t)key, sizeof (key)); ! 928: if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str, ! 929: &auth_len, verf_str, verf_len)) { ! 930: error = nfs_getauth(nmp, rep, cred, &auth_str, ! 931: &auth_len, verf_str, &verf_len, key); ! 932: if (error) { ! 933: _FREE_ZONE((caddr_t)rep, ! 934: sizeof (struct nfsreq), M_NFSREQ); ! 935: m_freem(mrest); ! 936: return (error); ! 937: } ! 938: } ! 939: } else { ! 940: auth_type = RPCAUTH_UNIX; ! 941: if (cred->cr_ngroups < 1) ! 942: panic("nfsreq nogrps"); ! 943: auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ? ! 944: nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + ! 945: 5 * NFSX_UNSIGNED; ! 946: } ! 947: m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, ! 948: auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid); ! 949: if (auth_str) ! 950: _FREE(auth_str, M_TEMP); ! 951: ! 952: /* ! 953: * For stream protocols, insert a Sun RPC Record Mark. ! 954: */ ! 955: if (nmp->nm_sotype == SOCK_STREAM) { ! 956: M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); ! 957: *mtod(m, u_long *) = htonl(0x80000000 | ! 958: (m->m_pkthdr.len - NFSX_UNSIGNED)); ! 959: } ! 960: rep->r_mreq = m; ! 961: rep->r_xid = xid; ! 962: tryagain: ! 963: if (nmp->nm_flag & NFSMNT_SOFT) ! 964: rep->r_retry = nmp->nm_retry; ! 965: else ! 966: rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */ ! 967: rep->r_rtt = rep->r_rexmit = 0; ! 968: if (proct[procnum] > 0) ! 969: rep->r_flags = R_TIMING; ! 970: else ! 971: rep->r_flags = 0; ! 972: rep->r_mrep = NULL; ! 973: ! 974: /* ! 975: * Do the client side RPC. ! 976: */ ! 977: nfsstats.rpcrequests++; ! 978: /* ! 979: * Chain request into list of outstanding requests. Be sure ! 980: * to put it LAST so timer finds oldest requests first. ! 981: */ ! 982: s = splsoftclock(); ! 983: TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain); ! 984: ! 985: /* Get send time for nqnfs */ ! 986: reqtime = time.tv_sec; ! 987: ! 988: /* ! 989: * If backing off another request or avoiding congestion, don't ! 990: * send this one now but let timer do it. If not timing a request, ! 991: * do it now. ! 992: */ ! 993: if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM || ! 994: (nmp->nm_flag & NFSMNT_DUMBTIMR) || ! 995: nmp->nm_sent < nmp->nm_cwnd)) { ! 996: splx(s); ! 997: if (nmp->nm_soflags & PR_CONNREQUIRED) ! 998: error = nfs_sndlock(&nmp->nm_flag, rep); ! 999: if (!error) { ! 1000: m = m_copym(m, 0, M_COPYALL, M_WAIT); ! 1001: error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep); ! 1002: if (nmp->nm_soflags & PR_CONNREQUIRED) ! 1003: nfs_sndunlock(&nmp->nm_flag); ! 1004: } ! 1005: if (!error && (rep->r_flags & R_MUSTRESEND) == 0) { ! 1006: nmp->nm_sent += NFS_CWNDSCALE; ! 1007: rep->r_flags |= R_SENT; ! 1008: } ! 1009: } else { ! 1010: splx(s); ! 1011: rep->r_rtt = -1; ! 1012: } ! 1013: ! 1014: /* ! 1015: * Wait for the reply from our send or the timer's. ! 1016: */ ! 1017: if (!error || error == EPIPE) ! 1018: error = nfs_reply(rep); ! 1019: ! 1020: /* ! 1021: * RPC done, unlink the request. ! 1022: */ ! 1023: s = splsoftclock(); ! 1024: TAILQ_REMOVE(&nfs_reqq, rep, r_chain); ! 1025: splx(s); ! 1026: ! 1027: /* ! 1028: * Decrement the outstanding request count. ! 1029: */ ! 1030: if (rep->r_flags & R_SENT) { ! 1031: rep->r_flags &= ~R_SENT; /* paranoia */ ! 1032: nmp->nm_sent -= NFS_CWNDSCALE; ! 1033: } ! 1034: ! 1035: /* ! 1036: * If there was a successful reply and a tprintf msg. ! 1037: * tprintf a response. ! 1038: */ ! 1039: if (!error && (rep->r_flags & R_TPRINTFMSG)) ! 1040: nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname, ! 1041: "is alive again"); ! 1042: mrep = rep->r_mrep; ! 1043: md = rep->r_md; ! 1044: dpos = rep->r_dpos; ! 1045: if (error) { ! 1046: m_freem(rep->r_mreq); ! 1047: _FREE_ZONE((caddr_t)rep, sizeof (struct nfsreq), M_NFSREQ); ! 1048: return (error); ! 1049: } ! 1050: ! 1051: /* ! 1052: * break down the rpc header and check if ok ! 1053: */ ! 1054: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); ! 1055: if (*tl++ == rpc_msgdenied) { ! 1056: if (*tl == rpc_mismatch) ! 1057: error = EOPNOTSUPP; ! 1058: else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { ! 1059: if (!failed_auth) { ! 1060: failed_auth++; ! 1061: mheadend->m_next = (struct mbuf *)0; ! 1062: m_freem(mrep); ! 1063: m_freem(rep->r_mreq); ! 1064: goto kerbauth; ! 1065: } else ! 1066: error = EAUTH; ! 1067: } else ! 1068: error = EACCES; ! 1069: m_freem(mrep); ! 1070: m_freem(rep->r_mreq); ! 1071: _FREE_ZONE((caddr_t)rep, sizeof (struct nfsreq), M_NFSREQ); ! 1072: return (error); ! 1073: } ! 1074: ! 1075: /* ! 1076: * Grab any Kerberos verifier, otherwise just throw it away. ! 1077: */ ! 1078: verf_type = fxdr_unsigned(int, *tl++); ! 1079: i = fxdr_unsigned(int, *tl); ! 1080: if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) { ! 1081: error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep); ! 1082: if (error) ! 1083: goto nfsmout; ! 1084: } else if (i > 0) ! 1085: nfsm_adv(nfsm_rndup(i)); ! 1086: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); ! 1087: /* 0 == ok */ ! 1088: if (*tl == 0) { ! 1089: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); ! 1090: if (*tl != 0) { ! 1091: error = fxdr_unsigned(int, *tl); ! 1092: if ((nmp->nm_flag & NFSMNT_NFSV3) && ! 1093: error == NFSERR_TRYLATER) { ! 1094: m_freem(mrep); ! 1095: error = 0; ! 1096: waituntil = time.tv_sec + trylater_delay; ! 1097: #if DIAGNOSTIC ! 1098: kprintf("nfs_request %s flag=%x trylater_cnt=%x waituntil=%lx trylater_delay=%x\n", nmp->nm_mountp->mnt_stat.f_mntfromname, nmp->nm_flag, trylater_cnt, waituntil, trylater_delay); ! 1099: #endif ! 1100: while (time.tv_sec < waituntil) ! 1101: (void) tsleep((caddr_t)&lbolt, ! 1102: PSOCK, "nqnfstry", 0); ! 1103: trylater_delay *= nfs_backoff[trylater_cnt]; ! 1104: if (trylater_cnt < 7) ! 1105: trylater_cnt++; ! 1106: goto tryagain; ! 1107: } ! 1108: ! 1109: /* ! 1110: * If the File Handle was stale, invalidate the ! 1111: * lookup cache, just in case. ! 1112: */ ! 1113: if (error == ESTALE) ! 1114: cache_purge(vp); ! 1115: if (nmp->nm_flag & NFSMNT_NFSV3) { ! 1116: *mrp = mrep; ! 1117: *mdp = md; ! 1118: *dposp = dpos; ! 1119: error |= NFSERR_RETERR; ! 1120: } else ! 1121: m_freem(mrep); ! 1122: m_freem(rep->r_mreq); ! 1123: _FREE_ZONE((caddr_t)rep, ! 1124: sizeof (struct nfsreq), M_NFSREQ); ! 1125: return (error); ! 1126: } ! 1127: ! 1128: /* ! 1129: * For nqnfs, get any lease in reply ! 1130: */ ! 1131: if (nmp->nm_flag & NFSMNT_NQNFS) { ! 1132: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); ! 1133: if (*tl) { ! 1134: np = VTONFS(vp); ! 1135: nqlflag = fxdr_unsigned(int, *tl); ! 1136: nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); ! 1137: cachable = fxdr_unsigned(int, *tl++); ! 1138: reqtime += fxdr_unsigned(int, *tl++); ! 1139: if (reqtime > time.tv_sec) { ! 1140: fxdr_hyper(tl, &frev); ! 1141: nqnfs_clientlease(nmp, np, nqlflag, ! 1142: cachable, reqtime, frev); ! 1143: } ! 1144: } ! 1145: } ! 1146: *mrp = mrep; ! 1147: *mdp = md; ! 1148: *dposp = dpos; ! 1149: m_freem(rep->r_mreq); ! 1150: FREE_ZONE((caddr_t)rep, sizeof (struct nfsreq), M_NFSREQ); ! 1151: return (0); ! 1152: } ! 1153: m_freem(mrep); ! 1154: error = EPROTONOSUPPORT; ! 1155: nfsmout: ! 1156: m_freem(rep->r_mreq); ! 1157: _FREE_ZONE((caddr_t)rep, sizeof (struct nfsreq), M_NFSREQ); ! 1158: return (error); ! 1159: } ! 1160: ! 1161: #ifndef NFS_NOSERVER ! 1162: /* ! 1163: * Generate the rpc reply header ! 1164: * siz arg. is used to decide if adding a cluster is worthwhile ! 1165: */ ! 1166: int ! 1167: nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp) ! 1168: int siz; ! 1169: struct nfsrv_descript *nd; ! 1170: struct nfssvc_sock *slp; ! 1171: int err; ! 1172: int cache; ! 1173: u_quad_t *frev; ! 1174: struct mbuf **mrq; ! 1175: struct mbuf **mbp; ! 1176: caddr_t *bposp; ! 1177: { ! 1178: register u_long *tl; ! 1179: register struct mbuf *mreq; ! 1180: caddr_t bpos; ! 1181: struct mbuf *mb, *mb2; ! 1182: ! 1183: MGETHDR(mreq, M_WAIT, MT_DATA); ! 1184: mb = mreq; ! 1185: /* ! 1186: * If this is a big reply, use a cluster else ! 1187: * try and leave leading space for the lower level headers. ! 1188: */ ! 1189: siz += RPC_REPLYSIZ; ! 1190: if (siz >= MINCLSIZE) { ! 1191: MCLGET(mreq, M_WAIT); ! 1192: } else ! 1193: mreq->m_data += max_hdr; ! 1194: tl = mtod(mreq, u_long *); ! 1195: mreq->m_len = 6 * NFSX_UNSIGNED; ! 1196: bpos = ((caddr_t)tl) + mreq->m_len; ! 1197: *tl++ = txdr_unsigned(nd->nd_retxid); ! 1198: *tl++ = rpc_reply; ! 1199: if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { ! 1200: *tl++ = rpc_msgdenied; ! 1201: if (err & NFSERR_AUTHERR) { ! 1202: *tl++ = rpc_autherr; ! 1203: *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); ! 1204: mreq->m_len -= NFSX_UNSIGNED; ! 1205: bpos -= NFSX_UNSIGNED; ! 1206: } else { ! 1207: *tl++ = rpc_mismatch; ! 1208: *tl++ = txdr_unsigned(RPC_VER2); ! 1209: *tl = txdr_unsigned(RPC_VER2); ! 1210: } ! 1211: } else { ! 1212: *tl++ = rpc_msgaccepted; ! 1213: ! 1214: /* ! 1215: * For Kerberos authentication, we must send the nickname ! 1216: * verifier back, otherwise just RPCAUTH_NULL. ! 1217: */ ! 1218: if (nd->nd_flag & ND_KERBFULL) { ! 1219: register struct nfsuid *nuidp; ! 1220: struct timeval ktvin, ktvout; ! 1221: ! 1222: for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first; ! 1223: nuidp != 0; nuidp = nuidp->nu_hash.le_next) { ! 1224: if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid && ! 1225: (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp), ! 1226: &nuidp->nu_haddr, nd->nd_nam2))) ! 1227: break; ! 1228: } ! 1229: if (nuidp) { ! 1230: ktvin.tv_sec = ! 1231: txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1); ! 1232: ktvin.tv_usec = ! 1233: txdr_unsigned(nuidp->nu_timestamp.tv_usec); ! 1234: ! 1235: /* ! 1236: * Encrypt the timestamp in ecb mode using the ! 1237: * session key. ! 1238: */ ! 1239: #if NFSKERB ! 1240: XXX ! 1241: #endif ! 1242: ! 1243: *tl++ = rpc_auth_kerb; ! 1244: *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); ! 1245: *tl = ktvout.tv_sec; ! 1246: nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); ! 1247: *tl++ = ktvout.tv_usec; ! 1248: *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid); ! 1249: } else { ! 1250: *tl++ = 0; ! 1251: *tl++ = 0; ! 1252: } ! 1253: } else { ! 1254: *tl++ = 0; ! 1255: *tl++ = 0; ! 1256: } ! 1257: switch (err) { ! 1258: case EPROGUNAVAIL: ! 1259: *tl = txdr_unsigned(RPC_PROGUNAVAIL); ! 1260: break; ! 1261: case EPROGMISMATCH: ! 1262: *tl = txdr_unsigned(RPC_PROGMISMATCH); ! 1263: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); ! 1264: if (nd->nd_flag & ND_NQNFS) { ! 1265: *tl++ = txdr_unsigned(3); ! 1266: *tl = txdr_unsigned(3); ! 1267: } else { ! 1268: *tl++ = txdr_unsigned(2); ! 1269: *tl = txdr_unsigned(3); ! 1270: } ! 1271: break; ! 1272: case EPROCUNAVAIL: ! 1273: *tl = txdr_unsigned(RPC_PROCUNAVAIL); ! 1274: break; ! 1275: case EBADRPC: ! 1276: *tl = txdr_unsigned(RPC_GARBAGE); ! 1277: break; ! 1278: default: ! 1279: *tl = 0; ! 1280: if (err != NFSERR_RETVOID) { ! 1281: nfsm_build(tl, u_long *, NFSX_UNSIGNED); ! 1282: if (err) ! 1283: *tl = txdr_unsigned(nfsrv_errmap(nd, err)); ! 1284: else ! 1285: *tl = 0; ! 1286: } ! 1287: break; ! 1288: }; ! 1289: } ! 1290: ! 1291: /* ! 1292: * For nqnfs, piggyback lease as requested. ! 1293: */ ! 1294: if ((nd->nd_flag & ND_NQNFS) && err == 0) { ! 1295: if (nd->nd_flag & ND_LEASE) { ! 1296: nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED); ! 1297: *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE); ! 1298: *tl++ = txdr_unsigned(cache); ! 1299: *tl++ = txdr_unsigned(nd->nd_duration); ! 1300: txdr_hyper(frev, tl); ! 1301: } else { ! 1302: nfsm_build(tl, u_long *, NFSX_UNSIGNED); ! 1303: *tl = 0; ! 1304: } ! 1305: } ! 1306: if (mrq != NULL) ! 1307: *mrq = mreq; ! 1308: *mbp = mb; ! 1309: *bposp = bpos; ! 1310: if (err != 0 && err != NFSERR_RETVOID) ! 1311: nfsstats.srvrpc_errs++; ! 1312: return (0); ! 1313: } ! 1314: ! 1315: ! 1316: #endif /* NFS_NOSERVER */ ! 1317: ! 1318: #if DIAGNOSTIC ! 1319: int nfsprnttimo = 2; ! 1320: #endif ! 1321: ! 1322: /* ! 1323: * Nfs timer routine ! 1324: * Scan the nfsreq list and retranmit any requests that have timed out ! 1325: * To avoid retransmission attempts on STREAM sockets (in the future) make ! 1326: * sure to set the r_retry field to 0 (implies nm_retry == 0). ! 1327: */ ! 1328: void ! 1329: nfs_timer(arg) ! 1330: void *arg; /* never used */ ! 1331: { ! 1332: register struct nfsreq *rep; ! 1333: register struct mbuf *m; ! 1334: register struct socket *so; ! 1335: register struct nfsmount *nmp; ! 1336: register int timeo; ! 1337: int s, error; ! 1338: #ifndef NFS_NOSERVER ! 1339: static long lasttime = 0; ! 1340: register struct nfssvc_sock *slp; ! 1341: u_quad_t cur_usec; ! 1342: #endif /* NFS_NOSERVER */ ! 1343: #if DIAGNOSTIC ! 1344: int rttdiag; ! 1345: #endif ! 1346: ! 1347: s = splnet(); ! 1348: for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) { ! 1349: nmp = rep->r_nmp; ! 1350: if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) ! 1351: continue; ! 1352: if (nfs_sigintr(nmp, rep, rep->r_procp)) { ! 1353: rep->r_flags |= R_SOFTTERM; ! 1354: continue; ! 1355: } ! 1356: if (rep->r_rtt >= 0) { ! 1357: rep->r_rtt++; ! 1358: if (nmp->nm_flag & NFSMNT_DUMBTIMR) ! 1359: timeo = nmp->nm_timeo; ! 1360: else ! 1361: timeo = NFS_RTO(nmp, proct[rep->r_procnum]); ! 1362: if (nmp->nm_timeouts > 0) ! 1363: timeo *= nfs_backoff[nmp->nm_timeouts - 1]; ! 1364: if (rep->r_rtt <= timeo) ! 1365: continue; ! 1366: if (nmp->nm_timeouts < 8) ! 1367: nmp->nm_timeouts++; ! 1368: } ! 1369: /* ! 1370: * Check for server not responding ! 1371: */ ! 1372: if ((rep->r_flags & R_TPRINTFMSG) == 0 && ! 1373: rep->r_rexmit > nmp->nm_deadthresh) { ! 1374: nfs_msg(rep->r_procp, ! 1375: nmp->nm_mountp->mnt_stat.f_mntfromname, ! 1376: "not responding"); ! 1377: rep->r_flags |= R_TPRINTFMSG; ! 1378: } ! 1379: if (rep->r_rexmit >= rep->r_retry) { /* too many */ ! 1380: nfsstats.rpctimeouts++; ! 1381: rep->r_flags |= R_SOFTTERM; ! 1382: continue; ! 1383: } ! 1384: if (nmp->nm_sotype != SOCK_DGRAM) { ! 1385: if (++rep->r_rexmit > NFS_MAXREXMIT) ! 1386: rep->r_rexmit = NFS_MAXREXMIT; ! 1387: continue; ! 1388: } ! 1389: if ((so = nmp->nm_so) == NULL) ! 1390: continue; ! 1391: ! 1392: /* ! 1393: * If there is enough space and the window allows.. ! 1394: * Resend it ! 1395: * Set r_rtt to -1 in case we fail to send it now. ! 1396: */ ! 1397: #if DIAGNOSTIC ! 1398: rttdiag = rep->r_rtt; ! 1399: #endif ! 1400: rep->r_rtt = -1; ! 1401: if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && ! 1402: ((nmp->nm_flag & NFSMNT_DUMBTIMR) || ! 1403: (rep->r_flags & R_SENT) || ! 1404: nmp->nm_sent < nmp->nm_cwnd) && ! 1405: (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){ ! 1406: #if DIAGNOSTIC ! 1407: if (rep->r_flags & R_SENT) { /* retry? */ ! 1408: if (nfsprnttimo && nmp->nm_timeouts >= nfsprnttimo) ! 1409: kprintf("nfs_timer %s f=0x%x nmtm=%d tms=%d rtt=%d tm=%d p#=%d\n", ! 1410: nmp->nm_mountp->mnt_stat.f_mntfromname, nmp->nm_flag, nmp->nm_timeo, nmp->nm_timeouts, rttdiag, timeo, rep->r_procnum); ! 1411: } ! 1412: #endif ! 1413: if ((nmp->nm_flag & NFSMNT_NOCONN) == 0) ! 1414: error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, ! 1415: (struct mbuf *)0, (struct mbuf *)0); ! 1416: else ! 1417: error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, ! 1418: nmp->nm_nam, (struct mbuf *)0); ! 1419: if (error) { ! 1420: if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) ! 1421: so->so_error = 0; ! 1422: } else { ! 1423: /* ! 1424: * Iff first send, start timing ! 1425: * else turn timing off, backoff timer ! 1426: * and divide congestion window by 2. ! 1427: */ ! 1428: if (rep->r_flags & R_SENT) { ! 1429: rep->r_flags &= ~R_TIMING; ! 1430: if (++rep->r_rexmit > NFS_MAXREXMIT) ! 1431: rep->r_rexmit = NFS_MAXREXMIT; ! 1432: nmp->nm_cwnd >>= 1; ! 1433: if (nmp->nm_cwnd < NFS_CWNDSCALE) ! 1434: nmp->nm_cwnd = NFS_CWNDSCALE; ! 1435: nfsstats.rpcretries++; ! 1436: } else { ! 1437: rep->r_flags |= R_SENT; ! 1438: nmp->nm_sent += NFS_CWNDSCALE; ! 1439: } ! 1440: rep->r_rtt = 0; ! 1441: } ! 1442: } ! 1443: } ! 1444: #ifndef NFS_NOSERVER ! 1445: /* ! 1446: * Call the nqnfs server timer once a second to handle leases. ! 1447: */ ! 1448: if (lasttime != time.tv_sec) { ! 1449: lasttime = time.tv_sec; ! 1450: nqnfs_serverd(); ! 1451: } ! 1452: ! 1453: /* ! 1454: * Scan the write gathering queues for writes that need to be ! 1455: * completed now. ! 1456: */ ! 1457: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; ! 1458: for (slp = nfssvc_sockhead.tqh_first; slp != 0; ! 1459: slp = slp->ns_chain.tqe_next) { ! 1460: if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec) ! 1461: nfsrv_wakenfsd(slp); ! 1462: } ! 1463: #endif /* NFS_NOSERVER */ ! 1464: splx(s); ! 1465: timeout(nfs_timer, (void *)0, nfs_ticks); ! 1466: } ! 1467: ! 1468: ! 1469: /* ! 1470: * Test for a termination condition pending on the process. ! 1471: * This is used for NFSMNT_INT mounts. ! 1472: */ ! 1473: int ! 1474: nfs_sigintr(nmp, rep, p) ! 1475: struct nfsmount *nmp; ! 1476: struct nfsreq *rep; ! 1477: register struct proc *p; ! 1478: { ! 1479: ! 1480: if (rep && (rep->r_flags & R_SOFTTERM)) ! 1481: return (EINTR); ! 1482: if (!(nmp->nm_flag & NFSMNT_INT)) ! 1483: return (0); ! 1484: if (p && p->p_siglist && ! 1485: (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) & ! 1486: NFSINT_SIGMASK)) ! 1487: return (EINTR); ! 1488: return (0); ! 1489: } ! 1490: ! 1491: /* ! 1492: * Lock a socket against others. ! 1493: * Necessary for STREAM sockets to ensure you get an entire rpc request/reply ! 1494: * and also to avoid race conditions between the processes with nfs requests ! 1495: * in progress when a reconnect is necessary. ! 1496: */ ! 1497: int ! 1498: nfs_sndlock(flagp, rep) ! 1499: register int *flagp; ! 1500: struct nfsreq *rep; ! 1501: { ! 1502: struct proc *p; ! 1503: int slpflag = 0, slptimeo = 0; ! 1504: ! 1505: if (rep) { ! 1506: p = rep->r_procp; ! 1507: if (rep->r_nmp->nm_flag & NFSMNT_INT) ! 1508: slpflag = PCATCH; ! 1509: } else ! 1510: p = (struct proc *)0; ! 1511: while (*flagp & NFSMNT_SNDLOCK) { ! 1512: if (nfs_sigintr(rep->r_nmp, rep, p)) ! 1513: return (EINTR); ! 1514: *flagp |= NFSMNT_WANTSND; ! 1515: (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsndlck", ! 1516: slptimeo); ! 1517: if (slpflag == PCATCH) { ! 1518: slpflag = 0; ! 1519: slptimeo = 2 * hz; ! 1520: } ! 1521: } ! 1522: *flagp |= NFSMNT_SNDLOCK; ! 1523: return (0); ! 1524: } ! 1525: ! 1526: /* ! 1527: * Unlock the stream socket for others. ! 1528: */ ! 1529: void ! 1530: nfs_sndunlock(flagp) ! 1531: register int *flagp; ! 1532: { ! 1533: ! 1534: if ((*flagp & NFSMNT_SNDLOCK) == 0) ! 1535: panic("nfs sndunlock"); ! 1536: *flagp &= ~NFSMNT_SNDLOCK; ! 1537: if (*flagp & NFSMNT_WANTSND) { ! 1538: *flagp &= ~NFSMNT_WANTSND; ! 1539: wakeup((caddr_t)flagp); ! 1540: } ! 1541: } ! 1542: ! 1543: #if DIAGNOSTIC ! 1544: uint nfstraceindx = 0; ! 1545: struct nfstracerec nfstracebuf[NFSTBUFSIZ] = {{0,0,0,0}}; ! 1546: uint nfstracemask = 0; /* enables trace points 0 to 31 (right to left) */ ! 1547: #endif /* DIAGNOSTIC */ ! 1548: ! 1549: static int ! 1550: nfs_rcvlock(rep) ! 1551: register struct nfsreq *rep; ! 1552: { ! 1553: register int *flagp = &rep->r_nmp->nm_flag; ! 1554: int slpflag, slptimeo = 0; ! 1555: ! 1556: if (*flagp & NFSMNT_INT) ! 1557: slpflag = PCATCH; ! 1558: else ! 1559: slpflag = 0; ! 1560: while (*flagp & NFSMNT_RCVLOCK) { ! 1561: NFSTRACE(NFSTRC_RCVLCKW, flagp); ! 1562: if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp)) ! 1563: return (EINTR); ! 1564: *flagp |= NFSMNT_WANTRCV; ! 1565: (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsrcvlk", ! 1566: slptimeo); ! 1567: /* ! 1568: * If our reply was recieved while we were sleeping, ! 1569: * then just return without taking the lock to avoid a ! 1570: * situation where a single iod could 'capture' the ! 1571: * recieve lock. ! 1572: */ ! 1573: if (rep->r_mrep != NULL) ! 1574: return (EALREADY); ! 1575: if (slpflag == PCATCH) { ! 1576: slpflag = 0; ! 1577: slptimeo = 2 * hz; ! 1578: } ! 1579: } ! 1580: NFSTRACE(NFSTRC_RCVLCK, flagp); ! 1581: *flagp |= NFSMNT_RCVLOCK; ! 1582: return (0); ! 1583: } ! 1584: ! 1585: /* ! 1586: * Unlock the stream socket for others. ! 1587: */ ! 1588: static void ! 1589: nfs_rcvunlock(flagp) ! 1590: register int *flagp; ! 1591: { ! 1592: ! 1593: if ((*flagp & NFSMNT_RCVLOCK) == 0) ! 1594: panic("nfs rcvunlock"); ! 1595: *flagp &= ~NFSMNT_RCVLOCK; ! 1596: if (*flagp & NFSMNT_WANTRCV) { ! 1597: NFSTRACE(NFSTRC_RCVUNLW, flagp); ! 1598: *flagp &= ~NFSMNT_WANTRCV; ! 1599: wakeup((caddr_t)flagp); ! 1600: } else { ! 1601: NFSTRACE(NFSTRC_RCVUNL, flagp); ! 1602: } ! 1603: } ! 1604: ! 1605: ! 1606: #ifndef NFS_NOSERVER ! 1607: /* ! 1608: * Socket upcall routine for the nfsd sockets. ! 1609: * The caddr_t arg is a pointer to the "struct nfssvc_sock". ! 1610: * Essentially do as much as possible non-blocking, else punt and it will ! 1611: * be called with M_WAIT from an nfsd. ! 1612: */ ! 1613: void ! 1614: nfsrv_rcv(so, arg, waitflag) ! 1615: struct socket *so; ! 1616: caddr_t arg; ! 1617: int waitflag; ! 1618: { ! 1619: register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg; ! 1620: register struct mbuf *m; ! 1621: struct mbuf *mp; ! 1622: struct mbuf *nam; ! 1623: struct uio auio; ! 1624: int flags, error; ! 1625: ! 1626: if ((slp->ns_flag & SLP_VALID) == 0) ! 1627: return; ! 1628: #ifdef notdef ! 1629: /* ! 1630: * Define this to test for nfsds handling this under heavy load. ! 1631: */ ! 1632: if (waitflag == M_DONTWAIT) { ! 1633: slp->ns_flag |= SLP_NEEDQ; goto dorecs; ! 1634: } ! 1635: #endif ! 1636: auio.uio_procp = NULL; ! 1637: if (so->so_type == SOCK_STREAM) { ! 1638: /* ! 1639: * If there are already records on the queue, defer soreceive() ! 1640: * to an nfsd so that there is feedback to the TCP layer that ! 1641: * the nfs servers are heavily loaded. ! 1642: */ ! 1643: if (slp->ns_rec && waitflag == M_DONTWAIT) { ! 1644: slp->ns_flag |= SLP_NEEDQ; ! 1645: goto dorecs; ! 1646: } ! 1647: ! 1648: /* ! 1649: * Do soreceive(). ! 1650: */ ! 1651: auio.uio_resid = 1000000000; ! 1652: flags = MSG_DONTWAIT; ! 1653: error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags); ! 1654: if (error || mp == (struct mbuf *)0) { ! 1655: if (error == EWOULDBLOCK) ! 1656: slp->ns_flag |= SLP_NEEDQ; ! 1657: else ! 1658: slp->ns_flag |= SLP_DISCONN; ! 1659: goto dorecs; ! 1660: } ! 1661: m = mp; ! 1662: if (slp->ns_rawend) { ! 1663: slp->ns_rawend->m_next = m; ! 1664: slp->ns_cc += 1000000000 - auio.uio_resid; ! 1665: } else { ! 1666: slp->ns_raw = m; ! 1667: slp->ns_cc = 1000000000 - auio.uio_resid; ! 1668: } ! 1669: while (m->m_next) ! 1670: m = m->m_next; ! 1671: slp->ns_rawend = m; ! 1672: ! 1673: /* ! 1674: * Now try and parse record(s) out of the raw stream data. ! 1675: */ ! 1676: error = nfsrv_getstream(slp, waitflag); ! 1677: if (error) { ! 1678: if (error == EPERM) ! 1679: slp->ns_flag |= SLP_DISCONN; ! 1680: else ! 1681: slp->ns_flag |= SLP_NEEDQ; ! 1682: } ! 1683: } else { ! 1684: do { ! 1685: auio.uio_resid = 1000000000; ! 1686: flags = MSG_DONTWAIT; ! 1687: error = soreceive(so, &nam, &auio, &mp, ! 1688: (struct mbuf **)0, &flags); ! 1689: if (mp) { ! 1690: if (nam) { ! 1691: m = nam; ! 1692: m->m_next = mp; ! 1693: } else ! 1694: m = mp; ! 1695: if (slp->ns_recend) ! 1696: slp->ns_recend->m_nextpkt = m; ! 1697: else ! 1698: slp->ns_rec = m; ! 1699: slp->ns_recend = m; ! 1700: m->m_nextpkt = (struct mbuf *)0; ! 1701: } ! 1702: if (error) { ! 1703: if ((so->so_proto->pr_flags & PR_CONNREQUIRED) ! 1704: && error != EWOULDBLOCK) { ! 1705: slp->ns_flag |= SLP_DISCONN; ! 1706: goto dorecs; ! 1707: } ! 1708: } ! 1709: } while (mp); ! 1710: } ! 1711: ! 1712: /* ! 1713: * Now try and process the request records, non-blocking. ! 1714: */ ! 1715: dorecs: ! 1716: if (waitflag == M_DONTWAIT && ! 1717: (slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) ! 1718: nfsrv_wakenfsd(slp); ! 1719: } ! 1720: ! 1721: /* ! 1722: * Try and extract an RPC request from the mbuf data list received on a ! 1723: * stream socket. The "waitflag" argument indicates whether or not it ! 1724: * can sleep. ! 1725: */ ! 1726: static int ! 1727: nfsrv_getstream(slp, waitflag) ! 1728: register struct nfssvc_sock *slp; ! 1729: int waitflag; ! 1730: { ! 1731: register struct mbuf *m, **mpp; ! 1732: register char *cp1, *cp2; ! 1733: register int len; ! 1734: struct mbuf *om, *m2, *recm = 0; ! 1735: u_long recmark; ! 1736: ! 1737: if (slp->ns_flag & SLP_GETSTREAM) ! 1738: panic("nfs getstream"); ! 1739: slp->ns_flag |= SLP_GETSTREAM; ! 1740: for (;;) { ! 1741: if (slp->ns_reclen == 0) { ! 1742: if (slp->ns_cc < NFSX_UNSIGNED) { ! 1743: slp->ns_flag &= ~SLP_GETSTREAM; ! 1744: return (0); ! 1745: } ! 1746: m = slp->ns_raw; ! 1747: if (m->m_len >= NFSX_UNSIGNED) { ! 1748: bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED); ! 1749: m->m_data += NFSX_UNSIGNED; ! 1750: m->m_len -= NFSX_UNSIGNED; ! 1751: } else { ! 1752: cp1 = (caddr_t)&recmark; ! 1753: cp2 = mtod(m, caddr_t); ! 1754: while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) { ! 1755: while (m->m_len == 0) { ! 1756: m = m->m_next; ! 1757: cp2 = mtod(m, caddr_t); ! 1758: } ! 1759: *cp1++ = *cp2++; ! 1760: m->m_data++; ! 1761: m->m_len--; ! 1762: } ! 1763: } ! 1764: slp->ns_cc -= NFSX_UNSIGNED; ! 1765: recmark = ntohl(recmark); ! 1766: slp->ns_reclen = recmark & ~0x80000000; ! 1767: if (recmark & 0x80000000) ! 1768: slp->ns_flag |= SLP_LASTFRAG; ! 1769: else ! 1770: slp->ns_flag &= ~SLP_LASTFRAG; ! 1771: if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) { ! 1772: slp->ns_flag &= ~SLP_GETSTREAM; ! 1773: return (EPERM); ! 1774: } ! 1775: } ! 1776: ! 1777: /* ! 1778: * Now get the record part. ! 1779: */ ! 1780: if (slp->ns_cc == slp->ns_reclen) { ! 1781: recm = slp->ns_raw; ! 1782: slp->ns_raw = slp->ns_rawend = (struct mbuf *)0; ! 1783: slp->ns_cc = slp->ns_reclen = 0; ! 1784: } else if (slp->ns_cc > slp->ns_reclen) { ! 1785: len = 0; ! 1786: m = slp->ns_raw; ! 1787: om = (struct mbuf *)0; ! 1788: while (len < slp->ns_reclen) { ! 1789: if ((len + m->m_len) > slp->ns_reclen) { ! 1790: m2 = m_copym(m, 0, slp->ns_reclen - len, ! 1791: waitflag); ! 1792: if (m2) { ! 1793: if (om) { ! 1794: om->m_next = m2; ! 1795: recm = slp->ns_raw; ! 1796: } else ! 1797: recm = m2; ! 1798: m->m_data += slp->ns_reclen - len; ! 1799: m->m_len -= slp->ns_reclen - len; ! 1800: len = slp->ns_reclen; ! 1801: } else { ! 1802: slp->ns_flag &= ~SLP_GETSTREAM; ! 1803: return (EWOULDBLOCK); ! 1804: } ! 1805: } else if ((len + m->m_len) == slp->ns_reclen) { ! 1806: om = m; ! 1807: len += m->m_len; ! 1808: m = m->m_next; ! 1809: recm = slp->ns_raw; ! 1810: om->m_next = (struct mbuf *)0; ! 1811: } else { ! 1812: om = m; ! 1813: len += m->m_len; ! 1814: m = m->m_next; ! 1815: } ! 1816: } ! 1817: slp->ns_raw = m; ! 1818: slp->ns_cc -= len; ! 1819: slp->ns_reclen = 0; ! 1820: } else { ! 1821: slp->ns_flag &= ~SLP_GETSTREAM; ! 1822: return (0); ! 1823: } ! 1824: ! 1825: /* ! 1826: * Accumulate the fragments into a record. ! 1827: */ ! 1828: mpp = &slp->ns_frag; ! 1829: while (*mpp) ! 1830: mpp = &((*mpp)->m_next); ! 1831: *mpp = recm; ! 1832: if (slp->ns_flag & SLP_LASTFRAG) { ! 1833: if (slp->ns_recend) ! 1834: slp->ns_recend->m_nextpkt = slp->ns_frag; ! 1835: else ! 1836: slp->ns_rec = slp->ns_frag; ! 1837: slp->ns_recend = slp->ns_frag; ! 1838: slp->ns_frag = (struct mbuf *)0; ! 1839: } ! 1840: } ! 1841: } ! 1842: ! 1843: /* ! 1844: * Parse an RPC header. ! 1845: */ ! 1846: int ! 1847: nfsrv_dorec(slp, nfsd, ndp) ! 1848: register struct nfssvc_sock *slp; ! 1849: struct nfsd *nfsd; ! 1850: struct nfsrv_descript **ndp; ! 1851: { ! 1852: register struct mbuf *m; ! 1853: register struct mbuf *nam; ! 1854: register struct nfsrv_descript *nd; ! 1855: int error; ! 1856: ! 1857: *ndp = NULL; ! 1858: if ((slp->ns_flag & SLP_VALID) == 0 || ! 1859: (m = slp->ns_rec) == (struct mbuf *)0) ! 1860: return (ENOBUFS); ! 1861: slp->ns_rec = m->m_nextpkt; ! 1862: if (slp->ns_rec) ! 1863: m->m_nextpkt = (struct mbuf *)0; ! 1864: else ! 1865: slp->ns_recend = (struct mbuf *)0; ! 1866: if (m->m_type == MT_SONAME) { ! 1867: nam = m; ! 1868: m = m->m_next; ! 1869: nam->m_next = NULL; ! 1870: } else ! 1871: nam = NULL; ! 1872: MALLOC_ZONE(nd, struct nfsrv_descript *, ! 1873: sizeof (struct nfsrv_descript), M_NFSRVDESC, M_WAITOK); ! 1874: nd->nd_md = nd->nd_mrep = m; ! 1875: nd->nd_nam2 = nam; ! 1876: nd->nd_dpos = mtod(m, caddr_t); ! 1877: error = nfs_getreq(nd, nfsd, TRUE); ! 1878: if (error) { ! 1879: m_freem(nam); ! 1880: _FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC); ! 1881: return (error); ! 1882: } ! 1883: *ndp = nd; ! 1884: nfsd->nfsd_nd = nd; ! 1885: return (0); ! 1886: } ! 1887: ! 1888: /* ! 1889: * Parse an RPC request ! 1890: * - verify it ! 1891: * - fill in the cred struct. ! 1892: */ ! 1893: int ! 1894: nfs_getreq(nd, nfsd, has_header) ! 1895: register struct nfsrv_descript *nd; ! 1896: struct nfsd *nfsd; ! 1897: int has_header; ! 1898: { ! 1899: register int len, i; ! 1900: register u_long *tl; ! 1901: register long t1; ! 1902: struct uio uio; ! 1903: struct iovec iov; ! 1904: caddr_t dpos, cp2, cp; ! 1905: u_long nfsvers, auth_type; ! 1906: uid_t nickuid; ! 1907: int error = 0, nqnfs = 0, ticklen; ! 1908: struct mbuf *mrep, *md; ! 1909: register struct nfsuid *nuidp; ! 1910: struct timeval tvin, tvout; ! 1911: #if 0 /* until encrypted keys are implemented */ ! 1912: NFSKERBKEYSCHED_T keys; /* stores key schedule */ ! 1913: #endif ! 1914: ! 1915: mrep = nd->nd_mrep; ! 1916: md = nd->nd_md; ! 1917: dpos = nd->nd_dpos; ! 1918: if (has_header) { ! 1919: nfsm_dissect(tl, u_long *, 10 * NFSX_UNSIGNED); ! 1920: nd->nd_retxid = fxdr_unsigned(u_long, *tl++); ! 1921: if (*tl++ != rpc_call) { ! 1922: m_freem(mrep); ! 1923: return (EBADRPC); ! 1924: } ! 1925: } else ! 1926: nfsm_dissect(tl, u_long *, 8 * NFSX_UNSIGNED); ! 1927: nd->nd_repstat = 0; ! 1928: nd->nd_flag = 0; ! 1929: if (*tl++ != rpc_vers) { ! 1930: nd->nd_repstat = ERPCMISMATCH; ! 1931: nd->nd_procnum = NFSPROC_NOOP; ! 1932: return (0); ! 1933: } ! 1934: if (*tl != nfs_prog) { ! 1935: if (*tl == nqnfs_prog) ! 1936: nqnfs++; ! 1937: else { ! 1938: nd->nd_repstat = EPROGUNAVAIL; ! 1939: nd->nd_procnum = NFSPROC_NOOP; ! 1940: return (0); ! 1941: } ! 1942: } ! 1943: tl++; ! 1944: nfsvers = fxdr_unsigned(u_long, *tl++); ! 1945: if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) || ! 1946: (nfsvers != NQNFS_VER3 && nqnfs)) { ! 1947: nd->nd_repstat = EPROGMISMATCH; ! 1948: nd->nd_procnum = NFSPROC_NOOP; ! 1949: return (0); ! 1950: } ! 1951: if (nqnfs) ! 1952: nd->nd_flag = (ND_NFSV3 | ND_NQNFS); ! 1953: else if (nfsvers == NFS_VER3) ! 1954: nd->nd_flag = ND_NFSV3; ! 1955: nd->nd_procnum = fxdr_unsigned(u_long, *tl++); ! 1956: if (nd->nd_procnum == NFSPROC_NULL) ! 1957: return (0); ! 1958: if (nd->nd_procnum >= NFS_NPROCS || ! 1959: (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) || ! 1960: (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) { ! 1961: nd->nd_repstat = EPROCUNAVAIL; ! 1962: nd->nd_procnum = NFSPROC_NOOP; ! 1963: return (0); ! 1964: } ! 1965: if ((nd->nd_flag & ND_NFSV3) == 0) ! 1966: nd->nd_procnum = nfsv3_procid[nd->nd_procnum]; ! 1967: auth_type = *tl++; ! 1968: len = fxdr_unsigned(int, *tl++); ! 1969: if (len < 0 || len > RPCAUTH_MAXSIZ) { ! 1970: m_freem(mrep); ! 1971: return (EBADRPC); ! 1972: } ! 1973: ! 1974: nd->nd_flag &= ~ND_KERBAUTH; ! 1975: /* ! 1976: * Handle auth_unix or auth_kerb. ! 1977: */ ! 1978: if (auth_type == rpc_auth_unix) { ! 1979: len = fxdr_unsigned(int, *++tl); ! 1980: if (len < 0 || len > NFS_MAXNAMLEN) { ! 1981: m_freem(mrep); ! 1982: return (EBADRPC); ! 1983: } ! 1984: nfsm_adv(nfsm_rndup(len)); ! 1985: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); ! 1986: bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred)); ! 1987: nd->nd_cr.cr_ref = 1; ! 1988: nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); ! 1989: nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); ! 1990: len = fxdr_unsigned(int, *tl); ! 1991: if (len < 0 || len > RPCAUTH_UNIXGIDS) { ! 1992: m_freem(mrep); ! 1993: return (EBADRPC); ! 1994: } ! 1995: nfsm_dissect(tl, u_long *, (len + 2) * NFSX_UNSIGNED); ! 1996: for (i = 1; i <= len; i++) ! 1997: if (i < NGROUPS) ! 1998: nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); ! 1999: else ! 2000: tl++; ! 2001: nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); ! 2002: if (nd->nd_cr.cr_ngroups > 1) ! 2003: nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups); ! 2004: len = fxdr_unsigned(int, *++tl); ! 2005: if (len < 0 || len > RPCAUTH_MAXSIZ) { ! 2006: m_freem(mrep); ! 2007: return (EBADRPC); ! 2008: } ! 2009: if (len > 0) ! 2010: nfsm_adv(nfsm_rndup(len)); ! 2011: } else if (auth_type == rpc_auth_kerb) { ! 2012: switch (fxdr_unsigned(int, *tl++)) { ! 2013: case RPCAKN_FULLNAME: ! 2014: ticklen = fxdr_unsigned(int, *tl); ! 2015: *((u_long *)nfsd->nfsd_authstr) = *tl; ! 2016: uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED; ! 2017: nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED; ! 2018: if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { ! 2019: m_freem(mrep); ! 2020: return (EBADRPC); ! 2021: } ! 2022: uio.uio_offset = 0; ! 2023: uio.uio_iov = &iov; ! 2024: uio.uio_iovcnt = 1; ! 2025: uio.uio_segflg = UIO_SYSSPACE; ! 2026: iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4]; ! 2027: iov.iov_len = RPCAUTH_MAXSIZ - 4; ! 2028: nfsm_mtouio(&uio, uio.uio_resid); ! 2029: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); ! 2030: if (*tl++ != rpc_auth_kerb || ! 2031: fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) { ! 2032: printf("Bad kerb verifier\n"); ! 2033: nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); ! 2034: nd->nd_procnum = NFSPROC_NOOP; ! 2035: return (0); ! 2036: } ! 2037: nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED); ! 2038: tl = (u_long *)cp; ! 2039: if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) { ! 2040: printf("Not fullname kerb verifier\n"); ! 2041: nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); ! 2042: nd->nd_procnum = NFSPROC_NOOP; ! 2043: return (0); ! 2044: } ! 2045: cp += NFSX_UNSIGNED; ! 2046: bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED); ! 2047: nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED; ! 2048: nd->nd_flag |= ND_KERBFULL; ! 2049: nfsd->nfsd_flag |= NFSD_NEEDAUTH; ! 2050: break; ! 2051: case RPCAKN_NICKNAME: ! 2052: if (len != 2 * NFSX_UNSIGNED) { ! 2053: printf("Kerb nickname short\n"); ! 2054: nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED); ! 2055: nd->nd_procnum = NFSPROC_NOOP; ! 2056: return (0); ! 2057: } ! 2058: nickuid = fxdr_unsigned(uid_t, *tl); ! 2059: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); ! 2060: if (*tl++ != rpc_auth_kerb || ! 2061: fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) { ! 2062: printf("Kerb nick verifier bad\n"); ! 2063: nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); ! 2064: nd->nd_procnum = NFSPROC_NOOP; ! 2065: return (0); ! 2066: } ! 2067: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); ! 2068: tvin.tv_sec = *tl++; ! 2069: tvin.tv_usec = *tl; ! 2070: ! 2071: for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first; ! 2072: nuidp != 0; nuidp = nuidp->nu_hash.le_next) { ! 2073: if (nuidp->nu_cr.cr_uid == nickuid && ! 2074: (!nd->nd_nam2 || ! 2075: netaddr_match(NU_NETFAM(nuidp), ! 2076: &nuidp->nu_haddr, nd->nd_nam2))) ! 2077: break; ! 2078: } ! 2079: if (!nuidp) { ! 2080: nd->nd_repstat = ! 2081: (NFSERR_AUTHERR|AUTH_REJECTCRED); ! 2082: nd->nd_procnum = NFSPROC_NOOP; ! 2083: return (0); ! 2084: } ! 2085: ! 2086: /* ! 2087: * Now, decrypt the timestamp using the session key ! 2088: * and validate it. ! 2089: */ ! 2090: #if NFSKERB ! 2091: XXX ! 2092: #endif ! 2093: ! 2094: tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec); ! 2095: tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec); ! 2096: if (nuidp->nu_expire < time.tv_sec || ! 2097: nuidp->nu_timestamp.tv_sec > tvout.tv_sec || ! 2098: (nuidp->nu_timestamp.tv_sec == tvout.tv_sec && ! 2099: nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) { ! 2100: nuidp->nu_expire = 0; ! 2101: nd->nd_repstat = ! 2102: (NFSERR_AUTHERR|AUTH_REJECTVERF); ! 2103: nd->nd_procnum = NFSPROC_NOOP; ! 2104: return (0); ! 2105: } ! 2106: nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr); ! 2107: nd->nd_flag |= ND_KERBNICK; ! 2108: }; ! 2109: } else { ! 2110: nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED); ! 2111: nd->nd_procnum = NFSPROC_NOOP; ! 2112: return (0); ! 2113: } ! 2114: ! 2115: /* ! 2116: * For nqnfs, get piggybacked lease request. ! 2117: */ ! 2118: if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { ! 2119: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); ! 2120: nd->nd_flag |= fxdr_unsigned(int, *tl); ! 2121: if (nd->nd_flag & ND_LEASE) { ! 2122: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); ! 2123: nd->nd_duration = fxdr_unsigned(int, *tl); ! 2124: } else ! 2125: nd->nd_duration = NQ_MINLEASE; ! 2126: } else ! 2127: nd->nd_duration = NQ_MINLEASE; ! 2128: nd->nd_md = md; ! 2129: nd->nd_dpos = dpos; ! 2130: return (0); ! 2131: nfsmout: ! 2132: return (error); ! 2133: } ! 2134: ! 2135: /* ! 2136: * Search for a sleeping nfsd and wake it up. ! 2137: * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the ! 2138: * running nfsds will go look for the work in the nfssvc_sock list. ! 2139: */ ! 2140: void ! 2141: nfsrv_wakenfsd(slp) ! 2142: struct nfssvc_sock *slp; ! 2143: { ! 2144: register struct nfsd *nd; ! 2145: ! 2146: if ((slp->ns_flag & SLP_VALID) == 0) ! 2147: return; ! 2148: for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) { ! 2149: if (nd->nfsd_flag & NFSD_WAITING) { ! 2150: nd->nfsd_flag &= ~NFSD_WAITING; ! 2151: if (nd->nfsd_slp) ! 2152: panic("nfsd wakeup"); ! 2153: slp->ns_sref++; ! 2154: nd->nfsd_slp = slp; ! 2155: wakeup((caddr_t)nd); ! 2156: return; ! 2157: } ! 2158: } ! 2159: slp->ns_flag |= SLP_DOREC; ! 2160: nfsd_head_flag |= NFSD_CHECKSLP; ! 2161: } ! 2162: #endif /* NFS_NOSERVER */ ! 2163: ! 2164: static int ! 2165: nfs_msg(p, server, msg) ! 2166: struct proc *p; ! 2167: char *server, *msg; ! 2168: { ! 2169: tpr_t tpr; ! 2170: ! 2171: if (p) ! 2172: tpr = tprintf_open(p); ! 2173: else ! 2174: tpr = NULL; ! 2175: tprintf(tpr, "nfs server %s: %s\n", server, msg); ! 2176: tprintf_close(tpr); ! 2177: return (0); ! 2178: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.