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