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); 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 bp->b_error = error; 823 biodone(info->bio); 824 } 825 } 826 827 /* 828 * Caller is expected to abort if a non-zero error is returned. 829 */ 830 int 831 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen) 832 { 833 u_int32_t *tl; 834 int error; 835 int n; 836 837 if (len > maxlen) { 838 m_freem(info->mreq); 839 info->mreq = NULL; 840 return(ENAMETOOLONG); 841 } 842 n = nfsm_rndup(len) + NFSX_UNSIGNED; 843 if (n <= M_TRAILINGSPACE(info->mb)) { 844 tl = nfsm_build(info, n); 845 *tl++ = txdr_unsigned(len); 846 *(tl + ((n >> 2) - 2)) = 0; 847 bcopy(data, tl, len); 848 error = 0; 849 } else { 850 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len); 851 if (error) { 852 m_freem(info->mreq); 853 info->mreq = NULL; 854 } 855 } 856 return (error); 857 } 858 859 /* 860 * Caller is expected to abort if a negative value is returned. This 861 * function sets *errorp. Caller should not modify the error code. 862 */ 863 int 864 nfsm_reply(nfsm_info_t info, 865 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 866 int siz, int *errorp) 867 { 868 nfsd->nd_repstat = *errorp; 869 if (*errorp && !(nfsd->nd_flag & ND_NFSV3)) 870 siz = 0; 871 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq, 872 &info->mb, &info->bpos); 873 if (info->mrep != NULL) { 874 m_freem(info->mrep); 875 info->mrep = NULL; 876 } 877 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) { 878 *errorp = 0; 879 return(-1); 880 } 881 return(0); 882 } 883 884 void 885 nfsm_writereply(nfsm_info_t info, 886 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 887 int error, int siz) 888 { 889 nfsd->nd_repstat = error; 890 if (error && !(info->v3)) 891 siz = 0; 892 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos); 893 } 894 895 /* 896 * Caller is expected to abort if a non-zero error is returned. 897 */ 898 int 899 nfsm_adv(nfsm_info_t info, int len) 900 { 901 int error; 902 int n; 903 904 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos; 905 if (n >= len) { 906 info->dpos += len; 907 error = 0; 908 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) { 909 m_freem(info->mrep); 910 info->mrep = NULL; 911 } 912 return (error); 913 } 914 915 /* 916 * Caller is expected to abort if a negative length is returned, but also 917 * call nfsm_reply(0) if -2 is returned. 918 * 919 * This function sets *errorp. Caller should not modify the error code. 920 */ 921 int 922 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd, 923 fhandle_t *fhp, int *errorp) 924 { 925 u_int32_t *tl; 926 int fhlen; 927 928 if (nfsd->nd_flag & ND_NFSV3) { 929 tl = nfsm_dissect(info, NFSX_UNSIGNED); 930 if (tl == NULL) { 931 *errorp = EBADRPC; 932 return(-1); 933 } 934 fhlen = fxdr_unsigned(int, *tl); 935 if (fhlen != 0 && fhlen != NFSX_V3FH) { 936 *errorp = EBADRPC; 937 return(-2); 938 } 939 } else { 940 fhlen = NFSX_V2FH; 941 } 942 if (fhlen != 0) { 943 tl = nfsm_dissect(info, fhlen); 944 if (tl == NULL) { 945 *errorp = EBADRPC; 946 return(-1); 947 } 948 bcopy(tl, fhp, fhlen); 949 } else { 950 bzero(fhp, NFSX_V3FH); 951 } 952 return(0); 953 } 954 955 void * 956 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2, 957 char **bp, char **be) 958 { 959 if (*bp >= *be) { 960 if (*mp1 == info->mb) 961 (*mp1)->m_len += *bp - info->bpos; 962 *mp1 = m_getcl(MB_WAIT, MT_DATA, 0); 963 (*mp1)->m_len = MCLBYTES; 964 (*mp2)->m_next = *mp1; 965 *mp2 = *mp1; 966 *bp = mtod(*mp1, caddr_t); 967 *be = *bp + (*mp1)->m_len; 968 } 969 return(*bp); 970 } 971 972 int 973 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap) 974 { 975 u_int32_t *tl; 976 int error = 0; 977 978 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 979 if (*tl == nfs_true) { 980 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 981 vap->va_mode = nfstov_mode(*tl); 982 } 983 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 984 if (*tl == nfs_true) { 985 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 986 vap->va_uid = fxdr_unsigned(uid_t, *tl); 987 } 988 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 989 if (*tl == nfs_true) { 990 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 991 vap->va_gid = fxdr_unsigned(gid_t, *tl); 992 } 993 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 994 if (*tl == nfs_true) { 995 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED)); 996 vap->va_size = fxdr_hyper(tl); 997 } 998 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 999 switch (fxdr_unsigned(int, *tl)) { 1000 case NFSV3SATTRTIME_TOCLIENT: 1001 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED)); 1002 fxdr_nfsv3time(tl, &vap->va_atime); 1003 break; 1004 case NFSV3SATTRTIME_TOSERVER: 1005 getnanotime(&vap->va_atime); 1006 break; 1007 }; 1008 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED)); 1009 switch (fxdr_unsigned(int, *tl)) { 1010 case NFSV3SATTRTIME_TOCLIENT: 1011 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED)); 1012 fxdr_nfsv3time(tl, &vap->va_mtime); 1013 break; 1014 case NFSV3SATTRTIME_TOSERVER: 1015 getnanotime(&vap->va_mtime); 1016 break; 1017 } 1018 nfsmout: 1019 return (error); 1020 } 1021 1022 /* 1023 * copies mbuf chain to the uio scatter/gather list 1024 */ 1025 int 1026 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos) 1027 { 1028 char *mbufcp, *uiocp; 1029 int xfer, left, len; 1030 struct mbuf *mp; 1031 long uiosiz, rem; 1032 int error = 0; 1033 1034 mp = *mrep; 1035 mbufcp = *dpos; 1036 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 1037 rem = nfsm_rndup(siz)-siz; 1038 while (siz > 0) { 1039 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 1040 return (EFBIG); 1041 left = uiop->uio_iov->iov_len; 1042 uiocp = uiop->uio_iov->iov_base; 1043 if (left > siz) 1044 left = siz; 1045 uiosiz = left; 1046 while (left > 0) { 1047 while (len == 0) { 1048 mp = mp->m_next; 1049 if (mp == NULL) 1050 return (EBADRPC); 1051 mbufcp = mtod(mp, caddr_t); 1052 len = mp->m_len; 1053 } 1054 xfer = (left > len) ? len : left; 1055 #ifdef notdef 1056 /* Not Yet.. */ 1057 if (uiop->uio_iov->iov_op != NULL) 1058 (*(uiop->uio_iov->iov_op)) 1059 (mbufcp, uiocp, xfer); 1060 else 1061 #endif 1062 if (uiop->uio_segflg == UIO_SYSSPACE) 1063 bcopy(mbufcp, uiocp, xfer); 1064 else 1065 copyout(mbufcp, uiocp, xfer); 1066 left -= xfer; 1067 len -= xfer; 1068 mbufcp += xfer; 1069 uiocp += xfer; 1070 uiop->uio_offset += xfer; 1071 uiop->uio_resid -= xfer; 1072 } 1073 if (uiop->uio_iov->iov_len <= siz) { 1074 uiop->uio_iovcnt--; 1075 uiop->uio_iov++; 1076 } else { 1077 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz; 1078 uiop->uio_iov->iov_len -= uiosiz; 1079 } 1080 siz -= uiosiz; 1081 } 1082 *dpos = mbufcp; 1083 *mrep = mp; 1084 if (rem > 0) { 1085 if (len < rem) 1086 error = nfs_adv(mrep, dpos, rem, len); 1087 else 1088 *dpos += rem; 1089 } 1090 return (error); 1091 } 1092 1093 /* 1094 * copies mbuf chain to the bio buffer 1095 */ 1096 int 1097 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos) 1098 { 1099 struct buf *bp = bio->bio_buf; 1100 char *mbufcp; 1101 char *bio_cp; 1102 int xfer, len; 1103 struct mbuf *mp; 1104 long rem; 1105 int error = 0; 1106 int bio_left; 1107 1108 mp = *mrep; 1109 mbufcp = *dpos; 1110 len = mtod(mp, caddr_t) + mp->m_len - mbufcp; 1111 rem = nfsm_rndup(size) - size; 1112 1113 bio_left = bp->b_bcount; 1114 bio_cp = bp->b_data; 1115 1116 while (size > 0) { 1117 while (len == 0) { 1118 mp = mp->m_next; 1119 if (mp == NULL) 1120 return (EBADRPC); 1121 mbufcp = mtod(mp, caddr_t); 1122 len = mp->m_len; 1123 } 1124 if ((xfer = len) > size) 1125 xfer = size; 1126 if (bio_left) { 1127 if (xfer > bio_left) 1128 xfer = bio_left; 1129 bcopy(mbufcp, bio_cp, xfer); 1130 } else { 1131 /* 1132 * Not enough buffer space in the bio. 1133 */ 1134 return(EFBIG); 1135 } 1136 size -= xfer; 1137 bio_left -= xfer; 1138 bio_cp += xfer; 1139 len -= xfer; 1140 mbufcp += xfer; 1141 } 1142 *dpos = mbufcp; 1143 *mrep = mp; 1144 if (rem > 0) { 1145 if (len < rem) 1146 error = nfs_adv(mrep, dpos, rem, len); 1147 else 1148 *dpos += rem; 1149 } 1150 return (error); 1151 } 1152 1153 /* 1154 * copies a uio scatter/gather list to an mbuf chain. 1155 * NOTE: can ony handle iovcnt == 1 1156 */ 1157 int 1158 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 1159 { 1160 char *uiocp; 1161 struct mbuf *mp, *mp2; 1162 int xfer, left, mlen; 1163 int uiosiz, rem; 1164 boolean_t getcluster; 1165 char *cp; 1166 1167 #ifdef DIAGNOSTIC 1168 if (uiop->uio_iovcnt != 1) 1169 panic("nfsm_uiotombuf: iovcnt != 1"); 1170 #endif 1171 1172 if (siz >= MINCLSIZE) 1173 getcluster = TRUE; 1174 else 1175 getcluster = FALSE; 1176 rem = nfsm_rndup(siz) - siz; 1177 mp = mp2 = *mq; 1178 while (siz > 0) { 1179 left = uiop->uio_iov->iov_len; 1180 uiocp = uiop->uio_iov->iov_base; 1181 if (left > siz) 1182 left = siz; 1183 uiosiz = left; 1184 while (left > 0) { 1185 mlen = M_TRAILINGSPACE(mp); 1186 if (mlen == 0) { 1187 if (getcluster) 1188 mp = m_getcl(MB_WAIT, MT_DATA, 0); 1189 else 1190 mp = m_get(MB_WAIT, MT_DATA); 1191 mp->m_len = 0; 1192 mp2->m_next = mp; 1193 mp2 = mp; 1194 mlen = M_TRAILINGSPACE(mp); 1195 } 1196 xfer = (left > mlen) ? mlen : left; 1197 #ifdef notdef 1198 /* Not Yet.. */ 1199 if (uiop->uio_iov->iov_op != NULL) 1200 (*(uiop->uio_iov->iov_op)) 1201 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 1202 else 1203 #endif 1204 if (uiop->uio_segflg == UIO_SYSSPACE) 1205 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 1206 else 1207 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 1208 mp->m_len += xfer; 1209 left -= xfer; 1210 uiocp += xfer; 1211 uiop->uio_offset += xfer; 1212 uiop->uio_resid -= xfer; 1213 } 1214 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz; 1215 uiop->uio_iov->iov_len -= uiosiz; 1216 siz -= uiosiz; 1217 } 1218 if (rem > 0) { 1219 if (rem > M_TRAILINGSPACE(mp)) { 1220 MGET(mp, MB_WAIT, MT_DATA); 1221 mp->m_len = 0; 1222 mp2->m_next = mp; 1223 } 1224 cp = mtod(mp, caddr_t)+mp->m_len; 1225 for (left = 0; left < rem; left++) 1226 *cp++ = '\0'; 1227 mp->m_len += rem; 1228 *bpos = cp; 1229 } else 1230 *bpos = mtod(mp, caddr_t)+mp->m_len; 1231 *mq = mp; 1232 return (0); 1233 } 1234 1235 int 1236 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off, 1237 int siz, caddr_t *bpos) 1238 { 1239 struct buf *bp = bio->bio_buf; 1240 struct mbuf *mp, *mp2; 1241 char *bio_cp; 1242 int bio_left; 1243 int xfer, mlen; 1244 int rem; 1245 boolean_t getcluster; 1246 char *cp; 1247 1248 if (siz >= MINCLSIZE) 1249 getcluster = TRUE; 1250 else 1251 getcluster = FALSE; 1252 rem = nfsm_rndup(siz) - siz; 1253 mp = mp2 = *mq; 1254 1255 bio_cp = bp->b_data + off; 1256 bio_left = siz; 1257 1258 while (bio_left) { 1259 mlen = M_TRAILINGSPACE(mp); 1260 if (mlen == 0) { 1261 if (getcluster) 1262 mp = m_getcl(MB_WAIT, MT_DATA, 0); 1263 else 1264 mp = m_get(MB_WAIT, MT_DATA); 1265 mp->m_len = 0; 1266 mp2->m_next = mp; 1267 mp2 = mp; 1268 mlen = M_TRAILINGSPACE(mp); 1269 } 1270 xfer = (bio_left < mlen) ? bio_left : mlen; 1271 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer); 1272 mp->m_len += xfer; 1273 bio_left -= xfer; 1274 bio_cp += xfer; 1275 } 1276 if (rem > 0) { 1277 if (rem > M_TRAILINGSPACE(mp)) { 1278 MGET(mp, MB_WAIT, MT_DATA); 1279 mp->m_len = 0; 1280 mp2->m_next = mp; 1281 } 1282 cp = mtod(mp, caddr_t) + mp->m_len; 1283 for (mlen = 0; mlen < rem; mlen++) 1284 *cp++ = '\0'; 1285 mp->m_len += rem; 1286 *bpos = cp; 1287 } else { 1288 *bpos = mtod(mp, caddr_t) + mp->m_len; 1289 } 1290 *mq = mp; 1291 return(0); 1292 } 1293 1294 /* 1295 * Help break down an mbuf chain by setting the first siz bytes contiguous 1296 * pointed to by returned val. 1297 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 1298 * cases. (The macros use the vars. dpos and dpos2) 1299 */ 1300 int 1301 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2) 1302 { 1303 struct mbuf *mp, *mp2; 1304 int siz2, xfer; 1305 caddr_t p; 1306 1307 mp = *mdp; 1308 while (left == 0) { 1309 *mdp = mp = mp->m_next; 1310 if (mp == NULL) 1311 return (EBADRPC); 1312 left = mp->m_len; 1313 *dposp = mtod(mp, caddr_t); 1314 } 1315 if (left >= siz) { 1316 *cp2 = *dposp; 1317 *dposp += siz; 1318 } else if (mp->m_next == NULL) { 1319 return (EBADRPC); 1320 } else if (siz > MHLEN) { 1321 panic("nfs S too big"); 1322 } else { 1323 MGET(mp2, MB_WAIT, MT_DATA); 1324 mp2->m_next = mp->m_next; 1325 mp->m_next = mp2; 1326 mp->m_len -= left; 1327 mp = mp2; 1328 *cp2 = p = mtod(mp, caddr_t); 1329 bcopy(*dposp, p, left); /* Copy what was left */ 1330 siz2 = siz-left; 1331 p += left; 1332 mp2 = mp->m_next; 1333 /* Loop around copying up the siz2 bytes */ 1334 while (siz2 > 0) { 1335 if (mp2 == NULL) 1336 return (EBADRPC); 1337 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 1338 if (xfer > 0) { 1339 bcopy(mtod(mp2, caddr_t), p, xfer); 1340 mp2->m_len -= xfer; 1341 mp2->m_data += xfer; 1342 p += xfer; 1343 siz2 -= xfer; 1344 } 1345 if (siz2 > 0) 1346 mp2 = mp2->m_next; 1347 } 1348 mp->m_len = siz; 1349 *mdp = mp2; 1350 *dposp = mtod(mp2, caddr_t); 1351 } 1352 return (0); 1353 } 1354 1355 /* 1356 * Advance the position in the mbuf chain. 1357 */ 1358 int 1359 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left) 1360 { 1361 struct mbuf *m; 1362 int s; 1363 1364 m = *mdp; 1365 s = left; 1366 while (s < offs) { 1367 offs -= s; 1368 m = m->m_next; 1369 if (m == NULL) 1370 return (EBADRPC); 1371 s = m->m_len; 1372 } 1373 *mdp = m; 1374 *dposp = mtod(m, caddr_t)+offs; 1375 return (0); 1376 } 1377 1378 /* 1379 * Copy a string into mbufs for the hard cases... 1380 */ 1381 int 1382 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 1383 { 1384 struct mbuf *m1 = NULL, *m2; 1385 long left, xfer, len, tlen; 1386 u_int32_t *tl; 1387 int putsize; 1388 1389 putsize = 1; 1390 m2 = *mb; 1391 left = M_TRAILINGSPACE(m2); 1392 if (left > 0) { 1393 tl = ((u_int32_t *)(*bpos)); 1394 *tl++ = txdr_unsigned(siz); 1395 putsize = 0; 1396 left -= NFSX_UNSIGNED; 1397 m2->m_len += NFSX_UNSIGNED; 1398 if (left > 0) { 1399 bcopy(cp, (caddr_t) tl, left); 1400 siz -= left; 1401 cp += left; 1402 m2->m_len += left; 1403 left = 0; 1404 } 1405 } 1406 /* Loop around adding mbufs */ 1407 while (siz > 0) { 1408 int msize; 1409 1410 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize); 1411 m1->m_len = msize; 1412 m2->m_next = m1; 1413 m2 = m1; 1414 tl = mtod(m1, u_int32_t *); 1415 tlen = 0; 1416 if (putsize) { 1417 *tl++ = txdr_unsigned(siz); 1418 m1->m_len -= NFSX_UNSIGNED; 1419 tlen = NFSX_UNSIGNED; 1420 putsize = 0; 1421 } 1422 if (siz < m1->m_len) { 1423 len = nfsm_rndup(siz); 1424 xfer = siz; 1425 if (xfer < len) 1426 *(tl+(xfer>>2)) = 0; 1427 } else { 1428 xfer = len = m1->m_len; 1429 } 1430 bcopy(cp, (caddr_t) tl, xfer); 1431 m1->m_len = len+tlen; 1432 siz -= xfer; 1433 cp += xfer; 1434 } 1435 *mb = m1; 1436 *bpos = mtod(m1, caddr_t)+m1->m_len; 1437 return (0); 1438 } 1439 1440 /* 1441 * A fiddled version of m_adj() that ensures null fill to a long 1442 * boundary and only trims off the back end 1443 */ 1444 void 1445 nfsm_adj(struct mbuf *mp, int len, int nul) 1446 { 1447 struct mbuf *m; 1448 int count, i; 1449 char *cp; 1450 1451 /* 1452 * Trim from tail. Scan the mbuf chain, 1453 * calculating its length and finding the last mbuf. 1454 * If the adjustment only affects this mbuf, then just 1455 * adjust and return. Otherwise, rescan and truncate 1456 * after the remaining size. 1457 */ 1458 count = 0; 1459 m = mp; 1460 for (;;) { 1461 count += m->m_len; 1462 if (m->m_next == NULL) 1463 break; 1464 m = m->m_next; 1465 } 1466 if (m->m_len > len) { 1467 m->m_len -= len; 1468 if (nul > 0) { 1469 cp = mtod(m, caddr_t)+m->m_len-nul; 1470 for (i = 0; i < nul; i++) 1471 *cp++ = '\0'; 1472 } 1473 return; 1474 } 1475 count -= len; 1476 if (count < 0) 1477 count = 0; 1478 /* 1479 * Correct length for chain is "count". 1480 * Find the mbuf with last data, adjust its length, 1481 * and toss data from remaining mbufs on chain. 1482 */ 1483 for (m = mp; m; m = m->m_next) { 1484 if (m->m_len >= count) { 1485 m->m_len = count; 1486 if (nul > 0) { 1487 cp = mtod(m, caddr_t)+m->m_len-nul; 1488 for (i = 0; i < nul; i++) 1489 *cp++ = '\0'; 1490 } 1491 break; 1492 } 1493 count -= m->m_len; 1494 } 1495 for (m = m->m_next;m;m = m->m_next) 1496 m->m_len = 0; 1497 } 1498 1499 /* 1500 * Make these functions instead of macros, so that the kernel text size 1501 * doesn't get too big... 1502 */ 1503 void 1504 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd, 1505 int before_ret, struct vattr *before_vap, 1506 int after_ret, struct vattr *after_vap) 1507 { 1508 u_int32_t *tl; 1509 1510 /* 1511 * before_ret is 0 if before_vap is valid, non-zero if it isn't. 1512 */ 1513 if (before_ret) { 1514 tl = nfsm_build(info, NFSX_UNSIGNED); 1515 *tl = nfs_false; 1516 } else { 1517 tl = nfsm_build(info, 7 * NFSX_UNSIGNED); 1518 *tl++ = nfs_true; 1519 txdr_hyper(before_vap->va_size, tl); 1520 tl += 2; 1521 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1522 tl += 2; 1523 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1524 } 1525 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap); 1526 } 1527 1528 void 1529 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd, 1530 int after_ret, struct vattr *after_vap) 1531 { 1532 struct nfs_fattr *fp; 1533 u_int32_t *tl; 1534 1535 if (after_ret) { 1536 tl = nfsm_build(info, NFSX_UNSIGNED); 1537 *tl = nfs_false; 1538 } else { 1539 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR); 1540 *tl++ = nfs_true; 1541 fp = (struct nfs_fattr *)tl; 1542 nfsm_srvfattr(nfsd, after_vap, fp); 1543 } 1544 } 1545 1546 void 1547 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 1548 struct nfs_fattr *fp) 1549 { 1550 /* 1551 * NFS seems to truncate nlink to 16 bits, don't let it overflow. 1552 */ 1553 if (vap->va_nlink > 65535) 1554 fp->fa_nlink = 65535; 1555 else 1556 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1557 fp->fa_uid = txdr_unsigned(vap->va_uid); 1558 fp->fa_gid = txdr_unsigned(vap->va_gid); 1559 if (nfsd->nd_flag & ND_NFSV3) { 1560 fp->fa_type = vtonfsv3_type(vap->va_type); 1561 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1562 txdr_hyper(vap->va_size, &fp->fa3_size); 1563 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1564 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor); 1565 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor); 1566 fp->fa3_fsid.nfsuquad[0] = 0; 1567 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1568 txdr_hyper(vap->va_fileid, &fp->fa3_fileid); 1569 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1570 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1571 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1572 } else { 1573 fp->fa_type = vtonfsv2_type(vap->va_type); 1574 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1575 fp->fa2_size = txdr_unsigned(vap->va_size); 1576 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1577 if (vap->va_type == VFIFO) 1578 fp->fa2_rdev = 0xffffffff; 1579 else 1580 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor)); 1581 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1582 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1583 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1584 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1585 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1586 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1587 } 1588 } 1589