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