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