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