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