1 /* 2 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Copyright (c) 1989, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This code is derived from software contributed to Berkeley by 39 * Rick Macklem at The University of Guelph. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 */ 65 66 /* 67 * These functions support the macros and help fiddle mbuf chains for 68 * the nfs op functions. They do things like create the rpc header and 69 * copy data between mbuf chains and uio lists. 70 */ 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/kernel.h> 74 #include <sys/buf.h> 75 #include <sys/proc.h> 76 #include <sys/mount.h> 77 #include <sys/vnode.h> 78 #include <sys/nlookup.h> 79 #include <sys/namei.h> 80 #include <sys/mbuf.h> 81 #include <sys/socket.h> 82 #include <sys/stat.h> 83 #include <sys/malloc.h> 84 #include <sys/sysent.h> 85 #include <sys/syscall.h> 86 #include <sys/conf.h> 87 #include <sys/objcache.h> 88 89 #include <vm/vm.h> 90 #include <vm/vm_object.h> 91 #include <vm/vm_extern.h> 92 93 #include <sys/buf2.h> 94 95 #include "rpcv2.h" 96 #include "nfsproto.h" 97 #include "nfs.h" 98 #include "nfsmount.h" 99 #include "nfsnode.h" 100 #include "xdr_subs.h" 101 #include "nfsm_subs.h" 102 #include "nfsrtt.h" 103 104 #include <netinet/in.h> 105 106 static u_int32_t nfs_xid = 0; 107 108 /* 109 * Create the header for an rpc request packet 110 * The hsiz is the size of the rest of the nfs request header. 111 * (just used to decide if a cluster is a good idea) 112 */ 113 void 114 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz) 115 { 116 info->mb = m_getl(hsiz, MB_WAIT, MT_DATA, 0, NULL); 117 info->mb->m_len = 0; 118 info->mreq = info->mb; 119 info->bpos = mtod(info->mb, caddr_t); 120 } 121 122 /* 123 * Build the RPC header and fill in the authorization info. 124 * The authorization string argument is only used when the credentials 125 * come from outside of the kernel. 126 * Returns the head of the mbuf list. 127 */ 128 struct mbuf * 129 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 130 int auth_len, char *auth_str, int verf_len, char *verf_str, 131 struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 132 u_int32_t *xidp) 133 { 134 struct nfsm_info info; 135 struct mbuf *mb2; 136 u_int32_t *tl; 137 u_int32_t xid; 138 int siz, grpsiz, authsiz, dsiz; 139 int i; 140 141 authsiz = nfsm_rndup(auth_len); 142 dsiz = authsiz + 10 * NFSX_UNSIGNED; 143 info.mb = m_getl(dsiz, MB_WAIT, MT_DATA, M_PKTHDR, NULL); 144 if (dsiz < MINCLSIZE) { 145 if (dsiz < MHLEN) 146 MH_ALIGN(info.mb, dsiz); 147 else 148 MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED); 149 } 150 info.mb->m_len = info.mb->m_pkthdr.len = 0; 151 info.mreq = info.mb; 152 info.bpos = mtod(info.mb, caddr_t); 153 154 /* 155 * First the RPC header. 156 */ 157 tl = nfsm_build(&info, 8 * NFSX_UNSIGNED); 158 159 /* Get a pretty random xid to start with */ 160 if (!nfs_xid) 161 nfs_xid = krandom(); 162 163 do { 164 xid = atomic_fetchadd_int(&nfs_xid, 1); 165 } while (xid == 0); 166 167 *tl++ = *xidp = txdr_unsigned(xid); 168 *tl++ = rpc_call; 169 *tl++ = rpc_vers; 170 *tl++ = txdr_unsigned(NFS_PROG); 171 if (nmflag & NFSMNT_NFSV3) 172 *tl++ = txdr_unsigned(NFS_VER3); 173 else 174 *tl++ = txdr_unsigned(NFS_VER2); 175 if (nmflag & NFSMNT_NFSV3) 176 *tl++ = txdr_unsigned(procid); 177 else 178 *tl++ = txdr_unsigned(nfsv2_procid[procid]); 179 180 /* 181 * And then the authorization cred. 182 */ 183 *tl++ = txdr_unsigned(auth_type); 184 *tl = txdr_unsigned(authsiz); 185 switch (auth_type) { 186 case RPCAUTH_UNIX: 187 tl = nfsm_build(&info, auth_len); 188 *tl++ = 0; /* stamp ?? */ 189 *tl++ = 0; /* NULL hostname */ 190 *tl++ = txdr_unsigned(cr->cr_uid); 191 *tl++ = txdr_unsigned(cr->cr_groups[0]); 192 grpsiz = (auth_len >> 2) - 5; 193 *tl++ = txdr_unsigned(grpsiz); 194 for (i = 1; i <= grpsiz; i++) 195 *tl++ = txdr_unsigned(cr->cr_groups[i]); 196 break; 197 case RPCAUTH_KERB4: 198 siz = auth_len; 199 while (siz > 0) { 200 if (M_TRAILINGSPACE(info.mb) == 0) { 201 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL); 202 mb2->m_len = 0; 203 info.mb->m_next = mb2; 204 info.mb = mb2; 205 info.bpos = mtod(info.mb, caddr_t); 206 } 207 i = min(siz, M_TRAILINGSPACE(info.mb)); 208 bcopy(auth_str, info.bpos, i); 209 info.mb->m_len += i; 210 auth_str += i; 211 info.bpos += i; 212 siz -= i; 213 } 214 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 215 for (i = 0; i < siz; i++) 216 *info.bpos++ = '\0'; 217 info.mb->m_len += siz; 218 } 219 break; 220 }; 221 222 /* 223 * And the verifier... 224 */ 225 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED); 226 if (verf_str) { 227 *tl++ = txdr_unsigned(RPCAUTH_KERB4); 228 *tl = txdr_unsigned(verf_len); 229 siz = verf_len; 230 while (siz > 0) { 231 if (M_TRAILINGSPACE(info.mb) == 0) { 232 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 233 0, NULL); 234 mb2->m_len = 0; 235 info.mb->m_next = mb2; 236 info.mb = mb2; 237 info.bpos = mtod(info.mb, caddr_t); 238 } 239 i = min(siz, M_TRAILINGSPACE(info.mb)); 240 bcopy(verf_str, info.bpos, i); 241 info.mb->m_len += i; 242 verf_str += i; 243 info.bpos += i; 244 siz -= i; 245 } 246 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 247 for (i = 0; i < siz; i++) 248 *info.bpos++ = '\0'; 249 info.mb->m_len += siz; 250 } 251 } else { 252 *tl++ = txdr_unsigned(RPCAUTH_NULL); 253 *tl = 0; 254 } 255 info.mb->m_next = mrest; 256 info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 257 info.mreq->m_pkthdr.rcvif = NULL; 258 *mbp = info.mb; 259 return (info.mreq); 260 } 261 262 void * 263 nfsm_build(nfsm_info_t info, int bytes) 264 { 265 struct mbuf *mb2; 266 void *ptr; 267 268 if (bytes > M_TRAILINGSPACE(info->mb)) { 269 MGET(mb2, MB_WAIT, MT_DATA); 270 if (bytes > MLEN) 271 panic("build > MLEN"); 272 info->mb->m_next = mb2; 273 info->mb = mb2; 274 info->mb->m_len = 0; 275 info->bpos = mtod(info->mb, caddr_t); 276 } 277 ptr = info->bpos; 278 info->mb->m_len += bytes; 279 info->bpos += bytes; 280 return (ptr); 281 } 282 283 /* 284 * 285 * If NULL returned caller is expected to abort with an EBADRPC error. 286 * Caller will usually use the NULLOUT macro. 287 */ 288 void * 289 nfsm_dissect(nfsm_info_t info, int bytes) 290 { 291 caddr_t cp2; 292 void *ptr; 293 int error; 294 int n; 295 296 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos; 297 if (bytes <= n) { 298 ptr = info->dpos; 299 info->dpos += bytes; 300 } else { 301 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2); 302 if (error) { 303 m_freem(info->mrep); 304 info->mrep = NULL; 305 ptr = NULL; 306 } else { 307 ptr = cp2; 308 } 309 } 310 return (ptr); 311 } 312 313 /* 314 * 315 * Caller is expected to abort if non-zero error is returned. 316 */ 317 int 318 nfsm_fhtom(nfsm_info_t info, struct vnode *vp) 319 { 320 u_int32_t *tl; 321 caddr_t cp; 322 int error; 323 int n; 324 325 if (info->v3) { 326 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED; 327 if (n <= M_TRAILINGSPACE(info->mb)) { 328 tl = nfsm_build(info, n); 329 *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize); 330 *(tl + ((n >> 2) - 2)) = 0; 331 bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl, 332 VTONFS(vp)->n_fhsize); 333 error = 0; 334 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos, 335 (caddr_t)VTONFS(vp)->n_fhp, 336 VTONFS(vp)->n_fhsize)) != 0) { 337 m_freem(info->mreq); 338 info->mreq = NULL; 339 } 340 } else { 341 cp = nfsm_build(info, NFSX_V2FH); 342 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH); 343 error = 0; 344 } 345 return (error); 346 } 347 348 void 349 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp) 350 { 351 u_int32_t *tl; 352 353 if (info->v3) { 354 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH); 355 *tl++ = txdr_unsigned(NFSX_V3FH); 356 bcopy(fhp, tl, NFSX_V3FH); 357 } else { 358 tl = nfsm_build(info, NFSX_V2FH); 359 bcopy(fhp, tl, NFSX_V2FH); 360 } 361 } 362 363 void 364 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp) 365 { 366 u_int32_t *tl; 367 368 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH); 369 *tl++ = nfs_true; 370 *tl++ = txdr_unsigned(NFSX_V3FH); 371 bcopy(fhp, tl, NFSX_V3FH); 372 } 373 374 /* 375 * Caller is expected to abort if non-zero error is returned. 376 * 377 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp) 378 * winds up 0. The caller is responsible for dealing with (*vpp). 379 */ 380 int 381 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp) 382 { 383 struct nfsnode *ttnp; 384 nfsfh_t *ttfhp; 385 u_int32_t *tl; 386 int ttfhsize; 387 int error = 0; 388 389 if (info->v3) { 390 tl = nfsm_dissect(info, NFSX_UNSIGNED); 391 if (tl == NULL) 392 return(EBADRPC); 393 *gotvpp = fxdr_unsigned(int, *tl); 394 } else { 395 *gotvpp = 1; 396 } 397 if (*gotvpp) { 398 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp)); 399 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp, NULL); 400 if (error) { 401 m_freem(info->mrep); 402 info->mrep = NULL; 403 return (error); 404 } 405 *vpp = NFSTOV(ttnp); 406 } 407 if (info->v3) { 408 tl = nfsm_dissect(info, NFSX_UNSIGNED); 409 if (tl == NULL) 410 return (EBADRPC); 411 if (*gotvpp) { 412 *gotvpp = fxdr_unsigned(int, *tl); 413 } else if (fxdr_unsigned(int, *tl)) { 414 error = nfsm_adv(info, NFSX_V3FATTR); 415 if (error) 416 return (error); 417 } 418 } 419 if (*gotvpp) 420 error = nfsm_loadattr(info, *vpp, NULL); 421 nfsmout: 422 return (error); 423 } 424 425 /* 426 * 427 * Caller is expected to abort with EBADRPC if a negative length is returned. 428 */ 429 int 430 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp) 431 { 432 u_int32_t *tl; 433 int n; 434 435 *fhpp = NULL; 436 if (info->v3) { 437 tl = nfsm_dissect(info, NFSX_UNSIGNED); 438 if (tl == NULL) 439 return(-1); 440 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) { 441 m_freem(info->mrep); 442 info->mrep = NULL; 443 return(-1); 444 } 445 } else { 446 n = NFSX_V2FH; 447 } 448 *fhpp = nfsm_dissect(info, nfsm_rndup(n)); 449 if (*fhpp == NULL) 450 return(-1); 451 return(n); 452 } 453 454 /* 455 * Caller is expected to abort if a non-zero error is returned. 456 */ 457 int 458 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap) 459 { 460 int error; 461 462 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0); 463 if (error) { 464 m_freem(info->mrep); 465 info->mrep = NULL; 466 return (error); 467 } 468 return (0); 469 } 470 471 /* 472 * Caller is expected to abort if a non-zero error is returned. 473 */ 474 int 475 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags) 476 { 477 u_int32_t *tl; 478 int error; 479 480 tl = nfsm_dissect(info, NFSX_UNSIGNED); 481 if (tl == NULL) 482 return(EBADRPC); 483 *attrp = fxdr_unsigned(int, *tl); 484 if (*attrp) { 485 error = nfs_loadattrcache(vp, &info->md, &info->dpos, 486 NULL, lflags); 487 if (error) { 488 *attrp = 0; 489 m_freem(info->mrep); 490 info->mrep = NULL; 491 return (error); 492 } 493 } 494 return (0); 495 } 496 497 /* 498 * Caller is expected to abort if a non-zero error is returned. 499 */ 500 int 501 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp) 502 { 503 u_int32_t *tl; 504 int error; 505 int ttattrf; 506 int ttretf = 0; 507 508 tl = nfsm_dissect(info, NFSX_UNSIGNED); 509 if (tl == NULL) 510 return (EBADRPC); 511 if (*tl == nfs_true) { 512 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED); 513 if (tl == NULL) 514 return (EBADRPC); 515 if (*attrp) { 516 ttretf = (VTONFS(vp)->n_mtime == 517 fxdr_unsigned(u_int32_t, *(tl + 2))); 518 if (ttretf == 0) 519 VTONFS(vp)->n_flag |= NRMODIFIED; 520 } 521 error = nfsm_postop_attr(info, vp, &ttattrf, 522 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK); 523 if (error) 524 return(error); 525 } else { 526 error = nfsm_postop_attr(info, vp, &ttattrf, 527 NFS_LATTR_NOSHRINK); 528 if (error) 529 return(error); 530 } 531 if (*attrp) 532 *attrp = ttretf; 533 else 534 *attrp = ttattrf; 535 return(0); 536 } 537 538 /* 539 * This function updates the attribute cache based on data returned in the 540 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds 541 * a 'before' and 'after' mtime is returned that allows us to determine if 542 * the new mtime attribute represents our modification or someone else's 543 * modification. 544 * 545 * The flag argument returns non-0 if the original times matched, zero if 546 * they did not match. NRMODIFIED is automatically set if the before time 547 * does not match the original n_mtime, and n_mtime is automatically updated 548 * to the new after time (by nfsm_postop_attr()). 549 * 550 * If full is true, set all fields, otherwise just set mode and time fields 551 */ 552 void 553 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full) 554 { 555 u_int32_t *tl; 556 557 if (vap->va_mode != (mode_t)VNOVAL) { 558 tl = nfsm_build(info, 2 * NFSX_UNSIGNED); 559 *tl++ = nfs_true; 560 *tl = txdr_unsigned(vap->va_mode); 561 } else { 562 tl = nfsm_build(info, NFSX_UNSIGNED); 563 *tl = nfs_false; 564 } 565 if (full && vap->va_uid != (uid_t)VNOVAL) { 566 tl = nfsm_build(info, 2 * NFSX_UNSIGNED); 567 *tl++ = nfs_true; 568 *tl = txdr_unsigned(vap->va_uid); 569 } else { 570 tl = nfsm_build(info, NFSX_UNSIGNED); 571 *tl = nfs_false; 572 } 573 if (full && vap->va_gid != (gid_t)VNOVAL) { 574 tl = nfsm_build(info, 2 * NFSX_UNSIGNED); 575 *tl++ = nfs_true; 576 *tl = txdr_unsigned(vap->va_gid); 577 } else { 578 tl = nfsm_build(info, NFSX_UNSIGNED); 579 *tl = nfs_false; 580 } 581 if (full && vap->va_size != VNOVAL) { 582 tl = nfsm_build(info, 3 * NFSX_UNSIGNED); 583 *tl++ = nfs_true; 584 txdr_hyper(vap->va_size, tl); 585 } else { 586 tl = nfsm_build(info, NFSX_UNSIGNED); 587 *tl = nfs_false; 588 } 589 if (vap->va_atime.tv_sec != VNOVAL) { 590 if (vap->va_atime.tv_sec != time_second) { 591 tl = nfsm_build(info, 3 * NFSX_UNSIGNED); 592 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 593 txdr_nfsv3time(&vap->va_atime, tl); 594 } else { 595 tl = nfsm_build(info, NFSX_UNSIGNED); 596 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 597 } 598 } else { 599 tl = nfsm_build(info, NFSX_UNSIGNED); 600 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 601 } 602 if (vap->va_mtime.tv_sec != VNOVAL) { 603 if (vap->va_mtime.tv_sec != time_second) { 604 tl = nfsm_build(info, 3 * NFSX_UNSIGNED); 605 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 606 txdr_nfsv3time(&vap->va_mtime, tl); 607 } else { 608 tl = nfsm_build(info, NFSX_UNSIGNED); 609 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 610 } 611 } else { 612 tl = nfsm_build(info, NFSX_UNSIGNED); 613 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 614 } 615 } 616 617 /* 618 * Caller is expected to abort with EBADRPC if a negative length is returned. 619 */ 620 int 621 nfsm_strsiz(nfsm_info_t info, int maxlen) 622 { 623 u_int32_t *tl; 624 int len; 625 626 tl = nfsm_dissect(info, NFSX_UNSIGNED); 627 if (tl == NULL) 628 return(-1); 629 len = fxdr_unsigned(int32_t, *tl); 630 if (len < 0 || len > maxlen) 631 return(-1); 632 return (len); 633 } 634 635 /* 636 * Caller is expected to abort if a negative length is returned, but also 637 * call nfsm_reply(0) if -2 is returned. 638 * 639 * This function sets *errorp. Caller should not modify the error code. 640 */ 641 int 642 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp) 643 { 644 u_int32_t *tl; 645 int len; 646 647 tl = nfsm_dissect(info, NFSX_UNSIGNED); 648 if (tl == NULL) { 649 *errorp = EBADRPC; 650 return(-1); 651 } 652 len = fxdr_unsigned(int32_t,*tl); 653 if (len > maxlen || len <= 0) { 654 *errorp = EBADRPC; 655 return(-2); 656 } 657 return(len); 658 } 659 660 /* 661 * Caller is expected to abort if a negative length is returned, but also 662 * call nfsm_reply(0) if -2 is returned. 663 * 664 * This function sets *errorp. Caller should not modify the error code. 665 */ 666 int 667 nfsm_srvnamesiz(nfsm_info_t info, int *errorp) 668 { 669 u_int32_t *tl; 670 int len; 671 672 tl = nfsm_dissect(info, NFSX_UNSIGNED); 673 if (tl == NULL) { 674 *errorp = EBADRPC; 675 return(-1); 676 } 677 678 /* 679 * In this case if *errorp is not EBADRPC and we are NFSv3, 680 * nfsm_reply() will not return a negative number. But all 681 * call cases assume len is valid so we really do want 682 * to return -1. 683 */ 684 len = fxdr_unsigned(int32_t,*tl); 685 if (len > NFS_MAXNAMLEN) 686 *errorp = NFSERR_NAMETOL; 687 if (len <= 0) 688 *errorp = EBADRPC; 689 if (*errorp) 690 return(-2); 691 return (len); 692 } 693 694 /* 695 * Caller is expected to abort if a non-zero error is returned. 696 */ 697 int 698 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len) 699 { 700 int error; 701 702 if (len > 0 && 703 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) { 704 m_freem(info->mrep); 705 info->mrep = NULL; 706 return(error); 707 } 708 return(0); 709 } 710 711 /* 712 * Caller is expected to abort if a non-zero error is returned. 713 */ 714 int 715 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len) 716 { 717 int error; 718 719 if (len > 0 && 720 (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) { 721 m_freem(info->mrep); 722 info->mrep = NULL; 723 return(error); 724 } 725 return (0); 726 } 727 728 /* 729 * Caller is expected to abort if a non-zero error is returned. 730 */ 731 int 732 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len) 733 { 734 int error; 735 736 error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos); 737 if (error) { 738 m_freem(info->mreq); 739 info->mreq = NULL; 740 return (error); 741 } 742 return(0); 743 } 744 745 int 746 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len) 747 { 748 int error; 749 750 error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos); 751 if (error) { 752 m_freem(info->mreq); 753 info->mreq = NULL; 754 return (error); 755 } 756 return(0); 757 } 758 759 /* 760 * Caller is expected to abort if a negative value is returned. This 761 * function sets *errorp. Caller should not modify the error code. 762 * 763 * We load up the remaining info fields and run the request state 764 * machine until it is done. 765 * 766 * This call runs the entire state machine and does not return until 767 * the command is complete. 768 */ 769 int 770 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum, 771 thread_t td, struct ucred *cred, int *errorp) 772 { 773 info->state = NFSM_STATE_SETUP; 774 info->procnum = procnum; 775 info->vp = vp; 776 info->td = td; 777 info->cred = cred; 778 info->bio = NULL; 779 info->nmp = VFSTONFS(vp->v_mount); 780 781 *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE); 782 if (*errorp) { 783 if ((*errorp & NFSERR_RETERR) == 0) 784 return(-1); 785 *errorp &= ~NFSERR_RETERR; 786 } 787 return(0); 788 } 789 790 /* 791 * This call starts the state machine through the initial transmission. 792 * Completion is via the bio. The info structure must have installed 793 * a 'done' callback. 794 * 795 * If we are unable to do the initial tx we generate the bio completion 796 * ourselves. 797 */ 798 void 799 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum, 800 thread_t td, struct ucred *cred) 801 { 802 struct buf *bp; 803 int error; 804 805 info->state = NFSM_STATE_SETUP; 806 info->procnum = procnum; 807 info->vp = vp; 808 info->td = td; 809 info->cred = cred; 810 info->nmp = VFSTONFS(vp->v_mount); 811 812 error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY); 813 if (error != EINPROGRESS) { 814 kprintf("nfsm_request_bio: early abort %d\n", error); 815 bp = info->bio->bio_buf; 816 if (error) { 817 bp->b_flags |= B_ERROR; 818 if (error == EIO) /* unrecoverable */ 819 bp->b_flags |= B_INVAL; 820 } 821 bp->b_error = error; 822 biodone(info->bio); 823 } 824 } 825 826 /* 827 * Caller is expected to abort if a non-zero error is returned. 828 */ 829 int 830 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen) 831 { 832 u_int32_t *tl; 833 int error; 834 int n; 835 836 if (len > maxlen) { 837 m_freem(info->mreq); 838 info->mreq = NULL; 839 return(ENAMETOOLONG); 840 } 841 n = nfsm_rndup(len) + NFSX_UNSIGNED; 842 if (n <= M_TRAILINGSPACE(info->mb)) { 843 tl = nfsm_build(info, n); 844 *tl++ = txdr_unsigned(len); 845 *(tl + ((n >> 2) - 2)) = 0; 846 bcopy(data, tl, len); 847 error = 0; 848 } else { 849 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len); 850 if (error) { 851 m_freem(info->mreq); 852 info->mreq = NULL; 853 } 854 } 855 return (error); 856 } 857 858 /* 859 * Caller is expected to abort if a negative value is returned. This 860 * function sets *errorp. Caller should not modify the error code. 861 */ 862 int 863 nfsm_reply(nfsm_info_t info, 864 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 865 int siz, int *errorp) 866 { 867 nfsd->nd_repstat = *errorp; 868 if (*errorp && !(nfsd->nd_flag & ND_NFSV3)) 869 siz = 0; 870 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq, 871 &info->mb, &info->bpos); 872 if (info->mrep != NULL) { 873 m_freem(info->mrep); 874 info->mrep = NULL; 875 } 876 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) { 877 *errorp = 0; 878 return(-1); 879 } 880 return(0); 881 } 882 883 void 884 nfsm_writereply(nfsm_info_t info, 885 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 886 int error, int siz) 887 { 888 nfsd->nd_repstat = error; 889 if (error && !(info->v3)) 890 siz = 0; 891 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos); 892 } 893 894 /* 895 * Caller is expected to abort if a non-zero error is returned. 896 */ 897 int 898 nfsm_adv(nfsm_info_t info, int len) 899 { 900 int error; 901 int n; 902 903 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos; 904 if (n >= len) { 905 info->dpos += len; 906 error = 0; 907 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) { 908 m_freem(info->mrep); 909 info->mrep = NULL; 910 } 911 return (error); 912 } 913 914 /* 915 * Caller is expected to abort if a negative length is returned, but also 916 * call nfsm_reply(0) if -2 is returned. 917 * 918 * This function sets *errorp. Caller should not modify the error code. 919 */ 920 int 921 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd, 922 fhandle_t *fhp, int *errorp) 923 { 924 u_int32_t *tl; 925 int fhlen; 926 927 if (nfsd->nd_flag & ND_NFSV3) { 928 tl = nfsm_dissect(info, NFSX_UNSIGNED); 929 if (tl == NULL) { 930 *errorp = EBADRPC; 931 return(-1); 932 } 933 fhlen = fxdr_unsigned(int, *tl); 934 if (fhlen != 0 && fhlen != NFSX_V3FH) { 935 *errorp = EBADRPC; 936 return(-2); 937 } 938 } else { 939 fhlen = NFSX_V2FH; 940 } 941 if (fhlen != 0) { 942 tl = nfsm_dissect(info, fhlen); 943 if (tl == NULL) { 944 *errorp = EBADRPC; 945 return(-1); 946 } 947 bcopy(tl, fhp, fhlen); 948 } else { 949 bzero(fhp, NFSX_V3FH); 950 } 951 return(0); 952 } 953 954 void * 955 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2, 956 char **bp, char **be) 957 { 958 if (*bp >= *be) { 959 if (*mp1 == info->mb) 960 (*mp1)->m_len += *bp - info->bpos; 961 *mp1 = m_getcl(MB_WAIT, MT_DATA, 0); 962 (*mp1)->m_len = MCLBYTES; 963 (*mp2)->m_next = *mp1; 964 *mp2 = *mp1; 965 *bp = mtod(*mp1, caddr_t); 966 *be = *bp + (*mp1)->m_len; 967 } 968 return(*bp); 969 } 970 971 int 972 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap) 973 { 974 u_int32_t *tl; 975 int error = 0; 976 977 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 978 if (*tl == nfs_true) { 979 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 980 vap->va_mode = nfstov_mode(*tl); 981 } 982 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 983 if (*tl == nfs_true) { 984 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 985 vap->va_uid = fxdr_unsigned(uid_t, *tl); 986 } 987 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 988 if (*tl == nfs_true) { 989 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 990 vap->va_gid = fxdr_unsigned(gid_t, *tl); 991 } 992 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 993 if (*tl == nfs_true) { 994 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED)); 995 vap->va_size = fxdr_hyper(tl); 996 } 997 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 998 switch (fxdr_unsigned(int, *tl)) { 999 case NFSV3SATTRTIME_TOCLIENT: 1000 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED)); 1001 fxdr_nfsv3time(tl, &vap->va_atime); 1002 break; 1003 case NFSV3SATTRTIME_TOSERVER: 1004 getnanotime(&vap->va_atime); 1005 break; 1006 }; 1007 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 1008 switch (fxdr_unsigned(int, *tl)) { 1009 case NFSV3SATTRTIME_TOCLIENT: 1010 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED)); 1011 fxdr_nfsv3time(tl, &vap->va_mtime); 1012 break; 1013 case NFSV3SATTRTIME_TOSERVER: 1014 getnanotime(&vap->va_mtime); 1015 break; 1016 } 1017 nfsmout: 1018 return (error); 1019 } 1020 1021 /* 1022 * copies mbuf chain to the uio scatter/gather list 1023 */ 1024 int 1025 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos) 1026 { 1027 char *mbufcp, *uiocp; 1028 int xfer, left, len; 1029 struct mbuf *mp; 1030 long uiosiz, rem; 1031 int error = 0; 1032 1033 mp = *mrep; 1034 mbufcp = *dpos; 1035 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 1036 rem = nfsm_rndup(siz)-siz; 1037 while (siz > 0) { 1038 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 1039 return (EFBIG); 1040 left = uiop->uio_iov->iov_len; 1041 uiocp = uiop->uio_iov->iov_base; 1042 if (left > siz) 1043 left = siz; 1044 uiosiz = left; 1045 while (left > 0) { 1046 while (len == 0) { 1047 mp = mp->m_next; 1048 if (mp == NULL) 1049 return (EBADRPC); 1050 mbufcp = mtod(mp, caddr_t); 1051 len = mp->m_len; 1052 } 1053 xfer = (left > len) ? len : left; 1054 #ifdef notdef 1055 /* Not Yet.. */ 1056 if (uiop->uio_iov->iov_op != NULL) 1057 (*(uiop->uio_iov->iov_op)) 1058 (mbufcp, uiocp, xfer); 1059 else 1060 #endif 1061 if (uiop->uio_segflg == UIO_SYSSPACE) 1062 bcopy(mbufcp, uiocp, xfer); 1063 else 1064 copyout(mbufcp, uiocp, xfer); 1065 left -= xfer; 1066 len -= xfer; 1067 mbufcp += xfer; 1068 uiocp += xfer; 1069 uiop->uio_offset += xfer; 1070 uiop->uio_resid -= xfer; 1071 } 1072 if (uiop->uio_iov->iov_len <= siz) { 1073 uiop->uio_iovcnt--; 1074 uiop->uio_iov++; 1075 } else { 1076 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz; 1077 uiop->uio_iov->iov_len -= uiosiz; 1078 } 1079 siz -= uiosiz; 1080 } 1081 *dpos = mbufcp; 1082 *mrep = mp; 1083 if (rem > 0) { 1084 if (len < rem) 1085 error = nfs_adv(mrep, dpos, rem, len); 1086 else 1087 *dpos += rem; 1088 } 1089 return (error); 1090 } 1091 1092 /* 1093 * copies mbuf chain to the bio buffer 1094 */ 1095 int 1096 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos) 1097 { 1098 struct buf *bp = bio->bio_buf; 1099 char *mbufcp; 1100 char *bio_cp; 1101 int xfer, len; 1102 struct mbuf *mp; 1103 long rem; 1104 int error = 0; 1105 int bio_left; 1106 1107 mp = *mrep; 1108 mbufcp = *dpos; 1109 len = mtod(mp, caddr_t) + mp->m_len - mbufcp; 1110 rem = nfsm_rndup(size) - size; 1111 1112 bio_left = bp->b_bcount; 1113 bio_cp = bp->b_data; 1114 1115 while (size > 0) { 1116 while (len == 0) { 1117 mp = mp->m_next; 1118 if (mp == NULL) 1119 return (EBADRPC); 1120 mbufcp = mtod(mp, caddr_t); 1121 len = mp->m_len; 1122 } 1123 if ((xfer = len) > size) 1124 xfer = size; 1125 if (bio_left) { 1126 if (xfer > bio_left) 1127 xfer = bio_left; 1128 bcopy(mbufcp, bio_cp, xfer); 1129 } else { 1130 /* 1131 * Not enough buffer space in the bio. 1132 */ 1133 return(EFBIG); 1134 } 1135 size -= xfer; 1136 bio_left -= xfer; 1137 bio_cp += xfer; 1138 len -= xfer; 1139 mbufcp += xfer; 1140 } 1141 *dpos = mbufcp; 1142 *mrep = mp; 1143 if (rem > 0) { 1144 if (len < rem) 1145 error = nfs_adv(mrep, dpos, rem, len); 1146 else 1147 *dpos += rem; 1148 } 1149 return (error); 1150 } 1151 1152 /* 1153 * copies a uio scatter/gather list to an mbuf chain. 1154 * NOTE: can ony handle iovcnt == 1 1155 */ 1156 int 1157 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 1158 { 1159 char *uiocp; 1160 struct mbuf *mp, *mp2; 1161 int xfer, left, mlen; 1162 int uiosiz, rem; 1163 boolean_t getcluster; 1164 char *cp; 1165 1166 #ifdef DIAGNOSTIC 1167 if (uiop->uio_iovcnt != 1) 1168 panic("nfsm_uiotombuf: iovcnt != 1"); 1169 #endif 1170 1171 if (siz >= MINCLSIZE) 1172 getcluster = TRUE; 1173 else 1174 getcluster = FALSE; 1175 rem = nfsm_rndup(siz) - siz; 1176 mp = mp2 = *mq; 1177 while (siz > 0) { 1178 left = uiop->uio_iov->iov_len; 1179 uiocp = uiop->uio_iov->iov_base; 1180 if (left > siz) 1181 left = siz; 1182 uiosiz = left; 1183 while (left > 0) { 1184 mlen = M_TRAILINGSPACE(mp); 1185 if (mlen == 0) { 1186 if (getcluster) 1187 mp = m_getcl(MB_WAIT, MT_DATA, 0); 1188 else 1189 mp = m_get(MB_WAIT, MT_DATA); 1190 mp->m_len = 0; 1191 mp2->m_next = mp; 1192 mp2 = mp; 1193 mlen = M_TRAILINGSPACE(mp); 1194 } 1195 xfer = (left > mlen) ? mlen : left; 1196 #ifdef notdef 1197 /* Not Yet.. */ 1198 if (uiop->uio_iov->iov_op != NULL) 1199 (*(uiop->uio_iov->iov_op)) 1200 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 1201 else 1202 #endif 1203 if (uiop->uio_segflg == UIO_SYSSPACE) 1204 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 1205 else 1206 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 1207 mp->m_len += xfer; 1208 left -= xfer; 1209 uiocp += xfer; 1210 uiop->uio_offset += xfer; 1211 uiop->uio_resid -= xfer; 1212 } 1213 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz; 1214 uiop->uio_iov->iov_len -= uiosiz; 1215 siz -= uiosiz; 1216 } 1217 if (rem > 0) { 1218 if (rem > M_TRAILINGSPACE(mp)) { 1219 MGET(mp, MB_WAIT, MT_DATA); 1220 mp->m_len = 0; 1221 mp2->m_next = mp; 1222 } 1223 cp = mtod(mp, caddr_t)+mp->m_len; 1224 for (left = 0; left < rem; left++) 1225 *cp++ = '\0'; 1226 mp->m_len += rem; 1227 *bpos = cp; 1228 } else 1229 *bpos = mtod(mp, caddr_t)+mp->m_len; 1230 *mq = mp; 1231 return (0); 1232 } 1233 1234 int 1235 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off, 1236 int siz, caddr_t *bpos) 1237 { 1238 struct buf *bp = bio->bio_buf; 1239 struct mbuf *mp, *mp2; 1240 char *bio_cp; 1241 int bio_left; 1242 int xfer, mlen; 1243 int rem; 1244 boolean_t getcluster; 1245 char *cp; 1246 1247 if (siz >= MINCLSIZE) 1248 getcluster = TRUE; 1249 else 1250 getcluster = FALSE; 1251 rem = nfsm_rndup(siz) - siz; 1252 mp = mp2 = *mq; 1253 1254 bio_cp = bp->b_data + off; 1255 bio_left = siz; 1256 1257 while (bio_left) { 1258 mlen = M_TRAILINGSPACE(mp); 1259 if (mlen == 0) { 1260 if (getcluster) 1261 mp = m_getcl(MB_WAIT, MT_DATA, 0); 1262 else 1263 mp = m_get(MB_WAIT, MT_DATA); 1264 mp->m_len = 0; 1265 mp2->m_next = mp; 1266 mp2 = mp; 1267 mlen = M_TRAILINGSPACE(mp); 1268 } 1269 xfer = (bio_left < mlen) ? bio_left : mlen; 1270 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer); 1271 mp->m_len += xfer; 1272 bio_left -= xfer; 1273 bio_cp += xfer; 1274 } 1275 if (rem > 0) { 1276 if (rem > M_TRAILINGSPACE(mp)) { 1277 MGET(mp, MB_WAIT, MT_DATA); 1278 mp->m_len = 0; 1279 mp2->m_next = mp; 1280 } 1281 cp = mtod(mp, caddr_t) + mp->m_len; 1282 for (mlen = 0; mlen < rem; mlen++) 1283 *cp++ = '\0'; 1284 mp->m_len += rem; 1285 *bpos = cp; 1286 } else { 1287 *bpos = mtod(mp, caddr_t) + mp->m_len; 1288 } 1289 *mq = mp; 1290 return(0); 1291 } 1292 1293 /* 1294 * Help break down an mbuf chain by setting the first siz bytes contiguous 1295 * pointed to by returned val. 1296 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 1297 * cases. (The macros use the vars. dpos and dpos2) 1298 */ 1299 int 1300 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2) 1301 { 1302 struct mbuf *mp, *mp2; 1303 int siz2, xfer; 1304 caddr_t p; 1305 1306 mp = *mdp; 1307 while (left == 0) { 1308 *mdp = mp = mp->m_next; 1309 if (mp == NULL) 1310 return (EBADRPC); 1311 left = mp->m_len; 1312 *dposp = mtod(mp, caddr_t); 1313 } 1314 if (left >= siz) { 1315 *cp2 = *dposp; 1316 *dposp += siz; 1317 } else if (mp->m_next == NULL) { 1318 return (EBADRPC); 1319 } else if (siz > MHLEN) { 1320 panic("nfs S too big"); 1321 } else { 1322 MGET(mp2, MB_WAIT, MT_DATA); 1323 mp2->m_next = mp->m_next; 1324 mp->m_next = mp2; 1325 mp->m_len -= left; 1326 mp = mp2; 1327 *cp2 = p = mtod(mp, caddr_t); 1328 bcopy(*dposp, p, left); /* Copy what was left */ 1329 siz2 = siz-left; 1330 p += left; 1331 mp2 = mp->m_next; 1332 /* Loop around copying up the siz2 bytes */ 1333 while (siz2 > 0) { 1334 if (mp2 == NULL) 1335 return (EBADRPC); 1336 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 1337 if (xfer > 0) { 1338 bcopy(mtod(mp2, caddr_t), p, xfer); 1339 mp2->m_len -= xfer; 1340 mp2->m_data += xfer; 1341 p += xfer; 1342 siz2 -= xfer; 1343 } 1344 if (siz2 > 0) 1345 mp2 = mp2->m_next; 1346 } 1347 mp->m_len = siz; 1348 *mdp = mp2; 1349 *dposp = mtod(mp2, caddr_t); 1350 } 1351 return (0); 1352 } 1353 1354 /* 1355 * Advance the position in the mbuf chain. 1356 */ 1357 int 1358 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left) 1359 { 1360 struct mbuf *m; 1361 int s; 1362 1363 m = *mdp; 1364 s = left; 1365 while (s < offs) { 1366 offs -= s; 1367 m = m->m_next; 1368 if (m == NULL) 1369 return (EBADRPC); 1370 s = m->m_len; 1371 } 1372 *mdp = m; 1373 *dposp = mtod(m, caddr_t)+offs; 1374 return (0); 1375 } 1376 1377 /* 1378 * Copy a string into mbufs for the hard cases... 1379 */ 1380 int 1381 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 1382 { 1383 struct mbuf *m1 = NULL, *m2; 1384 long left, xfer, len, tlen; 1385 u_int32_t *tl; 1386 int putsize; 1387 1388 putsize = 1; 1389 m2 = *mb; 1390 left = M_TRAILINGSPACE(m2); 1391 if (left > 0) { 1392 tl = ((u_int32_t *)(*bpos)); 1393 *tl++ = txdr_unsigned(siz); 1394 putsize = 0; 1395 left -= NFSX_UNSIGNED; 1396 m2->m_len += NFSX_UNSIGNED; 1397 if (left > 0) { 1398 bcopy(cp, (caddr_t) tl, left); 1399 siz -= left; 1400 cp += left; 1401 m2->m_len += left; 1402 left = 0; 1403 } 1404 } 1405 /* Loop around adding mbufs */ 1406 while (siz > 0) { 1407 int msize; 1408 1409 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize); 1410 m1->m_len = msize; 1411 m2->m_next = m1; 1412 m2 = m1; 1413 tl = mtod(m1, u_int32_t *); 1414 tlen = 0; 1415 if (putsize) { 1416 *tl++ = txdr_unsigned(siz); 1417 m1->m_len -= NFSX_UNSIGNED; 1418 tlen = NFSX_UNSIGNED; 1419 putsize = 0; 1420 } 1421 if (siz < m1->m_len) { 1422 len = nfsm_rndup(siz); 1423 xfer = siz; 1424 if (xfer < len) 1425 *(tl+(xfer>>2)) = 0; 1426 } else { 1427 xfer = len = m1->m_len; 1428 } 1429 bcopy(cp, (caddr_t) tl, xfer); 1430 m1->m_len = len+tlen; 1431 siz -= xfer; 1432 cp += xfer; 1433 } 1434 *mb = m1; 1435 *bpos = mtod(m1, caddr_t)+m1->m_len; 1436 return (0); 1437 } 1438 1439 /* 1440 * A fiddled version of m_adj() that ensures null fill to a long 1441 * boundary and only trims off the back end 1442 */ 1443 void 1444 nfsm_adj(struct mbuf *mp, int len, int nul) 1445 { 1446 struct mbuf *m; 1447 int count, i; 1448 char *cp; 1449 1450 /* 1451 * Trim from tail. Scan the mbuf chain, 1452 * calculating its length and finding the last mbuf. 1453 * If the adjustment only affects this mbuf, then just 1454 * adjust and return. Otherwise, rescan and truncate 1455 * after the remaining size. 1456 */ 1457 count = 0; 1458 m = mp; 1459 for (;;) { 1460 count += m->m_len; 1461 if (m->m_next == NULL) 1462 break; 1463 m = m->m_next; 1464 } 1465 if (m->m_len > len) { 1466 m->m_len -= len; 1467 if (nul > 0) { 1468 cp = mtod(m, caddr_t)+m->m_len-nul; 1469 for (i = 0; i < nul; i++) 1470 *cp++ = '\0'; 1471 } 1472 return; 1473 } 1474 count -= len; 1475 if (count < 0) 1476 count = 0; 1477 /* 1478 * Correct length for chain is "count". 1479 * Find the mbuf with last data, adjust its length, 1480 * and toss data from remaining mbufs on chain. 1481 */ 1482 for (m = mp; m; m = m->m_next) { 1483 if (m->m_len >= count) { 1484 m->m_len = count; 1485 if (nul > 0) { 1486 cp = mtod(m, caddr_t)+m->m_len-nul; 1487 for (i = 0; i < nul; i++) 1488 *cp++ = '\0'; 1489 } 1490 break; 1491 } 1492 count -= m->m_len; 1493 } 1494 for (m = m->m_next;m;m = m->m_next) 1495 m->m_len = 0; 1496 } 1497 1498 /* 1499 * Make these functions instead of macros, so that the kernel text size 1500 * doesn't get too big... 1501 */ 1502 void 1503 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd, 1504 int before_ret, struct vattr *before_vap, 1505 int after_ret, struct vattr *after_vap) 1506 { 1507 u_int32_t *tl; 1508 1509 /* 1510 * before_ret is 0 if before_vap is valid, non-zero if it isn't. 1511 */ 1512 if (before_ret) { 1513 tl = nfsm_build(info, NFSX_UNSIGNED); 1514 *tl = nfs_false; 1515 } else { 1516 tl = nfsm_build(info, 7 * NFSX_UNSIGNED); 1517 *tl++ = nfs_true; 1518 txdr_hyper(before_vap->va_size, tl); 1519 tl += 2; 1520 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1521 tl += 2; 1522 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1523 } 1524 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap); 1525 } 1526 1527 void 1528 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd, 1529 int after_ret, struct vattr *after_vap) 1530 { 1531 struct nfs_fattr *fp; 1532 u_int32_t *tl; 1533 1534 if (after_ret) { 1535 tl = nfsm_build(info, NFSX_UNSIGNED); 1536 *tl = nfs_false; 1537 } else { 1538 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR); 1539 *tl++ = nfs_true; 1540 fp = (struct nfs_fattr *)tl; 1541 nfsm_srvfattr(nfsd, after_vap, fp); 1542 } 1543 } 1544 1545 void 1546 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 1547 struct nfs_fattr *fp) 1548 { 1549 /* 1550 * NFS seems to truncate nlink to 16 bits, don't let it overflow. 1551 */ 1552 if (vap->va_nlink > 65535) 1553 fp->fa_nlink = 65535; 1554 else 1555 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1556 fp->fa_uid = txdr_unsigned(vap->va_uid); 1557 fp->fa_gid = txdr_unsigned(vap->va_gid); 1558 if (nfsd->nd_flag & ND_NFSV3) { 1559 fp->fa_type = vtonfsv3_type(vap->va_type); 1560 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1561 txdr_hyper(vap->va_size, &fp->fa3_size); 1562 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1563 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor); 1564 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor); 1565 fp->fa3_fsid.nfsuquad[0] = 0; 1566 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1567 txdr_hyper(vap->va_fileid, &fp->fa3_fileid); 1568 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1569 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1570 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1571 } else { 1572 fp->fa_type = vtonfsv2_type(vap->va_type); 1573 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1574 fp->fa2_size = txdr_unsigned(vap->va_size); 1575 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1576 if (vap->va_type == VFIFO) 1577 fp->fa2_rdev = 0xffffffff; 1578 else 1579 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor)); 1580 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1581 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1582 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1583 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1584 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1585 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1586 } 1587 } 1588