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