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