nfs_srvsubs.c revision 164585
1/*-
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 164585 2006-11-24 11:53:16Z rwatson $");
37
38/*
39 * These functions support the macros and help fiddle mbuf chains for
40 * the nfs op functions. They do things like create the rpc header and
41 * copy data between mbuf chains and uio lists.
42 */
43
44#include "opt_inet6.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/bio.h>
50#include <sys/buf.h>
51#include <sys/proc.h>
52#include <sys/mount.h>
53#include <sys/vnode.h>
54#include <sys/namei.h>
55#include <sys/mbuf.h>
56#include <sys/refcount.h>
57#include <sys/socket.h>
58#include <sys/stat.h>
59#include <sys/malloc.h>
60#include <sys/module.h>
61#include <sys/sysent.h>
62#include <sys/syscall.h>
63#include <sys/sysproto.h>
64
65#include <vm/vm.h>
66#include <vm/vm_object.h>
67#include <vm/vm_extern.h>
68#include <vm/uma.h>
69
70#include <nfs/rpcv2.h>
71#include <nfs/nfsproto.h>
72#include <nfsserver/nfs.h>
73#include <nfs/xdr_subs.h>
74#include <nfsserver/nfsm_subs.h>
75
76#include <netinet/in.h>
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 */
82u_int32_t nfsrv_nfs_xdrneg1;
83u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
84	nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
85	nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
86u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
87
88/* And other global data */
89static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR,
90				       NFLNK, NFNON, NFCHR, NFNON };
91#define vtonfsv2_type(a)	txdr_unsigned(nfsv2_type[((int32_t)(a))])
92#define vtonfsv3_mode(m)	txdr_unsigned((m) & ALLPERMS)
93
94int nfsrv_ticks;
95
96struct nfssvc_sockhead nfssvc_sockhead;
97int nfssvc_sockhead_flag;
98struct nfsd_head nfsd_head;
99int nfsd_head_flag;
100
101static int nfs_prev_nfssvc_sy_narg;
102static sy_call_t *nfs_prev_nfssvc_sy_call;
103
104struct mtx nfsd_mtx;
105
106/*
107 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
108 */
109const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
110	NFSPROC_NULL,
111	NFSPROC_GETATTR,
112	NFSPROC_SETATTR,
113	NFSPROC_NOOP,
114	NFSPROC_LOOKUP,
115	NFSPROC_READLINK,
116	NFSPROC_READ,
117	NFSPROC_NOOP,
118	NFSPROC_WRITE,
119	NFSPROC_CREATE,
120	NFSPROC_REMOVE,
121	NFSPROC_RENAME,
122	NFSPROC_LINK,
123	NFSPROC_SYMLINK,
124	NFSPROC_MKDIR,
125	NFSPROC_RMDIR,
126	NFSPROC_READDIR,
127	NFSPROC_FSSTAT,
128	NFSPROC_NOOP,
129	NFSPROC_NOOP,
130	NFSPROC_NOOP,
131	NFSPROC_NOOP,
132	NFSPROC_NOOP,
133};
134
135/*
136 * and the reverse mapping from generic to Version 2 procedure numbers
137 */
138const int nfsrvv2_procid[NFS_NPROCS] = {
139	NFSV2PROC_NULL,
140	NFSV2PROC_GETATTR,
141	NFSV2PROC_SETATTR,
142	NFSV2PROC_LOOKUP,
143	NFSV2PROC_NOOP,
144	NFSV2PROC_READLINK,
145	NFSV2PROC_READ,
146	NFSV2PROC_WRITE,
147	NFSV2PROC_CREATE,
148	NFSV2PROC_MKDIR,
149	NFSV2PROC_SYMLINK,
150	NFSV2PROC_CREATE,
151	NFSV2PROC_REMOVE,
152	NFSV2PROC_RMDIR,
153	NFSV2PROC_RENAME,
154	NFSV2PROC_LINK,
155	NFSV2PROC_READDIR,
156	NFSV2PROC_NOOP,
157	NFSV2PROC_STATFS,
158	NFSV2PROC_NOOP,
159	NFSV2PROC_NOOP,
160	NFSV2PROC_NOOP,
161	NFSV2PROC_NOOP,
162};
163
164/*
165 * Maps errno values to nfs error numbers.
166 * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
167 * specifically defined in RFC 1094.
168 */
169static const u_char nfsrv_v2errmap[ELAST] = {
170  NFSERR_PERM,	NFSERR_NOENT,	0,		0,		0,
171  NFSERR_NXIO,	0,		0,		0,		0,
172  0,		0,		NFSERR_ACCES,	0,		0,
173  0,		NFSERR_EXIST,	0,		NFSERR_NODEV,	NFSERR_NOTDIR,
174  NFSERR_ISDIR,	0,		0,		0,		0,
175  0,		NFSERR_FBIG,	NFSERR_NOSPC,	0,		NFSERR_ROFS,
176  0,		0,		0,		0,		0,
177  0,		0,		0,		0,		0,
178  0,		0,		0,		0,		0,
179  0,		0,		0,		0,		0,
180  0,		0,		0,		0,		0,
181  0,		0,		0,		0,		0,
182  0,		0,		NFSERR_NAMETOL,	0,		0,
183  NFSERR_NOTEMPTY, 0,		0,		NFSERR_DQUOT,	NFSERR_STALE,
184  0
185};
186
187/*
188 * Maps errno values to nfs error numbers.
189 * Although it is not obvious whether or not NFS clients really care if
190 * a returned error value is in the specified list for the procedure, the
191 * safest thing to do is filter them appropriately. For Version 2, the
192 * X/Open XNFS document is the only specification that defines error values
193 * for each RPC (The RFC simply lists all possible error values for all RPCs),
194 * so I have decided to not do this for Version 2.
195 * The first entry is the default error return and the rest are the valid
196 * errors for that RPC in increasing numeric order.
197 */
198static const short nfsv3err_null[] = {
199	0,
200	0,
201};
202
203static const short nfsv3err_getattr[] = {
204	NFSERR_IO,
205	NFSERR_IO,
206	NFSERR_STALE,
207	NFSERR_BADHANDLE,
208	NFSERR_SERVERFAULT,
209	0,
210};
211
212static const short nfsv3err_setattr[] = {
213	NFSERR_IO,
214	NFSERR_PERM,
215	NFSERR_IO,
216	NFSERR_ACCES,
217	NFSERR_INVAL,
218	NFSERR_NOSPC,
219	NFSERR_ROFS,
220	NFSERR_DQUOT,
221	NFSERR_STALE,
222	NFSERR_BADHANDLE,
223	NFSERR_NOT_SYNC,
224	NFSERR_SERVERFAULT,
225	0,
226};
227
228static const short nfsv3err_lookup[] = {
229	NFSERR_IO,
230	NFSERR_NOENT,
231	NFSERR_IO,
232	NFSERR_ACCES,
233	NFSERR_NOTDIR,
234	NFSERR_NAMETOL,
235	NFSERR_STALE,
236	NFSERR_BADHANDLE,
237	NFSERR_SERVERFAULT,
238	0,
239};
240
241static const short nfsv3err_access[] = {
242	NFSERR_IO,
243	NFSERR_IO,
244	NFSERR_STALE,
245	NFSERR_BADHANDLE,
246	NFSERR_SERVERFAULT,
247	0,
248};
249
250static const short nfsv3err_readlink[] = {
251	NFSERR_IO,
252	NFSERR_IO,
253	NFSERR_ACCES,
254	NFSERR_INVAL,
255	NFSERR_STALE,
256	NFSERR_BADHANDLE,
257	NFSERR_NOTSUPP,
258	NFSERR_SERVERFAULT,
259	0,
260};
261
262static const short nfsv3err_read[] = {
263	NFSERR_IO,
264	NFSERR_IO,
265	NFSERR_NXIO,
266	NFSERR_ACCES,
267	NFSERR_INVAL,
268	NFSERR_STALE,
269	NFSERR_BADHANDLE,
270	NFSERR_SERVERFAULT,
271	0,
272};
273
274static const short nfsv3err_write[] = {
275	NFSERR_IO,
276	NFSERR_IO,
277	NFSERR_ACCES,
278	NFSERR_INVAL,
279	NFSERR_FBIG,
280	NFSERR_NOSPC,
281	NFSERR_ROFS,
282	NFSERR_DQUOT,
283	NFSERR_STALE,
284	NFSERR_BADHANDLE,
285	NFSERR_SERVERFAULT,
286	0,
287};
288
289static const short nfsv3err_create[] = {
290	NFSERR_IO,
291	NFSERR_IO,
292	NFSERR_ACCES,
293	NFSERR_EXIST,
294	NFSERR_NOTDIR,
295	NFSERR_NOSPC,
296	NFSERR_ROFS,
297	NFSERR_NAMETOL,
298	NFSERR_DQUOT,
299	NFSERR_STALE,
300	NFSERR_BADHANDLE,
301	NFSERR_NOTSUPP,
302	NFSERR_SERVERFAULT,
303	0,
304};
305
306static const short nfsv3err_mkdir[] = {
307	NFSERR_IO,
308	NFSERR_IO,
309	NFSERR_ACCES,
310	NFSERR_EXIST,
311	NFSERR_NOTDIR,
312	NFSERR_NOSPC,
313	NFSERR_ROFS,
314	NFSERR_NAMETOL,
315	NFSERR_DQUOT,
316	NFSERR_STALE,
317	NFSERR_BADHANDLE,
318	NFSERR_NOTSUPP,
319	NFSERR_SERVERFAULT,
320	0,
321};
322
323static const short nfsv3err_symlink[] = {
324	NFSERR_IO,
325	NFSERR_IO,
326	NFSERR_ACCES,
327	NFSERR_EXIST,
328	NFSERR_NOTDIR,
329	NFSERR_NOSPC,
330	NFSERR_ROFS,
331	NFSERR_NAMETOL,
332	NFSERR_DQUOT,
333	NFSERR_STALE,
334	NFSERR_BADHANDLE,
335	NFSERR_NOTSUPP,
336	NFSERR_SERVERFAULT,
337	0,
338};
339
340static const short nfsv3err_mknod[] = {
341	NFSERR_IO,
342	NFSERR_IO,
343	NFSERR_ACCES,
344	NFSERR_EXIST,
345	NFSERR_NOTDIR,
346	NFSERR_NOSPC,
347	NFSERR_ROFS,
348	NFSERR_NAMETOL,
349	NFSERR_DQUOT,
350	NFSERR_STALE,
351	NFSERR_BADHANDLE,
352	NFSERR_NOTSUPP,
353	NFSERR_SERVERFAULT,
354	NFSERR_BADTYPE,
355	0,
356};
357
358static const short nfsv3err_remove[] = {
359	NFSERR_IO,
360	NFSERR_NOENT,
361	NFSERR_IO,
362	NFSERR_ACCES,
363	NFSERR_NOTDIR,
364	NFSERR_ROFS,
365	NFSERR_NAMETOL,
366	NFSERR_STALE,
367	NFSERR_BADHANDLE,
368	NFSERR_SERVERFAULT,
369	0,
370};
371
372static const short nfsv3err_rmdir[] = {
373	NFSERR_IO,
374	NFSERR_NOENT,
375	NFSERR_IO,
376	NFSERR_ACCES,
377	NFSERR_EXIST,
378	NFSERR_NOTDIR,
379	NFSERR_INVAL,
380	NFSERR_ROFS,
381	NFSERR_NAMETOL,
382	NFSERR_NOTEMPTY,
383	NFSERR_STALE,
384	NFSERR_BADHANDLE,
385	NFSERR_NOTSUPP,
386	NFSERR_SERVERFAULT,
387	0,
388};
389
390static const short nfsv3err_rename[] = {
391	NFSERR_IO,
392	NFSERR_NOENT,
393	NFSERR_IO,
394	NFSERR_ACCES,
395	NFSERR_EXIST,
396	NFSERR_XDEV,
397	NFSERR_NOTDIR,
398	NFSERR_ISDIR,
399	NFSERR_INVAL,
400	NFSERR_NOSPC,
401	NFSERR_ROFS,
402	NFSERR_MLINK,
403	NFSERR_NAMETOL,
404	NFSERR_NOTEMPTY,
405	NFSERR_DQUOT,
406	NFSERR_STALE,
407	NFSERR_BADHANDLE,
408	NFSERR_NOTSUPP,
409	NFSERR_SERVERFAULT,
410	0,
411};
412
413static const short nfsv3err_link[] = {
414	NFSERR_IO,
415	NFSERR_IO,
416	NFSERR_ACCES,
417	NFSERR_EXIST,
418	NFSERR_XDEV,
419	NFSERR_NOTDIR,
420	NFSERR_INVAL,
421	NFSERR_NOSPC,
422	NFSERR_ROFS,
423	NFSERR_MLINK,
424	NFSERR_NAMETOL,
425	NFSERR_DQUOT,
426	NFSERR_STALE,
427	NFSERR_BADHANDLE,
428	NFSERR_NOTSUPP,
429	NFSERR_SERVERFAULT,
430	0,
431};
432
433static const short nfsv3err_readdir[] = {
434	NFSERR_IO,
435	NFSERR_IO,
436	NFSERR_ACCES,
437	NFSERR_NOTDIR,
438	NFSERR_STALE,
439	NFSERR_BADHANDLE,
440	NFSERR_BAD_COOKIE,
441	NFSERR_TOOSMALL,
442	NFSERR_SERVERFAULT,
443	0,
444};
445
446static const short nfsv3err_readdirplus[] = {
447	NFSERR_IO,
448	NFSERR_IO,
449	NFSERR_ACCES,
450	NFSERR_NOTDIR,
451	NFSERR_STALE,
452	NFSERR_BADHANDLE,
453	NFSERR_BAD_COOKIE,
454	NFSERR_NOTSUPP,
455	NFSERR_TOOSMALL,
456	NFSERR_SERVERFAULT,
457	0,
458};
459
460static const short nfsv3err_fsstat[] = {
461	NFSERR_IO,
462	NFSERR_IO,
463	NFSERR_STALE,
464	NFSERR_BADHANDLE,
465	NFSERR_SERVERFAULT,
466	0,
467};
468
469static const short nfsv3err_fsinfo[] = {
470	NFSERR_STALE,
471	NFSERR_STALE,
472	NFSERR_BADHANDLE,
473	NFSERR_SERVERFAULT,
474	0,
475};
476
477static const short nfsv3err_pathconf[] = {
478	NFSERR_STALE,
479	NFSERR_STALE,
480	NFSERR_BADHANDLE,
481	NFSERR_SERVERFAULT,
482	0,
483};
484
485static const short nfsv3err_commit[] = {
486	NFSERR_IO,
487	NFSERR_IO,
488	NFSERR_STALE,
489	NFSERR_BADHANDLE,
490	NFSERR_SERVERFAULT,
491	0,
492};
493
494static const short *nfsrv_v3errmap[] = {
495	nfsv3err_null,
496	nfsv3err_getattr,
497	nfsv3err_setattr,
498	nfsv3err_lookup,
499	nfsv3err_access,
500	nfsv3err_readlink,
501	nfsv3err_read,
502	nfsv3err_write,
503	nfsv3err_create,
504	nfsv3err_mkdir,
505	nfsv3err_symlink,
506	nfsv3err_mknod,
507	nfsv3err_remove,
508	nfsv3err_rmdir,
509	nfsv3err_rename,
510	nfsv3err_link,
511	nfsv3err_readdir,
512	nfsv3err_readdirplus,
513	nfsv3err_fsstat,
514	nfsv3err_fsinfo,
515	nfsv3err_pathconf,
516	nfsv3err_commit,
517};
518
519/*
520 * Called once to initialize data structures...
521 */
522static int
523nfsrv_modevent(module_t mod, int type, void *data)
524{
525	int error = 0;
526
527	NET_LOCK_GIANT();
528	switch (type) {
529	case MOD_LOAD:
530		mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
531		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
532		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
533		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
534		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
535		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
536		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
537		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
538		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
539		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
540		nfsrv_nfs_true = txdr_unsigned(TRUE);
541		nfsrv_nfs_false = txdr_unsigned(FALSE);
542		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
543		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
544		if (nfsrv_ticks < 1)
545			nfsrv_ticks = 1;
546
547		nfsrv_initcache();	/* Init the server request cache */
548		NFSD_LOCK();
549		nfsrv_init(0);		/* Init server data structures */
550		if (debug_mpsafenet)
551			callout_init(&nfsrv_callout, CALLOUT_MPSAFE);
552		else
553			callout_init(&nfsrv_callout, 0);
554		NFSD_UNLOCK();
555		nfsrv_timer(0);
556
557		/* XXX: Should use SYSCALL_MODULE() */
558		nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
559		sysent[SYS_nfssvc].sy_narg = 2;
560		nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
561		sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
562		break;
563
564	case MOD_UNLOAD:
565		if (nfsrv_numnfsd != 0) {
566			error = EBUSY;
567			break;
568		}
569
570		callout_drain(&nfsrv_callout);
571		sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
572		sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
573		nfsrv_destroycache();	/* Free the server request cache */
574		mtx_destroy(&nfsd_mtx);
575		break;
576	default:
577		error = EOPNOTSUPP;
578		break;
579	}
580	NET_UNLOCK_GIANT();
581	return error;
582}
583static moduledata_t nfsserver_mod = {
584	"nfsserver",
585	nfsrv_modevent,
586	NULL,
587};
588DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
589
590/* So that loader and kldload(2) can find us, wherever we are.. */
591MODULE_VERSION(nfsserver, 1);
592
593/*
594 * Set up nameidata for a lookup() call and do it.
595 *
596 * If pubflag is set, this call is done for a lookup operation on the
597 * public filehandle. In that case we allow crossing mountpoints and
598 * absolute pathnames. However, the caller is expected to check that
599 * the lookup result is within the public fs, and deny access if
600 * it is not.
601 *
602 * nfs_namei() clears out garbage fields that namei() might leave garbage.
603 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
604 * error occurs but the parent was not requested.
605 *
606 * dirp may be set whether an error is returned or not, and must be
607 * released by the caller.
608 */
609int
610nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
611    struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
612    caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
613    int *retdirattr_retp, struct thread *td, int pubflag)
614{
615	int i, rem;
616	struct mbuf *md;
617	char *fromcp, *tocp, *cp;
618	struct iovec aiov;
619	struct uio auio;
620	struct vnode *dp;
621	int error, rdonly, linklen;
622	struct componentname *cnp = &ndp->ni_cnd;
623	int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
624
625	NFSD_LOCK_ASSERT();
626	NFSD_UNLOCK();
627
628	*retdirp = NULL;
629	cnp->cn_flags |= NOMACCHECK;
630	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
631
632	/*
633	 * Copy the name from the mbuf list to ndp->ni_pnbuf
634	 * and set the various ndp fields appropriately.
635	 */
636	fromcp = *dposp;
637	tocp = cnp->cn_pnbuf;
638	md = *mdp;
639	rem = mtod(md, caddr_t) + md->m_len - fromcp;
640	for (i = 0; i < len; i++) {
641		while (rem == 0) {
642			md = md->m_next;
643			if (md == NULL) {
644				error = EBADRPC;
645				goto out_nogiant;
646			}
647			fromcp = mtod(md, caddr_t);
648			rem = md->m_len;
649		}
650		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
651			error = EACCES;
652			goto out_nogiant;
653		}
654		*tocp++ = *fromcp++;
655		rem--;
656	}
657	*tocp = '\0';
658	*mdp = md;
659	*dposp = fromcp;
660	len = nfsm_rndup(len)-len;
661	if (len > 0) {
662		if (rem >= len)
663			*dposp += len;
664		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
665			goto out_nogiant;
666	}
667
668	/*
669	 * Extract and set starting directory.
670	 *
671	 * XXXRW: For now, acquire Giant unconditionally to avoid tracking it
672	 * on multiple vnodes.
673	 */
674	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
675	    nam, &rdonly, pubflag);
676	mtx_lock(&Giant);	/* VFS */
677	if (error)
678		goto out;
679	if (dp->v_type != VDIR) {
680		vrele(dp);
681		error = ENOTDIR;
682		goto out;
683	}
684
685	if (rdonly)
686		cnp->cn_flags |= RDONLY;
687
688	/*
689	 * Set return directory.  Reference to dp is implicitly transfered
690	 * to the returned pointer
691	 */
692	*retdirp = dp;
693	if (v3) {
694		vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
695		*retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
696			ndp->ni_cnd.cn_cred, td);
697		VOP_UNLOCK(dp, 0, td);
698	}
699
700	if (pubflag) {
701		/*
702		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
703		 * and the 'native path' indicator.
704		 */
705		cp = uma_zalloc(namei_zone, M_WAITOK);
706		fromcp = cnp->cn_pnbuf;
707		tocp = cp;
708		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
709			switch ((unsigned char)*fromcp) {
710			case WEBNFS_NATIVE_CHAR:
711				/*
712				 * 'Native' path for us is the same
713				 * as a path according to the NFS spec,
714				 * just skip the escape char.
715				 */
716				fromcp++;
717				break;
718			/*
719			 * More may be added in the future, range 0x80-0xff
720			 */
721			default:
722				error = EIO;
723				uma_zfree(namei_zone, cp);
724				goto out;
725			}
726		}
727		/*
728		 * Translate the '%' escapes, URL-style.
729		 */
730		while (*fromcp != '\0') {
731			if (*fromcp == WEBNFS_ESC_CHAR) {
732				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
733					fromcp++;
734					*tocp++ = HEXSTRTOI(fromcp);
735					fromcp += 2;
736					continue;
737				} else {
738					error = ENOENT;
739					uma_zfree(namei_zone, cp);
740					goto out;
741				}
742			} else
743				*tocp++ = *fromcp++;
744		}
745		*tocp = '\0';
746		uma_zfree(namei_zone, cnp->cn_pnbuf);
747		cnp->cn_pnbuf = cp;
748	}
749
750	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
751	ndp->ni_segflg = UIO_SYSSPACE;
752
753	if (pubflag) {
754		ndp->ni_rootdir = rootvnode;
755		ndp->ni_loopcnt = 0;
756		if (cnp->cn_pnbuf[0] == '/')
757			dp = rootvnode;
758	} else {
759		cnp->cn_flags |= NOCROSSMOUNT;
760	}
761
762	/*
763	 * Initialize for scan, set ni_startdir and bump ref on dp again
764	 * because lookup() will dereference ni_startdir.
765	 */
766
767	cnp->cn_thread = td;
768	VREF(dp);
769	ndp->ni_startdir = dp;
770
771	if (!lockleaf)
772		cnp->cn_flags |= LOCKLEAF;
773	for (;;) {
774		cnp->cn_nameptr = cnp->cn_pnbuf;
775		/*
776		 * Call lookup() to do the real work.  If an error occurs,
777		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
778		 * we do not have to dereference anything before returning.
779		 * In either case ni_startdir will be dereferenced and NULLed
780		 * out.
781		 */
782		error = lookup(ndp);
783		if (error)
784			break;
785
786		/*
787		 * Check for encountering a symbolic link.  Trivial
788		 * termination occurs if no symlink encountered.
789		 * Note: zfree is safe because error is 0, so we will
790		 * not zfree it again when we break.
791		 */
792		if ((cnp->cn_flags & ISSYMLINK) == 0) {
793			if (cnp->cn_flags & (SAVENAME | SAVESTART))
794				cnp->cn_flags |= HASBUF;
795			else
796				uma_zfree(namei_zone, cnp->cn_pnbuf);
797			if (ndp->ni_vp && !lockleaf)
798				VOP_UNLOCK(ndp->ni_vp, 0, td);
799			break;
800		}
801
802		/*
803		 * Validate symlink
804		 */
805		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
806			VOP_UNLOCK(ndp->ni_dvp, 0, td);
807		if (!pubflag) {
808			error = EINVAL;
809			goto badlink2;
810		}
811
812		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
813			error = ELOOP;
814			goto badlink2;
815		}
816		if (ndp->ni_pathlen > 1)
817			cp = uma_zalloc(namei_zone, M_WAITOK);
818		else
819			cp = cnp->cn_pnbuf;
820		aiov.iov_base = cp;
821		aiov.iov_len = MAXPATHLEN;
822		auio.uio_iov = &aiov;
823		auio.uio_iovcnt = 1;
824		auio.uio_offset = 0;
825		auio.uio_rw = UIO_READ;
826		auio.uio_segflg = UIO_SYSSPACE;
827		auio.uio_td = NULL;
828		auio.uio_resid = MAXPATHLEN;
829		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
830		if (error) {
831		badlink1:
832			if (ndp->ni_pathlen > 1)
833				uma_zfree(namei_zone, cp);
834		badlink2:
835			vput(ndp->ni_vp);
836			vrele(ndp->ni_dvp);
837			break;
838		}
839		linklen = MAXPATHLEN - auio.uio_resid;
840		if (linklen == 0) {
841			error = ENOENT;
842			goto badlink1;
843		}
844		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
845			error = ENAMETOOLONG;
846			goto badlink1;
847		}
848
849		/*
850		 * Adjust or replace path
851		 */
852		if (ndp->ni_pathlen > 1) {
853			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
854			uma_zfree(namei_zone, cnp->cn_pnbuf);
855			cnp->cn_pnbuf = cp;
856		} else
857			cnp->cn_pnbuf[linklen] = '\0';
858		ndp->ni_pathlen += linklen;
859
860		/*
861		 * Cleanup refs for next loop and check if root directory
862		 * should replace current directory.  Normally ni_dvp
863		 * becomes the new base directory and is cleaned up when
864		 * we loop.  Explicitly null pointers after invalidation
865		 * to clarify operation.
866		 */
867		vput(ndp->ni_vp);
868		ndp->ni_vp = NULL;
869
870		if (cnp->cn_pnbuf[0] == '/') {
871			vrele(ndp->ni_dvp);
872			ndp->ni_dvp = ndp->ni_rootdir;
873			VREF(ndp->ni_dvp);
874		}
875		ndp->ni_startdir = ndp->ni_dvp;
876		ndp->ni_dvp = NULL;
877	}
878	if (!lockleaf)
879		cnp->cn_flags &= ~LOCKLEAF;
880	if (cnp->cn_flags & GIANTHELD) {
881		mtx_unlock(&Giant);
882		cnp->cn_flags &= ~GIANTHELD;
883	}
884
885	/*
886	 * nfs_namei() guarentees that fields will not contain garbage
887	 * whether an error occurs or not.  This allows the caller to track
888	 * cleanup state trivially.
889	 */
890out:
891	mtx_unlock(&Giant);	/* VFS */
892out_nogiant:
893	if (error) {
894		uma_zfree(namei_zone, cnp->cn_pnbuf);
895		ndp->ni_vp = NULL;
896		ndp->ni_dvp = NULL;
897		ndp->ni_startdir = NULL;
898		cnp->cn_flags &= ~HASBUF;
899	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
900		ndp->ni_dvp = NULL;
901	}
902	NFSD_LOCK();
903	return (error);
904}
905
906/*
907 * A fiddled version of m_adj() that ensures null fill to a long
908 * boundary and only trims off the back end
909 */
910void
911nfsm_adj(struct mbuf *mp, int len, int nul)
912{
913	struct mbuf *m;
914	int count, i;
915	char *cp;
916
917	NFSD_LOCK_DONTCARE();
918
919	/*
920	 * Trim from tail.  Scan the mbuf chain,
921	 * calculating its length and finding the last mbuf.
922	 * If the adjustment only affects this mbuf, then just
923	 * adjust and return.  Otherwise, rescan and truncate
924	 * after the remaining size.
925	 */
926	count = 0;
927	m = mp;
928	for (;;) {
929		count += m->m_len;
930		if (m->m_next == NULL)
931			break;
932		m = m->m_next;
933	}
934	if (m->m_len > len) {
935		m->m_len -= len;
936		if (nul > 0) {
937			cp = mtod(m, caddr_t)+m->m_len-nul;
938			for (i = 0; i < nul; i++)
939				*cp++ = '\0';
940		}
941		return;
942	}
943	count -= len;
944	if (count < 0)
945		count = 0;
946	/*
947	 * Correct length for chain is "count".
948	 * Find the mbuf with last data, adjust its length,
949	 * and toss data from remaining mbufs on chain.
950	 */
951	for (m = mp; m; m = m->m_next) {
952		if (m->m_len >= count) {
953			m->m_len = count;
954			if (nul > 0) {
955				cp = mtod(m, caddr_t)+m->m_len-nul;
956				for (i = 0; i < nul; i++)
957					*cp++ = '\0';
958			}
959			if (m->m_next != NULL) {
960				m_freem(m->m_next);
961				m->m_next = NULL;
962			}
963			break;
964		}
965		count -= m->m_len;
966	}
967}
968
969/*
970 * Make these functions instead of macros, so that the kernel text size
971 * doesn't get too big...
972 */
973void
974nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
975    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
976    struct mbuf **mbp, char **bposp)
977{
978	struct mbuf *mb = *mbp;
979	char *bpos = *bposp;
980	u_int32_t *tl;
981
982	if (before_ret) {
983		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
984		*tl = nfsrv_nfs_false;
985	} else {
986		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
987		*tl++ = nfsrv_nfs_true;
988		txdr_hyper(before_vap->va_size, tl);
989		tl += 2;
990		txdr_nfsv3time(&(before_vap->va_mtime), tl);
991		tl += 2;
992		txdr_nfsv3time(&(before_vap->va_ctime), tl);
993	}
994	*bposp = bpos;
995	*mbp = mb;
996	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
997}
998
999void
1000nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
1001    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1002{
1003	struct mbuf *mb = *mbp;
1004	char *bpos = *bposp;
1005	u_int32_t *tl;
1006	struct nfs_fattr *fp;
1007
1008	if (after_ret) {
1009		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1010		*tl = nfsrv_nfs_false;
1011	} else {
1012		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1013		*tl++ = nfsrv_nfs_true;
1014		fp = (struct nfs_fattr *)tl;
1015		nfsm_srvfattr(nfsd, after_vap, fp);
1016	}
1017	*mbp = mb;
1018	*bposp = bpos;
1019}
1020
1021void
1022nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1023    struct nfs_fattr *fp)
1024{
1025
1026	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1027	fp->fa_uid = txdr_unsigned(vap->va_uid);
1028	fp->fa_gid = txdr_unsigned(vap->va_gid);
1029	if (nfsd->nd_flag & ND_NFSV3) {
1030		fp->fa_type = vtonfsv3_type(vap->va_type);
1031		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1032		txdr_hyper(vap->va_size, &fp->fa3_size);
1033		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1034		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1035		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1036		fp->fa3_fsid.nfsuquad[0] = 0;
1037		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1038		fp->fa3_fileid.nfsuquad[0] = 0;
1039		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1040		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1041		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1042		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1043	} else {
1044		fp->fa_type = vtonfsv2_type(vap->va_type);
1045		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1046		fp->fa2_size = txdr_unsigned(vap->va_size);
1047		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1048		if (vap->va_type == VFIFO)
1049			fp->fa2_rdev = 0xffffffff;
1050		else
1051			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1052		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1053		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1054		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1055		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1056		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1057		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1058	}
1059}
1060
1061/*
1062 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1063 * 	- look up fsid in mount list (if not found ret error)
1064 *	- get vp and export rights by calling VFS_FHTOVP()
1065 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1066 *	- if not lockflag unlock it with VOP_UNLOCK()
1067 *
1068 * As this routine may acquire Giant and may sleep, it can't be called with
1069 * nfsd_mtx.  Caller should invoke nfsrv_fhtovp_locked() if the lock is held
1070 * so that it can be automatically dropped and re-acquired.
1071 */
1072int
1073nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1074    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1075    int *rdonlyp, int pubflag)
1076{
1077	struct thread *td = curthread; /* XXX */
1078	struct mount *mp;
1079	int i;
1080	struct ucred *credanon;
1081	int error, exflags;
1082	int vfslocked;
1083#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1084	struct sockaddr_int *saddr;
1085#endif
1086
1087	NFSD_UNLOCK_ASSERT();
1088
1089	*vpp = NULL;
1090
1091	if (nfs_ispublicfh(fhp)) {
1092		if (!pubflag || !nfs_pub.np_valid)
1093			return (ESTALE);
1094		fhp = &nfs_pub.np_handle;
1095	}
1096
1097	mp = vfs_getvfs(&fhp->fh_fsid);
1098	if (!mp)
1099		return (ESTALE);
1100	vfslocked = VFS_LOCK_GIANT(mp);
1101	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1102	if (error)
1103		goto out;
1104	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1105	if (error)
1106		goto out;
1107#ifdef MNT_EXNORESPORT
1108	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1109		saddr = (struct sockaddr_in *)nam;
1110		if ((saddr->sin_family == AF_INET ||
1111		     saddr->sin_family == AF_INET6) &&
1112	/* same code for INET and INET6: sin*_port at same offet */
1113		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1114			vput(*vpp);
1115			*vpp = NULL;
1116			error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1117		}
1118	}
1119#endif
1120	/*
1121	 * Check/setup credentials.
1122	 */
1123	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1124		cred->cr_uid = credanon->cr_uid;
1125		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1126			cred->cr_groups[i] = credanon->cr_groups[i];
1127		cred->cr_ngroups = i;
1128	}
1129	if (exflags & MNT_EXRDONLY)
1130		*rdonlyp = 1;
1131	else
1132		*rdonlyp = 0;
1133
1134	if (!lockflag)
1135		VOP_UNLOCK(*vpp, 0, td);
1136out:
1137	vfs_rel(mp);
1138	VFS_UNLOCK_GIANT(vfslocked);
1139	return (error);
1140}
1141
1142/*
1143 * Version of nfsrv_fhtovp() that can be called holding nfsd_mtx: it will
1144 * drop and re-acquire the lock for the caller.
1145 */
1146int
1147nfsrv_fhtovp_locked(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1148    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1149    int *rdonlyp, int pubflag)
1150{
1151	int error;
1152
1153	NFSD_LOCK_ASSERT();
1154	NFSD_UNLOCK();
1155	error = nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp,
1156	    pubflag);
1157	NFSD_LOCK();
1158	return (error);
1159}
1160
1161/*
1162 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1163 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1164 * transformed this to all zeroes in both cases, so check for it.
1165 */
1166int
1167nfs_ispublicfh(fhandle_t *fhp)
1168{
1169	char *cp = (char *)fhp;
1170	int i;
1171
1172	NFSD_LOCK_DONTCARE();
1173
1174	for (i = 0; i < NFSX_V3FH; i++)
1175		if (*cp++ != 0)
1176			return (FALSE);
1177	return (TRUE);
1178}
1179
1180/*
1181 * This function compares two net addresses by family and returns TRUE
1182 * if they are the same host.
1183 * If there is any doubt, return FALSE.
1184 * The AF_INET family is handled as a special case so that address mbufs
1185 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1186 */
1187int
1188netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1189{
1190	struct sockaddr_in *inetaddr;
1191
1192	NFSD_LOCK_DONTCARE();
1193
1194	switch (family) {
1195	case AF_INET:
1196		inetaddr = (struct sockaddr_in *)nam;
1197		if (inetaddr->sin_family == AF_INET &&
1198		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1199			return (1);
1200		break;
1201#ifdef INET6
1202	case AF_INET6:
1203	{
1204		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1205
1206		inet6addr1 = (struct sockaddr_in6 *)nam;
1207		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1208	/* XXX - should test sin6_scope_id ? */
1209		if (inet6addr1->sin6_family == AF_INET6 &&
1210		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1211				       &inet6addr2->sin6_addr))
1212			return (1);
1213		break;
1214	}
1215#endif
1216	default:
1217		break;
1218	};
1219	return (0);
1220}
1221
1222/*
1223 * Map errnos to NFS error numbers. For Version 3 also filter out error
1224 * numbers not specified for the associated procedure.
1225 */
1226int
1227nfsrv_errmap(struct nfsrv_descript *nd, int err)
1228{
1229	const short *defaulterrp, *errp;
1230	int e;
1231
1232	NFSD_LOCK_DONTCARE();
1233
1234	if (nd->nd_flag & ND_NFSV3) {
1235	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1236		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1237		while (*++errp) {
1238			if (*errp == err)
1239				return (err);
1240			else if (*errp > err)
1241				break;
1242		}
1243		return ((int)*defaulterrp);
1244	    } else
1245		return (err & 0xffff);
1246	}
1247	e = 0;
1248	if (err <= ELAST)
1249		e = nfsrv_v2errmap[err - 1];
1250	if (e != 0)
1251		return (e);
1252	return (NFSERR_IO);
1253}
1254
1255/*
1256 * Sort the group list in increasing numerical order.
1257 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1258 *  that used to be here.)
1259 */
1260void
1261nfsrvw_sort(gid_t *list, int num)
1262{
1263	int i, j;
1264	gid_t v;
1265
1266	NFSD_LOCK_DONTCARE();
1267
1268	/* Insertion sort. */
1269	for (i = 1; i < num; i++) {
1270		v = list[i];
1271		/* find correct slot for value v, moving others up */
1272		for (j = i; --j >= 0 && v < list[j];)
1273			list[j + 1] = list[j];
1274		list[j + 1] = v;
1275	}
1276}
1277
1278/*
1279 * copy credentials making sure that the result can be compared with bcmp().
1280 */
1281void
1282nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1283{
1284	int i;
1285
1286	NFSD_LOCK_DONTCARE();
1287
1288	bzero((caddr_t)outcred, sizeof (struct ucred));
1289	refcount_init(&outcred->cr_ref, 1);
1290	outcred->cr_uid = incred->cr_uid;
1291	outcred->cr_ngroups = incred->cr_ngroups;
1292	for (i = 0; i < incred->cr_ngroups; i++)
1293		outcred->cr_groups[i] = incred->cr_groups[i];
1294	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1295}
1296
1297/*
1298 * Helper functions for macros.
1299 */
1300
1301void
1302nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1303{
1304	u_int32_t *tl;
1305
1306	NFSD_LOCK_DONTCARE();
1307
1308	if (v3) {
1309		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1310		*tl++ = txdr_unsigned(NFSX_V3FH);
1311		bcopy(f, tl, NFSX_V3FH);
1312	} else {
1313		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1314		bcopy(f, tl, NFSX_V2FH);
1315	}
1316}
1317
1318void
1319nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1320{
1321	u_int32_t *tl;
1322
1323	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1324	*tl++ = nfsrv_nfs_true;
1325	*tl++ = txdr_unsigned(NFSX_V3FH);
1326	bcopy(f, tl, NFSX_V3FH);
1327}
1328
1329int
1330nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1331{
1332	u_int32_t *tl;
1333
1334	NFSD_LOCK_DONTCARE();
1335
1336	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1337	if (tl == NULL)
1338		return EBADRPC;
1339	*s = fxdr_unsigned(int32_t, *tl);
1340	if (*s > m || *s <= 0)
1341		return EBADRPC;
1342	return 0;
1343}
1344
1345int
1346nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1347{
1348	u_int32_t *tl;
1349
1350	NFSD_LOCK_DONTCARE();
1351
1352	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1353	if (tl == NULL)
1354		return EBADRPC;
1355	*s = fxdr_unsigned(int32_t, *tl);
1356	if (*s > m)
1357		return NFSERR_NAMETOL;
1358	if (*s <= 0)
1359		return EBADRPC;
1360	return 0;
1361}
1362
1363void
1364nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1365    char **bp, char **be, caddr_t bpos, int droplock)
1366{
1367	struct mbuf *nmp;
1368
1369	NFSD_LOCK_DONTCARE();
1370
1371	if (droplock)
1372		NFSD_LOCK_ASSERT();
1373	else
1374		NFSD_UNLOCK_ASSERT();
1375
1376	if (*bp >= *be) {
1377		if (*mp == mb)
1378			(*mp)->m_len += *bp - bpos;
1379		if (droplock)
1380			NFSD_UNLOCK();
1381		MGET(nmp, M_TRYWAIT, MT_DATA);
1382		MCLGET(nmp, M_TRYWAIT);
1383		if (droplock)
1384			NFSD_LOCK();
1385		nmp->m_len = NFSMSIZ(nmp);
1386		(*mp)->m_next = nmp;
1387		*mp = nmp;
1388		*bp = mtod(*mp, caddr_t);
1389		*be = *bp + (*mp)->m_len;
1390	}
1391	*tl = (u_int32_t *)*bp;
1392}
1393
1394int
1395nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1396    caddr_t *dpos)
1397{
1398	u_int32_t *tl;
1399	int fhlen;
1400
1401	NFSD_LOCK_DONTCARE();
1402
1403	if (nfsd->nd_flag & ND_NFSV3) {
1404		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1405		if (tl == NULL)
1406			return EBADRPC;
1407		fhlen = fxdr_unsigned(int, *tl);
1408		if (fhlen != 0 && fhlen != NFSX_V3FH)
1409			return EBADRPC;
1410	} else {
1411		fhlen = NFSX_V2FH;
1412	}
1413	if (fhlen != 0) {
1414		tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1415		if (tl == NULL)
1416			return EBADRPC;
1417		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1418	} else {
1419		bzero((caddr_t)(f), NFSX_V3FH);
1420	}
1421	return 0;
1422}
1423
1424int
1425nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1426{
1427	u_int32_t *tl;
1428	int toclient = 0;
1429
1430	NFSD_LOCK_DONTCARE();
1431
1432	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1433	if (tl == NULL)
1434		return EBADRPC;
1435	if (*tl == nfsrv_nfs_true) {
1436		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1437		if (tl == NULL)
1438			return EBADRPC;
1439		(a)->va_mode = nfstov_mode(*tl);
1440	}
1441	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1442	if (tl == NULL)
1443		return EBADRPC;
1444	if (*tl == nfsrv_nfs_true) {
1445		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1446		if (tl == NULL)
1447			return EBADRPC;
1448		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
1449	}
1450	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1451	if (tl == NULL)
1452		return EBADRPC;
1453	if (*tl == nfsrv_nfs_true) {
1454		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1455		if (tl == NULL)
1456			return EBADRPC;
1457		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
1458	}
1459	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1460	if (tl == NULL)
1461		return EBADRPC;
1462	if (*tl == nfsrv_nfs_true) {
1463		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1464		if (tl == NULL)
1465			return EBADRPC;
1466		(a)->va_size = fxdr_hyper(tl);
1467	}
1468	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1469	if (tl == NULL)
1470		return EBADRPC;
1471	switch (fxdr_unsigned(int, *tl)) {
1472	case NFSV3SATTRTIME_TOCLIENT:
1473		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1474		if (tl == NULL)
1475			return EBADRPC;
1476		fxdr_nfsv3time(tl, &(a)->va_atime);
1477		toclient = 1;
1478		break;
1479	case NFSV3SATTRTIME_TOSERVER:
1480		getnanotime(&(a)->va_atime);
1481		a->va_vaflags |= VA_UTIMES_NULL;
1482		break;
1483	}
1484	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1485	if (tl == NULL)
1486		return EBADRPC;
1487	switch (fxdr_unsigned(int, *tl)) {
1488	case NFSV3SATTRTIME_TOCLIENT:
1489		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1490		if (tl == NULL)
1491			return EBADRPC;
1492		fxdr_nfsv3time(tl, &(a)->va_mtime);
1493		a->va_vaflags &= ~VA_UTIMES_NULL;
1494		break;
1495	case NFSV3SATTRTIME_TOSERVER:
1496		getnanotime(&(a)->va_mtime);
1497		if (toclient == 0)
1498			a->va_vaflags |= VA_UTIMES_NULL;
1499		break;
1500	}
1501	return 0;
1502}
1503