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