xref: /openbsd-src/sys/nfs/nfs_subs.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: nfs_subs.c,v 1.116 2014/07/08 17:19:26 deraadt Exp $	*/
2 /*	$NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $	*/
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Rick Macklem at The University of Guelph.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
36  */
37 
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #include <sys/param.h>
45 #include <sys/proc.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <sys/namei.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/stat.h>
55 #include <sys/pool.h>
56 #include <sys/time.h>
57 #include <sys/specdev.h>
58 
59 #include <nfs/rpcv2.h>
60 #include <nfs/nfsproto.h>
61 #include <nfs/nfsnode.h>
62 #include <nfs/nfs.h>
63 #include <nfs/xdr_subs.h>
64 #include <nfs/nfsm_subs.h>
65 #include <nfs/nfsmount.h>
66 #include <nfs/nfs_var.h>
67 
68 
69 #include <netinet/in.h>
70 
71 #include <dev/rndvar.h>
72 #include <crypto/idgen.h>
73 
74 int	nfs_attrtimeo(struct nfsnode *np);
75 
76 /*
77  * Data items converted to xdr at startup, since they are constant
78  * This is kinda hokey, but may save a little time doing byte swaps
79  */
80 u_int32_t nfs_xdrneg1;
81 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
82 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
83 u_int32_t nfs_prog, nfs_true, nfs_false;
84 
85 /* And other global data */
86 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
87 		      NFCHR, NFNON };
88 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
89 		      NFFIFO, NFNON };
90 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
91 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
92 int nfs_ticks;
93 struct nfsstats nfsstats;
94 
95 /*
96  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
97  */
98 int nfsv3_procid[NFS_NPROCS] = {
99 	NFSPROC_NULL,
100 	NFSPROC_GETATTR,
101 	NFSPROC_SETATTR,
102 	NFSPROC_NOOP,
103 	NFSPROC_LOOKUP,
104 	NFSPROC_READLINK,
105 	NFSPROC_READ,
106 	NFSPROC_NOOP,
107 	NFSPROC_WRITE,
108 	NFSPROC_CREATE,
109 	NFSPROC_REMOVE,
110 	NFSPROC_RENAME,
111 	NFSPROC_LINK,
112 	NFSPROC_SYMLINK,
113 	NFSPROC_MKDIR,
114 	NFSPROC_RMDIR,
115 	NFSPROC_READDIR,
116 	NFSPROC_FSSTAT,
117 	NFSPROC_NOOP,
118 	NFSPROC_NOOP,
119 	NFSPROC_NOOP,
120 	NFSPROC_NOOP,
121 	NFSPROC_NOOP
122 };
123 
124 /*
125  * and the reverse mapping from generic to Version 2 procedure numbers
126  */
127 int nfsv2_procid[NFS_NPROCS] = {
128 	NFSV2PROC_NULL,
129 	NFSV2PROC_GETATTR,
130 	NFSV2PROC_SETATTR,
131 	NFSV2PROC_LOOKUP,
132 	NFSV2PROC_NOOP,
133 	NFSV2PROC_READLINK,
134 	NFSV2PROC_READ,
135 	NFSV2PROC_WRITE,
136 	NFSV2PROC_CREATE,
137 	NFSV2PROC_MKDIR,
138 	NFSV2PROC_SYMLINK,
139 	NFSV2PROC_CREATE,
140 	NFSV2PROC_REMOVE,
141 	NFSV2PROC_RMDIR,
142 	NFSV2PROC_RENAME,
143 	NFSV2PROC_LINK,
144 	NFSV2PROC_READDIR,
145 	NFSV2PROC_NOOP,
146 	NFSV2PROC_STATFS,
147 	NFSV2PROC_NOOP,
148 	NFSV2PROC_NOOP,
149 	NFSV2PROC_NOOP,
150 	NFSV2PROC_NOOP
151 };
152 
153 /*
154  * Maps errno values to nfs error numbers.
155  * Use NFSERR_IO as the catch all for ones not specifically defined in
156  * RFC 1094.
157  */
158 static u_char nfsrv_v2errmap[] = {
159   NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
160   NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
161   NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
162   NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
163   NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
164   NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
165   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
166   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
167   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
168   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
169   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
170   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
171   NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
172   NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE
173   /* Everything after this maps to NFSERR_IO, so far */
174 };
175 
176 /*
177  * Maps errno values to nfs error numbers.
178  * Although it is not obvious whether or not NFS clients really care if
179  * a returned error value is in the specified list for the procedure, the
180  * safest thing to do is filter them appropriately. For Version 2, the
181  * X/Open XNFS document is the only specification that defines error values
182  * for each RPC (The RFC simply lists all possible error values for all RPCs),
183  * so I have decided to not do this for Version 2.
184  * The first entry is the default error return and the rest are the valid
185  * errors for that RPC in increasing numeric order.
186  */
187 static short nfsv3err_null[] = {
188 	0,
189 	0,
190 };
191 
192 static short nfsv3err_getattr[] = {
193 	NFSERR_IO,
194 	NFSERR_IO,
195 	NFSERR_STALE,
196 	NFSERR_BADHANDLE,
197 	NFSERR_SERVERFAULT,
198 	0,
199 };
200 
201 static short nfsv3err_setattr[] = {
202 	NFSERR_IO,
203 	NFSERR_PERM,
204 	NFSERR_IO,
205 	NFSERR_ACCES,
206 	NFSERR_INVAL,
207 	NFSERR_NOSPC,
208 	NFSERR_ROFS,
209 	NFSERR_DQUOT,
210 	NFSERR_STALE,
211 	NFSERR_BADHANDLE,
212 	NFSERR_NOT_SYNC,
213 	NFSERR_SERVERFAULT,
214 	0,
215 };
216 
217 static short nfsv3err_lookup[] = {
218 	NFSERR_IO,
219 	NFSERR_NOENT,
220 	NFSERR_IO,
221 	NFSERR_ACCES,
222 	NFSERR_NOTDIR,
223 	NFSERR_NAMETOL,
224 	NFSERR_STALE,
225 	NFSERR_BADHANDLE,
226 	NFSERR_SERVERFAULT,
227 	0,
228 };
229 
230 static short nfsv3err_access[] = {
231 	NFSERR_IO,
232 	NFSERR_IO,
233 	NFSERR_STALE,
234 	NFSERR_BADHANDLE,
235 	NFSERR_SERVERFAULT,
236 	0,
237 };
238 
239 static short nfsv3err_readlink[] = {
240 	NFSERR_IO,
241 	NFSERR_IO,
242 	NFSERR_ACCES,
243 	NFSERR_INVAL,
244 	NFSERR_STALE,
245 	NFSERR_BADHANDLE,
246 	NFSERR_NOTSUPP,
247 	NFSERR_SERVERFAULT,
248 	0,
249 };
250 
251 static short nfsv3err_read[] = {
252 	NFSERR_IO,
253 	NFSERR_IO,
254 	NFSERR_NXIO,
255 	NFSERR_ACCES,
256 	NFSERR_INVAL,
257 	NFSERR_STALE,
258 	NFSERR_BADHANDLE,
259 	NFSERR_SERVERFAULT,
260 	0,
261 };
262 
263 static short nfsv3err_write[] = {
264 	NFSERR_IO,
265 	NFSERR_IO,
266 	NFSERR_ACCES,
267 	NFSERR_INVAL,
268 	NFSERR_FBIG,
269 	NFSERR_NOSPC,
270 	NFSERR_ROFS,
271 	NFSERR_DQUOT,
272 	NFSERR_STALE,
273 	NFSERR_BADHANDLE,
274 	NFSERR_SERVERFAULT,
275 	0,
276 };
277 
278 static short nfsv3err_create[] = {
279 	NFSERR_IO,
280 	NFSERR_IO,
281 	NFSERR_ACCES,
282 	NFSERR_EXIST,
283 	NFSERR_NOTDIR,
284 	NFSERR_NOSPC,
285 	NFSERR_ROFS,
286 	NFSERR_NAMETOL,
287 	NFSERR_DQUOT,
288 	NFSERR_STALE,
289 	NFSERR_BADHANDLE,
290 	NFSERR_NOTSUPP,
291 	NFSERR_SERVERFAULT,
292 	0,
293 };
294 
295 static short nfsv3err_mkdir[] = {
296 	NFSERR_IO,
297 	NFSERR_IO,
298 	NFSERR_ACCES,
299 	NFSERR_EXIST,
300 	NFSERR_NOTDIR,
301 	NFSERR_NOSPC,
302 	NFSERR_ROFS,
303 	NFSERR_NAMETOL,
304 	NFSERR_DQUOT,
305 	NFSERR_STALE,
306 	NFSERR_BADHANDLE,
307 	NFSERR_NOTSUPP,
308 	NFSERR_SERVERFAULT,
309 	0,
310 };
311 
312 static short nfsv3err_symlink[] = {
313 	NFSERR_IO,
314 	NFSERR_IO,
315 	NFSERR_ACCES,
316 	NFSERR_EXIST,
317 	NFSERR_NOTDIR,
318 	NFSERR_NOSPC,
319 	NFSERR_ROFS,
320 	NFSERR_NAMETOL,
321 	NFSERR_DQUOT,
322 	NFSERR_STALE,
323 	NFSERR_BADHANDLE,
324 	NFSERR_NOTSUPP,
325 	NFSERR_SERVERFAULT,
326 	0,
327 };
328 
329 static short nfsv3err_mknod[] = {
330 	NFSERR_IO,
331 	NFSERR_IO,
332 	NFSERR_ACCES,
333 	NFSERR_EXIST,
334 	NFSERR_NOTDIR,
335 	NFSERR_NOSPC,
336 	NFSERR_ROFS,
337 	NFSERR_NAMETOL,
338 	NFSERR_DQUOT,
339 	NFSERR_STALE,
340 	NFSERR_BADHANDLE,
341 	NFSERR_NOTSUPP,
342 	NFSERR_SERVERFAULT,
343 	NFSERR_BADTYPE,
344 	0,
345 };
346 
347 static short nfsv3err_remove[] = {
348 	NFSERR_IO,
349 	NFSERR_NOENT,
350 	NFSERR_IO,
351 	NFSERR_ACCES,
352 	NFSERR_NOTDIR,
353 	NFSERR_ROFS,
354 	NFSERR_NAMETOL,
355 	NFSERR_STALE,
356 	NFSERR_BADHANDLE,
357 	NFSERR_SERVERFAULT,
358 	0,
359 };
360 
361 static short nfsv3err_rmdir[] = {
362 	NFSERR_IO,
363 	NFSERR_NOENT,
364 	NFSERR_IO,
365 	NFSERR_ACCES,
366 	NFSERR_EXIST,
367 	NFSERR_NOTDIR,
368 	NFSERR_INVAL,
369 	NFSERR_ROFS,
370 	NFSERR_NAMETOL,
371 	NFSERR_NOTEMPTY,
372 	NFSERR_STALE,
373 	NFSERR_BADHANDLE,
374 	NFSERR_NOTSUPP,
375 	NFSERR_SERVERFAULT,
376 	0,
377 };
378 
379 static short nfsv3err_rename[] = {
380 	NFSERR_IO,
381 	NFSERR_NOENT,
382 	NFSERR_IO,
383 	NFSERR_ACCES,
384 	NFSERR_EXIST,
385 	NFSERR_XDEV,
386 	NFSERR_NOTDIR,
387 	NFSERR_ISDIR,
388 	NFSERR_INVAL,
389 	NFSERR_NOSPC,
390 	NFSERR_ROFS,
391 	NFSERR_MLINK,
392 	NFSERR_NAMETOL,
393 	NFSERR_NOTEMPTY,
394 	NFSERR_DQUOT,
395 	NFSERR_STALE,
396 	NFSERR_BADHANDLE,
397 	NFSERR_NOTSUPP,
398 	NFSERR_SERVERFAULT,
399 	0,
400 };
401 
402 static short nfsv3err_link[] = {
403 	NFSERR_IO,
404 	NFSERR_IO,
405 	NFSERR_ACCES,
406 	NFSERR_EXIST,
407 	NFSERR_XDEV,
408 	NFSERR_NOTDIR,
409 	NFSERR_INVAL,
410 	NFSERR_NOSPC,
411 	NFSERR_ROFS,
412 	NFSERR_MLINK,
413 	NFSERR_NAMETOL,
414 	NFSERR_DQUOT,
415 	NFSERR_STALE,
416 	NFSERR_BADHANDLE,
417 	NFSERR_NOTSUPP,
418 	NFSERR_SERVERFAULT,
419 	0,
420 };
421 
422 static short nfsv3err_readdir[] = {
423 	NFSERR_IO,
424 	NFSERR_IO,
425 	NFSERR_ACCES,
426 	NFSERR_NOTDIR,
427 	NFSERR_STALE,
428 	NFSERR_BADHANDLE,
429 	NFSERR_BAD_COOKIE,
430 	NFSERR_TOOSMALL,
431 	NFSERR_SERVERFAULT,
432 	0,
433 };
434 
435 static short nfsv3err_readdirplus[] = {
436 	NFSERR_IO,
437 	NFSERR_IO,
438 	NFSERR_ACCES,
439 	NFSERR_NOTDIR,
440 	NFSERR_STALE,
441 	NFSERR_BADHANDLE,
442 	NFSERR_BAD_COOKIE,
443 	NFSERR_NOTSUPP,
444 	NFSERR_TOOSMALL,
445 	NFSERR_SERVERFAULT,
446 	0,
447 };
448 
449 static short nfsv3err_fsstat[] = {
450 	NFSERR_IO,
451 	NFSERR_IO,
452 	NFSERR_STALE,
453 	NFSERR_BADHANDLE,
454 	NFSERR_SERVERFAULT,
455 	0,
456 };
457 
458 static short nfsv3err_fsinfo[] = {
459 	NFSERR_STALE,
460 	NFSERR_STALE,
461 	NFSERR_BADHANDLE,
462 	NFSERR_SERVERFAULT,
463 	0,
464 };
465 
466 static short nfsv3err_pathconf[] = {
467 	NFSERR_STALE,
468 	NFSERR_STALE,
469 	NFSERR_BADHANDLE,
470 	NFSERR_SERVERFAULT,
471 	0,
472 };
473 
474 static short nfsv3err_commit[] = {
475 	NFSERR_IO,
476 	NFSERR_IO,
477 	NFSERR_STALE,
478 	NFSERR_BADHANDLE,
479 	NFSERR_SERVERFAULT,
480 	0,
481 };
482 
483 static short *nfsrv_v3errmap[] = {
484 	nfsv3err_null,
485 	nfsv3err_getattr,
486 	nfsv3err_setattr,
487 	nfsv3err_lookup,
488 	nfsv3err_access,
489 	nfsv3err_readlink,
490 	nfsv3err_read,
491 	nfsv3err_write,
492 	nfsv3err_create,
493 	nfsv3err_mkdir,
494 	nfsv3err_symlink,
495 	nfsv3err_mknod,
496 	nfsv3err_remove,
497 	nfsv3err_rmdir,
498 	nfsv3err_rename,
499 	nfsv3err_link,
500 	nfsv3err_readdir,
501 	nfsv3err_readdirplus,
502 	nfsv3err_fsstat,
503 	nfsv3err_fsinfo,
504 	nfsv3err_pathconf,
505 	nfsv3err_commit,
506 };
507 
508 struct pool nfsreqpl;
509 
510 /*
511  * Create the header for an rpc request packet
512  * The hsiz is the size of the rest of the nfs request header.
513  * (just used to decide if a cluster is a good idea)
514  */
515 struct mbuf *
516 nfsm_reqhead(int hsiz)
517 {
518 	struct mbuf *mb;
519 
520 	MGET(mb, M_WAIT, MT_DATA);
521 	if (hsiz > MLEN)
522 		MCLGET(mb, M_WAIT);
523 	mb->m_len = 0;
524 
525 	/* Finally, return values */
526 	return (mb);
527 }
528 
529 /*
530  * Return an unpredictable XID in XDR form.
531  */
532 u_int32_t
533 nfs_get_xid(void)
534 {
535 	static struct idgen32_ctx nfs_xid_ctx;
536 	static int called = 0;
537 
538 	if (!called) {
539 		called = 1;
540 		idgen32_init(&nfs_xid_ctx);
541 	}
542 	return (txdr_unsigned(idgen32(&nfs_xid_ctx)));
543 }
544 
545 /*
546  * Build the RPC header and fill in the authorization info.
547  * Right now we are pretty centric around RPCAUTH_UNIX, in the
548  * future, this function will need some love to be able to handle
549  * other authorization methods, such as Kerberos.
550  */
551 void
552 nfsm_rpchead(struct nfsreq *req, struct ucred *cr, int auth_type)
553 {
554 	struct mbuf	*mb;
555 	u_int32_t	*tl;
556 	int		i, authsiz, auth_len, ngroups;
557 
558 	KASSERT(auth_type == RPCAUTH_UNIX);
559 
560 	/*
561 	 * RPCAUTH_UNIX fits in an hdr mbuf, in the future other
562 	 * authorization methods need to figure out their own sizes
563 	 * and allocate and chain mbuf's accorindgly.
564 	 */
565 	mb = req->r_mreq;
566 
567 	/*
568 	 * We need to start out by finding how big the authorization cred
569 	 * and verifer are for the auth_type, to be able to correctly
570 	 * align the mbuf header/chain.
571 	 */
572 	switch (auth_type) {
573 	case RPCAUTH_UNIX:
574 		/*
575 		 * In the RPCAUTH_UNIX case, the size is the static
576 		 * part as shown in RFC1831 + the number of groups,
577 		 * RPCAUTH_UNIX has a zero verifer.
578 		 */
579 		if (cr->cr_ngroups > req->r_nmp->nm_numgrps)
580 			ngroups = req->r_nmp->nm_numgrps;
581 		else
582 			ngroups = cr->cr_ngroups;
583 
584 		auth_len = (ngroups << 2) + 5 * NFSX_UNSIGNED;
585 		authsiz = nfsm_rndup(auth_len);
586 		/* The authorization size + the size of the static part */
587 		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
588 		break;
589 	}
590 
591 	mb->m_len = 0;
592 
593 	/* First the RPC header. */
594 	tl = nfsm_build(&mb, 6 * NFSX_UNSIGNED);
595 
596 	/* Get a new (non-zero) xid */
597 	*tl++ = req->r_xid = nfs_get_xid();
598 	*tl++ = rpc_call;
599 	*tl++ = rpc_vers;
600 	*tl++ = nfs_prog;
601 	if (ISSET(req->r_nmp->nm_flag, NFSMNT_NFSV3)) {
602 		*tl++ = txdr_unsigned(NFS_VER3);
603 		*tl = txdr_unsigned(req->r_procnum);
604 	} else {
605 		*tl++ = txdr_unsigned(NFS_VER2);
606 		*tl = txdr_unsigned(nfsv2_procid[req->r_procnum]);
607 	}
608 
609 	/* The Authorization cred and its verifier */
610 	switch (auth_type) {
611 	case RPCAUTH_UNIX:
612 		tl = nfsm_build(&mb, auth_len + 4 * NFSX_UNSIGNED);
613 		*tl++ = txdr_unsigned(RPCAUTH_UNIX);
614 		*tl++ = txdr_unsigned(authsiz);
615 
616 		/* The authorization cred */
617 		*tl++ = 0;		/* stamp */
618 		*tl++ = 0;		/* NULL hostname */
619 		*tl++ = txdr_unsigned(cr->cr_uid);
620 		*tl++ = txdr_unsigned(cr->cr_gid);
621 		*tl++ = txdr_unsigned(ngroups);
622 		for (i = 0; i < ngroups; i++)
623 			*tl++ = txdr_unsigned(cr->cr_groups[i]);
624 		/* The authorization verifier */
625 		*tl++ = txdr_unsigned(RPCAUTH_NULL);
626 		*tl = 0;
627 		break;
628 	}
629 
630 	mb->m_pkthdr.len += authsiz + 10 * NFSX_UNSIGNED;
631 	mb->m_pkthdr.rcvif = NULL;
632 }
633 
634 /*
635  * copies mbuf chain to the uio scatter/gather list
636  */
637 int
638 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
639 {
640 	char *mbufcp, *uiocp;
641 	int xfer, left, len;
642 	struct mbuf *mp;
643 	long uiosiz, rem;
644 	int error = 0;
645 
646 	mp = *mrep;
647 	mbufcp = *dpos;
648 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
649 	rem = nfsm_padlen(siz);
650 	while (siz > 0) {
651 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
652 			return (EFBIG);
653 		left = uiop->uio_iov->iov_len;
654 		uiocp = uiop->uio_iov->iov_base;
655 		if (left > siz)
656 			left = siz;
657 		uiosiz = left;
658 		while (left > 0) {
659 			while (len == 0) {
660 				mp = mp->m_next;
661 				if (mp == NULL)
662 					return (EBADRPC);
663 				mbufcp = mtod(mp, caddr_t);
664 				len = mp->m_len;
665 			}
666 			xfer = (left > len) ? len : left;
667 			if (uiop->uio_segflg == UIO_SYSSPACE)
668 				bcopy(mbufcp, uiocp, xfer);
669 			else
670 				copyout(mbufcp, uiocp, xfer);
671 			left -= xfer;
672 			len -= xfer;
673 			mbufcp += xfer;
674 			uiocp += xfer;
675 			uiop->uio_offset += xfer;
676 			uiop->uio_resid -= xfer;
677 		}
678 		if (uiop->uio_iov->iov_len <= siz) {
679 			uiop->uio_iovcnt--;
680 			uiop->uio_iov++;
681 		} else {
682 			uiop->uio_iov->iov_base =
683 			    (char *)uiop->uio_iov->iov_base + uiosiz;
684 			uiop->uio_iov->iov_len -= uiosiz;
685 		}
686 		siz -= uiosiz;
687 	}
688 	*dpos = mbufcp;
689 	*mrep = mp;
690 	if (rem > 0) {
691 		if (len < rem)
692 			error = nfs_adv(mrep, dpos, rem, len);
693 		else
694 			*dpos += rem;
695 	}
696 	return (error);
697 }
698 
699 /*
700  * Copy a uio scatter/gather list to an mbuf chain.
701  */
702 void
703 nfsm_uiotombuf(struct mbuf **mp, struct uio *uiop, size_t len)
704 {
705 	struct mbuf *mb, *mb2;
706 	size_t xfer, pad;
707 
708 	mb = *mp;
709 
710 	pad = nfsm_padlen(len);
711 
712 	/* XXX -- the following should be done by the caller */
713 	uiop->uio_resid = len;
714 	uiop->uio_rw = UIO_WRITE;
715 
716 	while (len) {
717 		xfer = min(len, M_TRAILINGSPACE(mb));
718 		uiomove(mb_offset(mb), xfer, uiop);
719 		mb->m_len += xfer;
720 		len -= xfer;
721 		if (len > 0) {
722 			MGET(mb2, M_WAIT, MT_DATA);
723 			if (len > MLEN)
724 				MCLGET(mb2, M_WAIT);
725 			mb2->m_len = 0;
726 			mb->m_next = mb2;
727 			mb = mb2;
728 		}
729 	}
730 
731 	if (pad > 0) {
732 		if (pad > M_TRAILINGSPACE(mb)) {
733 			MGET(mb2, M_WAIT, MT_DATA);
734 			mb2->m_len = 0;
735 			mb->m_next = mb2;
736 			mb = mb2;
737 		}
738 		bzero(mb_offset(mb), pad);
739 		mb->m_len += pad;
740 	}
741 
742 	*mp = mb;
743 }
744 
745 /*
746  * Copy a buffer to an mbuf chain
747  */
748 void
749 nfsm_buftombuf(struct mbuf **mp, void *buf, size_t len)
750 {
751 	struct iovec iov;
752 	struct uio io;
753 
754 	iov.iov_base = buf;
755 	iov.iov_len = len;
756 
757 	io.uio_iov = &iov;
758 	io.uio_iovcnt = 1;
759 	io.uio_resid = len;
760 	io.uio_segflg = UIO_SYSSPACE;
761 	io.uio_rw = UIO_WRITE;
762 
763 	nfsm_uiotombuf(mp, &io, len);
764 }
765 
766 /*
767  * Copy a string to an mbuf chain
768  */
769 void
770 nfsm_strtombuf(struct mbuf **mp, void *str, size_t len)
771 {
772 	struct iovec iov[2];
773 	struct uio io;
774 	uint32_t strlen;
775 
776 	strlen = txdr_unsigned(len);
777 
778 	iov[0].iov_base = &strlen;
779 	iov[0].iov_len = sizeof(uint32_t);
780 	iov[1].iov_base = str;
781 	iov[1].iov_len = len;
782 
783 	io.uio_iov = iov;
784 	io.uio_iovcnt = 2;
785 	io.uio_resid = sizeof(uint32_t) + len;
786 	io.uio_segflg = UIO_SYSSPACE;
787 	io.uio_rw = UIO_WRITE;
788 
789 	nfsm_uiotombuf(mp, &io, io.uio_resid);
790 }
791 
792 /*
793  * Help break down an mbuf chain by setting the first siz bytes contiguous
794  * pointed to by returned val.
795  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
796  * cases. (The macros use the vars. dpos and dpos2)
797  */
798 int
799 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
800 {
801 	struct mbuf *mp, *mp2;
802 	int siz2, xfer;
803 	caddr_t p;
804 
805 	mp = *mdp;
806 	while (left == 0) {
807 		*mdp = mp = mp->m_next;
808 		if (mp == NULL)
809 			return (EBADRPC);
810 		left = mp->m_len;
811 		*dposp = mtod(mp, caddr_t);
812 	}
813 	if (left >= siz) {
814 		*cp2 = *dposp;
815 		*dposp += siz;
816 	} else if (mp->m_next == NULL) {
817 		return (EBADRPC);
818 	} else if (siz > MHLEN) {
819 		panic("nfs S too big");
820 	} else {
821 		MGET(mp2, M_WAIT, MT_DATA);
822 		mp2->m_next = mp->m_next;
823 		mp->m_next = mp2;
824 		mp->m_len -= left;
825 		mp = mp2;
826 		*cp2 = p = mtod(mp, caddr_t);
827 		bcopy(*dposp, p, left);		/* Copy what was left */
828 		siz2 = siz-left;
829 		p += left;
830 		mp2 = mp->m_next;
831 		/* Loop around copying up the siz2 bytes */
832 		while (siz2 > 0) {
833 			if (mp2 == NULL)
834 				return (EBADRPC);
835 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
836 			if (xfer > 0) {
837 				bcopy(mtod(mp2, caddr_t), p, xfer);
838 				mp2->m_data += xfer;
839 				mp2->m_len -= xfer;
840 				p += xfer;
841 				siz2 -= xfer;
842 			}
843 			if (siz2 > 0)
844 				mp2 = mp2->m_next;
845 		}
846 		mp->m_len = siz;
847 		*mdp = mp2;
848 		*dposp = mtod(mp2, caddr_t);
849 	}
850 	return (0);
851 }
852 
853 /*
854  * Advance the position in the mbuf chain.
855  */
856 int
857 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
858 {
859 	struct mbuf *m;
860 	int s;
861 
862 	m = *mdp;
863 	s = left;
864 	while (s < offs) {
865 		offs -= s;
866 		m = m->m_next;
867 		if (m == NULL)
868 			return (EBADRPC);
869 		s = m->m_len;
870 	}
871 	*mdp = m;
872 	*dposp = mtod(m, caddr_t)+offs;
873 	return (0);
874 }
875 
876 /*
877  * Called once to initialize data structures...
878  */
879 void
880 nfs_init(void)
881 {
882 	rpc_vers = txdr_unsigned(RPC_VER2);
883 	rpc_call = txdr_unsigned(RPC_CALL);
884 	rpc_reply = txdr_unsigned(RPC_REPLY);
885 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
886 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
887 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
888 	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
889 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
890 	nfs_prog = txdr_unsigned(NFS_PROG);
891 	nfs_true = txdr_unsigned(1);
892 	nfs_false = txdr_unsigned(0);
893 	nfs_xdrneg1 = txdr_unsigned(-1);
894 	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
895 	if (nfs_ticks < 1)
896 		nfs_ticks = 1;
897 #ifdef NFSSERVER
898 	nfsrv_init(0);			/* Init server data structures */
899 	nfsrv_initcache();		/* Init the server request cache */
900 #endif /* NFSSERVER */
901 
902 	pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, 0, 0, "nfsreqpl",
903 	    &pool_allocator_nointr);
904 }
905 
906 #ifdef NFSCLIENT
907 int
908 nfs_vfs_init(struct vfsconf *vfsp)
909 {
910 	extern struct pool nfs_node_pool;
911 
912 	TAILQ_INIT(&nfs_bufq);
913 
914 	pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, 0, 0,
915 	    "nfsnodepl", NULL);
916 
917 	return (0);
918 }
919 
920 /*
921  * Attribute cache routines.
922  * nfs_loadattrcache() - loads or updates the cache contents from attributes
923  *	that are on the mbuf list
924  * nfs_getattrcache() - returns valid attributes if found in cache, returns
925  *	error otherwise
926  */
927 
928 /*
929  * Load the attribute cache (that lives in the nfsnode entry) with
930  * the values on the mbuf list and
931  * Iff vap not NULL
932  *    copy the attributes to *vaper
933  */
934 int
935 nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
936     struct vattr *vaper)
937 {
938 	struct vnode *vp = *vpp;
939 	struct vattr *vap;
940 	struct nfs_fattr *fp;
941 	extern struct vops nfs_specvops;
942 	struct nfsnode *np;
943 	int32_t t1;
944 	caddr_t cp2;
945 	int error = 0;
946 	int32_t rdev;
947 	struct mbuf *md;
948 	enum vtype vtyp;
949 	mode_t vmode;
950 	struct timespec mtime;
951 	struct vnode *nvp;
952 	int v3 = NFS_ISV3(vp);
953 	uid_t uid;
954 	gid_t gid;
955 
956 	md = *mdp;
957 	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
958 	error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
959 	if (error)
960 		return (error);
961 	fp = (struct nfs_fattr *)cp2;
962 	if (v3) {
963 		vtyp = nfsv3tov_type(fp->fa_type);
964 		vmode = fxdr_unsigned(mode_t, fp->fa_mode);
965 		rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
966 			fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
967 		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
968 	} else {
969 		vtyp = nfsv2tov_type(fp->fa_type);
970 		vmode = fxdr_unsigned(mode_t, fp->fa_mode);
971 		if (vtyp == VNON || vtyp == VREG)
972 			vtyp = IFTOVT(vmode);
973 		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
974 		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
975 
976 		/*
977 		 * Really ugly NFSv2 kludge.
978 		 */
979 		if (vtyp == VCHR && rdev == 0xffffffff)
980 			vtyp = VFIFO;
981 	}
982 
983 	/*
984 	 * If v_type == VNON it is a new node, so fill in the v_type,
985 	 * n_mtime fields. Check to see if it represents a special
986 	 * device, and if so, check for a possible alias. Once the
987 	 * correct vnode has been obtained, fill in the rest of the
988 	 * information.
989 	 */
990 	np = VTONFS(vp);
991 	if (vp->v_type != vtyp) {
992 		cache_purge(vp);
993 		vp->v_type = vtyp;
994 		if (vp->v_type == VFIFO) {
995 #ifndef FIFO
996 			return (EOPNOTSUPP);
997 #else
998                         extern struct vops nfs_fifovops;
999 			vp->v_op = &nfs_fifovops;
1000 #endif /* FIFO */
1001 		}
1002 		if (vp->v_type == VCHR || vp->v_type == VBLK) {
1003 			vp->v_op = &nfs_specvops;
1004 			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1005 			if (nvp) {
1006 				/*
1007 				 * Discard unneeded vnode, but save its nfsnode.
1008 				 * Since the nfsnode does not have a lock, its
1009 				 * vnode lock has to be carried over.
1010 				 */
1011 
1012 				nvp->v_data = vp->v_data;
1013 				vp->v_data = NULL;
1014 				vp->v_op = &spec_vops;
1015 				vrele(vp);
1016 				vgone(vp);
1017 				/*
1018 				 * Reinitialize aliased node.
1019 				 */
1020 				np->n_vnode = nvp;
1021 				*vpp = vp = nvp;
1022 			}
1023 		}
1024 		np->n_mtime = mtime;
1025 	}
1026 	vap = &np->n_vattr;
1027 	vap->va_type = vtyp;
1028 	vap->va_rdev = (dev_t)rdev;
1029 	vap->va_mtime = mtime;
1030 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1031 
1032 	uid = fxdr_unsigned(uid_t, fp->fa_uid);
1033 	gid = fxdr_unsigned(gid_t, fp->fa_gid);
1034 	/* Invalidate access cache if uid, gid or mode changed. */
1035 	if (np->n_accstamp != -1 &&
1036 	    (gid != vap->va_gid || uid != vap->va_uid ||
1037 	    (vmode & 07777) != vap->va_mode))
1038 		np->n_accstamp = -1;
1039 
1040 	vap->va_mode = (vmode & 07777);
1041 
1042 	switch (vtyp) {
1043 	case VBLK:
1044 		vap->va_blocksize = BLKDEV_IOSIZE;
1045 		break;
1046 	case VCHR:
1047 		vap->va_blocksize = MAXBSIZE;
1048 		break;
1049 	default:
1050 		vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
1051 		     fxdr_unsigned(int32_t, fp->fa2_blocksize);
1052 		break;
1053 	}
1054 	if (v3) {
1055 		vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
1056 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1057 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1058 		vap->va_size = fxdr_hyper(&fp->fa3_size);
1059 		vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1060 		vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1061 		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1062 		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1063 		vap->va_flags = 0;
1064 		vap->va_filerev = 0;
1065 	} else {
1066 		vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
1067 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1068 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1069 		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1070 		vap->va_bytes =
1071 		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
1072 		    NFS_FABLKSIZE;
1073 		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1074 		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1075 		vap->va_flags = 0;
1076 		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1077 		    fp->fa2_ctime.nfsv2_sec);
1078 		vap->va_ctime.tv_nsec = 0;
1079 		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1080 		vap->va_filerev = 0;
1081 	}
1082 
1083 	if (vap->va_size != np->n_size) {
1084 		if (vap->va_type == VREG) {
1085 			if (np->n_flag & NMODIFIED) {
1086 				if (vap->va_size < np->n_size)
1087 					vap->va_size = np->n_size;
1088 				else
1089 					np->n_size = vap->va_size;
1090 			} else
1091 				np->n_size = vap->va_size;
1092 			uvm_vnp_setsize(vp, np->n_size);
1093 		} else
1094 			np->n_size = vap->va_size;
1095 	}
1096 	np->n_attrstamp = time_second;
1097 	if (vaper != NULL) {
1098 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1099 		if (np->n_flag & NCHG) {
1100 			if (np->n_flag & NACC)
1101 				vaper->va_atime = np->n_atim;
1102 			if (np->n_flag & NUPD)
1103 				vaper->va_mtime = np->n_mtim;
1104 		}
1105 	}
1106 	return (0);
1107 }
1108 
1109 int
1110 nfs_attrtimeo(struct nfsnode *np)
1111 {
1112 	struct vnode *vp = np->n_vnode;
1113 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1114 	int tenthage = (time_second - np->n_mtime.tv_sec) / 10;
1115 	int minto, maxto;
1116 
1117 	if (vp->v_type == VDIR) {
1118 		maxto = nmp->nm_acdirmax;
1119 		minto = nmp->nm_acdirmin;
1120 	}
1121 	else {
1122 		maxto = nmp->nm_acregmax;
1123 		minto = nmp->nm_acregmin;
1124 	}
1125 
1126 	if (np->n_flag & NMODIFIED || tenthage < minto)
1127 		return minto;
1128 	else if (tenthage < maxto)
1129 		return tenthage;
1130 	else
1131 		return maxto;
1132 }
1133 
1134 /*
1135  * Check the time stamp
1136  * If the cache is valid, copy contents to *vap and return 0
1137  * otherwise return an error
1138  */
1139 int
1140 nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
1141 {
1142 	struct nfsnode *np = VTONFS(vp);
1143 	struct vattr *vap;
1144 
1145 	if (np->n_attrstamp == 0 ||
1146 	    (time_second - np->n_attrstamp) >= nfs_attrtimeo(np)) {
1147 		nfsstats.attrcache_misses++;
1148 		return (ENOENT);
1149 	}
1150 	nfsstats.attrcache_hits++;
1151 	vap = &np->n_vattr;
1152 	if (vap->va_size != np->n_size) {
1153 		if (vap->va_type == VREG) {
1154 			if (np->n_flag & NMODIFIED) {
1155 				if (vap->va_size < np->n_size)
1156 					vap->va_size = np->n_size;
1157 				else
1158 					np->n_size = vap->va_size;
1159 			} else
1160 				np->n_size = vap->va_size;
1161 			uvm_vnp_setsize(vp, np->n_size);
1162 		} else
1163 			np->n_size = vap->va_size;
1164 	}
1165 	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1166 	if (np->n_flag & NCHG) {
1167 		if (np->n_flag & NACC)
1168 			vaper->va_atime = np->n_atim;
1169 		if (np->n_flag & NUPD)
1170 			vaper->va_mtime = np->n_mtim;
1171 	}
1172 	return (0);
1173 }
1174 #endif /* NFSCLIENT */
1175 
1176 /*
1177  * Set up nameidata for a lookup() call and do it
1178  */
1179 int
1180 nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
1181     struct nfssvc_sock *slp, struct mbuf *nam, struct mbuf **mdp,
1182     caddr_t *dposp, struct vnode **retdirp, struct proc *p)
1183 {
1184 	int i, rem;
1185 	struct mbuf *md;
1186 	char *fromcp, *tocp;
1187 	struct vnode *dp;
1188 	int error, rdonly;
1189 	struct componentname *cnp = &ndp->ni_cnd;
1190 
1191 	*retdirp = NULL;
1192 	cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
1193 	/*
1194 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1195 	 * and set the various ndp fields appropriately.
1196 	 */
1197 	fromcp = *dposp;
1198 	tocp = cnp->cn_pnbuf;
1199 	md = *mdp;
1200 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1201 	for (i = 0; i < len; i++) {
1202 		while (rem == 0) {
1203 			md = md->m_next;
1204 			if (md == NULL) {
1205 				error = EBADRPC;
1206 				goto out;
1207 			}
1208 			fromcp = mtod(md, caddr_t);
1209 			rem = md->m_len;
1210 		}
1211 		if (*fromcp == '\0' || *fromcp == '/') {
1212 			error = EACCES;
1213 			goto out;
1214 		}
1215 		*tocp++ = *fromcp++;
1216 		rem--;
1217 	}
1218 	*tocp = '\0';
1219 	*mdp = md;
1220 	*dposp = fromcp;
1221 	len = nfsm_padlen(len);
1222 	if (len > 0) {
1223 		if (rem >= len)
1224 			*dposp += len;
1225 		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1226 			goto out;
1227 	}
1228 	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
1229 	cnp->cn_nameptr = cnp->cn_pnbuf;
1230 	/*
1231 	 * Extract and set starting directory.
1232 	 */
1233 	error = nfsrv_fhtovp(fhp, 0, &dp, ndp->ni_cnd.cn_cred, slp,
1234 	    nam, &rdonly);
1235 	if (error)
1236 		goto out;
1237 	if (dp->v_type != VDIR) {
1238 		vrele(dp);
1239 		error = ENOTDIR;
1240 		goto out;
1241 	}
1242 	vref(dp);
1243 	*retdirp = dp;
1244 	ndp->ni_startdir = dp;
1245 	if (rdonly)
1246 		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
1247 	else
1248 		cnp->cn_flags |= NOCROSSMOUNT;
1249 	/*
1250 	 * And call lookup() to do the real work
1251 	 */
1252 	cnp->cn_proc = p;
1253 	error = vfs_lookup(ndp);
1254 	if (error)
1255 		goto out;
1256 	/*
1257 	 * Check for encountering a symbolic link
1258 	 */
1259 	if (cnp->cn_flags & ISSYMLINK) {
1260 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1261 			vput(ndp->ni_dvp);
1262 		else
1263 			vrele(ndp->ni_dvp);
1264 		vput(ndp->ni_vp);
1265 		ndp->ni_vp = NULL;
1266 		error = EINVAL;
1267 		goto out;
1268 	}
1269 	/*
1270 	 * Check for saved name request
1271 	 */
1272 	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1273 		cnp->cn_flags |= HASBUF;
1274 		return (0);
1275 	}
1276 out:
1277 	pool_put(&namei_pool, cnp->cn_pnbuf);
1278 	return (error);
1279 }
1280 
1281 /*
1282  * A fiddled version of m_adj() that ensures null fill to a long
1283  * boundary and only trims off the back end
1284  */
1285 void
1286 nfsm_adj(struct mbuf *mp, int len, int nul)
1287 {
1288 	struct mbuf *m;
1289 	int count, i;
1290 	char *cp;
1291 
1292 	/*
1293 	 * Trim from tail.  Scan the mbuf chain,
1294 	 * calculating its length and finding the last mbuf.
1295 	 * If the adjustment only affects this mbuf, then just
1296 	 * adjust and return.  Otherwise, rescan and truncate
1297 	 * after the remaining size.
1298 	 */
1299 	count = 0;
1300 	m = mp;
1301 	for (;;) {
1302 		count += m->m_len;
1303 		if (m->m_next == NULL)
1304 			break;
1305 		m = m->m_next;
1306 	}
1307 	if (m->m_len > len) {
1308 		m->m_len -= len;
1309 		if (nul > 0) {
1310 			cp = mtod(m, caddr_t)+m->m_len-nul;
1311 			for (i = 0; i < nul; i++)
1312 				*cp++ = '\0';
1313 		}
1314 		return;
1315 	}
1316 	count -= len;
1317 	if (count < 0)
1318 		count = 0;
1319 	/*
1320 	 * Correct length for chain is "count".
1321 	 * Find the mbuf with last data, adjust its length,
1322 	 * and toss data from remaining mbufs on chain.
1323 	 */
1324 	for (m = mp; m; m = m->m_next) {
1325 		if (m->m_len >= count) {
1326 			m->m_len = count;
1327 			if (nul > 0) {
1328 				cp = mtod(m, caddr_t)+m->m_len-nul;
1329 				for (i = 0; i < nul; i++)
1330 					*cp++ = '\0';
1331 			}
1332 			break;
1333 		}
1334 		count -= m->m_len;
1335 	}
1336 	for (m = m->m_next;m;m = m->m_next)
1337 		m->m_len = 0;
1338 }
1339 
1340 /*
1341  * Make these functions instead of macros, so that the kernel text size
1342  * doesn't get too big...
1343  */
1344 void
1345 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
1346     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
1347     struct nfsm_info *info)
1348 {
1349 	u_int32_t *tl;
1350 
1351 	if (before_ret) {
1352 		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
1353 		*tl = nfs_false;
1354 	} else {
1355 		tl = nfsm_build(&info->nmi_mb, 7 * NFSX_UNSIGNED);
1356 		*tl++ = nfs_true;
1357 		txdr_hyper(before_vap->va_size, tl);
1358 		tl += 2;
1359 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1360 		tl += 2;
1361 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1362 	}
1363 	nfsm_srvpostop_attr(nfsd, after_ret, after_vap, info);
1364 }
1365 
1366 void
1367 nfsm_srvpostop_attr(struct nfsrv_descript *nfsd, int after_ret,
1368     struct vattr *after_vap, struct nfsm_info *info)
1369 {
1370 	u_int32_t *tl;
1371 	struct nfs_fattr *fp;
1372 
1373 	if (after_ret) {
1374 		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
1375 		*tl = nfs_false;
1376 	} else {
1377 		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED + NFSX_V3FATTR);
1378 		*tl++ = nfs_true;
1379 		fp = (struct nfs_fattr *)tl;
1380 		nfsm_srvfattr(nfsd, after_vap, fp);
1381 	}
1382 }
1383 
1384 void
1385 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1386     struct nfs_fattr *fp)
1387 {
1388 
1389 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1390 	fp->fa_uid = txdr_unsigned(vap->va_uid);
1391 	fp->fa_gid = txdr_unsigned(vap->va_gid);
1392 	if (nfsd->nd_flag & ND_NFSV3) {
1393 		fp->fa_type = vtonfsv3_type(vap->va_type);
1394 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1395 		txdr_hyper(vap->va_size, &fp->fa3_size);
1396 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1397 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1398 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1399 		fp->fa3_fsid.nfsuquad[0] = 0;
1400 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1401 		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1402 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1403 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1404 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1405 	} else {
1406 		fp->fa_type = vtonfsv2_type(vap->va_type);
1407 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1408 		fp->fa2_size = txdr_unsigned(vap->va_size);
1409 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1410 		if (vap->va_type == VFIFO)
1411 			fp->fa2_rdev = 0xffffffff;
1412 		else
1413 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1414 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1415 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1416 		fp->fa2_fileid = txdr_unsigned((u_int32_t)vap->va_fileid);
1417 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1418 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1419 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1420 	}
1421 }
1422 
1423 /*
1424  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1425  * 	- look up fsid in mount list (if not found ret error)
1426  *	- get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
1427  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1428  *	- if not lockflag unlock it with VOP_UNLOCK()
1429  */
1430 int
1431 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1432     struct ucred *cred, struct nfssvc_sock *slp, struct mbuf *nam,
1433     int *rdonlyp)
1434 {
1435 	struct proc *p = curproc;	/* XXX */
1436 	struct mount *mp;
1437 	int i;
1438 	struct ucred *credanon;
1439 	int error, exflags;
1440 	struct sockaddr_in *saddr;
1441 
1442 	*vpp = NULL;
1443 	mp = vfs_getvfs(&fhp->fh_fsid);
1444 
1445 	if (!mp)
1446 		return (ESTALE);
1447 	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1448 	if (error)
1449 		return (error);
1450 	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1451 	if (error)
1452 		return (error);
1453 
1454 	saddr = mtod(nam, struct sockaddr_in *);
1455 	if (saddr->sin_family == AF_INET &&
1456 	    (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
1457 	    (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
1458 		vput(*vpp);
1459 		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1460 	}
1461 
1462 	/* Check/setup credentials. */
1463 	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1464 		cred->cr_uid = credanon->cr_uid;
1465 		cred->cr_gid = credanon->cr_gid;
1466 		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1467 			cred->cr_groups[i] = credanon->cr_groups[i];
1468 		cred->cr_ngroups = i;
1469 	}
1470 	if (exflags & MNT_EXRDONLY)
1471 		*rdonlyp = 1;
1472 	else
1473 		*rdonlyp = 0;
1474 	if (!lockflag)
1475 		VOP_UNLOCK(*vpp, 0, p);
1476 
1477 	return (0);
1478 }
1479 
1480 /*
1481  * This function compares two net addresses by family and returns non zero
1482  * if they are the same host, or if there is any doubt it returns 0.
1483  * The AF_INET family is handled as a special case so that address mbufs
1484  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1485  */
1486 int
1487 netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
1488 {
1489 	struct sockaddr_in *inetaddr;
1490 
1491 	switch (family) {
1492 	case AF_INET:
1493 		inetaddr = mtod(nam, struct sockaddr_in *);
1494 		if (inetaddr->sin_family == AF_INET &&
1495 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1496 			return (1);
1497 		break;
1498 	default:
1499 		break;
1500 	};
1501 	return (0);
1502 }
1503 
1504 /*
1505  * The write verifier has changed (probably due to a server reboot), so all
1506  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1507  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1508  * flag. Once done the new write verifier can be set for the mount point.
1509  */
1510 void
1511 nfs_clearcommit(struct mount *mp)
1512 {
1513 	struct vnode *vp, *nvp;
1514 	struct buf *bp, *nbp;
1515 	int s;
1516 
1517 	s = splbio();
1518 loop:
1519 	for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
1520 		if (vp->v_mount != mp)	/* Paranoia */
1521 			goto loop;
1522 		nvp = LIST_NEXT(vp, v_mntvnodes);
1523 		for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) {
1524 			nbp = LIST_NEXT(bp, b_vnbufs);
1525 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1526 				== (B_DELWRI | B_NEEDCOMMIT))
1527 				bp->b_flags &= ~B_NEEDCOMMIT;
1528 		}
1529 	}
1530 	splx(s);
1531 }
1532 
1533 void
1534 nfs_merge_commit_ranges(struct vnode *vp)
1535 {
1536 	struct nfsnode *np = VTONFS(vp);
1537 
1538 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1539 		np->n_pushedlo = np->n_pushlo;
1540 		np->n_pushedhi = np->n_pushhi;
1541 		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1542 	} else {
1543 		if (np->n_pushlo < np->n_pushedlo)
1544 			np->n_pushedlo = np->n_pushlo;
1545 		if (np->n_pushhi > np->n_pushedhi)
1546 			np->n_pushedhi = np->n_pushhi;
1547 	}
1548 
1549 	np->n_pushlo = np->n_pushhi = 0;
1550 	np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
1551 }
1552 
1553 int
1554 nfs_in_committed_range(struct vnode *vp, struct buf *bp)
1555 {
1556 	struct nfsnode *np = VTONFS(vp);
1557 	off_t lo, hi;
1558 
1559 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1560 		return 0;
1561 	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1562 	hi = lo + bp->b_dirtyend;
1563 
1564 	return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
1565 }
1566 
1567 int
1568 nfs_in_tobecommitted_range(struct vnode *vp, struct buf *bp)
1569 {
1570 	struct nfsnode *np = VTONFS(vp);
1571 	off_t lo, hi;
1572 
1573 	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1574 		return 0;
1575 	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1576 	hi = lo + bp->b_dirtyend;
1577 
1578 	return (lo >= np->n_pushlo && hi <= np->n_pushhi);
1579 }
1580 
1581 void
1582 nfs_add_committed_range(struct vnode *vp, struct buf *bp)
1583 {
1584 	struct nfsnode *np = VTONFS(vp);
1585 	off_t lo, hi;
1586 
1587 	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1588 	hi = lo + bp->b_dirtyend;
1589 
1590 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1591 		np->n_pushedlo = lo;
1592 		np->n_pushedhi = hi;
1593 		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1594 	} else {
1595 		if (hi > np->n_pushedhi)
1596 			np->n_pushedhi = hi;
1597 		if (lo < np->n_pushedlo)
1598 			np->n_pushedlo = lo;
1599 	}
1600 }
1601 
1602 void
1603 nfs_del_committed_range(struct vnode *vp, struct buf *bp)
1604 {
1605 	struct nfsnode *np = VTONFS(vp);
1606 	off_t lo, hi;
1607 
1608 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1609 		return;
1610 
1611 	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1612 	hi = lo + bp->b_dirtyend;
1613 
1614 	if (lo > np->n_pushedhi || hi < np->n_pushedlo)
1615 		return;
1616 	if (lo <= np->n_pushedlo)
1617 		np->n_pushedlo = hi;
1618 	else if (hi >= np->n_pushedhi)
1619 		np->n_pushedhi = lo;
1620 	else {
1621 		/*
1622 		 * XXX There's only one range. If the deleted range
1623 		 * is in the middle, pick the largest of the
1624 		 * contiguous ranges that it leaves.
1625 		 */
1626 		if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
1627 			np->n_pushedhi = lo;
1628 		else
1629 			np->n_pushedlo = hi;
1630 	}
1631 }
1632 
1633 void
1634 nfs_add_tobecommitted_range(struct vnode *vp, struct buf *bp)
1635 {
1636 	struct nfsnode *np = VTONFS(vp);
1637 	off_t lo, hi;
1638 
1639 	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1640 	hi = lo + bp->b_dirtyend;
1641 
1642 	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
1643 		np->n_pushlo = lo;
1644 		np->n_pushhi = hi;
1645 		np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
1646 	} else {
1647 		if (lo < np->n_pushlo)
1648 			np->n_pushlo = lo;
1649 		if (hi > np->n_pushhi)
1650 			np->n_pushhi = hi;
1651 	}
1652 }
1653 
1654 void
1655 nfs_del_tobecommitted_range(struct vnode *vp, struct buf *bp)
1656 {
1657 	struct nfsnode *np = VTONFS(vp);
1658 	off_t lo, hi;
1659 
1660 	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1661 		return;
1662 
1663 	lo = (off_t)bp->b_blkno * DEV_BSIZE;
1664 	hi = lo + bp->b_dirtyend;
1665 
1666 	if (lo > np->n_pushhi || hi < np->n_pushlo)
1667 		return;
1668 
1669 	if (lo <= np->n_pushlo)
1670 		np->n_pushlo = hi;
1671 	else if (hi >= np->n_pushhi)
1672 		np->n_pushhi = lo;
1673 	else {
1674 		/*
1675 		 * XXX There's only one range. If the deleted range
1676 		 * is in the middle, pick the largest of the
1677 		 * contiguous ranges that it leaves.
1678 		 */
1679 		if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
1680 			np->n_pushhi = lo;
1681 		else
1682 			np->n_pushlo = hi;
1683 	}
1684 }
1685 
1686 /*
1687  * Map errnos to NFS error numbers. For Version 3 also filter out error
1688  * numbers not specified for the associated procedure.
1689  */
1690 int
1691 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1692 {
1693 	short *defaulterrp, *errp;
1694 
1695 	if (nd->nd_flag & ND_NFSV3) {
1696 	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1697 		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1698 		while (*++errp) {
1699 			if (*errp == err)
1700 				return (err);
1701 			else if (*errp > err)
1702 				break;
1703 		}
1704 		return ((int)*defaulterrp);
1705 	    } else
1706 		return (err & 0xffff);
1707 	}
1708 	if (err <= nitems(nfsrv_v2errmap))
1709 		return ((int)nfsrv_v2errmap[err - 1]);
1710 	return (NFSERR_IO);
1711 }
1712 
1713 /*
1714  * If full is non zero, set all fields, otherwise just set mode and time fields
1715  */
1716 void
1717 nfsm_v3attrbuild(struct mbuf **mp, struct vattr *a, int full)
1718 {
1719 	struct mbuf *mb;
1720 	u_int32_t *tl;
1721 
1722 	mb = *mp;
1723 
1724 	if (a->va_mode != (mode_t)VNOVAL) {
1725 		tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
1726 		*tl++ = nfs_true;
1727 		*tl = txdr_unsigned(a->va_mode);
1728 	} else {
1729 		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1730 		*tl = nfs_false;
1731 	}
1732 	if (full && a->va_uid != (uid_t)VNOVAL) {
1733 		tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
1734 		*tl++ = nfs_true;
1735 		*tl = txdr_unsigned(a->va_uid);
1736 	} else {
1737 		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1738 		*tl = nfs_false;
1739 	}
1740 	if (full && a->va_gid != (gid_t)VNOVAL) {
1741 		tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
1742 		*tl++ = nfs_true;
1743 		*tl = txdr_unsigned((a)->va_gid);
1744 	} else {
1745 		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1746 		*tl = nfs_false;
1747 	}
1748 	if (full && a->va_size != VNOVAL) {
1749 		tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
1750 		*tl++ = nfs_true;
1751 		txdr_hyper(a->va_size, tl);
1752 	} else {
1753 		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1754 		*tl = nfs_false;
1755 	}
1756 	if (a->va_atime.tv_sec != VNOVAL) {
1757 		if (a->va_atime.tv_sec != time_second) {
1758 			tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
1759 			*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1760 			txdr_nfsv3time(&a->va_atime, tl);
1761 		} else {
1762 			tl = nfsm_build(&mb, NFSX_UNSIGNED);
1763 			*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1764 		}
1765 	} else {
1766 		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1767 		*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1768 	}
1769 	if (a->va_mtime.tv_sec != VNOVAL) {
1770 		if (a->va_mtime.tv_sec != time_second) {
1771 			tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
1772 			*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1773 			txdr_nfsv3time(&a->va_mtime, tl);
1774 		} else {
1775 			tl = nfsm_build(&mb, NFSX_UNSIGNED);
1776 			*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1777 		}
1778 	} else {
1779 		tl = nfsm_build(&mb, NFSX_UNSIGNED);
1780 		*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1781 	}
1782 
1783 	*mp = mb;
1784 }
1785 
1786 /*
1787  * Ensure a contiguous buffer len bytes long
1788  */
1789 void *
1790 nfsm_build(struct mbuf **mp, u_int len)
1791 {
1792 	struct mbuf *mb, *mb2;
1793 	caddr_t bpos;
1794 
1795 	mb = *mp;
1796 	bpos = mb_offset(mb);
1797 
1798 	if (len > M_TRAILINGSPACE(mb)) {
1799 		MGET(mb2, M_WAIT, MT_DATA);
1800 		if (len > MLEN)
1801 			panic("build > MLEN");
1802 		mb->m_next = mb2;
1803 		mb = mb2;
1804 		mb->m_len = 0;
1805 		bpos = mtod(mb, caddr_t);
1806 	}
1807 	mb->m_len += len;
1808 
1809 	*mp = mb;
1810 
1811 	return (bpos);
1812 }
1813 
1814 void
1815 nfsm_fhtom(struct nfsm_info *info, struct vnode *v, int v3)
1816 {
1817 	struct nfsnode *n = VTONFS(v);
1818 
1819 	if (v3) {
1820 		nfsm_strtombuf(&info->nmi_mb, n->n_fhp, n->n_fhsize);
1821 	} else {
1822 		nfsm_buftombuf(&info->nmi_mb, n->n_fhp, NFSX_V2FH);
1823 	}
1824 }
1825 
1826 void
1827 nfsm_srvfhtom(struct mbuf **mp, fhandle_t *f, int v3)
1828 {
1829 	if (v3) {
1830 		nfsm_strtombuf(mp, f, NFSX_V3FH);
1831 	} else {
1832 		nfsm_buftombuf(mp, f, NFSX_V2FH);
1833 	}
1834 }
1835 
1836 int
1837 nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
1838     caddr_t *dposp)
1839 {
1840 	struct nfsm_info	info;
1841 	uint32_t *tl, t1;
1842 	caddr_t cp2;
1843 	int error = 0;
1844 
1845 	info.nmi_md = *mp;
1846 	info.nmi_dpos = *dposp;
1847 
1848 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1849 	if (*tl == nfs_true) {
1850 		nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1851 		va->va_mode = nfstov_mode(*tl);
1852 	}
1853 
1854 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1855 	if (*tl == nfs_true) {
1856 		nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1857 		va->va_uid = fxdr_unsigned(uid_t, *tl);
1858 	}
1859 
1860 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1861 	if (*tl == nfs_true) {
1862 		nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1863 		va->va_gid = fxdr_unsigned(gid_t, *tl);
1864 	}
1865 
1866 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1867 	if (*tl == nfs_true) {
1868 		nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1869 		va->va_size = fxdr_hyper(tl);
1870 	}
1871 
1872 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1873 	switch (fxdr_unsigned(int, *tl)) {
1874 	case NFSV3SATTRTIME_TOCLIENT:
1875 		va->va_vaflags &= ~VA_UTIMES_NULL;
1876 		nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1877 		fxdr_nfsv3time(tl, &va->va_atime);
1878 		break;
1879 	case NFSV3SATTRTIME_TOSERVER:
1880 		getnanotime(&va->va_atime);
1881 		break;
1882 	};
1883 
1884 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1885 	switch (fxdr_unsigned(int, *tl)) {
1886 	case NFSV3SATTRTIME_TOCLIENT:
1887 		va->va_vaflags &= ~VA_UTIMES_NULL;
1888 		nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1889 		fxdr_nfsv3time(tl, &va->va_mtime);
1890 		break;
1891 	case NFSV3SATTRTIME_TOSERVER:
1892 		getnanotime(&va->va_mtime);
1893 		break;
1894 	};
1895 
1896 	*dposp = info.nmi_dpos;
1897 	*mp = info.nmi_md;
1898 nfsmout:
1899 	return (error);
1900 }
1901