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