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