1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 37 * $FreeBSD: src/sys/nfs/nfsm_subs.h,v 1.27.2.1 2000/10/28 16:27:27 dwmalone Exp $ 38 * $DragonFly: src/sys/vfs/nfs/nfsm_subs.h,v 1.5 2003/11/15 21:05:44 dillon Exp $ 39 */ 40 41 42 #ifndef _NFS_NFSM_SUBS_H_ 43 #define _NFS_NFSM_SUBS_H_ 44 45 struct ucred; 46 struct vnode; 47 48 /* 49 * These macros do strange and peculiar things to mbuf chains for 50 * the assistance of the nfs code. To attempt to use them for any 51 * other purpose will be dangerous. (they make weird assumptions) 52 */ 53 54 /* 55 * First define what the actual subs. return 56 */ 57 struct mbuf *nfsm_reqh (struct vnode *vp, u_long procid, int hsiz, 58 caddr_t *bposp); 59 struct mbuf *nfsm_rpchead (struct ucred *cr, int nmflag, int procid, 60 int auth_type, int auth_len, char *auth_str, 61 int verf_len, char *verf_str, 62 struct mbuf *mrest, int mrest_len, 63 struct mbuf **mbp, u_int32_t *xidp); 64 65 #define M_HASCL(m) ((m)->m_flags & M_EXT) 66 #define NFSMINOFF(m) \ 67 do { \ 68 if (M_HASCL(m)) \ 69 (m)->m_data = (m)->m_ext.ext_buf; \ 70 else if ((m)->m_flags & M_PKTHDR) \ 71 (m)->m_data = (m)->m_pktdat; \ 72 else \ 73 (m)->m_data = (m)->m_dat; \ 74 } while (0) 75 #define NFSMADV(m, s) \ 76 do { \ 77 (m)->m_data += (s); \ 78 } while (0) 79 #define NFSMSIZ(m) ((M_HASCL(m))?MCLBYTES: \ 80 (((m)->m_flags & M_PKTHDR)?MHLEN:MLEN)) 81 82 /* 83 * Now for the macros that do the simple stuff and call the functions 84 * for the hard stuff. 85 * These macros use several vars. declared in nfsm_reqhead and these 86 * vars. must not be used elsewhere unless you are careful not to corrupt 87 * them. The vars. starting with pN and tN (N=1,2,3,..) are temporaries 88 * that may be used so long as the value is not expected to retained 89 * after a macro. 90 * I know, this is kind of dorkey, but it makes the actual op functions 91 * fairly clean and deals with the mess caused by the xdr discriminating 92 * unions. 93 */ 94 95 #define nfsm_build(a,c,s) \ 96 do { \ 97 if ((s) > M_TRAILINGSPACE(mb)) { \ 98 MGET(mb2, M_WAIT, MT_DATA); \ 99 if ((s) > MLEN) \ 100 panic("build > MLEN"); \ 101 mb->m_next = mb2; \ 102 mb = mb2; \ 103 mb->m_len = 0; \ 104 bpos = mtod(mb, caddr_t); \ 105 } \ 106 (a) = (c)(bpos); \ 107 mb->m_len += (s); \ 108 bpos += (s); \ 109 } while (0) 110 111 #define nfsm_dissect(a, c, s) \ 112 do { \ 113 t1 = mtod(md, caddr_t)+md->m_len-dpos; \ 114 if (t1 >= (s)) { \ 115 (a) = (c)(dpos); \ 116 dpos += (s); \ 117 } else if ((t1 = nfsm_disct(&md, &dpos, (s), t1, &cp2)) != 0){ \ 118 error = t1; \ 119 m_freem(mrep); \ 120 goto nfsmout; \ 121 } else { \ 122 (a) = (c)cp2; \ 123 } \ 124 } while (0) 125 126 #define nfsm_fhtom(v, v3) \ 127 do { \ 128 if (v3) { \ 129 t2 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; \ 130 if (t2 <= M_TRAILINGSPACE(mb)) { \ 131 nfsm_build(tl, u_int32_t *, t2); \ 132 *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); \ 133 *(tl + ((t2>>2) - 2)) = 0; \ 134 bcopy((caddr_t)VTONFS(v)->n_fhp,(caddr_t)tl, \ 135 VTONFS(v)->n_fhsize); \ 136 } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, \ 137 (caddr_t)VTONFS(v)->n_fhp, \ 138 VTONFS(v)->n_fhsize)) != 0) { \ 139 error = t2; \ 140 m_freem(mreq); \ 141 goto nfsmout; \ 142 } \ 143 } else { \ 144 nfsm_build(cp, caddr_t, NFSX_V2FH); \ 145 bcopy((caddr_t)VTONFS(v)->n_fhp, cp, NFSX_V2FH); \ 146 } \ 147 } while (0) 148 149 #define nfsm_srvfhtom(f, v3) \ 150 do { \ 151 if (v3) { \ 152 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FH);\ 153 *tl++ = txdr_unsigned(NFSX_V3FH); \ 154 bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ 155 } else { \ 156 nfsm_build(cp, caddr_t, NFSX_V2FH); \ 157 bcopy((caddr_t)(f), cp, NFSX_V2FH); \ 158 } \ 159 } while (0) 160 161 #define nfsm_srvpostop_fh(f) \ 162 do { \ 163 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED + NFSX_V3FH); \ 164 *tl++ = nfs_true; \ 165 *tl++ = txdr_unsigned(NFSX_V3FH); \ 166 bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ 167 } while (0) 168 169 #define nfsm_mtofh(d, v, v3, f) \ 170 do { \ 171 struct nfsnode *ttnp; nfsfh_t *ttfhp; int ttfhsize; \ 172 if (v3) { \ 173 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 174 (f) = fxdr_unsigned(int, *tl); \ 175 } else \ 176 (f) = 1; \ 177 if (f) { \ 178 nfsm_getfh(ttfhp, ttfhsize, (v3)); \ 179 if ((t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \ 180 &ttnp)) != 0) { \ 181 error = t1; \ 182 m_freem(mrep); \ 183 goto nfsmout; \ 184 } \ 185 (v) = NFSTOV(ttnp); \ 186 } \ 187 if (v3) { \ 188 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 189 if (f) \ 190 (f) = fxdr_unsigned(int, *tl); \ 191 else if (fxdr_unsigned(int, *tl)) \ 192 nfsm_adv(NFSX_V3FATTR); \ 193 } \ 194 if (f) \ 195 nfsm_loadattr((v), (struct vattr *)0); \ 196 } while (0) 197 198 #define nfsm_getfh(f, s, v3) \ 199 do { \ 200 if (v3) { \ 201 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 202 if (((s) = fxdr_unsigned(int, *tl)) <= 0 || \ 203 (s) > NFSX_V3FHMAX) { \ 204 m_freem(mrep); \ 205 error = EBADRPC; \ 206 goto nfsmout; \ 207 } \ 208 } else \ 209 (s) = NFSX_V2FH; \ 210 nfsm_dissect((f), nfsfh_t *, nfsm_rndup(s)); \ 211 } while (0) 212 213 #define nfsm_loadattr(v, a) \ 214 do { \ 215 struct vnode *ttvp = (v); \ 216 if ((t1 = nfs_loadattrcache(&ttvp, &md, &dpos, (a), 0)) != 0) { \ 217 error = t1; \ 218 m_freem(mrep); \ 219 goto nfsmout; \ 220 } \ 221 (v) = ttvp; \ 222 } while (0) 223 224 #define nfsm_postop_attr(v, f) \ 225 do { \ 226 struct vnode *ttvp = (v); \ 227 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 228 if (((f) = fxdr_unsigned(int, *tl)) != 0) { \ 229 if ((t1 = nfs_loadattrcache(&ttvp, &md, &dpos, \ 230 (struct vattr *)0, 1)) != 0) { \ 231 error = t1; \ 232 (f) = 0; \ 233 m_freem(mrep); \ 234 goto nfsmout; \ 235 } \ 236 (v) = ttvp; \ 237 } \ 238 } while (0) 239 240 /* Used as (f) for nfsm_wcc_data() */ 241 #define NFSV3_WCCRATTR 0 242 #define NFSV3_WCCCHK 1 243 244 #define nfsm_wcc_data(v, f) \ 245 do { \ 246 int ttattrf, ttretf = 0; \ 247 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 248 if (*tl == nfs_true) { \ 249 nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); \ 250 if (f) \ 251 ttretf = (VTONFS(v)->n_mtime == \ 252 fxdr_unsigned(u_int32_t, *(tl + 2))); \ 253 } \ 254 nfsm_postop_attr((v), ttattrf); \ 255 if (f) { \ 256 (f) = ttretf; \ 257 } else { \ 258 (f) = ttattrf; \ 259 } \ 260 } while (0) 261 262 /* If full is true, set all fields, otherwise just set mode and time fields */ 263 #define nfsm_v3attrbuild(a, full) \ 264 do { \ 265 if ((a)->va_mode != (mode_t)VNOVAL) { \ 266 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ 267 *tl++ = nfs_true; \ 268 *tl = txdr_unsigned((a)->va_mode); \ 269 } else { \ 270 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 271 *tl = nfs_false; \ 272 } \ 273 if ((full) && (a)->va_uid != (uid_t)VNOVAL) { \ 274 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ 275 *tl++ = nfs_true; \ 276 *tl = txdr_unsigned((a)->va_uid); \ 277 } else { \ 278 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 279 *tl = nfs_false; \ 280 } \ 281 if ((full) && (a)->va_gid != (gid_t)VNOVAL) { \ 282 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ 283 *tl++ = nfs_true; \ 284 *tl = txdr_unsigned((a)->va_gid); \ 285 } else { \ 286 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 287 *tl = nfs_false; \ 288 } \ 289 if ((full) && (a)->va_size != VNOVAL) { \ 290 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); \ 291 *tl++ = nfs_true; \ 292 txdr_hyper((a)->va_size, tl); \ 293 } else { \ 294 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 295 *tl = nfs_false; \ 296 } \ 297 if ((a)->va_atime.tv_sec != VNOVAL) { \ 298 if ((a)->va_atime.tv_sec != time_second) { \ 299 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);\ 300 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);\ 301 txdr_nfsv3time(&(a)->va_atime, tl); \ 302 } else { \ 303 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 304 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); \ 305 } \ 306 } else { \ 307 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 308 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); \ 309 } \ 310 if ((a)->va_mtime.tv_sec != VNOVAL) { \ 311 if ((a)->va_mtime.tv_sec != time_second) { \ 312 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);\ 313 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);\ 314 txdr_nfsv3time(&(a)->va_mtime, tl); \ 315 } else { \ 316 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 317 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); \ 318 } \ 319 } else { \ 320 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ 321 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); \ 322 } \ 323 } while (0) 324 325 326 #define nfsm_strsiz(s,m) \ 327 do { \ 328 nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ 329 if (((s) = fxdr_unsigned(int32_t,*tl)) > (m)) { \ 330 m_freem(mrep); \ 331 error = EBADRPC; \ 332 goto nfsmout; \ 333 } \ 334 } while (0) 335 336 #define nfsm_srvstrsiz(s,m) \ 337 do { \ 338 nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ 339 if (((s) = fxdr_unsigned(int32_t,*tl)) > (m) || (s) <= 0) { \ 340 error = EBADRPC; \ 341 nfsm_reply(0); \ 342 } \ 343 } while (0) 344 345 #define nfsm_srvnamesiz(s) \ 346 do { \ 347 nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ 348 if (((s) = fxdr_unsigned(int32_t,*tl)) > NFS_MAXNAMLEN) \ 349 error = NFSERR_NAMETOL; \ 350 if ((s) <= 0) \ 351 error = EBADRPC; \ 352 if (error) \ 353 nfsm_reply(0); \ 354 } while (0) 355 356 #define nfsm_mtouio(p,s) \ 357 do {\ 358 if ((s) > 0 && \ 359 (t1 = nfsm_mbuftouio(&md,(p),(s),&dpos)) != 0) { \ 360 error = t1; \ 361 m_freem(mrep); \ 362 goto nfsmout; \ 363 } \ 364 } while (0) 365 366 #define nfsm_uiotom(p,s) \ 367 do { \ 368 if ((t1 = nfsm_uiotombuf((p),&mb,(s),&bpos)) != 0) { \ 369 error = t1; \ 370 m_freem(mreq); \ 371 goto nfsmout; \ 372 } \ 373 } while (0) 374 375 #define nfsm_reqhead(v,a,s) \ 376 do { \ 377 mb = mreq = nfsm_reqh((v),(a),(s),&bpos); \ 378 } while (0) 379 380 #define nfsm_rndup(a) (((a)+3)&(~0x3)) 381 382 #define nfsm_request(v, t, td, c) \ 383 do { \ 384 if ((error = nfs_request((v), mreq, (t), (td), \ 385 (c), &mrep, &md, &dpos)) != 0) { \ 386 if (error & NFSERR_RETERR) \ 387 error &= ~NFSERR_RETERR; \ 388 else \ 389 goto nfsmout; \ 390 } \ 391 } while (0) 392 393 #define nfsm_strtom(a,s,m) \ 394 do {\ 395 if ((s) > (m)) { \ 396 m_freem(mreq); \ 397 error = ENAMETOOLONG; \ 398 goto nfsmout; \ 399 } \ 400 t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \ 401 if (t2 <= M_TRAILINGSPACE(mb)) { \ 402 nfsm_build(tl,u_int32_t *,t2); \ 403 *tl++ = txdr_unsigned(s); \ 404 *(tl+((t2>>2)-2)) = 0; \ 405 bcopy((const char *)(a), (caddr_t)tl, (s)); \ 406 } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, (a), (s))) != 0) { \ 407 error = t2; \ 408 m_freem(mreq); \ 409 goto nfsmout; \ 410 } \ 411 } while (0) 412 413 #define nfsm_srvdone \ 414 do { \ 415 nfsmout: \ 416 return (error); \ 417 } while (0) 418 419 #define nfsm_reply(s) \ 420 do { \ 421 nfsd->nd_repstat = error; \ 422 if (error && !(nfsd->nd_flag & ND_NFSV3)) \ 423 (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ 424 mrq, &mb, &bpos); \ 425 else \ 426 (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ 427 mrq, &mb, &bpos); \ 428 if (mrep != NULL) { \ 429 m_freem(mrep); \ 430 mrep = NULL; \ 431 } \ 432 mreq = *mrq; \ 433 if (error && (!(nfsd->nd_flag & ND_NFSV3) || \ 434 error == EBADRPC)) { \ 435 error = 0; \ 436 goto nfsmout; \ 437 } \ 438 } while (0) 439 440 #define nfsm_writereply(s, v3) \ 441 do { \ 442 nfsd->nd_repstat = error; \ 443 if (error && !(v3)) \ 444 (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ 445 &mreq, &mb, &bpos); \ 446 else \ 447 (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ 448 &mreq, &mb, &bpos); \ 449 } while (0) 450 451 #define nfsm_adv(s) \ 452 do { \ 453 t1 = mtod(md, caddr_t)+md->m_len-dpos; \ 454 if (t1 >= (s)) { \ 455 dpos += (s); \ 456 } else if ((t1 = nfs_adv(&md, &dpos, (s), t1)) != 0) { \ 457 error = t1; \ 458 m_freem(mrep); \ 459 goto nfsmout; \ 460 } \ 461 } while (0) 462 463 #define nfsm_srvmtofh(f) \ 464 do { \ 465 int fhlen; \ 466 if (nfsd->nd_flag & ND_NFSV3) { \ 467 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 468 fhlen = fxdr_unsigned(int, *tl); \ 469 if (fhlen != 0 && fhlen != NFSX_V3FH) { \ 470 error = EBADRPC; \ 471 nfsm_reply(0); \ 472 } \ 473 } else { \ 474 fhlen = NFSX_V2FH; \ 475 } \ 476 if (fhlen != 0) { \ 477 nfsm_dissect(tl, u_int32_t *, fhlen); \ 478 bcopy((caddr_t)tl, (caddr_t)(f), fhlen); \ 479 } else {\ 480 bzero((caddr_t)(f), NFSX_V3FH); \ 481 } \ 482 } while (0) 483 484 #define nfsm_clget \ 485 do { \ 486 if (bp >= be) { \ 487 if (mp == mb) \ 488 mp->m_len += bp-bpos; \ 489 MGET(mp, M_WAIT, MT_DATA); \ 490 MCLGET(mp, M_WAIT); \ 491 mp->m_len = NFSMSIZ(mp); \ 492 mp2->m_next = mp; \ 493 mp2 = mp; \ 494 bp = mtod(mp, caddr_t); \ 495 be = bp+mp->m_len; \ 496 } \ 497 tl = (u_int32_t *)bp; \ 498 } while (0) 499 500 #define nfsm_srvfillattr(a, f) \ 501 do { \ 502 nfsm_srvfattr(nfsd, (a), (f)); \ 503 } while (0) 504 505 #define nfsm_srvwcc_data(br, b, ar, a) \ 506 do { \ 507 nfsm_srvwcc(nfsd, (br), (b), (ar), (a), &mb, &bpos); \ 508 } while (0) 509 510 #define nfsm_srvpostop_attr(r, a) \ 511 do { \ 512 nfsm_srvpostopattr(nfsd, (r), (a), &mb, &bpos); \ 513 } while (0) 514 515 #define nfsm_srvsattr(a) \ 516 do { \ 517 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 518 if (*tl == nfs_true) { \ 519 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 520 (a)->va_mode = nfstov_mode(*tl); \ 521 } \ 522 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 523 if (*tl == nfs_true) { \ 524 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 525 (a)->va_uid = fxdr_unsigned(uid_t, *tl); \ 526 } \ 527 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 528 if (*tl == nfs_true) { \ 529 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 530 (a)->va_gid = fxdr_unsigned(gid_t, *tl); \ 531 } \ 532 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 533 if (*tl == nfs_true) { \ 534 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ 535 (a)->va_size = fxdr_hyper(tl); \ 536 } \ 537 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 538 switch (fxdr_unsigned(int, *tl)) { \ 539 case NFSV3SATTRTIME_TOCLIENT: \ 540 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ 541 fxdr_nfsv3time(tl, &(a)->va_atime); \ 542 break; \ 543 case NFSV3SATTRTIME_TOSERVER: \ 544 getnanotime(&(a)->va_atime); \ 545 break; \ 546 }; \ 547 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ 548 switch (fxdr_unsigned(int, *tl)) { \ 549 case NFSV3SATTRTIME_TOCLIENT: \ 550 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ 551 fxdr_nfsv3time(tl, &(a)->va_mtime); \ 552 break; \ 553 case NFSV3SATTRTIME_TOSERVER: \ 554 getnanotime(&(a)->va_mtime); \ 555 break; \ 556 } \ 557 } while (0) 558 559 #endif 560