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