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