1 /* $NetBSD: nfs_subs.c,v 1.18 1994/08/18 22:47:53 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 39 */ 40 41 /* 42 * These functions support the macros and help fiddle mbuf chains for 43 * the nfs op functions. They do things like create the rpc header and 44 * copy data between mbuf chains and uio lists. 45 */ 46 #include <sys/param.h> 47 #include <sys/proc.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/mount.h> 51 #include <sys/vnode.h> 52 #include <sys/namei.h> 53 #include <sys/mbuf.h> 54 #include <sys/socket.h> 55 #include <sys/stat.h> 56 57 #include <nfs/rpcv2.h> 58 #include <nfs/nfsv2.h> 59 #include <nfs/nfsnode.h> 60 #include <nfs/nfs.h> 61 #include <nfs/xdr_subs.h> 62 #include <nfs/nfsm_subs.h> 63 #include <nfs/nfsmount.h> 64 #include <nfs/nqnfs.h> 65 #include <nfs/nfsrtt.h> 66 67 #include <miscfs/specfs/specdev.h> 68 69 #include <netinet/in.h> 70 #ifdef ISO 71 #include <netiso/iso.h> 72 #endif 73 74 #define TRUE 1 75 #define FALSE 0 76 77 /* 78 * Data items converted to xdr at startup, since they are constant 79 * This is kinda hokey, but may save a little time doing byte swaps 80 */ 81 u_long nfs_procids[NFS_NPROCS]; 82 u_long nfs_xdrneg1; 83 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 84 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 85 rpc_auth_kerb; 86 u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 87 88 /* And other global data */ 89 static u_long nfs_xid = 0; 90 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 91 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 92 extern int nqnfs_piggy[NFS_NPROCS]; 93 extern struct nfsrtt nfsrtt; 94 extern time_t nqnfsstarttime; 95 extern u_long nqnfs_prog, nqnfs_vers; 96 extern int nqsrv_clockskew; 97 extern int nqsrv_writeslack; 98 extern int nqsrv_maxlease; 99 100 LIST_HEAD(nfsnodehashhead, nfsnode); 101 extern struct nfsnodehashhead *nfs_hash __P((nfsv2fh_t *)); 102 103 /* 104 * Create the header for an rpc request packet 105 * The hsiz is the size of the rest of the nfs request header. 106 * (just used to decide if a cluster is a good idea) 107 */ 108 struct mbuf * 109 nfsm_reqh(vp, procid, hsiz, bposp) 110 struct vnode *vp; 111 u_long procid; 112 int hsiz; 113 caddr_t *bposp; 114 { 115 register struct mbuf *mb; 116 register u_long *tl; 117 register caddr_t bpos; 118 struct mbuf *mb2; 119 struct nfsmount *nmp; 120 int nqflag; 121 122 MGET(mb, M_WAIT, MT_DATA); 123 if (hsiz >= MINCLSIZE) 124 MCLGET(mb, M_WAIT); 125 mb->m_len = 0; 126 bpos = mtod(mb, caddr_t); 127 128 /* 129 * For NQNFS, add lease request. 130 */ 131 if (vp) { 132 nmp = VFSTONFS(vp->v_mount); 133 if (nmp->nm_flag & NFSMNT_NQNFS) { 134 nqflag = NQNFS_NEEDLEASE(vp, procid); 135 if (nqflag) { 136 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 137 *tl++ = txdr_unsigned(nqflag); 138 *tl = txdr_unsigned(nmp->nm_leaseterm); 139 } else { 140 nfsm_build(tl, u_long *, NFSX_UNSIGNED); 141 *tl = 0; 142 } 143 } 144 } 145 /* Finally, return values */ 146 *bposp = bpos; 147 return (mb); 148 } 149 150 /* 151 * Build the RPC header and fill in the authorization info. 152 * The authorization string argument is only used when the credentials 153 * come from outside of the kernel. 154 * Returns the head of the mbuf list. 155 */ 156 struct mbuf * 157 nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 158 mrest_len, mbp, xidp) 159 register struct ucred *cr; 160 int nqnfs; 161 int procid; 162 int auth_type; 163 int auth_len; 164 char *auth_str; 165 struct mbuf *mrest; 166 int mrest_len; 167 struct mbuf **mbp; 168 u_long *xidp; 169 { 170 register struct mbuf *mb; 171 register u_long *tl; 172 register caddr_t bpos; 173 register int i; 174 struct mbuf *mreq, *mb2; 175 int siz, grpsiz, authsiz; 176 177 authsiz = nfsm_rndup(auth_len); 178 if (auth_type == RPCAUTH_NQNFS) 179 authsiz += 2 * NFSX_UNSIGNED; 180 MGETHDR(mb, M_WAIT, MT_DATA); 181 if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 182 MCLGET(mb, M_WAIT); 183 } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 184 MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 185 } else { 186 MH_ALIGN(mb, 8*NFSX_UNSIGNED); 187 } 188 mb->m_len = 0; 189 mreq = mb; 190 bpos = mtod(mb, caddr_t); 191 192 /* 193 * First the RPC header. 194 */ 195 nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 196 if (++nfs_xid == 0) 197 nfs_xid++; 198 *tl++ = *xidp = txdr_unsigned(nfs_xid); 199 *tl++ = rpc_call; 200 *tl++ = rpc_vers; 201 if (nqnfs) { 202 *tl++ = txdr_unsigned(NQNFS_PROG); 203 *tl++ = txdr_unsigned(NQNFS_VER1); 204 } else { 205 *tl++ = txdr_unsigned(NFS_PROG); 206 *tl++ = txdr_unsigned(NFS_VER2); 207 } 208 *tl++ = txdr_unsigned(procid); 209 210 /* 211 * And then the authorization cred. 212 */ 213 *tl++ = txdr_unsigned(auth_type); 214 *tl = txdr_unsigned(authsiz); 215 switch (auth_type) { 216 case RPCAUTH_UNIX: 217 nfsm_build(tl, u_long *, auth_len); 218 *tl++ = 0; /* stamp ?? */ 219 *tl++ = 0; /* NULL hostname */ 220 *tl++ = txdr_unsigned(cr->cr_uid); 221 *tl++ = txdr_unsigned(cr->cr_groups[0]); 222 grpsiz = (auth_len >> 2) - 5; 223 *tl++ = txdr_unsigned(grpsiz); 224 for (i = 1; i <= grpsiz; i++) 225 *tl++ = txdr_unsigned(cr->cr_groups[i]); 226 break; 227 case RPCAUTH_NQNFS: 228 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 229 *tl++ = txdr_unsigned(cr->cr_uid); 230 *tl = txdr_unsigned(auth_len); 231 siz = auth_len; 232 while (siz > 0) { 233 if (M_TRAILINGSPACE(mb) == 0) { 234 MGET(mb2, M_WAIT, MT_DATA); 235 if (siz >= MINCLSIZE) 236 MCLGET(mb2, M_WAIT); 237 mb->m_next = mb2; 238 mb = mb2; 239 mb->m_len = 0; 240 bpos = mtod(mb, caddr_t); 241 } 242 i = min(siz, M_TRAILINGSPACE(mb)); 243 bcopy(auth_str, bpos, i); 244 mb->m_len += i; 245 auth_str += i; 246 bpos += i; 247 siz -= i; 248 } 249 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 250 for (i = 0; i < siz; i++) 251 *bpos++ = '\0'; 252 mb->m_len += siz; 253 } 254 break; 255 }; 256 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 257 *tl++ = txdr_unsigned(RPCAUTH_NULL); 258 *tl = 0; 259 mb->m_next = mrest; 260 mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 261 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 262 *mbp = mb; 263 return (mreq); 264 } 265 266 /* 267 * copies mbuf chain to the uio scatter/gather list 268 */ 269 nfsm_mbuftouio(mrep, uiop, siz, dpos) 270 struct mbuf **mrep; 271 register struct uio *uiop; 272 int siz; 273 caddr_t *dpos; 274 { 275 register char *mbufcp, *uiocp; 276 register int xfer, left, len; 277 register struct mbuf *mp; 278 long uiosiz, rem; 279 int error = 0; 280 281 mp = *mrep; 282 mbufcp = *dpos; 283 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 284 rem = nfsm_rndup(siz)-siz; 285 while (siz > 0) { 286 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 287 return (EFBIG); 288 left = uiop->uio_iov->iov_len; 289 uiocp = uiop->uio_iov->iov_base; 290 if (left > siz) 291 left = siz; 292 uiosiz = left; 293 while (left > 0) { 294 while (len == 0) { 295 mp = mp->m_next; 296 if (mp == NULL) 297 return (EBADRPC); 298 mbufcp = mtod(mp, caddr_t); 299 len = mp->m_len; 300 } 301 xfer = (left > len) ? len : left; 302 #ifdef notdef 303 /* Not Yet.. */ 304 if (uiop->uio_iov->iov_op != NULL) 305 (*(uiop->uio_iov->iov_op)) 306 (mbufcp, uiocp, xfer); 307 else 308 #endif 309 if (uiop->uio_segflg == UIO_SYSSPACE) 310 bcopy(mbufcp, uiocp, xfer); 311 else 312 copyout(mbufcp, uiocp, xfer); 313 left -= xfer; 314 len -= xfer; 315 mbufcp += xfer; 316 uiocp += xfer; 317 uiop->uio_offset += xfer; 318 uiop->uio_resid -= xfer; 319 } 320 if (uiop->uio_iov->iov_len <= siz) { 321 uiop->uio_iovcnt--; 322 uiop->uio_iov++; 323 } else { 324 uiop->uio_iov->iov_base += uiosiz; 325 uiop->uio_iov->iov_len -= uiosiz; 326 } 327 siz -= uiosiz; 328 } 329 *dpos = mbufcp; 330 *mrep = mp; 331 if (rem > 0) { 332 if (len < rem) 333 error = nfs_adv(mrep, dpos, rem, len); 334 else 335 *dpos += rem; 336 } 337 return (error); 338 } 339 340 /* 341 * copies a uio scatter/gather list to an mbuf chain... 342 */ 343 nfsm_uiotombuf(uiop, mq, siz, bpos) 344 register struct uio *uiop; 345 struct mbuf **mq; 346 int siz; 347 caddr_t *bpos; 348 { 349 register char *uiocp; 350 register struct mbuf *mp, *mp2; 351 register int xfer, left, mlen; 352 int uiosiz, clflg, rem; 353 char *cp; 354 355 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 356 clflg = 1; 357 else 358 clflg = 0; 359 rem = nfsm_rndup(siz)-siz; 360 mp = mp2 = *mq; 361 while (siz > 0) { 362 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 363 return (EINVAL); 364 left = uiop->uio_iov->iov_len; 365 uiocp = uiop->uio_iov->iov_base; 366 if (left > siz) 367 left = siz; 368 uiosiz = left; 369 while (left > 0) { 370 mlen = M_TRAILINGSPACE(mp); 371 if (mlen == 0) { 372 MGET(mp, M_WAIT, MT_DATA); 373 if (clflg) 374 MCLGET(mp, M_WAIT); 375 mp->m_len = 0; 376 mp2->m_next = mp; 377 mp2 = mp; 378 mlen = M_TRAILINGSPACE(mp); 379 } 380 xfer = (left > mlen) ? mlen : left; 381 #ifdef notdef 382 /* Not Yet.. */ 383 if (uiop->uio_iov->iov_op != NULL) 384 (*(uiop->uio_iov->iov_op)) 385 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 386 else 387 #endif 388 if (uiop->uio_segflg == UIO_SYSSPACE) 389 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 390 else 391 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 392 mp->m_len += xfer; 393 left -= xfer; 394 uiocp += xfer; 395 uiop->uio_offset += xfer; 396 uiop->uio_resid -= xfer; 397 } 398 if (uiop->uio_iov->iov_len <= siz) { 399 uiop->uio_iovcnt--; 400 uiop->uio_iov++; 401 } else { 402 uiop->uio_iov->iov_base += uiosiz; 403 uiop->uio_iov->iov_len -= uiosiz; 404 } 405 siz -= uiosiz; 406 } 407 if (rem > 0) { 408 if (rem > M_TRAILINGSPACE(mp)) { 409 MGET(mp, M_WAIT, MT_DATA); 410 mp->m_len = 0; 411 mp2->m_next = mp; 412 } 413 cp = mtod(mp, caddr_t)+mp->m_len; 414 for (left = 0; left < rem; left++) 415 *cp++ = '\0'; 416 mp->m_len += rem; 417 *bpos = cp; 418 } else 419 *bpos = mtod(mp, caddr_t)+mp->m_len; 420 *mq = mp; 421 return (0); 422 } 423 424 /* 425 * Help break down an mbuf chain by setting the first siz bytes contiguous 426 * pointed to by returned val. 427 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 428 * cases. (The macros use the vars. dpos and dpos2) 429 */ 430 nfsm_disct(mdp, dposp, siz, left, cp2) 431 struct mbuf **mdp; 432 caddr_t *dposp; 433 int siz; 434 int left; 435 caddr_t *cp2; 436 { 437 register struct mbuf *mp, *mp2; 438 register int siz2, xfer; 439 register caddr_t p; 440 441 mp = *mdp; 442 while (left == 0) { 443 *mdp = mp = mp->m_next; 444 if (mp == NULL) 445 return (EBADRPC); 446 left = mp->m_len; 447 *dposp = mtod(mp, caddr_t); 448 } 449 if (left >= siz) { 450 *cp2 = *dposp; 451 *dposp += siz; 452 } else if (mp->m_next == NULL) { 453 return (EBADRPC); 454 } else if (siz > MHLEN) { 455 panic("nfs S too big"); 456 } else { 457 MGET(mp2, M_WAIT, MT_DATA); 458 mp2->m_next = mp->m_next; 459 mp->m_next = mp2; 460 mp->m_len -= left; 461 mp = mp2; 462 *cp2 = p = mtod(mp, caddr_t); 463 bcopy(*dposp, p, left); /* Copy what was left */ 464 siz2 = siz-left; 465 p += left; 466 mp2 = mp->m_next; 467 /* Loop around copying up the siz2 bytes */ 468 while (siz2 > 0) { 469 if (mp2 == NULL) 470 return (EBADRPC); 471 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 472 if (xfer > 0) { 473 bcopy(mtod(mp2, caddr_t), p, xfer); 474 NFSMADV(mp2, xfer); 475 mp2->m_len -= xfer; 476 p += xfer; 477 siz2 -= xfer; 478 } 479 if (siz2 > 0) 480 mp2 = mp2->m_next; 481 } 482 mp->m_len = siz; 483 *mdp = mp2; 484 *dposp = mtod(mp2, caddr_t); 485 } 486 return (0); 487 } 488 489 /* 490 * Advance the position in the mbuf chain. 491 */ 492 nfs_adv(mdp, dposp, offs, left) 493 struct mbuf **mdp; 494 caddr_t *dposp; 495 int offs; 496 int left; 497 { 498 register struct mbuf *m; 499 register int s; 500 501 m = *mdp; 502 s = left; 503 while (s < offs) { 504 offs -= s; 505 m = m->m_next; 506 if (m == NULL) 507 return (EBADRPC); 508 s = m->m_len; 509 } 510 *mdp = m; 511 *dposp = mtod(m, caddr_t)+offs; 512 return (0); 513 } 514 515 /* 516 * Copy a string into mbufs for the hard cases... 517 */ 518 nfsm_strtmbuf(mb, bpos, cp, siz) 519 struct mbuf **mb; 520 char **bpos; 521 char *cp; 522 long siz; 523 { 524 register struct mbuf *m1, *m2; 525 long left, xfer, len, tlen; 526 u_long *tl; 527 int putsize; 528 529 putsize = 1; 530 m2 = *mb; 531 left = M_TRAILINGSPACE(m2); 532 if (left > 0) { 533 tl = ((u_long *)(*bpos)); 534 *tl++ = txdr_unsigned(siz); 535 putsize = 0; 536 left -= NFSX_UNSIGNED; 537 m2->m_len += NFSX_UNSIGNED; 538 if (left > 0) { 539 bcopy(cp, (caddr_t) tl, left); 540 siz -= left; 541 cp += left; 542 m2->m_len += left; 543 left = 0; 544 } 545 } 546 /* Loop around adding mbufs */ 547 while (siz > 0) { 548 MGET(m1, M_WAIT, MT_DATA); 549 if (siz > MLEN) 550 MCLGET(m1, M_WAIT); 551 m1->m_len = NFSMSIZ(m1); 552 m2->m_next = m1; 553 m2 = m1; 554 tl = mtod(m1, u_long *); 555 tlen = 0; 556 if (putsize) { 557 *tl++ = txdr_unsigned(siz); 558 m1->m_len -= NFSX_UNSIGNED; 559 tlen = NFSX_UNSIGNED; 560 putsize = 0; 561 } 562 if (siz < m1->m_len) { 563 len = nfsm_rndup(siz); 564 xfer = siz; 565 if (xfer < len) 566 *(tl+(xfer>>2)) = 0; 567 } else { 568 xfer = len = m1->m_len; 569 } 570 bcopy(cp, (caddr_t) tl, xfer); 571 m1->m_len = len+tlen; 572 siz -= xfer; 573 cp += xfer; 574 } 575 *mb = m1; 576 *bpos = mtod(m1, caddr_t)+m1->m_len; 577 return (0); 578 } 579 580 /* 581 * Called once to initialize data structures... 582 */ 583 nfs_init() 584 { 585 register int i; 586 587 nfsrtt.pos = 0; 588 rpc_vers = txdr_unsigned(RPC_VER2); 589 rpc_call = txdr_unsigned(RPC_CALL); 590 rpc_reply = txdr_unsigned(RPC_REPLY); 591 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 592 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 593 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 594 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 595 rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 596 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 597 rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 598 nfs_vers = txdr_unsigned(NFS_VER2); 599 nfs_prog = txdr_unsigned(NFS_PROG); 600 nfs_true = txdr_unsigned(TRUE); 601 nfs_false = txdr_unsigned(FALSE); 602 nfs_xdrneg1 = txdr_unsigned(-1); 603 /* Loop thru nfs procids */ 604 for (i = 0; i < NFS_NPROCS; i++) 605 nfs_procids[i] = txdr_unsigned(i); 606 #ifdef NFSCLIENT 607 /* Ensure async daemons disabled */ 608 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 609 nfs_iodwant[i] = (struct proc *)0; 610 TAILQ_INIT(&nfs_bufq); 611 nfs_nhinit(); /* Init the nfsnode table */ 612 #endif /* NFSCLIENT */ 613 #ifdef NFSSERVER 614 nfsrv_init(0); /* Init server data structures */ 615 nfsrv_initcache(); /* Init the server request cache */ 616 #endif /* NFSSERVER */ 617 618 /* 619 * Initialize the nqnfs server stuff. 620 */ 621 if (nqnfsstarttime == 0) { 622 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 623 + nqsrv_clockskew + nqsrv_writeslack; 624 NQLOADNOVRAM(nqnfsstarttime); 625 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 626 nqnfs_vers = txdr_unsigned(NQNFS_VER1); 627 CIRCLEQ_INIT(&nqtimerhead); 628 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 629 } 630 631 /* 632 * Initialize reply list and start timer 633 */ 634 TAILQ_INIT(&nfs_reqq); 635 nfs_timer(); 636 } 637 638 #ifdef NFSCLIENT 639 /* 640 * Attribute cache routines. 641 * nfs_loadattrcache() - loads or updates the cache contents from attributes 642 * that are on the mbuf list 643 * nfs_getattrcache() - returns valid attributes if found in cache, returns 644 * error otherwise 645 */ 646 647 /* 648 * Load the attribute cache (that lives in the nfsnode entry) with 649 * the values on the mbuf list and 650 * Iff vap not NULL 651 * copy the attributes to *vaper 652 */ 653 nfs_loadattrcache(vpp, mdp, dposp, vaper) 654 struct vnode **vpp; 655 struct mbuf **mdp; 656 caddr_t *dposp; 657 struct vattr *vaper; 658 { 659 register struct vnode *vp = *vpp; 660 register struct vattr *vap; 661 register struct nfsv2_fattr *fp; 662 extern int (**spec_nfsv2nodeop_p)(); 663 register struct nfsnode *np; 664 register struct nfsnodehashhead *nhpp; 665 register long t1; 666 caddr_t dpos, cp2; 667 int error = 0, isnq; 668 struct mbuf *md; 669 enum vtype vtyp; 670 u_short vmode; 671 long rdev; 672 struct timespec mtime; 673 struct vnode *nvp; 674 675 md = *mdp; 676 dpos = *dposp; 677 t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 678 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 679 if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2)) 680 return (error); 681 fp = (struct nfsv2_fattr *)cp2; 682 vtyp = nfstov_type(fp->fa_type); 683 vmode = fxdr_unsigned(u_short, fp->fa_mode); 684 if (vtyp == VNON || vtyp == VREG) 685 vtyp = IFTOVT(vmode); 686 if (isnq) { 687 rdev = fxdr_unsigned(long, fp->fa_nqrdev); 688 fxdr_nqtime(&fp->fa_nqmtime, &mtime); 689 } else { 690 rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 691 fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 692 } 693 /* 694 * If v_type == VNON it is a new node, so fill in the v_type, 695 * n_mtime fields. Check to see if it represents a special 696 * device, and if so, check for a possible alias. Once the 697 * correct vnode has been obtained, fill in the rest of the 698 * information. 699 */ 700 np = VTONFS(vp); 701 if (vp->v_type == VNON) { 702 if (vtyp == VCHR && rdev == 0xffffffff) 703 vp->v_type = vtyp = VFIFO; 704 else 705 vp->v_type = vtyp; 706 if (vp->v_type == VFIFO) { 707 #ifdef FIFO 708 extern int (**fifo_nfsv2nodeop_p)(); 709 vp->v_op = fifo_nfsv2nodeop_p; 710 #else 711 return (EOPNOTSUPP); 712 #endif /* FIFO */ 713 } 714 if (vp->v_type == VCHR || vp->v_type == VBLK) { 715 vp->v_op = spec_nfsv2nodeop_p; 716 if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 717 /* 718 * Discard unneeded vnode, but save its nfsnode. 719 */ 720 LIST_REMOVE(np, n_hash); 721 nvp->v_data = vp->v_data; 722 vp->v_data = NULL; 723 vp->v_op = spec_vnodeop_p; 724 vrele(vp); 725 vgone(vp); 726 /* 727 * Reinitialize aliased node. 728 */ 729 np->n_vnode = nvp; 730 nhpp = nfs_hash(&np->n_fh); 731 LIST_INSERT_HEAD(nhpp, np, n_hash); 732 *vpp = vp = nvp; 733 } 734 } 735 np->n_mtime = mtime.ts_sec; 736 } 737 vap = &np->n_vattr; 738 vap->va_type = vtyp; 739 vap->va_mode = (vmode & 07777); 740 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 741 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 742 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 743 vap->va_rdev = (dev_t)rdev; 744 vap->va_mtime = mtime; 745 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 746 if (isnq) { 747 fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 748 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 749 fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 750 vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 751 fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 752 vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 753 fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 754 vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 755 fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 756 } else { 757 vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 758 vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 759 vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 760 vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 761 fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 762 vap->va_flags = 0; 763 fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime); 764 vap->va_gen = 0; 765 vap->va_filerev = 0; 766 } 767 if (vap->va_size != np->n_size) { 768 if (vap->va_type == VREG) { 769 if (np->n_flag & NMODIFIED) { 770 if (vap->va_size < np->n_size) 771 vap->va_size = np->n_size; 772 else 773 np->n_size = vap->va_size; 774 } else 775 np->n_size = vap->va_size; 776 vnode_pager_setsize(vp, (u_long)np->n_size); 777 } else 778 np->n_size = vap->va_size; 779 } 780 np->n_attrstamp = time.tv_sec; 781 *dposp = dpos; 782 *mdp = md; 783 if (vaper != NULL) { 784 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 785 #ifdef notdef 786 if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 787 if (np->n_size > vap->va_size) 788 vaper->va_size = np->n_size; 789 #endif 790 if (np->n_flag & NCHG) { 791 if (np->n_flag & NACC) { 792 vaper->va_atime.ts_sec = np->n_atim.tv_sec; 793 vaper->va_atime.ts_nsec = 794 np->n_atim.tv_usec * 1000; 795 } 796 if (np->n_flag & NUPD) { 797 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 798 vaper->va_mtime.ts_nsec = 799 np->n_mtim.tv_usec * 1000; 800 } 801 } 802 } 803 return (0); 804 } 805 806 /* 807 * Check the time stamp 808 * If the cache is valid, copy contents to *vap and return 0 809 * otherwise return an error 810 */ 811 nfs_getattrcache(vp, vaper) 812 register struct vnode *vp; 813 struct vattr *vaper; 814 { 815 register struct nfsnode *np = VTONFS(vp); 816 register struct vattr *vap; 817 818 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 819 if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 820 nfsstats.attrcache_misses++; 821 return (ENOENT); 822 } 823 } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 824 nfsstats.attrcache_misses++; 825 return (ENOENT); 826 } 827 nfsstats.attrcache_hits++; 828 vap = &np->n_vattr; 829 if (vap->va_size != np->n_size) { 830 if (vap->va_type == VREG) { 831 if (np->n_flag & NMODIFIED) { 832 if (vap->va_size < np->n_size) 833 vap->va_size = np->n_size; 834 else 835 np->n_size = vap->va_size; 836 } else 837 np->n_size = vap->va_size; 838 vnode_pager_setsize(vp, (u_long)np->n_size); 839 } else 840 np->n_size = vap->va_size; 841 } 842 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 843 #ifdef notdef 844 if ((np->n_flag & NMODIFIED) == 0) { 845 np->n_size = vaper->va_size; 846 vnode_pager_setsize(vp, (u_long)np->n_size); 847 } else if (np->n_size > vaper->va_size) 848 if (np->n_size > vaper->va_size) 849 vaper->va_size = np->n_size; 850 #endif 851 if (np->n_flag & NCHG) { 852 if (np->n_flag & NACC) { 853 vaper->va_atime.ts_sec = np->n_atim.tv_sec; 854 vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 855 } 856 if (np->n_flag & NUPD) { 857 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 858 vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 859 } 860 } 861 return (0); 862 } 863 #endif 864 865 /* 866 * Set up nameidata for a lookup() call and do it 867 */ 868 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 869 register struct nameidata *ndp; 870 fhandle_t *fhp; 871 int len; 872 struct nfssvc_sock *slp; 873 struct mbuf *nam; 874 struct mbuf **mdp; 875 caddr_t *dposp; 876 struct proc *p; 877 { 878 register int i, rem; 879 register struct mbuf *md; 880 register char *fromcp, *tocp; 881 struct vnode *dp; 882 int error, rdonly; 883 struct componentname *cnp = &ndp->ni_cnd; 884 885 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 886 /* 887 * Copy the name from the mbuf list to ndp->ni_pnbuf 888 * and set the various ndp fields appropriately. 889 */ 890 fromcp = *dposp; 891 tocp = cnp->cn_pnbuf; 892 md = *mdp; 893 rem = mtod(md, caddr_t) + md->m_len - fromcp; 894 cnp->cn_hash = 0; 895 for (i = 0; i < len; i++) { 896 while (rem == 0) { 897 md = md->m_next; 898 if (md == NULL) { 899 error = EBADRPC; 900 goto out; 901 } 902 fromcp = mtod(md, caddr_t); 903 rem = md->m_len; 904 } 905 if (*fromcp == '\0' || *fromcp == '/') { 906 error = EINVAL; 907 goto out; 908 } 909 cnp->cn_hash += (unsigned char)*fromcp; 910 *tocp++ = *fromcp++; 911 rem--; 912 } 913 *tocp = '\0'; 914 *mdp = md; 915 *dposp = fromcp; 916 len = nfsm_rndup(len)-len; 917 if (len > 0) { 918 if (rem >= len) 919 *dposp += len; 920 else if (error = nfs_adv(mdp, dposp, len, rem)) 921 goto out; 922 } 923 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 924 cnp->cn_nameptr = cnp->cn_pnbuf; 925 /* 926 * Extract and set starting directory. 927 */ 928 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 929 nam, &rdonly)) 930 goto out; 931 if (dp->v_type != VDIR) { 932 vrele(dp); 933 error = ENOTDIR; 934 goto out; 935 } 936 ndp->ni_startdir = dp; 937 if (rdonly) 938 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 939 else 940 cnp->cn_flags |= NOCROSSMOUNT; 941 /* 942 * And call lookup() to do the real work 943 */ 944 cnp->cn_proc = p; 945 if (error = lookup(ndp)) 946 goto out; 947 /* 948 * Check for encountering a symbolic link 949 */ 950 if (cnp->cn_flags & ISSYMLINK) { 951 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 952 vput(ndp->ni_dvp); 953 else 954 vrele(ndp->ni_dvp); 955 vput(ndp->ni_vp); 956 ndp->ni_vp = NULL; 957 error = EINVAL; 958 goto out; 959 } 960 /* 961 * Check for saved name request 962 */ 963 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 964 cnp->cn_flags |= HASBUF; 965 return (0); 966 } 967 out: 968 FREE(cnp->cn_pnbuf, M_NAMEI); 969 return (error); 970 } 971 972 /* 973 * A fiddled version of m_adj() that ensures null fill to a long 974 * boundary and only trims off the back end 975 */ 976 void 977 nfsm_adj(mp, len, nul) 978 struct mbuf *mp; 979 register int len; 980 int nul; 981 { 982 register struct mbuf *m; 983 register int count, i; 984 register char *cp; 985 986 /* 987 * Trim from tail. Scan the mbuf chain, 988 * calculating its length and finding the last mbuf. 989 * If the adjustment only affects this mbuf, then just 990 * adjust and return. Otherwise, rescan and truncate 991 * after the remaining size. 992 */ 993 count = 0; 994 m = mp; 995 for (;;) { 996 count += m->m_len; 997 if (m->m_next == (struct mbuf *)0) 998 break; 999 m = m->m_next; 1000 } 1001 if (m->m_len > len) { 1002 m->m_len -= len; 1003 if (nul > 0) { 1004 cp = mtod(m, caddr_t)+m->m_len-nul; 1005 for (i = 0; i < nul; i++) 1006 *cp++ = '\0'; 1007 } 1008 return; 1009 } 1010 count -= len; 1011 if (count < 0) 1012 count = 0; 1013 /* 1014 * Correct length for chain is "count". 1015 * Find the mbuf with last data, adjust its length, 1016 * and toss data from remaining mbufs on chain. 1017 */ 1018 for (m = mp; m; m = m->m_next) { 1019 if (m->m_len >= count) { 1020 m->m_len = count; 1021 if (nul > 0) { 1022 cp = mtod(m, caddr_t)+m->m_len-nul; 1023 for (i = 0; i < nul; i++) 1024 *cp++ = '\0'; 1025 } 1026 break; 1027 } 1028 count -= m->m_len; 1029 } 1030 while (m = m->m_next) 1031 m->m_len = 0; 1032 } 1033 1034 /* 1035 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1036 * - look up fsid in mount list (if not found ret error) 1037 * - get vp and export rights by calling VFS_FHTOVP() 1038 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1039 * - if not lockflag unlock it with VOP_UNLOCK() 1040 */ 1041 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 1042 fhandle_t *fhp; 1043 int lockflag; 1044 struct vnode **vpp; 1045 struct ucred *cred; 1046 struct nfssvc_sock *slp; 1047 struct mbuf *nam; 1048 int *rdonlyp; 1049 { 1050 register struct mount *mp; 1051 register struct nfsuid *uidp; 1052 register int i; 1053 struct ucred *credanon; 1054 int error, exflags; 1055 1056 *vpp = (struct vnode *)0; 1057 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 1058 return (ESTALE); 1059 if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 1060 return (error); 1061 /* 1062 * Check/setup credentials. 1063 */ 1064 if (exflags & MNT_EXKERB) { 1065 for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0; 1066 uidp = uidp->nu_hash.le_next) { 1067 if (uidp->nu_uid == cred->cr_uid) 1068 break; 1069 } 1070 if (uidp == 0) { 1071 vput(*vpp); 1072 return (NQNFS_AUTHERR); 1073 } 1074 cred->cr_uid = uidp->nu_cr.cr_uid; 1075 for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 1076 cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 1077 cred->cr_ngroups = i; 1078 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1079 cred->cr_uid = credanon->cr_uid; 1080 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1081 cred->cr_groups[i] = credanon->cr_groups[i]; 1082 cred->cr_ngroups = i; 1083 } 1084 if (exflags & MNT_EXRDONLY) 1085 *rdonlyp = 1; 1086 else 1087 *rdonlyp = 0; 1088 if (!lockflag) 1089 VOP_UNLOCK(*vpp); 1090 return (0); 1091 } 1092 1093 /* 1094 * This function compares two net addresses by family and returns TRUE 1095 * if they are the same host. 1096 * If there is any doubt, return FALSE. 1097 * The AF_INET family is handled as a special case so that address mbufs 1098 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1099 */ 1100 netaddr_match(family, haddr, nam) 1101 int family; 1102 union nethostaddr *haddr; 1103 struct mbuf *nam; 1104 { 1105 register struct sockaddr_in *inetaddr; 1106 1107 switch (family) { 1108 case AF_INET: 1109 inetaddr = mtod(nam, struct sockaddr_in *); 1110 if (inetaddr->sin_family == AF_INET && 1111 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1112 return (1); 1113 break; 1114 #ifdef ISO 1115 case AF_ISO: 1116 { 1117 register struct sockaddr_iso *isoaddr1, *isoaddr2; 1118 1119 isoaddr1 = mtod(nam, struct sockaddr_iso *); 1120 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 1121 if (isoaddr1->siso_family == AF_ISO && 1122 isoaddr1->siso_nlen > 0 && 1123 isoaddr1->siso_nlen == isoaddr2->siso_nlen && 1124 SAME_ISOADDR(isoaddr1, isoaddr2)) 1125 return (1); 1126 break; 1127 } 1128 #endif /* ISO */ 1129 default: 1130 break; 1131 }; 1132 return (0); 1133 } 1134