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