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