1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 1989, 1993
3191783Srmacklem *	The Regents of the University of California.  All rights reserved.
4191783Srmacklem *
5191783Srmacklem * This code is derived from software contributed to Berkeley by
6191783Srmacklem * Rick Macklem at The University of Guelph.
7191783Srmacklem *
8191783Srmacklem * Redistribution and use in source and binary forms, with or without
9191783Srmacklem * modification, are permitted provided that the following conditions
10191783Srmacklem * are met:
11191783Srmacklem * 1. Redistributions of source code must retain the above copyright
12191783Srmacklem *    notice, this list of conditions and the following disclaimer.
13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
14191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
15191783Srmacklem *    documentation and/or other materials provided with the distribution.
16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors
17191783Srmacklem *    may be used to endorse or promote products derived from this software
18191783Srmacklem *    without specific prior written permission.
19191783Srmacklem *
20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23191783Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30191783Srmacklem * SUCH DAMAGE.
31191783Srmacklem *
32191783Srmacklem */
33191783Srmacklem
34191783Srmacklem#include <sys/cdefs.h>
35191783Srmacklem__FBSDID("$FreeBSD$");
36191783Srmacklem
37191783Srmacklem#ifndef APPLEKEXT
38191783Srmacklem/*
39191783Srmacklem * These functions support the macros and help fiddle mbuf chains for
40191783Srmacklem * the nfs op functions. They do things like create the rpc header and
41191783Srmacklem * copy data between mbuf chains and uio lists.
42191783Srmacklem */
43191783Srmacklem#include <fs/nfs/nfsport.h>
44191783Srmacklem
45191783Srmacklemextern u_int32_t newnfs_true, newnfs_false;
46191783Srmacklemextern int nfs_pubfhset;
47191783Srmacklemextern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
48191783Srmacklemextern struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE];
49191783Srmacklemextern int nfsrv_useacl;
50191783Srmacklemextern uid_t nfsrv_defaultuid;
51191783Srmacklemextern gid_t nfsrv_defaultgid;
52191783Srmacklem
53191783Srmacklemchar nfs_v2pubfh[NFSX_V2FH];
54191783Srmacklemstatic nfstype newnfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
55191783Srmacklem    NFNON, NFCHR, NFNON };
56191783Srmacklemextern nfstype nfsv34_type[9];
57191783Srmacklem#endif	/* !APPLEKEXT */
58191783Srmacklem
59228260SrmacklemSYSCTL_DECL(_vfs_nfsd);
60228260Srmacklem
61228260Srmacklemstatic int	disable_checkutf8 = 0;
62228260SrmacklemSYSCTL_INT(_vfs_nfsd, OID_AUTO, disable_checkutf8, CTLFLAG_RW,
63228260Srmacklem    &disable_checkutf8, 0,
64228260Srmacklem    "Disable the NFSv4 check for a UTF8 compliant name");
65228260Srmacklem
66191783Srmacklemstatic char nfsrv_hexdigit(char, int *);
67191783Srmacklem
68191783Srmacklem/*
69191783Srmacklem * Maps errno values to nfs error numbers.
70191783Srmacklem * Use NFSERR_IO as the catch all for ones not specifically defined in
71191783Srmacklem * RFC 1094.
72191783Srmacklem */
73191783Srmacklemstatic u_char nfsrv_v2errmap[ELAST] = {
74191783Srmacklem  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
75191783Srmacklem  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
76191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
77191783Srmacklem  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
78191783Srmacklem  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
79191783Srmacklem  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
80191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
81191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
82191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
83191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
84191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
85191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
86191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
87191783Srmacklem  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
88191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
89191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
90191783Srmacklem  NFSERR_IO,
91191783Srmacklem};
92191783Srmacklem
93191783Srmacklem/*
94191783Srmacklem * Maps errno values to nfs error numbers.
95191783Srmacklem * Although it is not obvious whether or not NFS clients really care if
96191783Srmacklem * a returned error value is in the specified list for the procedure, the
97191783Srmacklem * safest thing to do is filter them appropriately. For Version 2, the
98191783Srmacklem * X/Open XNFS document is the only specification that defines error values
99191783Srmacklem * for each RPC (The RFC simply lists all possible error values for all RPCs),
100191783Srmacklem * so I have decided to not do this for Version 2.
101191783Srmacklem * The first entry is the default error return and the rest are the valid
102191783Srmacklem * errors for that RPC in increasing numeric order.
103191783Srmacklem */
104191783Srmacklemstatic short nfsv3err_null[] = {
105191783Srmacklem	0,
106191783Srmacklem	0,
107191783Srmacklem};
108191783Srmacklem
109191783Srmacklemstatic short nfsv3err_getattr[] = {
110191783Srmacklem	NFSERR_IO,
111191783Srmacklem	NFSERR_IO,
112191783Srmacklem	NFSERR_STALE,
113191783Srmacklem	NFSERR_BADHANDLE,
114191783Srmacklem	NFSERR_SERVERFAULT,
115191783Srmacklem	NFSERR_DELAY,
116191783Srmacklem	0,
117191783Srmacklem};
118191783Srmacklem
119191783Srmacklemstatic short nfsv3err_setattr[] = {
120191783Srmacklem	NFSERR_IO,
121191783Srmacklem	NFSERR_ACCES,
122191783Srmacklem	NFSERR_PERM,
123191783Srmacklem	NFSERR_IO,
124191783Srmacklem	NFSERR_INVAL,
125191783Srmacklem	NFSERR_NOSPC,
126191783Srmacklem	NFSERR_ROFS,
127191783Srmacklem	NFSERR_DQUOT,
128191783Srmacklem	NFSERR_STALE,
129191783Srmacklem	NFSERR_BADHANDLE,
130191783Srmacklem	NFSERR_NOT_SYNC,
131191783Srmacklem	NFSERR_SERVERFAULT,
132191783Srmacklem	NFSERR_DELAY,
133191783Srmacklem	0,
134191783Srmacklem};
135191783Srmacklem
136191783Srmacklemstatic short nfsv3err_lookup[] = {
137191783Srmacklem	NFSERR_IO,
138191783Srmacklem	NFSERR_NOENT,
139191783Srmacklem	NFSERR_ACCES,
140191783Srmacklem	NFSERR_NAMETOL,
141191783Srmacklem	NFSERR_IO,
142191783Srmacklem	NFSERR_NOTDIR,
143191783Srmacklem	NFSERR_STALE,
144191783Srmacklem	NFSERR_BADHANDLE,
145191783Srmacklem	NFSERR_SERVERFAULT,
146191783Srmacklem	NFSERR_DELAY,
147191783Srmacklem	0,
148191783Srmacklem};
149191783Srmacklem
150191783Srmacklemstatic short nfsv3err_access[] = {
151191783Srmacklem	NFSERR_IO,
152191783Srmacklem	NFSERR_IO,
153191783Srmacklem	NFSERR_STALE,
154191783Srmacklem	NFSERR_BADHANDLE,
155191783Srmacklem	NFSERR_SERVERFAULT,
156191783Srmacklem	NFSERR_DELAY,
157191783Srmacklem	0,
158191783Srmacklem};
159191783Srmacklem
160191783Srmacklemstatic short nfsv3err_readlink[] = {
161191783Srmacklem	NFSERR_IO,
162191783Srmacklem	NFSERR_IO,
163191783Srmacklem	NFSERR_ACCES,
164191783Srmacklem	NFSERR_INVAL,
165191783Srmacklem	NFSERR_STALE,
166191783Srmacklem	NFSERR_BADHANDLE,
167191783Srmacklem	NFSERR_NOTSUPP,
168191783Srmacklem	NFSERR_SERVERFAULT,
169191783Srmacklem	NFSERR_DELAY,
170191783Srmacklem	0,
171191783Srmacklem};
172191783Srmacklem
173191783Srmacklemstatic short nfsv3err_read[] = {
174191783Srmacklem	NFSERR_IO,
175191783Srmacklem	NFSERR_IO,
176191783Srmacklem	NFSERR_NXIO,
177191783Srmacklem	NFSERR_ACCES,
178191783Srmacklem	NFSERR_INVAL,
179191783Srmacklem	NFSERR_STALE,
180191783Srmacklem	NFSERR_BADHANDLE,
181191783Srmacklem	NFSERR_SERVERFAULT,
182191783Srmacklem	NFSERR_DELAY,
183191783Srmacklem	0,
184191783Srmacklem};
185191783Srmacklem
186191783Srmacklemstatic short nfsv3err_write[] = {
187191783Srmacklem	NFSERR_IO,
188191783Srmacklem	NFSERR_IO,
189191783Srmacklem	NFSERR_ACCES,
190191783Srmacklem	NFSERR_NOSPC,
191191783Srmacklem	NFSERR_INVAL,
192191783Srmacklem	NFSERR_FBIG,
193191783Srmacklem	NFSERR_ROFS,
194191783Srmacklem	NFSERR_DQUOT,
195191783Srmacklem	NFSERR_STALE,
196191783Srmacklem	NFSERR_BADHANDLE,
197191783Srmacklem	NFSERR_SERVERFAULT,
198191783Srmacklem	NFSERR_DELAY,
199191783Srmacklem	0,
200191783Srmacklem};
201191783Srmacklem
202191783Srmacklemstatic short nfsv3err_create[] = {
203191783Srmacklem	NFSERR_IO,
204191783Srmacklem	NFSERR_EXIST,
205191783Srmacklem	NFSERR_NAMETOL,
206191783Srmacklem	NFSERR_ACCES,
207191783Srmacklem	NFSERR_IO,
208191783Srmacklem	NFSERR_NOTDIR,
209191783Srmacklem	NFSERR_NOSPC,
210191783Srmacklem	NFSERR_ROFS,
211191783Srmacklem	NFSERR_DQUOT,
212191783Srmacklem	NFSERR_STALE,
213191783Srmacklem	NFSERR_BADHANDLE,
214191783Srmacklem	NFSERR_NOTSUPP,
215191783Srmacklem	NFSERR_SERVERFAULT,
216191783Srmacklem	NFSERR_DELAY,
217191783Srmacklem	0,
218191783Srmacklem};
219191783Srmacklem
220191783Srmacklemstatic short nfsv3err_mkdir[] = {
221191783Srmacklem	NFSERR_IO,
222191783Srmacklem	NFSERR_EXIST,
223191783Srmacklem	NFSERR_ACCES,
224191783Srmacklem	NFSERR_NAMETOL,
225191783Srmacklem	NFSERR_IO,
226191783Srmacklem	NFSERR_NOTDIR,
227191783Srmacklem	NFSERR_NOSPC,
228191783Srmacklem	NFSERR_ROFS,
229191783Srmacklem	NFSERR_DQUOT,
230191783Srmacklem	NFSERR_STALE,
231191783Srmacklem	NFSERR_BADHANDLE,
232191783Srmacklem	NFSERR_NOTSUPP,
233191783Srmacklem	NFSERR_SERVERFAULT,
234191783Srmacklem	NFSERR_DELAY,
235191783Srmacklem	0,
236191783Srmacklem};
237191783Srmacklem
238191783Srmacklemstatic short nfsv3err_symlink[] = {
239191783Srmacklem	NFSERR_IO,
240191783Srmacklem	NFSERR_ACCES,
241191783Srmacklem	NFSERR_EXIST,
242191783Srmacklem	NFSERR_NAMETOL,
243191783Srmacklem	NFSERR_NOSPC,
244191783Srmacklem	NFSERR_IO,
245191783Srmacklem	NFSERR_NOTDIR,
246191783Srmacklem	NFSERR_ROFS,
247191783Srmacklem	NFSERR_DQUOT,
248191783Srmacklem	NFSERR_STALE,
249191783Srmacklem	NFSERR_BADHANDLE,
250191783Srmacklem	NFSERR_NOTSUPP,
251191783Srmacklem	NFSERR_SERVERFAULT,
252191783Srmacklem	NFSERR_DELAY,
253191783Srmacklem	0,
254191783Srmacklem};
255191783Srmacklem
256191783Srmacklemstatic short nfsv3err_mknod[] = {
257191783Srmacklem	NFSERR_IO,
258191783Srmacklem	NFSERR_ACCES,
259191783Srmacklem	NFSERR_EXIST,
260191783Srmacklem	NFSERR_NAMETOL,
261191783Srmacklem	NFSERR_NOSPC,
262191783Srmacklem	NFSERR_IO,
263191783Srmacklem	NFSERR_NOTDIR,
264191783Srmacklem	NFSERR_ROFS,
265191783Srmacklem	NFSERR_DQUOT,
266191783Srmacklem	NFSERR_STALE,
267191783Srmacklem	NFSERR_BADHANDLE,
268191783Srmacklem	NFSERR_NOTSUPP,
269191783Srmacklem	NFSERR_SERVERFAULT,
270191783Srmacklem	NFSERR_DELAY,
271191783Srmacklem	NFSERR_BADTYPE,
272191783Srmacklem	0,
273191783Srmacklem};
274191783Srmacklem
275191783Srmacklemstatic short nfsv3err_remove[] = {
276191783Srmacklem	NFSERR_IO,
277191783Srmacklem	NFSERR_NOENT,
278191783Srmacklem	NFSERR_ACCES,
279191783Srmacklem	NFSERR_NAMETOL,
280191783Srmacklem	NFSERR_IO,
281191783Srmacklem	NFSERR_NOTDIR,
282191783Srmacklem	NFSERR_ROFS,
283191783Srmacklem	NFSERR_STALE,
284191783Srmacklem	NFSERR_BADHANDLE,
285191783Srmacklem	NFSERR_SERVERFAULT,
286191783Srmacklem	NFSERR_DELAY,
287191783Srmacklem	0,
288191783Srmacklem};
289191783Srmacklem
290191783Srmacklemstatic short nfsv3err_rmdir[] = {
291191783Srmacklem	NFSERR_IO,
292191783Srmacklem	NFSERR_NOENT,
293191783Srmacklem	NFSERR_ACCES,
294191783Srmacklem	NFSERR_NOTDIR,
295191783Srmacklem	NFSERR_NAMETOL,
296191783Srmacklem	NFSERR_IO,
297191783Srmacklem	NFSERR_EXIST,
298191783Srmacklem	NFSERR_INVAL,
299191783Srmacklem	NFSERR_ROFS,
300191783Srmacklem	NFSERR_NOTEMPTY,
301191783Srmacklem	NFSERR_STALE,
302191783Srmacklem	NFSERR_BADHANDLE,
303191783Srmacklem	NFSERR_NOTSUPP,
304191783Srmacklem	NFSERR_SERVERFAULT,
305191783Srmacklem	NFSERR_DELAY,
306191783Srmacklem	0,
307191783Srmacklem};
308191783Srmacklem
309191783Srmacklemstatic short nfsv3err_rename[] = {
310191783Srmacklem	NFSERR_IO,
311191783Srmacklem	NFSERR_NOENT,
312191783Srmacklem	NFSERR_ACCES,
313191783Srmacklem	NFSERR_EXIST,
314191783Srmacklem	NFSERR_NAMETOL,
315191783Srmacklem	NFSERR_XDEV,
316191783Srmacklem	NFSERR_IO,
317191783Srmacklem	NFSERR_NOTDIR,
318191783Srmacklem	NFSERR_ISDIR,
319191783Srmacklem	NFSERR_INVAL,
320191783Srmacklem	NFSERR_NOSPC,
321191783Srmacklem	NFSERR_ROFS,
322191783Srmacklem	NFSERR_MLINK,
323191783Srmacklem	NFSERR_NOTEMPTY,
324191783Srmacklem	NFSERR_DQUOT,
325191783Srmacklem	NFSERR_STALE,
326191783Srmacklem	NFSERR_BADHANDLE,
327191783Srmacklem	NFSERR_NOTSUPP,
328191783Srmacklem	NFSERR_SERVERFAULT,
329191783Srmacklem	NFSERR_DELAY,
330191783Srmacklem	0,
331191783Srmacklem};
332191783Srmacklem
333191783Srmacklemstatic short nfsv3err_link[] = {
334191783Srmacklem	NFSERR_IO,
335191783Srmacklem	NFSERR_ACCES,
336191783Srmacklem	NFSERR_EXIST,
337191783Srmacklem	NFSERR_NAMETOL,
338191783Srmacklem	NFSERR_IO,
339191783Srmacklem	NFSERR_XDEV,
340191783Srmacklem	NFSERR_NOTDIR,
341191783Srmacklem	NFSERR_INVAL,
342191783Srmacklem	NFSERR_NOSPC,
343191783Srmacklem	NFSERR_ROFS,
344191783Srmacklem	NFSERR_MLINK,
345191783Srmacklem	NFSERR_DQUOT,
346191783Srmacklem	NFSERR_STALE,
347191783Srmacklem	NFSERR_BADHANDLE,
348191783Srmacklem	NFSERR_NOTSUPP,
349191783Srmacklem	NFSERR_SERVERFAULT,
350191783Srmacklem	NFSERR_DELAY,
351191783Srmacklem	0,
352191783Srmacklem};
353191783Srmacklem
354191783Srmacklemstatic short nfsv3err_readdir[] = {
355191783Srmacklem	NFSERR_IO,
356191783Srmacklem	NFSERR_ACCES,
357191783Srmacklem	NFSERR_NOTDIR,
358191783Srmacklem	NFSERR_IO,
359191783Srmacklem	NFSERR_STALE,
360191783Srmacklem	NFSERR_BADHANDLE,
361191783Srmacklem	NFSERR_BAD_COOKIE,
362191783Srmacklem	NFSERR_TOOSMALL,
363191783Srmacklem	NFSERR_SERVERFAULT,
364191783Srmacklem	NFSERR_DELAY,
365191783Srmacklem	0,
366191783Srmacklem};
367191783Srmacklem
368191783Srmacklemstatic short nfsv3err_readdirplus[] = {
369191783Srmacklem	NFSERR_IO,
370191783Srmacklem	NFSERR_ACCES,
371191783Srmacklem	NFSERR_NOTDIR,
372191783Srmacklem	NFSERR_IO,
373191783Srmacklem	NFSERR_STALE,
374191783Srmacklem	NFSERR_BADHANDLE,
375191783Srmacklem	NFSERR_BAD_COOKIE,
376191783Srmacklem	NFSERR_NOTSUPP,
377191783Srmacklem	NFSERR_TOOSMALL,
378191783Srmacklem	NFSERR_SERVERFAULT,
379191783Srmacklem	NFSERR_DELAY,
380191783Srmacklem	0,
381191783Srmacklem};
382191783Srmacklem
383191783Srmacklemstatic short nfsv3err_fsstat[] = {
384191783Srmacklem	NFSERR_IO,
385191783Srmacklem	NFSERR_IO,
386191783Srmacklem	NFSERR_STALE,
387191783Srmacklem	NFSERR_BADHANDLE,
388191783Srmacklem	NFSERR_SERVERFAULT,
389191783Srmacklem	NFSERR_DELAY,
390191783Srmacklem	0,
391191783Srmacklem};
392191783Srmacklem
393191783Srmacklemstatic short nfsv3err_fsinfo[] = {
394191783Srmacklem	NFSERR_STALE,
395191783Srmacklem	NFSERR_STALE,
396191783Srmacklem	NFSERR_BADHANDLE,
397191783Srmacklem	NFSERR_SERVERFAULT,
398191783Srmacklem	NFSERR_DELAY,
399191783Srmacklem	0,
400191783Srmacklem};
401191783Srmacklem
402191783Srmacklemstatic short nfsv3err_pathconf[] = {
403191783Srmacklem	NFSERR_STALE,
404191783Srmacklem	NFSERR_STALE,
405191783Srmacklem	NFSERR_BADHANDLE,
406191783Srmacklem	NFSERR_SERVERFAULT,
407191783Srmacklem	NFSERR_DELAY,
408191783Srmacklem	0,
409191783Srmacklem};
410191783Srmacklem
411191783Srmacklemstatic short nfsv3err_commit[] = {
412191783Srmacklem	NFSERR_IO,
413191783Srmacklem	NFSERR_IO,
414191783Srmacklem	NFSERR_STALE,
415191783Srmacklem	NFSERR_BADHANDLE,
416191783Srmacklem	NFSERR_SERVERFAULT,
417191783Srmacklem	NFSERR_DELAY,
418191783Srmacklem	0,
419191783Srmacklem};
420191783Srmacklem
421191783Srmacklemstatic short *nfsrv_v3errmap[] = {
422191783Srmacklem	nfsv3err_null,
423191783Srmacklem	nfsv3err_getattr,
424191783Srmacklem	nfsv3err_setattr,
425191783Srmacklem	nfsv3err_lookup,
426191783Srmacklem	nfsv3err_access,
427191783Srmacklem	nfsv3err_readlink,
428191783Srmacklem	nfsv3err_read,
429191783Srmacklem	nfsv3err_write,
430191783Srmacklem	nfsv3err_create,
431191783Srmacklem	nfsv3err_mkdir,
432191783Srmacklem	nfsv3err_symlink,
433191783Srmacklem	nfsv3err_mknod,
434191783Srmacklem	nfsv3err_remove,
435191783Srmacklem	nfsv3err_rmdir,
436191783Srmacklem	nfsv3err_rename,
437191783Srmacklem	nfsv3err_link,
438191783Srmacklem	nfsv3err_readdir,
439191783Srmacklem	nfsv3err_readdirplus,
440191783Srmacklem	nfsv3err_fsstat,
441191783Srmacklem	nfsv3err_fsinfo,
442191783Srmacklem	nfsv3err_pathconf,
443191783Srmacklem	nfsv3err_commit,
444191783Srmacklem};
445191783Srmacklem
446191783Srmacklem/*
447191783Srmacklem * And the same for V4.
448191783Srmacklem */
449191783Srmacklemstatic short nfsv4err_null[] = {
450191783Srmacklem	0,
451191783Srmacklem	0,
452191783Srmacklem};
453191783Srmacklem
454191783Srmacklemstatic short nfsv4err_access[] = {
455191783Srmacklem	NFSERR_IO,
456191783Srmacklem	NFSERR_ACCES,
457191783Srmacklem	NFSERR_BADHANDLE,
458191783Srmacklem	NFSERR_BADXDR,
459191783Srmacklem	NFSERR_DELAY,
460191783Srmacklem	NFSERR_FHEXPIRED,
461191783Srmacklem	NFSERR_INVAL,
462191783Srmacklem	NFSERR_IO,
463191783Srmacklem	NFSERR_MOVED,
464191783Srmacklem	NFSERR_NOFILEHANDLE,
465191783Srmacklem	NFSERR_RESOURCE,
466191783Srmacklem	NFSERR_SERVERFAULT,
467191783Srmacklem	NFSERR_STALE,
468191783Srmacklem	0,
469191783Srmacklem};
470191783Srmacklem
471191783Srmacklemstatic short nfsv4err_close[] = {
472191783Srmacklem	NFSERR_EXPIRED,
473191783Srmacklem	NFSERR_ADMINREVOKED,
474191783Srmacklem	NFSERR_BADHANDLE,
475191783Srmacklem	NFSERR_BADSEQID,
476191783Srmacklem	NFSERR_BADSTATEID,
477191783Srmacklem	NFSERR_BADXDR,
478191783Srmacklem	NFSERR_DELAY,
479191783Srmacklem	NFSERR_EXPIRED,
480191783Srmacklem	NFSERR_FHEXPIRED,
481191783Srmacklem	NFSERR_INVAL,
482191783Srmacklem	NFSERR_ISDIR,
483191783Srmacklem	NFSERR_LEASEMOVED,
484191783Srmacklem	NFSERR_LOCKSHELD,
485191783Srmacklem	NFSERR_MOVED,
486191783Srmacklem	NFSERR_NOFILEHANDLE,
487191783Srmacklem	NFSERR_OLDSTATEID,
488191783Srmacklem	NFSERR_RESOURCE,
489191783Srmacklem	NFSERR_SERVERFAULT,
490191783Srmacklem	NFSERR_STALE,
491191783Srmacklem	NFSERR_STALESTATEID,
492191783Srmacklem	0,
493191783Srmacklem};
494191783Srmacklem
495191783Srmacklemstatic short nfsv4err_commit[] = {
496191783Srmacklem	NFSERR_IO,
497191783Srmacklem	NFSERR_ACCES,
498191783Srmacklem	NFSERR_BADHANDLE,
499191783Srmacklem	NFSERR_BADXDR,
500191783Srmacklem	NFSERR_FHEXPIRED,
501191783Srmacklem	NFSERR_INVAL,
502191783Srmacklem	NFSERR_IO,
503191783Srmacklem	NFSERR_ISDIR,
504191783Srmacklem	NFSERR_MOVED,
505191783Srmacklem	NFSERR_NOFILEHANDLE,
506191783Srmacklem	NFSERR_RESOURCE,
507191783Srmacklem	NFSERR_ROFS,
508191783Srmacklem	NFSERR_SERVERFAULT,
509191783Srmacklem	NFSERR_STALE,
510191783Srmacklem	0,
511191783Srmacklem};
512191783Srmacklem
513191783Srmacklemstatic short nfsv4err_create[] = {
514191783Srmacklem	NFSERR_IO,
515191783Srmacklem	NFSERR_ACCES,
516191783Srmacklem	NFSERR_ATTRNOTSUPP,
517191783Srmacklem	NFSERR_BADCHAR,
518191783Srmacklem	NFSERR_BADHANDLE,
519191783Srmacklem	NFSERR_BADNAME,
520191783Srmacklem	NFSERR_BADOWNER,
521191783Srmacklem	NFSERR_BADTYPE,
522191783Srmacklem	NFSERR_BADXDR,
523191783Srmacklem	NFSERR_DELAY,
524191783Srmacklem	NFSERR_DQUOT,
525191783Srmacklem	NFSERR_EXIST,
526191783Srmacklem	NFSERR_FHEXPIRED,
527191783Srmacklem	NFSERR_INVAL,
528191783Srmacklem	NFSERR_IO,
529191783Srmacklem	NFSERR_MOVED,
530191783Srmacklem	NFSERR_NAMETOL,
531191783Srmacklem	NFSERR_NOFILEHANDLE,
532191783Srmacklem	NFSERR_NOSPC,
533191783Srmacklem	NFSERR_NOTDIR,
534191783Srmacklem	NFSERR_PERM,
535191783Srmacklem	NFSERR_RESOURCE,
536191783Srmacklem	NFSERR_ROFS,
537191783Srmacklem	NFSERR_SERVERFAULT,
538191783Srmacklem	NFSERR_STALE,
539191783Srmacklem	0,
540191783Srmacklem};
541191783Srmacklem
542191783Srmacklemstatic short nfsv4err_delegpurge[] = {
543191783Srmacklem	NFSERR_SERVERFAULT,
544191783Srmacklem	NFSERR_BADXDR,
545191783Srmacklem	NFSERR_NOTSUPP,
546191783Srmacklem	NFSERR_LEASEMOVED,
547191783Srmacklem	NFSERR_MOVED,
548191783Srmacklem	NFSERR_RESOURCE,
549191783Srmacklem	NFSERR_SERVERFAULT,
550191783Srmacklem	NFSERR_STALECLIENTID,
551191783Srmacklem	0,
552191783Srmacklem};
553191783Srmacklem
554191783Srmacklemstatic short nfsv4err_delegreturn[] = {
555191783Srmacklem	NFSERR_SERVERFAULT,
556191783Srmacklem	NFSERR_ADMINREVOKED,
557191783Srmacklem	NFSERR_BADSTATEID,
558191783Srmacklem	NFSERR_BADXDR,
559191783Srmacklem	NFSERR_EXPIRED,
560191783Srmacklem	NFSERR_INVAL,
561191783Srmacklem	NFSERR_LEASEMOVED,
562191783Srmacklem	NFSERR_MOVED,
563191783Srmacklem	NFSERR_NOFILEHANDLE,
564191783Srmacklem	NFSERR_NOTSUPP,
565191783Srmacklem	NFSERR_OLDSTATEID,
566191783Srmacklem	NFSERR_RESOURCE,
567191783Srmacklem	NFSERR_SERVERFAULT,
568191783Srmacklem	NFSERR_STALE,
569191783Srmacklem	NFSERR_STALESTATEID,
570191783Srmacklem	0,
571191783Srmacklem};
572191783Srmacklem
573191783Srmacklemstatic short nfsv4err_getattr[] = {
574191783Srmacklem	NFSERR_IO,
575191783Srmacklem	NFSERR_ACCES,
576191783Srmacklem	NFSERR_BADHANDLE,
577191783Srmacklem	NFSERR_BADXDR,
578191783Srmacklem	NFSERR_DELAY,
579191783Srmacklem	NFSERR_FHEXPIRED,
580191783Srmacklem	NFSERR_INVAL,
581191783Srmacklem	NFSERR_IO,
582191783Srmacklem	NFSERR_MOVED,
583191783Srmacklem	NFSERR_NOFILEHANDLE,
584191783Srmacklem	NFSERR_RESOURCE,
585191783Srmacklem	NFSERR_SERVERFAULT,
586191783Srmacklem	NFSERR_STALE,
587191783Srmacklem	0,
588191783Srmacklem};
589191783Srmacklem
590191783Srmacklemstatic short nfsv4err_getfh[] = {
591191783Srmacklem	NFSERR_BADHANDLE,
592191783Srmacklem	NFSERR_BADHANDLE,
593191783Srmacklem	NFSERR_FHEXPIRED,
594191783Srmacklem	NFSERR_MOVED,
595191783Srmacklem	NFSERR_NOFILEHANDLE,
596191783Srmacklem	NFSERR_RESOURCE,
597191783Srmacklem	NFSERR_SERVERFAULT,
598191783Srmacklem	NFSERR_STALE,
599191783Srmacklem	0,
600191783Srmacklem};
601191783Srmacklem
602191783Srmacklemstatic short nfsv4err_link[] = {
603191783Srmacklem	NFSERR_IO,
604191783Srmacklem	NFSERR_ACCES,
605191783Srmacklem	NFSERR_BADCHAR,
606191783Srmacklem	NFSERR_BADHANDLE,
607191783Srmacklem	NFSERR_BADNAME,
608191783Srmacklem	NFSERR_BADXDR,
609191783Srmacklem	NFSERR_DELAY,
610191783Srmacklem	NFSERR_DQUOT,
611191783Srmacklem	NFSERR_EXIST,
612191783Srmacklem	NFSERR_FHEXPIRED,
613191783Srmacklem	NFSERR_FILEOPEN,
614191783Srmacklem	NFSERR_INVAL,
615191783Srmacklem	NFSERR_IO,
616191783Srmacklem	NFSERR_ISDIR,
617191783Srmacklem	NFSERR_MLINK,
618191783Srmacklem	NFSERR_MOVED,
619191783Srmacklem	NFSERR_NAMETOL,
620191783Srmacklem	NFSERR_NOENT,
621191783Srmacklem	NFSERR_NOFILEHANDLE,
622191783Srmacklem	NFSERR_NOSPC,
623191783Srmacklem	NFSERR_NOTDIR,
624191783Srmacklem	NFSERR_NOTSUPP,
625191783Srmacklem	NFSERR_RESOURCE,
626191783Srmacklem	NFSERR_ROFS,
627191783Srmacklem	NFSERR_SERVERFAULT,
628191783Srmacklem	NFSERR_STALE,
629191783Srmacklem	NFSERR_WRONGSEC,
630191783Srmacklem	NFSERR_XDEV,
631191783Srmacklem	0,
632191783Srmacklem};
633191783Srmacklem
634191783Srmacklemstatic short nfsv4err_lock[] = {
635191783Srmacklem	NFSERR_SERVERFAULT,
636191783Srmacklem	NFSERR_ACCES,
637191783Srmacklem	NFSERR_ADMINREVOKED,
638191783Srmacklem	NFSERR_BADHANDLE,
639191783Srmacklem	NFSERR_BADRANGE,
640191783Srmacklem	NFSERR_BADSEQID,
641191783Srmacklem	NFSERR_BADSTATEID,
642191783Srmacklem	NFSERR_BADXDR,
643191783Srmacklem	NFSERR_DEADLOCK,
644191783Srmacklem	NFSERR_DELAY,
645191783Srmacklem	NFSERR_DENIED,
646191783Srmacklem	NFSERR_EXPIRED,
647191783Srmacklem	NFSERR_FHEXPIRED,
648191783Srmacklem	NFSERR_GRACE,
649191783Srmacklem	NFSERR_INVAL,
650191783Srmacklem	NFSERR_ISDIR,
651191783Srmacklem	NFSERR_LEASEMOVED,
652191783Srmacklem	NFSERR_LOCKNOTSUPP,
653191783Srmacklem	NFSERR_LOCKRANGE,
654191783Srmacklem	NFSERR_MOVED,
655191783Srmacklem	NFSERR_NOFILEHANDLE,
656191783Srmacklem	NFSERR_NOGRACE,
657191783Srmacklem	NFSERR_OLDSTATEID,
658191783Srmacklem	NFSERR_OPENMODE,
659191783Srmacklem	NFSERR_RECLAIMBAD,
660191783Srmacklem	NFSERR_RECLAIMCONFLICT,
661191783Srmacklem	NFSERR_RESOURCE,
662191783Srmacklem	NFSERR_SERVERFAULT,
663191783Srmacklem	NFSERR_STALE,
664191783Srmacklem	NFSERR_STALECLIENTID,
665191783Srmacklem	NFSERR_STALESTATEID,
666191783Srmacklem	0,
667191783Srmacklem};
668191783Srmacklem
669191783Srmacklemstatic short nfsv4err_lockt[] = {
670191783Srmacklem	NFSERR_SERVERFAULT,
671191783Srmacklem	NFSERR_ACCES,
672191783Srmacklem	NFSERR_BADHANDLE,
673191783Srmacklem	NFSERR_BADRANGE,
674191783Srmacklem	NFSERR_BADXDR,
675191783Srmacklem	NFSERR_DELAY,
676191783Srmacklem	NFSERR_DENIED,
677191783Srmacklem	NFSERR_FHEXPIRED,
678191783Srmacklem	NFSERR_GRACE,
679191783Srmacklem	NFSERR_INVAL,
680191783Srmacklem	NFSERR_ISDIR,
681191783Srmacklem	NFSERR_LEASEMOVED,
682191783Srmacklem	NFSERR_LOCKRANGE,
683191783Srmacklem	NFSERR_MOVED,
684191783Srmacklem	NFSERR_NOFILEHANDLE,
685191783Srmacklem	NFSERR_RESOURCE,
686191783Srmacklem	NFSERR_SERVERFAULT,
687191783Srmacklem	NFSERR_STALE,
688191783Srmacklem	NFSERR_STALECLIENTID,
689191783Srmacklem	0,
690191783Srmacklem};
691191783Srmacklem
692191783Srmacklemstatic short nfsv4err_locku[] = {
693191783Srmacklem	NFSERR_SERVERFAULT,
694191783Srmacklem	NFSERR_ACCES,
695191783Srmacklem	NFSERR_ADMINREVOKED,
696191783Srmacklem	NFSERR_BADHANDLE,
697191783Srmacklem	NFSERR_BADRANGE,
698191783Srmacklem	NFSERR_BADSEQID,
699191783Srmacklem	NFSERR_BADSTATEID,
700191783Srmacklem	NFSERR_BADXDR,
701191783Srmacklem	NFSERR_EXPIRED,
702191783Srmacklem	NFSERR_FHEXPIRED,
703191783Srmacklem	NFSERR_GRACE,
704191783Srmacklem	NFSERR_INVAL,
705191783Srmacklem	NFSERR_ISDIR,
706191783Srmacklem	NFSERR_LEASEMOVED,
707191783Srmacklem	NFSERR_LOCKRANGE,
708191783Srmacklem	NFSERR_MOVED,
709191783Srmacklem	NFSERR_NOFILEHANDLE,
710191783Srmacklem	NFSERR_OLDSTATEID,
711191783Srmacklem	NFSERR_RESOURCE,
712191783Srmacklem	NFSERR_SERVERFAULT,
713191783Srmacklem	NFSERR_STALE,
714191783Srmacklem	NFSERR_STALESTATEID,
715191783Srmacklem	0,
716191783Srmacklem};
717191783Srmacklem
718191783Srmacklemstatic short nfsv4err_lookup[] = {
719191783Srmacklem	NFSERR_IO,
720191783Srmacklem	NFSERR_ACCES,
721191783Srmacklem	NFSERR_BADCHAR,
722191783Srmacklem	NFSERR_BADHANDLE,
723191783Srmacklem	NFSERR_BADNAME,
724191783Srmacklem	NFSERR_BADXDR,
725191783Srmacklem	NFSERR_FHEXPIRED,
726191783Srmacklem	NFSERR_INVAL,
727191783Srmacklem	NFSERR_IO,
728191783Srmacklem	NFSERR_MOVED,
729191783Srmacklem	NFSERR_NAMETOL,
730191783Srmacklem	NFSERR_NOENT,
731191783Srmacklem	NFSERR_NOFILEHANDLE,
732191783Srmacklem	NFSERR_NOTDIR,
733191783Srmacklem	NFSERR_RESOURCE,
734191783Srmacklem	NFSERR_SERVERFAULT,
735191783Srmacklem	NFSERR_STALE,
736191783Srmacklem	NFSERR_SYMLINK,
737191783Srmacklem	NFSERR_WRONGSEC,
738191783Srmacklem	0,
739191783Srmacklem};
740191783Srmacklem
741191783Srmacklemstatic short nfsv4err_lookupp[] = {
742191783Srmacklem	NFSERR_IO,
743191783Srmacklem	NFSERR_ACCES,
744191783Srmacklem	NFSERR_BADHANDLE,
745191783Srmacklem	NFSERR_FHEXPIRED,
746191783Srmacklem	NFSERR_IO,
747191783Srmacklem	NFSERR_MOVED,
748191783Srmacklem	NFSERR_NOENT,
749191783Srmacklem	NFSERR_NOFILEHANDLE,
750191783Srmacklem	NFSERR_NOTDIR,
751191783Srmacklem	NFSERR_RESOURCE,
752191783Srmacklem	NFSERR_SERVERFAULT,
753191783Srmacklem	NFSERR_STALE,
754191783Srmacklem	0,
755191783Srmacklem};
756191783Srmacklem
757191783Srmacklemstatic short nfsv4err_nverify[] = {
758191783Srmacklem	NFSERR_IO,
759191783Srmacklem	NFSERR_ACCES,
760191783Srmacklem	NFSERR_ATTRNOTSUPP,
761191783Srmacklem	NFSERR_BADCHAR,
762191783Srmacklem	NFSERR_BADHANDLE,
763191783Srmacklem	NFSERR_BADXDR,
764191783Srmacklem	NFSERR_DELAY,
765191783Srmacklem	NFSERR_FHEXPIRED,
766191783Srmacklem	NFSERR_INVAL,
767191783Srmacklem	NFSERR_IO,
768191783Srmacklem	NFSERR_MOVED,
769191783Srmacklem	NFSERR_NOFILEHANDLE,
770191783Srmacklem	NFSERR_RESOURCE,
771191783Srmacklem	NFSERR_SAME,
772191783Srmacklem	NFSERR_SERVERFAULT,
773191783Srmacklem	NFSERR_STALE,
774191783Srmacklem	0,
775191783Srmacklem};
776191783Srmacklem
777191783Srmacklemstatic short nfsv4err_open[] = {
778191783Srmacklem	NFSERR_IO,
779191783Srmacklem	NFSERR_ACCES,
780191783Srmacklem	NFSERR_ADMINREVOKED,
781191783Srmacklem	NFSERR_ATTRNOTSUPP,
782191783Srmacklem	NFSERR_BADCHAR,
783191783Srmacklem	NFSERR_BADHANDLE,
784191783Srmacklem	NFSERR_BADNAME,
785191783Srmacklem	NFSERR_BADOWNER,
786191783Srmacklem	NFSERR_BADSEQID,
787191783Srmacklem	NFSERR_BADXDR,
788191783Srmacklem	NFSERR_DELAY,
789191783Srmacklem	NFSERR_DQUOT,
790191783Srmacklem	NFSERR_EXIST,
791191783Srmacklem	NFSERR_EXPIRED,
792191783Srmacklem	NFSERR_FHEXPIRED,
793191783Srmacklem	NFSERR_GRACE,
794191783Srmacklem	NFSERR_IO,
795191783Srmacklem	NFSERR_INVAL,
796191783Srmacklem	NFSERR_ISDIR,
797191783Srmacklem	NFSERR_LEASEMOVED,
798191783Srmacklem	NFSERR_MOVED,
799191783Srmacklem	NFSERR_NAMETOL,
800191783Srmacklem	NFSERR_NOENT,
801191783Srmacklem	NFSERR_NOFILEHANDLE,
802191783Srmacklem	NFSERR_NOGRACE,
803191783Srmacklem	NFSERR_NOSPC,
804191783Srmacklem	NFSERR_NOTDIR,
805191783Srmacklem	NFSERR_NOTSUPP,
806191783Srmacklem	NFSERR_PERM,
807191783Srmacklem	NFSERR_RECLAIMBAD,
808191783Srmacklem	NFSERR_RECLAIMCONFLICT,
809191783Srmacklem	NFSERR_RESOURCE,
810191783Srmacklem	NFSERR_ROFS,
811191783Srmacklem	NFSERR_SERVERFAULT,
812191783Srmacklem	NFSERR_SHAREDENIED,
813191783Srmacklem	NFSERR_STALE,
814191783Srmacklem	NFSERR_STALECLIENTID,
815191783Srmacklem	NFSERR_SYMLINK,
816191783Srmacklem	NFSERR_WRONGSEC,
817191783Srmacklem	0,
818191783Srmacklem};
819191783Srmacklem
820191783Srmacklemstatic short nfsv4err_openattr[] = {
821191783Srmacklem	NFSERR_IO,
822191783Srmacklem	NFSERR_ACCES,
823191783Srmacklem	NFSERR_BADHANDLE,
824191783Srmacklem	NFSERR_BADXDR,
825191783Srmacklem	NFSERR_DELAY,
826191783Srmacklem	NFSERR_DQUOT,
827191783Srmacklem	NFSERR_FHEXPIRED,
828191783Srmacklem	NFSERR_IO,
829191783Srmacklem	NFSERR_MOVED,
830191783Srmacklem	NFSERR_NOENT,
831191783Srmacklem	NFSERR_NOFILEHANDLE,
832191783Srmacklem	NFSERR_NOSPC,
833191783Srmacklem	NFSERR_NOTSUPP,
834191783Srmacklem	NFSERR_RESOURCE,
835191783Srmacklem	NFSERR_ROFS,
836191783Srmacklem	NFSERR_SERVERFAULT,
837191783Srmacklem	NFSERR_STALE,
838191783Srmacklem	0,
839191783Srmacklem};
840191783Srmacklem
841191783Srmacklemstatic short nfsv4err_openconfirm[] = {
842191783Srmacklem	NFSERR_SERVERFAULT,
843191783Srmacklem	NFSERR_ADMINREVOKED,
844191783Srmacklem	NFSERR_BADHANDLE,
845191783Srmacklem	NFSERR_BADSEQID,
846191783Srmacklem	NFSERR_BADSTATEID,
847191783Srmacklem	NFSERR_BADXDR,
848191783Srmacklem	NFSERR_EXPIRED,
849191783Srmacklem	NFSERR_FHEXPIRED,
850191783Srmacklem	NFSERR_INVAL,
851191783Srmacklem	NFSERR_ISDIR,
852191783Srmacklem	NFSERR_MOVED,
853191783Srmacklem	NFSERR_NOFILEHANDLE,
854191783Srmacklem	NFSERR_OLDSTATEID,
855191783Srmacklem	NFSERR_RESOURCE,
856191783Srmacklem	NFSERR_SERVERFAULT,
857191783Srmacklem	NFSERR_STALE,
858191783Srmacklem	NFSERR_STALESTATEID,
859191783Srmacklem	0,
860191783Srmacklem};
861191783Srmacklem
862191783Srmacklemstatic short nfsv4err_opendowngrade[] = {
863191783Srmacklem	NFSERR_SERVERFAULT,
864191783Srmacklem	NFSERR_ADMINREVOKED,
865191783Srmacklem	NFSERR_BADHANDLE,
866191783Srmacklem	NFSERR_BADSEQID,
867191783Srmacklem	NFSERR_BADSTATEID,
868191783Srmacklem	NFSERR_BADXDR,
869191783Srmacklem	NFSERR_EXPIRED,
870191783Srmacklem	NFSERR_FHEXPIRED,
871191783Srmacklem	NFSERR_INVAL,
872191783Srmacklem	NFSERR_MOVED,
873191783Srmacklem	NFSERR_NOFILEHANDLE,
874191783Srmacklem	NFSERR_OLDSTATEID,
875191783Srmacklem	NFSERR_RESOURCE,
876191783Srmacklem	NFSERR_SERVERFAULT,
877191783Srmacklem	NFSERR_STALE,
878191783Srmacklem	NFSERR_STALESTATEID,
879191783Srmacklem	0,
880191783Srmacklem};
881191783Srmacklem
882191783Srmacklemstatic short nfsv4err_putfh[] = {
883191783Srmacklem	NFSERR_SERVERFAULT,
884191783Srmacklem	NFSERR_BADHANDLE,
885191783Srmacklem	NFSERR_BADXDR,
886191783Srmacklem	NFSERR_FHEXPIRED,
887191783Srmacklem	NFSERR_MOVED,
888191783Srmacklem	NFSERR_RESOURCE,
889191783Srmacklem	NFSERR_SERVERFAULT,
890191783Srmacklem	NFSERR_STALE,
891191783Srmacklem	NFSERR_WRONGSEC,
892191783Srmacklem	0,
893191783Srmacklem};
894191783Srmacklem
895191783Srmacklemstatic short nfsv4err_putpubfh[] = {
896191783Srmacklem	NFSERR_SERVERFAULT,
897191783Srmacklem	NFSERR_RESOURCE,
898191783Srmacklem	NFSERR_SERVERFAULT,
899191783Srmacklem	NFSERR_WRONGSEC,
900191783Srmacklem	0,
901191783Srmacklem};
902191783Srmacklem
903191783Srmacklemstatic short nfsv4err_putrootfh[] = {
904191783Srmacklem	NFSERR_SERVERFAULT,
905191783Srmacklem	NFSERR_RESOURCE,
906191783Srmacklem	NFSERR_SERVERFAULT,
907191783Srmacklem	NFSERR_WRONGSEC,
908191783Srmacklem	0,
909191783Srmacklem};
910191783Srmacklem
911191783Srmacklemstatic short nfsv4err_read[] = {
912191783Srmacklem	NFSERR_IO,
913191783Srmacklem	NFSERR_ACCES,
914191783Srmacklem	NFSERR_ADMINREVOKED,
915191783Srmacklem	NFSERR_BADHANDLE,
916191783Srmacklem	NFSERR_BADSTATEID,
917191783Srmacklem	NFSERR_BADXDR,
918191783Srmacklem	NFSERR_DELAY,
919191783Srmacklem	NFSERR_EXPIRED,
920191783Srmacklem	NFSERR_FHEXPIRED,
921191783Srmacklem	NFSERR_GRACE,
922191783Srmacklem	NFSERR_IO,
923191783Srmacklem	NFSERR_INVAL,
924191783Srmacklem	NFSERR_ISDIR,
925191783Srmacklem	NFSERR_LEASEMOVED,
926191783Srmacklem	NFSERR_LOCKED,
927191783Srmacklem	NFSERR_MOVED,
928191783Srmacklem	NFSERR_NOFILEHANDLE,
929191783Srmacklem	NFSERR_NXIO,
930191783Srmacklem	NFSERR_OLDSTATEID,
931191783Srmacklem	NFSERR_OPENMODE,
932191783Srmacklem	NFSERR_RESOURCE,
933191783Srmacklem	NFSERR_SERVERFAULT,
934191783Srmacklem	NFSERR_STALE,
935191783Srmacklem	NFSERR_STALESTATEID,
936191783Srmacklem	0,
937191783Srmacklem};
938191783Srmacklem
939191783Srmacklemstatic short nfsv4err_readdir[] = {
940191783Srmacklem	NFSERR_IO,
941191783Srmacklem	NFSERR_ACCES,
942191783Srmacklem	NFSERR_BADHANDLE,
943191783Srmacklem	NFSERR_BAD_COOKIE,
944191783Srmacklem	NFSERR_BADXDR,
945191783Srmacklem	NFSERR_DELAY,
946191783Srmacklem	NFSERR_FHEXPIRED,
947191783Srmacklem	NFSERR_INVAL,
948191783Srmacklem	NFSERR_IO,
949191783Srmacklem	NFSERR_MOVED,
950191783Srmacklem	NFSERR_NOFILEHANDLE,
951191783Srmacklem	NFSERR_NOTDIR,
952191783Srmacklem	NFSERR_NOTSAME,
953191783Srmacklem	NFSERR_RESOURCE,
954191783Srmacklem	NFSERR_SERVERFAULT,
955191783Srmacklem	NFSERR_STALE,
956191783Srmacklem	NFSERR_TOOSMALL,
957191783Srmacklem	0,
958191783Srmacklem};
959191783Srmacklem
960191783Srmacklemstatic short nfsv4err_readlink[] = {
961191783Srmacklem	NFSERR_IO,
962191783Srmacklem	NFSERR_ACCES,
963191783Srmacklem	NFSERR_BADHANDLE,
964191783Srmacklem	NFSERR_DELAY,
965191783Srmacklem	NFSERR_FHEXPIRED,
966191783Srmacklem	NFSERR_INVAL,
967191783Srmacklem	NFSERR_IO,
968191783Srmacklem	NFSERR_ISDIR,
969191783Srmacklem	NFSERR_MOVED,
970191783Srmacklem	NFSERR_NOFILEHANDLE,
971191783Srmacklem	NFSERR_NOTSUPP,
972191783Srmacklem	NFSERR_RESOURCE,
973191783Srmacklem	NFSERR_SERVERFAULT,
974191783Srmacklem	NFSERR_STALE,
975191783Srmacklem	0,
976191783Srmacklem};
977191783Srmacklem
978191783Srmacklemstatic short nfsv4err_remove[] = {
979191783Srmacklem	NFSERR_IO,
980191783Srmacklem	NFSERR_ACCES,
981191783Srmacklem	NFSERR_BADCHAR,
982191783Srmacklem	NFSERR_BADHANDLE,
983191783Srmacklem	NFSERR_BADNAME,
984191783Srmacklem	NFSERR_BADXDR,
985191783Srmacklem	NFSERR_DELAY,
986191783Srmacklem	NFSERR_FHEXPIRED,
987191783Srmacklem	NFSERR_FILEOPEN,
988191783Srmacklem	NFSERR_INVAL,
989191783Srmacklem	NFSERR_IO,
990191783Srmacklem	NFSERR_MOVED,
991191783Srmacklem	NFSERR_NAMETOL,
992191783Srmacklem	NFSERR_NOENT,
993191783Srmacklem	NFSERR_NOFILEHANDLE,
994191783Srmacklem	NFSERR_NOTDIR,
995191783Srmacklem	NFSERR_NOTEMPTY,
996191783Srmacklem	NFSERR_RESOURCE,
997191783Srmacklem	NFSERR_ROFS,
998191783Srmacklem	NFSERR_SERVERFAULT,
999191783Srmacklem	NFSERR_STALE,
1000191783Srmacklem	0,
1001191783Srmacklem};
1002191783Srmacklem
1003191783Srmacklemstatic short nfsv4err_rename[] = {
1004191783Srmacklem	NFSERR_IO,
1005191783Srmacklem	NFSERR_ACCES,
1006191783Srmacklem	NFSERR_BADCHAR,
1007191783Srmacklem	NFSERR_BADHANDLE,
1008191783Srmacklem	NFSERR_BADNAME,
1009191783Srmacklem	NFSERR_BADXDR,
1010191783Srmacklem	NFSERR_DELAY,
1011191783Srmacklem	NFSERR_DQUOT,
1012191783Srmacklem	NFSERR_EXIST,
1013191783Srmacklem	NFSERR_FHEXPIRED,
1014191783Srmacklem	NFSERR_FILEOPEN,
1015191783Srmacklem	NFSERR_INVAL,
1016191783Srmacklem	NFSERR_IO,
1017191783Srmacklem	NFSERR_MOVED,
1018191783Srmacklem	NFSERR_NAMETOL,
1019191783Srmacklem	NFSERR_NOENT,
1020191783Srmacklem	NFSERR_NOFILEHANDLE,
1021191783Srmacklem	NFSERR_NOSPC,
1022191783Srmacklem	NFSERR_NOTDIR,
1023191783Srmacklem	NFSERR_NOTEMPTY,
1024191783Srmacklem	NFSERR_RESOURCE,
1025191783Srmacklem	NFSERR_ROFS,
1026191783Srmacklem	NFSERR_SERVERFAULT,
1027191783Srmacklem	NFSERR_STALE,
1028191783Srmacklem	NFSERR_WRONGSEC,
1029191783Srmacklem	NFSERR_XDEV,
1030191783Srmacklem	0,
1031191783Srmacklem};
1032191783Srmacklem
1033191783Srmacklemstatic short nfsv4err_renew[] = {
1034191783Srmacklem	NFSERR_SERVERFAULT,
1035191783Srmacklem	NFSERR_ACCES,
1036191783Srmacklem	NFSERR_ADMINREVOKED,
1037191783Srmacklem	NFSERR_BADXDR,
1038191783Srmacklem	NFSERR_CBPATHDOWN,
1039191783Srmacklem	NFSERR_EXPIRED,
1040191783Srmacklem	NFSERR_LEASEMOVED,
1041191783Srmacklem	NFSERR_RESOURCE,
1042191783Srmacklem	NFSERR_SERVERFAULT,
1043191783Srmacklem	NFSERR_STALECLIENTID,
1044191783Srmacklem	0,
1045191783Srmacklem};
1046191783Srmacklem
1047191783Srmacklemstatic short nfsv4err_restorefh[] = {
1048191783Srmacklem	NFSERR_SERVERFAULT,
1049191783Srmacklem	NFSERR_BADHANDLE,
1050191783Srmacklem	NFSERR_FHEXPIRED,
1051191783Srmacklem	NFSERR_MOVED,
1052191783Srmacklem	NFSERR_RESOURCE,
1053191783Srmacklem	NFSERR_RESTOREFH,
1054191783Srmacklem	NFSERR_SERVERFAULT,
1055191783Srmacklem	NFSERR_STALE,
1056191783Srmacklem	NFSERR_WRONGSEC,
1057191783Srmacklem	0,
1058191783Srmacklem};
1059191783Srmacklem
1060191783Srmacklemstatic short nfsv4err_savefh[] = {
1061191783Srmacklem	NFSERR_SERVERFAULT,
1062191783Srmacklem	NFSERR_BADHANDLE,
1063191783Srmacklem	NFSERR_FHEXPIRED,
1064191783Srmacklem	NFSERR_MOVED,
1065191783Srmacklem	NFSERR_NOFILEHANDLE,
1066191783Srmacklem	NFSERR_RESOURCE,
1067191783Srmacklem	NFSERR_SERVERFAULT,
1068191783Srmacklem	NFSERR_STALE,
1069191783Srmacklem	0,
1070191783Srmacklem};
1071191783Srmacklem
1072191783Srmacklemstatic short nfsv4err_secinfo[] = {
1073191783Srmacklem	NFSERR_SERVERFAULT,
1074191783Srmacklem	NFSERR_ACCES,
1075191783Srmacklem	NFSERR_BADCHAR,
1076191783Srmacklem	NFSERR_BADHANDLE,
1077191783Srmacklem	NFSERR_BADNAME,
1078191783Srmacklem	NFSERR_BADXDR,
1079191783Srmacklem	NFSERR_FHEXPIRED,
1080191783Srmacklem	NFSERR_INVAL,
1081191783Srmacklem	NFSERR_MOVED,
1082191783Srmacklem	NFSERR_NAMETOL,
1083191783Srmacklem	NFSERR_NOENT,
1084191783Srmacklem	NFSERR_NOFILEHANDLE,
1085191783Srmacklem	NFSERR_NOTDIR,
1086191783Srmacklem	NFSERR_RESOURCE,
1087191783Srmacklem	NFSERR_SERVERFAULT,
1088191783Srmacklem	NFSERR_STALE,
1089191783Srmacklem	0,
1090191783Srmacklem};
1091191783Srmacklem
1092191783Srmacklemstatic short nfsv4err_setattr[] = {
1093191783Srmacklem	NFSERR_IO,
1094191783Srmacklem	NFSERR_ACCES,
1095191783Srmacklem	NFSERR_ADMINREVOKED,
1096191783Srmacklem	NFSERR_ATTRNOTSUPP,
1097191783Srmacklem	NFSERR_BADCHAR,
1098191783Srmacklem	NFSERR_BADHANDLE,
1099191783Srmacklem	NFSERR_BADOWNER,
1100191783Srmacklem	NFSERR_BADSTATEID,
1101191783Srmacklem	NFSERR_BADXDR,
1102191783Srmacklem	NFSERR_DELAY,
1103191783Srmacklem	NFSERR_DQUOT,
1104191783Srmacklem	NFSERR_EXPIRED,
1105191783Srmacklem	NFSERR_FBIG,
1106191783Srmacklem	NFSERR_FHEXPIRED,
1107191783Srmacklem	NFSERR_GRACE,
1108191783Srmacklem	NFSERR_INVAL,
1109191783Srmacklem	NFSERR_IO,
1110191783Srmacklem	NFSERR_ISDIR,
1111191783Srmacklem	NFSERR_LOCKED,
1112191783Srmacklem	NFSERR_MOVED,
1113191783Srmacklem	NFSERR_NOFILEHANDLE,
1114191783Srmacklem	NFSERR_NOSPC,
1115191783Srmacklem	NFSERR_OLDSTATEID,
1116191783Srmacklem	NFSERR_OPENMODE,
1117191783Srmacklem	NFSERR_PERM,
1118191783Srmacklem	NFSERR_RESOURCE,
1119191783Srmacklem	NFSERR_ROFS,
1120191783Srmacklem	NFSERR_SERVERFAULT,
1121191783Srmacklem	NFSERR_STALE,
1122191783Srmacklem	NFSERR_STALESTATEID,
1123191783Srmacklem	0,
1124191783Srmacklem};
1125191783Srmacklem
1126191783Srmacklemstatic short nfsv4err_setclientid[] = {
1127191783Srmacklem	NFSERR_SERVERFAULT,
1128191783Srmacklem	NFSERR_BADXDR,
1129191783Srmacklem	NFSERR_CLIDINUSE,
1130191783Srmacklem	NFSERR_INVAL,
1131191783Srmacklem	NFSERR_RESOURCE,
1132191783Srmacklem	NFSERR_SERVERFAULT,
1133191783Srmacklem	0,
1134191783Srmacklem};
1135191783Srmacklem
1136191783Srmacklemstatic short nfsv4err_setclientidconfirm[] = {
1137191783Srmacklem	NFSERR_SERVERFAULT,
1138191783Srmacklem	NFSERR_BADXDR,
1139191783Srmacklem	NFSERR_CLIDINUSE,
1140191783Srmacklem	NFSERR_RESOURCE,
1141191783Srmacklem	NFSERR_SERVERFAULT,
1142191783Srmacklem	NFSERR_STALECLIENTID,
1143191783Srmacklem	0,
1144191783Srmacklem};
1145191783Srmacklem
1146191783Srmacklemstatic short nfsv4err_verify[] = {
1147191783Srmacklem	NFSERR_SERVERFAULT,
1148191783Srmacklem	NFSERR_ACCES,
1149191783Srmacklem	NFSERR_ATTRNOTSUPP,
1150191783Srmacklem	NFSERR_BADCHAR,
1151191783Srmacklem	NFSERR_BADHANDLE,
1152191783Srmacklem	NFSERR_BADXDR,
1153191783Srmacklem	NFSERR_DELAY,
1154191783Srmacklem	NFSERR_FHEXPIRED,
1155191783Srmacklem	NFSERR_INVAL,
1156191783Srmacklem	NFSERR_MOVED,
1157191783Srmacklem	NFSERR_NOFILEHANDLE,
1158191783Srmacklem	NFSERR_NOTSAME,
1159191783Srmacklem	NFSERR_RESOURCE,
1160191783Srmacklem	NFSERR_SERVERFAULT,
1161191783Srmacklem	NFSERR_STALE,
1162191783Srmacklem	0,
1163191783Srmacklem};
1164191783Srmacklem
1165191783Srmacklemstatic short nfsv4err_write[] = {
1166191783Srmacklem	NFSERR_IO,
1167191783Srmacklem	NFSERR_ACCES,
1168191783Srmacklem	NFSERR_ADMINREVOKED,
1169191783Srmacklem	NFSERR_BADHANDLE,
1170191783Srmacklem	NFSERR_BADSTATEID,
1171191783Srmacklem	NFSERR_BADXDR,
1172191783Srmacklem	NFSERR_DELAY,
1173191783Srmacklem	NFSERR_DQUOT,
1174191783Srmacklem	NFSERR_EXPIRED,
1175191783Srmacklem	NFSERR_FBIG,
1176191783Srmacklem	NFSERR_FHEXPIRED,
1177191783Srmacklem	NFSERR_GRACE,
1178191783Srmacklem	NFSERR_INVAL,
1179191783Srmacklem	NFSERR_IO,
1180191783Srmacklem	NFSERR_ISDIR,
1181191783Srmacklem	NFSERR_LEASEMOVED,
1182191783Srmacklem	NFSERR_LOCKED,
1183191783Srmacklem	NFSERR_MOVED,
1184191783Srmacklem	NFSERR_NOFILEHANDLE,
1185191783Srmacklem	NFSERR_NOSPC,
1186191783Srmacklem	NFSERR_NXIO,
1187191783Srmacklem	NFSERR_OLDSTATEID,
1188191783Srmacklem	NFSERR_OPENMODE,
1189191783Srmacklem	NFSERR_RESOURCE,
1190191783Srmacklem	NFSERR_ROFS,
1191191783Srmacklem	NFSERR_SERVERFAULT,
1192191783Srmacklem	NFSERR_STALE,
1193191783Srmacklem	NFSERR_STALESTATEID,
1194191783Srmacklem	0,
1195191783Srmacklem};
1196191783Srmacklem
1197191783Srmacklemstatic short nfsv4err_releaselockowner[] = {
1198191783Srmacklem	NFSERR_SERVERFAULT,
1199191783Srmacklem	NFSERR_ADMINREVOKED,
1200191783Srmacklem	NFSERR_BADXDR,
1201191783Srmacklem	NFSERR_EXPIRED,
1202191783Srmacklem	NFSERR_LEASEMOVED,
1203191783Srmacklem	NFSERR_LOCKSHELD,
1204191783Srmacklem	NFSERR_RESOURCE,
1205191783Srmacklem	NFSERR_SERVERFAULT,
1206191783Srmacklem	NFSERR_STALECLIENTID,
1207191783Srmacklem	0,
1208191783Srmacklem};
1209191783Srmacklem
1210191783Srmacklemstatic short *nfsrv_v4errmap[] = {
1211191783Srmacklem	nfsv4err_null,
1212191783Srmacklem	nfsv4err_null,
1213191783Srmacklem	nfsv4err_null,
1214191783Srmacklem	nfsv4err_access,
1215191783Srmacklem	nfsv4err_close,
1216191783Srmacklem	nfsv4err_commit,
1217191783Srmacklem	nfsv4err_create,
1218191783Srmacklem	nfsv4err_delegpurge,
1219191783Srmacklem	nfsv4err_delegreturn,
1220191783Srmacklem	nfsv4err_getattr,
1221191783Srmacklem	nfsv4err_getfh,
1222191783Srmacklem	nfsv4err_link,
1223191783Srmacklem	nfsv4err_lock,
1224191783Srmacklem	nfsv4err_lockt,
1225191783Srmacklem	nfsv4err_locku,
1226191783Srmacklem	nfsv4err_lookup,
1227191783Srmacklem	nfsv4err_lookupp,
1228191783Srmacklem	nfsv4err_nverify,
1229191783Srmacklem	nfsv4err_open,
1230191783Srmacklem	nfsv4err_openattr,
1231191783Srmacklem	nfsv4err_openconfirm,
1232191783Srmacklem	nfsv4err_opendowngrade,
1233191783Srmacklem	nfsv4err_putfh,
1234191783Srmacklem	nfsv4err_putpubfh,
1235191783Srmacklem	nfsv4err_putrootfh,
1236191783Srmacklem	nfsv4err_read,
1237191783Srmacklem	nfsv4err_readdir,
1238191783Srmacklem	nfsv4err_readlink,
1239191783Srmacklem	nfsv4err_remove,
1240191783Srmacklem	nfsv4err_rename,
1241191783Srmacklem	nfsv4err_renew,
1242191783Srmacklem	nfsv4err_restorefh,
1243191783Srmacklem	nfsv4err_savefh,
1244191783Srmacklem	nfsv4err_secinfo,
1245191783Srmacklem	nfsv4err_setattr,
1246191783Srmacklem	nfsv4err_setclientid,
1247191783Srmacklem	nfsv4err_setclientidconfirm,
1248191783Srmacklem	nfsv4err_verify,
1249191783Srmacklem	nfsv4err_write,
1250191783Srmacklem	nfsv4err_releaselockowner,
1251191783Srmacklem};
1252191783Srmacklem
1253191783Srmacklem/*
1254191783Srmacklem * A fiddled version of m_adj() that ensures null fill to a long
1255191783Srmacklem * boundary and only trims off the back end
1256191783Srmacklem */
1257191783SrmacklemAPPLESTATIC void
1258191783Srmacklemnfsrv_adj(mbuf_t mp, int len, int nul)
1259191783Srmacklem{
1260191783Srmacklem	mbuf_t m;
1261191783Srmacklem	int count, i;
1262191783Srmacklem	char *cp;
1263191783Srmacklem
1264191783Srmacklem	/*
1265191783Srmacklem	 * Trim from tail.  Scan the mbuf chain,
1266191783Srmacklem	 * calculating its length and finding the last mbuf.
1267191783Srmacklem	 * If the adjustment only affects this mbuf, then just
1268191783Srmacklem	 * adjust and return.  Otherwise, rescan and truncate
1269191783Srmacklem	 * after the remaining size.
1270191783Srmacklem	 */
1271191783Srmacklem	count = 0;
1272191783Srmacklem	m = mp;
1273191783Srmacklem	for (;;) {
1274191783Srmacklem		count += mbuf_len(m);
1275191783Srmacklem		if (mbuf_next(m) == NULL)
1276191783Srmacklem			break;
1277191783Srmacklem		m = mbuf_next(m);
1278191783Srmacklem	}
1279191783Srmacklem	if (mbuf_len(m) > len) {
1280191783Srmacklem		mbuf_setlen(m, mbuf_len(m) - len);
1281191783Srmacklem		if (nul > 0) {
1282191783Srmacklem			cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1283191783Srmacklem			for (i = 0; i < nul; i++)
1284191783Srmacklem				*cp++ = '\0';
1285191783Srmacklem		}
1286191783Srmacklem		return;
1287191783Srmacklem	}
1288191783Srmacklem	count -= len;
1289191783Srmacklem	if (count < 0)
1290191783Srmacklem		count = 0;
1291191783Srmacklem	/*
1292191783Srmacklem	 * Correct length for chain is "count".
1293191783Srmacklem	 * Find the mbuf with last data, adjust its length,
1294191783Srmacklem	 * and toss data from remaining mbufs on chain.
1295191783Srmacklem	 */
1296191783Srmacklem	for (m = mp; m; m = mbuf_next(m)) {
1297191783Srmacklem		if (mbuf_len(m) >= count) {
1298191783Srmacklem			mbuf_setlen(m, count);
1299191783Srmacklem			if (nul > 0) {
1300191783Srmacklem				cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1301191783Srmacklem				for (i = 0; i < nul; i++)
1302191783Srmacklem					*cp++ = '\0';
1303191783Srmacklem			}
1304191783Srmacklem			break;
1305191783Srmacklem		}
1306191783Srmacklem		count -= mbuf_len(m);
1307191783Srmacklem	}
1308191783Srmacklem	for (m = mbuf_next(m); m; m = mbuf_next(m))
1309191783Srmacklem		mbuf_setlen(m, 0);
1310191783Srmacklem}
1311191783Srmacklem
1312191783Srmacklem/*
1313191783Srmacklem * Make these functions instead of macros, so that the kernel text size
1314191783Srmacklem * doesn't get too big...
1315191783Srmacklem */
1316191783SrmacklemAPPLESTATIC void
1317191783Srmacklemnfsrv_wcc(struct nfsrv_descript *nd, int before_ret,
1318191783Srmacklem    struct nfsvattr *before_nvap, int after_ret, struct nfsvattr *after_nvap)
1319191783Srmacklem{
1320191783Srmacklem	u_int32_t *tl;
1321191783Srmacklem
1322191783Srmacklem	if (before_ret) {
1323191783Srmacklem		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1324191783Srmacklem		*tl = newnfs_false;
1325191783Srmacklem	} else {
1326191783Srmacklem		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1327191783Srmacklem		*tl++ = newnfs_true;
1328191783Srmacklem		txdr_hyper(before_nvap->na_size, tl);
1329191783Srmacklem		tl += 2;
1330191783Srmacklem		txdr_nfsv3time(&(before_nvap->na_mtime), tl);
1331191783Srmacklem		tl += 2;
1332191783Srmacklem		txdr_nfsv3time(&(before_nvap->na_ctime), tl);
1333191783Srmacklem	}
1334191783Srmacklem	nfsrv_postopattr(nd, after_ret, after_nvap);
1335191783Srmacklem}
1336191783Srmacklem
1337191783SrmacklemAPPLESTATIC void
1338191783Srmacklemnfsrv_postopattr(struct nfsrv_descript *nd, int after_ret,
1339191783Srmacklem    struct nfsvattr *after_nvap)
1340191783Srmacklem{
1341191783Srmacklem	u_int32_t *tl;
1342191783Srmacklem
1343191783Srmacklem	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1344191783Srmacklem	if (after_ret)
1345191783Srmacklem		*tl = newnfs_false;
1346191783Srmacklem	else {
1347191783Srmacklem		*tl = newnfs_true;
1348191783Srmacklem		nfsrv_fillattr(nd, after_nvap);
1349191783Srmacklem	}
1350191783Srmacklem}
1351191783Srmacklem
1352191783Srmacklem/*
1353191783Srmacklem * Fill in file attributes for V2 and 3. For V4, call a separate
1354191783Srmacklem * routine that sifts through all the attribute bits.
1355191783Srmacklem */
1356191783SrmacklemAPPLESTATIC void
1357191783Srmacklemnfsrv_fillattr(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1358191783Srmacklem{
1359191783Srmacklem	struct nfs_fattr *fp;
1360191783Srmacklem	int fattr_size;
1361191783Srmacklem
1362191783Srmacklem	/*
1363191783Srmacklem	 * Build space for the attribute structure.
1364191783Srmacklem	 */
1365191783Srmacklem	if (nd->nd_flag & ND_NFSV3)
1366191783Srmacklem		fattr_size = NFSX_V3FATTR;
1367191783Srmacklem	else
1368191783Srmacklem		fattr_size = NFSX_V2FATTR;
1369191783Srmacklem	NFSM_BUILD(fp, struct nfs_fattr *, fattr_size);
1370191783Srmacklem
1371191783Srmacklem	/*
1372191783Srmacklem	 * Now just fill it all in.
1373191783Srmacklem	 */
1374191783Srmacklem	fp->fa_nlink = txdr_unsigned(nvap->na_nlink);
1375191783Srmacklem	fp->fa_uid = txdr_unsigned(nvap->na_uid);
1376191783Srmacklem	fp->fa_gid = txdr_unsigned(nvap->na_gid);
1377191783Srmacklem	if (nd->nd_flag & ND_NFSV3) {
1378191783Srmacklem		fp->fa_type = vtonfsv34_type(nvap->na_type);
1379191783Srmacklem		fp->fa_mode = vtonfsv34_mode(nvap->na_mode);
1380191783Srmacklem		txdr_hyper(nvap->na_size, &fp->fa3_size);
1381191783Srmacklem		txdr_hyper(nvap->na_bytes, &fp->fa3_used);
1382191783Srmacklem		fp->fa3_rdev.specdata1 = txdr_unsigned(NFSMAJOR(nvap->na_rdev));
1383191783Srmacklem		fp->fa3_rdev.specdata2 = txdr_unsigned(NFSMINOR(nvap->na_rdev));
1384191783Srmacklem		fp->fa3_fsid.nfsuquad[0] = 0;
1385191783Srmacklem		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(nvap->na_fsid);
1386191783Srmacklem		fp->fa3_fileid.nfsuquad[0] = 0;
1387191783Srmacklem		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(nvap->na_fileid);
1388191783Srmacklem		txdr_nfsv3time(&nvap->na_atime, &fp->fa3_atime);
1389191783Srmacklem		txdr_nfsv3time(&nvap->na_mtime, &fp->fa3_mtime);
1390191783Srmacklem		txdr_nfsv3time(&nvap->na_ctime, &fp->fa3_ctime);
1391191783Srmacklem	} else {
1392191783Srmacklem		fp->fa_type = vtonfsv2_type(nvap->na_type);
1393191783Srmacklem		fp->fa_mode = vtonfsv2_mode(nvap->na_type, nvap->na_mode);
1394191783Srmacklem		fp->fa2_size = txdr_unsigned(nvap->na_size);
1395191783Srmacklem		fp->fa2_blocksize = txdr_unsigned(nvap->na_blocksize);
1396191783Srmacklem		if (nvap->na_type == VFIFO)
1397191783Srmacklem			fp->fa2_rdev = 0xffffffff;
1398191783Srmacklem		else
1399191783Srmacklem			fp->fa2_rdev = txdr_unsigned(nvap->na_rdev);
1400191783Srmacklem		fp->fa2_blocks = txdr_unsigned(nvap->na_bytes / NFS_FABLKSIZE);
1401191783Srmacklem		fp->fa2_fsid = txdr_unsigned(nvap->na_fsid);
1402191783Srmacklem		fp->fa2_fileid = txdr_unsigned(nvap->na_fileid);
1403191783Srmacklem		txdr_nfsv2time(&nvap->na_atime, &fp->fa2_atime);
1404191783Srmacklem		txdr_nfsv2time(&nvap->na_mtime, &fp->fa2_mtime);
1405191783Srmacklem		txdr_nfsv2time(&nvap->na_ctime, &fp->fa2_ctime);
1406191783Srmacklem	}
1407191783Srmacklem}
1408191783Srmacklem
1409191783Srmacklem/*
1410191783Srmacklem * This function gets a file handle out of an mbuf list.
1411191783Srmacklem * It returns 0 for success, EBADRPC otherwise.
1412191783Srmacklem * If sets the third flagp argument to 1 if the file handle is
1413191783Srmacklem * the public file handle.
1414191783Srmacklem * For NFSv4, if the length is incorrect, set nd_repstat == NFSERR_BADHANDLE
1415191783Srmacklem */
1416191783SrmacklemAPPLESTATIC int
1417191783Srmacklemnfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
1418191783Srmacklem{
1419191783Srmacklem	u_int32_t *tl;
1420191783Srmacklem	int error = 0, len, copylen;
1421191783Srmacklem
1422191783Srmacklem	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1423191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1424191783Srmacklem		len = fxdr_unsigned(int, *tl);
1425191783Srmacklem		if (len == 0 && nfs_pubfhset && (nd->nd_flag & ND_NFSV3) &&
1426191783Srmacklem		    nd->nd_procnum == NFSPROC_LOOKUP) {
1427191783Srmacklem			nd->nd_flag |= ND_PUBLOOKUP;
1428224086Szack			goto nfsmout;
1429191783Srmacklem		}
1430191783Srmacklem		if (len < NFSRV_MINFH || len > NFSRV_MAXFH) {
1431191783Srmacklem			if (nd->nd_flag & ND_NFSV4) {
1432191783Srmacklem			    if (len > 0 && len <= NFSX_V4FHMAX) {
1433191783Srmacklem				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1434191783Srmacklem				if (error)
1435224086Szack					goto nfsmout;
1436191783Srmacklem				nd->nd_repstat = NFSERR_BADHANDLE;
1437224086Szack				goto nfsmout;
1438191783Srmacklem			    } else {
1439224086Szack				    error = EBADRPC;
1440224086Szack				    goto nfsmout;
1441191783Srmacklem			    }
1442191783Srmacklem			} else {
1443224086Szack				error = EBADRPC;
1444224086Szack				goto nfsmout;
1445191783Srmacklem			}
1446191783Srmacklem		}
1447191783Srmacklem		copylen = len;
1448191783Srmacklem	} else {
1449191783Srmacklem		/*
1450191783Srmacklem		 * For NFSv2, the file handle is always 32 bytes on the
1451191783Srmacklem		 * wire, but this server only cares about the first
1452191783Srmacklem		 * NFSRV_MAXFH bytes.
1453191783Srmacklem		 */
1454191783Srmacklem		len = NFSX_V2FH;
1455191783Srmacklem		copylen = NFSRV_MAXFH;
1456191783Srmacklem	}
1457191783Srmacklem	NFSM_DISSECT(tl, u_int32_t *, len);
1458191783Srmacklem	if ((nd->nd_flag & ND_NFSV2) && nfs_pubfhset &&
1459191783Srmacklem	    nd->nd_procnum == NFSPROC_LOOKUP &&
1460191783Srmacklem	    !NFSBCMP((caddr_t)tl, nfs_v2pubfh, NFSX_V2FH)) {
1461191783Srmacklem		nd->nd_flag |= ND_PUBLOOKUP;
1462224086Szack		goto nfsmout;
1463191783Srmacklem	}
1464191783Srmacklem	NFSBCOPY(tl, (caddr_t)fhp->nfsrvfh_data, copylen);
1465191783Srmacklem	fhp->nfsrvfh_len = copylen;
1466191783Srmacklemnfsmout:
1467224086Szack	NFSEXITCODE2(error, nd);
1468191783Srmacklem	return (error);
1469191783Srmacklem}
1470191783Srmacklem
1471191783Srmacklem/*
1472191783Srmacklem * Map errnos to NFS error numbers. For Version 3 and 4 also filter out error
1473191783Srmacklem * numbers not specified for the associated procedure.
1474191783Srmacklem * NFSPROC_NOOP is a special case, where the high order bits of nd_repstat
1475191783Srmacklem * should be cleared. NFSPROC_NOOP is used to return errors when a valid
1476191783Srmacklem * RPC procedure is not involved.
1477191783Srmacklem * Returns the error number in XDR.
1478191783Srmacklem */
1479191783SrmacklemAPPLESTATIC int
1480191783Srmacklemnfsd_errmap(struct nfsrv_descript *nd)
1481191783Srmacklem{
1482191783Srmacklem	short *defaulterrp, *errp;
1483191783Srmacklem
1484191783Srmacklem	if (!nd->nd_repstat)
1485191783Srmacklem		return (0);
1486191783Srmacklem	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1487191783Srmacklem		if (nd->nd_procnum == NFSPROC_NOOP)
1488191783Srmacklem			return (txdr_unsigned(nd->nd_repstat & 0xffff));
1489191783Srmacklem		if (nd->nd_flag & ND_NFSV3)
1490191783Srmacklem		    errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1491191783Srmacklem		else if (nd->nd_repstat == EBADRPC)
1492191783Srmacklem			return (txdr_unsigned(NFSERR_BADXDR));
1493191783Srmacklem		else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
1494191783Srmacklem			 nd->nd_repstat == NFSERR_OPILLEGAL)
1495191783Srmacklem			return (txdr_unsigned(nd->nd_repstat));
1496191783Srmacklem		else
1497191783Srmacklem		    errp = defaulterrp = nfsrv_v4errmap[nd->nd_procnum];
1498191783Srmacklem		while (*++errp)
1499191783Srmacklem			if (*errp == nd->nd_repstat)
1500191783Srmacklem				return (txdr_unsigned(nd->nd_repstat));
1501191783Srmacklem		return (txdr_unsigned(*defaulterrp));
1502191783Srmacklem	}
1503191783Srmacklem	if (nd->nd_repstat <= ELAST)
1504191783Srmacklem		return (txdr_unsigned(nfsrv_v2errmap[nd->nd_repstat - 1]));
1505191783Srmacklem	return (txdr_unsigned(NFSERR_IO));
1506191783Srmacklem}
1507191783Srmacklem
1508191783Srmacklem/*
1509191783Srmacklem * Check to see if setting a uid/gid is permitted when creating a new
1510191783Srmacklem * file object. (Called when uid and/or gid is specified in the
1511191783Srmacklem * settable attributes for V4.
1512191783Srmacklem */
1513191783SrmacklemAPPLESTATIC int
1514191783Srmacklemnfsrv_checkuidgid(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1515191783Srmacklem{
1516224086Szack	int error = 0;
1517191783Srmacklem
1518191783Srmacklem	/*
1519191783Srmacklem	 * If not setting either uid nor gid, it's OK.
1520191783Srmacklem	 */
1521191783Srmacklem	if (NFSVNO_NOTSETUID(nvap) && NFSVNO_NOTSETGID(nvap))
1522224086Szack		goto out;
1523191783Srmacklem	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid == nfsrv_defaultuid)
1524224086Szack	    || (NFSVNO_ISSETGID(nvap) && nvap->na_gid == nfsrv_defaultgid)) {
1525224086Szack		error = NFSERR_BADOWNER;
1526224086Szack		goto out;
1527224086Szack	}
1528191783Srmacklem	if (nd->nd_cred->cr_uid == 0)
1529224086Szack		goto out;
1530191783Srmacklem	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid != nd->nd_cred->cr_uid) ||
1531191783Srmacklem	    (NFSVNO_ISSETGID(nvap) && nvap->na_gid != nd->nd_cred->cr_gid &&
1532191783Srmacklem	    !groupmember(nvap->na_gid, nd->nd_cred)))
1533224086Szack		error = NFSERR_PERM;
1534224086Szack
1535224086Szackout:
1536224086Szack	NFSEXITCODE2(error, nd);
1537224086Szack	return (error);
1538191783Srmacklem}
1539191783Srmacklem
1540191783Srmacklem/*
1541191783Srmacklem * and this routine fixes up the settable attributes for V4 if allowed
1542191783Srmacklem * by nfsrv_checkuidgid().
1543191783Srmacklem */
1544191783SrmacklemAPPLESTATIC void
1545191783Srmacklemnfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
1546191783Srmacklem    struct nfsvattr *nvap, NFSACL_T *aclp, NFSPROC_T *p, nfsattrbit_t *attrbitp,
1547191783Srmacklem    struct nfsexstuff *exp)
1548191783Srmacklem{
1549191783Srmacklem	int change = 0;
1550191783Srmacklem	struct nfsvattr nva;
1551191783Srmacklem	uid_t tuid;
1552191783Srmacklem	int error;
1553191783Srmacklem	nfsattrbit_t nattrbits;
1554191783Srmacklem
1555191783Srmacklem	/*
1556191783Srmacklem	 * Maybe this should be done for V2 and 3 but it never has been
1557191783Srmacklem	 * and nobody seems to be upset, so I think it's best not to change
1558191783Srmacklem	 * the V2 and 3 semantics.
1559191783Srmacklem	 */
1560191783Srmacklem	if ((nd->nd_flag & ND_NFSV4) == 0)
1561224086Szack		goto out;
1562191783Srmacklem	NFSVNO_ATTRINIT(&nva);
1563191783Srmacklem	NFSZERO_ATTRBIT(&nattrbits);
1564191783Srmacklem	tuid = nd->nd_cred->cr_uid;
1565191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) &&
1566191783Srmacklem	    NFSVNO_ISSETUID(nvap) &&
1567191783Srmacklem	    nvap->na_uid != nd->nd_cred->cr_uid) {
1568191783Srmacklem		if (nd->nd_cred->cr_uid == 0) {
1569191783Srmacklem			nva.na_uid = nvap->na_uid;
1570191783Srmacklem			change++;
1571191783Srmacklem			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNER);
1572191783Srmacklem		} else {
1573191783Srmacklem			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNER);
1574191783Srmacklem		}
1575191783Srmacklem	}
1576191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESSSET) &&
1577191783Srmacklem	    NFSVNO_ISSETATIME(nvap)) {
1578191783Srmacklem		nva.na_atime = nvap->na_atime;
1579191783Srmacklem		change++;
1580191783Srmacklem		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEACCESSSET);
1581191783Srmacklem	}
1582191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFYSET) &&
1583191783Srmacklem	    NFSVNO_ISSETMTIME(nvap)) {
1584191783Srmacklem		nva.na_mtime = nvap->na_mtime;
1585191783Srmacklem		change++;
1586191783Srmacklem		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEMODIFYSET);
1587191783Srmacklem	}
1588191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) &&
1589191783Srmacklem	    NFSVNO_ISSETGID(nvap)) {
1590191783Srmacklem		if (nvap->na_gid == nd->nd_cred->cr_gid ||
1591191783Srmacklem		    groupmember(nvap->na_gid, nd->nd_cred)) {
1592191783Srmacklem			nd->nd_cred->cr_uid = 0;
1593191783Srmacklem			nva.na_gid = nvap->na_gid;
1594191783Srmacklem			change++;
1595191783Srmacklem			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNERGROUP);
1596191783Srmacklem		} else {
1597191783Srmacklem			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP);
1598191783Srmacklem		}
1599191783Srmacklem	}
1600191783Srmacklem	if (change) {
1601191783Srmacklem		error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
1602191783Srmacklem		if (error) {
1603191783Srmacklem			NFSCLRALL_ATTRBIT(attrbitp, &nattrbits);
1604191783Srmacklem		}
1605191783Srmacklem	}
1606191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) &&
1607191783Srmacklem	    NFSVNO_ISSETSIZE(nvap) && nvap->na_size != (u_quad_t)0) {
1608191783Srmacklem		NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_SIZE);
1609191783Srmacklem	}
1610191783Srmacklem#ifdef NFS4_ACL_EXTATTR_NAME
1611191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL) &&
1612191783Srmacklem	    nfsrv_useacl != 0 && aclp != NULL) {
1613191783Srmacklem		if (aclp->acl_cnt > 0) {
1614191783Srmacklem			error = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
1615191783Srmacklem			if (error) {
1616191783Srmacklem				NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1617191783Srmacklem			}
1618191783Srmacklem		}
1619191783Srmacklem	} else
1620191783Srmacklem#endif
1621191783Srmacklem	NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1622191783Srmacklem	nd->nd_cred->cr_uid = tuid;
1623224086Szack
1624224086Szackout:
1625224086Szack	NFSEXITCODE2(0, nd);
1626191783Srmacklem}
1627191783Srmacklem
1628191783Srmacklem/*
1629191783Srmacklem * Translate an ASCII hex digit to it's binary value. Return -1 if the
1630191783Srmacklem * char isn't a hex digit.
1631191783Srmacklem */
1632191783Srmacklemstatic char
1633191783Srmacklemnfsrv_hexdigit(char c, int *err)
1634191783Srmacklem{
1635191783Srmacklem
1636191783Srmacklem	*err = 0;
1637191783Srmacklem	if (c >= '0' && c <= '9')
1638191783Srmacklem		return (c - '0');
1639191783Srmacklem	if (c >= 'a' && c <= 'f')
1640191783Srmacklem		return (c - 'a' + ((char)10));
1641191783Srmacklem	if (c >= 'A' && c <= 'F')
1642191783Srmacklem		return (c - 'A' + ((char)10));
1643191783Srmacklem	/* Not valid ! */
1644191783Srmacklem	*err = 1;
1645191783Srmacklem	return (1);	/* BOGUS */
1646191783Srmacklem}
1647191783Srmacklem
1648191783Srmacklem/*
1649191783Srmacklem * Check to see if NFSERR_MOVED can be returned for this op. Return 1 iff
1650191783Srmacklem * it can be.
1651191783Srmacklem */
1652191783SrmacklemAPPLESTATIC int
1653191783Srmacklemnfsrv_errmoved(int op)
1654191783Srmacklem{
1655191783Srmacklem	short *errp;
1656191783Srmacklem
1657191783Srmacklem	errp = nfsrv_v4errmap[op];
1658191783Srmacklem	while (*errp != 0) {
1659191783Srmacklem		if (*errp == NFSERR_MOVED)
1660191783Srmacklem			return (1);
1661191783Srmacklem		errp++;
1662191783Srmacklem	}
1663191783Srmacklem	return (0);
1664191783Srmacklem}
1665191783Srmacklem
1666191783Srmacklem/*
1667191783Srmacklem * Fill in attributes for a Referral.
1668191783Srmacklem * (Return the number of bytes of XDR created.)
1669191783Srmacklem */
1670191783SrmacklemAPPLESTATIC int
1671191783Srmacklemnfsrv_putreferralattr(struct nfsrv_descript *nd, nfsattrbit_t *retbitp,
1672191783Srmacklem    struct nfsreferral *refp, int getattr, int *reterrp)
1673191783Srmacklem{
1674191783Srmacklem	u_int32_t *tl, *retnump;
1675191783Srmacklem	u_char *cp, *cp2;
1676191783Srmacklem	int prefixnum, retnum = 0, i, len, bitpos, rderrbit = 0, nonrefbit = 0;
1677191783Srmacklem	int fslocationsbit = 0;
1678191783Srmacklem	nfsattrbit_t tmpbits, refbits;
1679191783Srmacklem
1680191783Srmacklem	NFSREFERRAL_ATTRBIT(&refbits);
1681191783Srmacklem	if (getattr)
1682191783Srmacklem		NFSCLRBIT_ATTRBIT(&refbits, NFSATTRBIT_RDATTRERROR);
1683191783Srmacklem	else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_RDATTRERROR))
1684191783Srmacklem		rderrbit = 1;
1685191783Srmacklem	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_FSLOCATIONS))
1686191783Srmacklem		fslocationsbit = 1;
1687191783Srmacklem
1688191783Srmacklem	/*
1689191783Srmacklem	 * Check for the case where unsupported referral attributes are
1690191783Srmacklem	 * requested.
1691191783Srmacklem	 */
1692191783Srmacklem	NFSSET_ATTRBIT(&tmpbits, retbitp);
1693191783Srmacklem	NFSCLRALL_ATTRBIT(&tmpbits, &refbits);
1694191783Srmacklem	if (NFSNONZERO_ATTRBIT(&tmpbits))
1695191783Srmacklem		nonrefbit = 1;
1696191783Srmacklem
1697191783Srmacklem	if (nonrefbit && !fslocationsbit && (getattr || !rderrbit)) {
1698191783Srmacklem		*reterrp = NFSERR_MOVED;
1699191783Srmacklem		return (0);
1700191783Srmacklem	}
1701191783Srmacklem
1702191783Srmacklem	/*
1703191783Srmacklem	 * Now we can fill in the attributes.
1704191783Srmacklem	 */
1705191783Srmacklem	NFSSET_ATTRBIT(&tmpbits, retbitp);
1706191783Srmacklem	NFSCLRNOT_ATTRBIT(&tmpbits, &refbits);
1707191783Srmacklem
1708191783Srmacklem	/*
1709191783Srmacklem	 * Put out the attribute bitmap for the ones being filled in
1710191783Srmacklem	 * and get the field for the number of attributes returned.
1711191783Srmacklem	 */
1712191783Srmacklem	prefixnum = nfsrv_putattrbit(nd, &tmpbits);
1713191783Srmacklem	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1714191783Srmacklem	prefixnum += NFSX_UNSIGNED;
1715191783Srmacklem
1716191783Srmacklem	/*
1717191783Srmacklem	 * Now, loop around filling in the attributes for each bit set.
1718191783Srmacklem	 */
1719191783Srmacklem	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1720191783Srmacklem	    if (NFSISSET_ATTRBIT(&tmpbits, bitpos)) {
1721191783Srmacklem		switch (bitpos) {
1722191783Srmacklem		case NFSATTRBIT_TYPE:
1723191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1724191783Srmacklem			*tl = txdr_unsigned(NFDIR);
1725191783Srmacklem			retnum += NFSX_UNSIGNED;
1726191783Srmacklem			break;
1727191783Srmacklem		case NFSATTRBIT_FSID:
1728191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
1729191783Srmacklem			*tl++ = 0;
1730191783Srmacklem			*tl++ = txdr_unsigned(NFSV4ROOT_FSID0);
1731191783Srmacklem			*tl++ = 0;
1732191783Srmacklem			*tl = txdr_unsigned(NFSV4ROOT_REFERRAL);
1733191783Srmacklem			retnum += NFSX_V4FSID;
1734191783Srmacklem			break;
1735191783Srmacklem		case NFSATTRBIT_RDATTRERROR:
1736191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1737191783Srmacklem			if (nonrefbit)
1738191783Srmacklem				*tl = txdr_unsigned(NFSERR_MOVED);
1739191783Srmacklem			else
1740191783Srmacklem				*tl = 0;
1741191783Srmacklem			retnum += NFSX_UNSIGNED;
1742191783Srmacklem			break;
1743191783Srmacklem		case NFSATTRBIT_FSLOCATIONS:
1744191783Srmacklem			retnum += nfsm_strtom(nd, "/", 1);
1745191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1746191783Srmacklem			*tl = txdr_unsigned(refp->nfr_srvcnt);
1747191783Srmacklem			retnum += NFSX_UNSIGNED;
1748191783Srmacklem			cp = refp->nfr_srvlist;
1749191783Srmacklem			for (i = 0; i < refp->nfr_srvcnt; i++) {
1750191783Srmacklem				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1751191783Srmacklem				*tl = txdr_unsigned(1);
1752191783Srmacklem				retnum += NFSX_UNSIGNED;
1753191783Srmacklem				cp2 = STRCHR(cp, ':');
1754191783Srmacklem				if (cp2 != NULL)
1755191783Srmacklem					len = cp2 - cp;
1756191783Srmacklem				else
1757191783Srmacklem					len = 1;
1758191783Srmacklem				retnum += nfsm_strtom(nd, cp, len);
1759191783Srmacklem				if (cp2 != NULL)
1760191783Srmacklem					cp = cp2 + 1;
1761191783Srmacklem				cp2 = STRCHR(cp, ',');
1762191783Srmacklem				if (cp2 != NULL)
1763191783Srmacklem					len = cp2 - cp;
1764191783Srmacklem				else
1765191783Srmacklem					len = strlen(cp);
1766191783Srmacklem				retnum += nfsm_strtom(nd, cp, len);
1767191783Srmacklem				if (cp2 != NULL)
1768191783Srmacklem					cp = cp2 + 1;
1769191783Srmacklem			}
1770191783Srmacklem			break;
1771191783Srmacklem		case NFSATTRBIT_MOUNTEDONFILEID:
1772191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
1773191783Srmacklem			*tl++ = 0;
1774191783Srmacklem			*tl = txdr_unsigned(refp->nfr_dfileno);
1775191783Srmacklem			retnum += NFSX_HYPER;
1776191783Srmacklem			break;
1777191783Srmacklem		default:
1778191783Srmacklem			printf("EEK! Bad V4 refattr bitpos=%d\n", bitpos);
1779191783Srmacklem		};
1780191783Srmacklem	    }
1781191783Srmacklem	}
1782191783Srmacklem	*retnump = txdr_unsigned(retnum);
1783191783Srmacklem	return (retnum + prefixnum);
1784191783Srmacklem}
1785191783Srmacklem
1786191783Srmacklem/*
1787191783Srmacklem * Parse a file name out of a request.
1788191783Srmacklem */
1789191783SrmacklemAPPLESTATIC int
1790191783Srmacklemnfsrv_parsename(struct nfsrv_descript *nd, char *bufp, u_long *hashp,
1791191783Srmacklem    NFSPATHLEN_T *outlenp)
1792191783Srmacklem{
1793191783Srmacklem	char *fromcp, *tocp, val = '\0';
1794191783Srmacklem	mbuf_t md;
1795191783Srmacklem	int i;
1796191783Srmacklem	int rem, len, error = 0, pubtype = 0, outlen = 0, percent = 0;
1797191783Srmacklem	char digit;
1798191783Srmacklem	u_int32_t *tl;
1799191783Srmacklem	u_long hash = 0;
1800191783Srmacklem
1801191783Srmacklem	if (hashp != NULL)
1802191783Srmacklem		*hashp = 0;
1803191783Srmacklem	tocp = bufp;
1804191783Srmacklem	/*
1805191783Srmacklem	 * For V4, check for lookup parent.
1806191783Srmacklem	 * Otherwise, get the component name.
1807191783Srmacklem	 */
1808191783Srmacklem	if ((nd->nd_flag & ND_NFSV4) && nd->nd_procnum == NFSV4OP_LOOKUPP) {
1809191783Srmacklem	    *tocp++ = '.';
1810191783Srmacklem	    hash += ((u_char)'.');
1811191783Srmacklem	    *tocp++ = '.';
1812191783Srmacklem	    hash += ((u_char)'.');
1813191783Srmacklem	    outlen = 2;
1814191783Srmacklem	} else {
1815191783Srmacklem	    /*
1816191783Srmacklem	     * First, get the name length.
1817191783Srmacklem	     */
1818191783Srmacklem	    NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1819191783Srmacklem	    len = fxdr_unsigned(int, *tl);
1820191783Srmacklem	    if (len > NFS_MAXNAMLEN) {
1821191783Srmacklem		nd->nd_repstat = NFSERR_NAMETOL;
1822224086Szack		error = 0;
1823224086Szack		goto nfsmout;
1824191783Srmacklem	    } else if (len <= 0) {
1825191783Srmacklem		nd->nd_repstat = NFSERR_INVAL;
1826224086Szack		error = 0;
1827224086Szack		goto nfsmout;
1828191783Srmacklem	    }
1829191783Srmacklem
1830191783Srmacklem	    /*
1831191783Srmacklem	     * Now, copy the component name into the buffer.
1832191783Srmacklem	     */
1833191783Srmacklem	    fromcp = nd->nd_dpos;
1834191783Srmacklem	    md = nd->nd_md;
1835191783Srmacklem	    rem = NFSMTOD(md, caddr_t) + mbuf_len(md) - fromcp;
1836191783Srmacklem	    for (i = 0; i < len; i++) {
1837191783Srmacklem		while (rem == 0) {
1838191783Srmacklem			md = mbuf_next(md);
1839224086Szack			if (md == NULL) {
1840224086Szack				error = EBADRPC;
1841224086Szack				goto nfsmout;
1842224086Szack			}
1843191783Srmacklem			fromcp = NFSMTOD(md, caddr_t);
1844191783Srmacklem			rem = mbuf_len(md);
1845191783Srmacklem		}
1846191783Srmacklem		if (*fromcp == '\0') {
1847191783Srmacklem			nd->nd_repstat = EACCES;
1848224086Szack			error = 0;
1849224086Szack			goto nfsmout;
1850191783Srmacklem		}
1851191783Srmacklem		/*
1852191783Srmacklem		 * For lookups on the public filehandle, do some special
1853191783Srmacklem		 * processing on the name. (The public file handle is the
1854191783Srmacklem		 * root of the public file system for this server.)
1855191783Srmacklem		 */
1856191783Srmacklem		if (nd->nd_flag & ND_PUBLOOKUP) {
1857191783Srmacklem			/*
1858191783Srmacklem			 * If the first char is ASCII, it is a canonical
1859191783Srmacklem			 * path, otherwise it is a native path. (RFC2054
1860191783Srmacklem			 * doesn't actually state what it is if the first
1861191783Srmacklem			 * char isn't ASCII or 0x80, so I assume native.)
1862191783Srmacklem			 * pubtype == 1 -> native path
1863191783Srmacklem			 * pubtype == 2 -> canonical path
1864191783Srmacklem			 */
1865191783Srmacklem			if (i == 0) {
1866191783Srmacklem				if (*fromcp & 0x80) {
1867191783Srmacklem					/*
1868191783Srmacklem					 * Since RFC2054 doesn't indicate
1869191783Srmacklem					 * that a native path of just 0x80
1870191783Srmacklem					 * isn't allowed, I'll replace the
1871191783Srmacklem					 * 0x80 with '/' instead of just
1872191783Srmacklem					 * throwing it away.
1873191783Srmacklem					 */
1874191783Srmacklem					*fromcp = '/';
1875191783Srmacklem					pubtype = 1;
1876191783Srmacklem				} else {
1877191783Srmacklem					pubtype = 2;
1878191783Srmacklem				}
1879191783Srmacklem			}
1880191783Srmacklem			/*
1881191783Srmacklem			 * '/' only allowed in a native path
1882191783Srmacklem			 */
1883191783Srmacklem			if (*fromcp == '/' && pubtype != 1) {
1884191783Srmacklem				nd->nd_repstat = EACCES;
1885224086Szack				error = 0;
1886224086Szack				goto nfsmout;
1887191783Srmacklem			}
1888191783Srmacklem
1889191783Srmacklem			/*
1890191783Srmacklem			 * For the special case of 2 hex digits after a
1891191783Srmacklem			 * '%' in an absolute path, calculate the value.
1892191783Srmacklem			 * percent == 1 -> indicates "get first hex digit"
1893191783Srmacklem			 * percent == 2 -> indicates "get second hex digit"
1894191783Srmacklem			 */
1895191783Srmacklem			if (percent > 0) {
1896191783Srmacklem				digit = nfsrv_hexdigit(*fromcp, &error);
1897191783Srmacklem				if (error) {
1898191783Srmacklem					nd->nd_repstat = EACCES;
1899224086Szack					error = 0;
1900224086Szack					goto nfsmout;
1901191783Srmacklem				}
1902191783Srmacklem				if (percent == 1) {
1903191783Srmacklem					val = (digit << 4);
1904191783Srmacklem					percent = 2;
1905191783Srmacklem				} else {
1906191783Srmacklem					val += digit;
1907191783Srmacklem					percent = 0;
1908191783Srmacklem					*tocp++ = val;
1909191783Srmacklem					hash += ((u_char)val);
1910191783Srmacklem					outlen++;
1911191783Srmacklem				}
1912191783Srmacklem			} else {
1913191783Srmacklem				if (*fromcp == '%' && pubtype == 2) {
1914191783Srmacklem					/*
1915191783Srmacklem					 * Must be followed by 2 hex digits
1916191783Srmacklem					 */
1917191783Srmacklem					if ((len - i) < 3) {
1918191783Srmacklem						nd->nd_repstat = EACCES;
1919224086Szack						error = 0;
1920224086Szack						goto nfsmout;
1921191783Srmacklem					}
1922191783Srmacklem					percent = 1;
1923191783Srmacklem				} else {
1924191783Srmacklem					*tocp++ = *fromcp;
1925191783Srmacklem					hash += ((u_char)*fromcp);
1926191783Srmacklem					outlen++;
1927191783Srmacklem				}
1928191783Srmacklem			}
1929191783Srmacklem		} else {
1930191783Srmacklem			/*
1931191783Srmacklem			 * Normal, non lookup on public, name.
1932191783Srmacklem			 */
1933191783Srmacklem			if (*fromcp == '/') {
1934191783Srmacklem				if (nd->nd_flag & ND_NFSV4)
1935191783Srmacklem					nd->nd_repstat = NFSERR_BADNAME;
1936191783Srmacklem				else
1937191783Srmacklem					nd->nd_repstat = EACCES;
1938224086Szack				error = 0;
1939224086Szack				goto nfsmout;
1940191783Srmacklem			}
1941191783Srmacklem			hash += ((u_char)*fromcp);
1942191783Srmacklem			*tocp++ = *fromcp;
1943191783Srmacklem			outlen++;
1944191783Srmacklem		}
1945191783Srmacklem		fromcp++;
1946191783Srmacklem		rem--;
1947191783Srmacklem	    }
1948191783Srmacklem	    nd->nd_md = md;
1949191783Srmacklem	    nd->nd_dpos = fromcp;
1950191783Srmacklem	    i = NFSM_RNDUP(len) - len;
1951191783Srmacklem	    if (i > 0) {
1952191783Srmacklem		if (rem >= i) {
1953191783Srmacklem			nd->nd_dpos += i;
1954191783Srmacklem		} else {
1955191783Srmacklem			error = nfsm_advance(nd, i, rem);
1956191783Srmacklem			if (error)
1957224086Szack				goto nfsmout;
1958191783Srmacklem		}
1959191783Srmacklem	    }
1960191783Srmacklem
1961191783Srmacklem	    /*
1962191783Srmacklem	     * For v4, don't allow lookups of '.' or '..' and
1963191783Srmacklem	     * also check for non-utf8 strings.
1964191783Srmacklem	     */
1965191783Srmacklem	    if (nd->nd_flag & ND_NFSV4) {
1966191783Srmacklem		if ((outlen == 1 && bufp[0] == '.') ||
1967191783Srmacklem		    (outlen == 2 && bufp[0] == '.' &&
1968191783Srmacklem		     bufp[1] == '.')) {
1969191783Srmacklem		    nd->nd_repstat = NFSERR_BADNAME;
1970224086Szack		    error = 0;
1971224086Szack		    goto nfsmout;
1972191783Srmacklem		}
1973228260Srmacklem		if (disable_checkutf8 == 0 &&
1974228260Srmacklem		    nfsrv_checkutf8((u_int8_t *)bufp, outlen)) {
1975191783Srmacklem		    nd->nd_repstat = NFSERR_INVAL;
1976224086Szack		    error = 0;
1977224086Szack		    goto nfsmout;
1978191783Srmacklem		}
1979191783Srmacklem	    }
1980191783Srmacklem	}
1981191783Srmacklem	*tocp = '\0';
1982191783Srmacklem	*outlenp = (size_t)outlen;
1983191783Srmacklem	if (hashp != NULL)
1984191783Srmacklem		*hashp = hash;
1985191783Srmacklemnfsmout:
1986224086Szack	NFSEXITCODE2(error, nd);
1987191783Srmacklem	return (error);
1988191783Srmacklem}
1989191783Srmacklem
1990191783Srmacklem/*
1991191783Srmacklem * Check the tcp socket sequence number has been acknowledged.
1992191783Srmacklem */
1993191783Srmacklemint
1994191783Srmacklemnfsrv_checksockseqnum(struct socket *so, tcp_seq tcpseqval)
1995191783Srmacklem{
1996191783Srmacklem	tcp_seq maxseq, unaseq;
1997191783Srmacklem	int error, ret;
1998191783Srmacklem
1999191783Srmacklem	error = nfsrv_getsocksndseq(so, &maxseq, &unaseq);
2000191783Srmacklem	if (error)
2001191783Srmacklem		return (0);
2002191783Srmacklem	ret = SEQ_GEQ(unaseq, tcpseqval);
2003191783Srmacklem	return (ret);
2004191783Srmacklem}
2005191783Srmacklem
2006191783Srmacklem/*
2007191783Srmacklem * Get the tcp sequence number to be acknowledged.
2008191783Srmacklem */
2009191783Srmacklemint
2010191783Srmacklemnfsrv_getsockseqnum(struct socket *so, tcp_seq *tcpseqp)
2011191783Srmacklem{
2012191783Srmacklem	tcp_seq maxseq, unaseq;
2013191783Srmacklem	u_int sbcc;
2014191783Srmacklem	int error;
2015191783Srmacklem
2016191783Srmacklem	sbcc = so->so_snd.sb_cc;
2017191783Srmacklem	error = nfsrv_getsocksndseq(so, &maxseq, &unaseq);
2018191783Srmacklem	if (error)
2019191783Srmacklem		return (0);
2020191783Srmacklem	/*
2021191783Srmacklem	 * Set the seq# to a value that will
2022191783Srmacklem	 * be at least the end of the reply.
2023191783Srmacklem	 * When this sequence# is acknowledged
2024191783Srmacklem	 * by the client, the client has received
2025191783Srmacklem	 * the reply.
2026191783Srmacklem	 */
2027191783Srmacklem	*tcpseqp = sbcc + maxseq;
2028191783Srmacklem	return (1);
2029191783Srmacklem}
2030191783Srmacklem
2031191783Srmacklemvoid
2032191783Srmacklemnfsd_init(void)
2033191783Srmacklem{
2034191783Srmacklem	int i;
2035191783Srmacklem	static int inited = 0;
2036191783Srmacklem
2037191783Srmacklem	if (inited)
2038191783Srmacklem		return;
2039191783Srmacklem	inited = 1;
2040191783Srmacklem
2041191783Srmacklem	/*
2042191783Srmacklem	 * Initialize client queues. Don't free/reinitialize
2043191783Srmacklem	 * them when nfsds are restarted.
2044191783Srmacklem	 */
2045191783Srmacklem	for (i = 0; i < NFSCLIENTHASHSIZE; i++)
2046191783Srmacklem		LIST_INIT(&nfsclienthash[i]);
2047191783Srmacklem	for (i = 0; i < NFSLOCKHASHSIZE; i++)
2048191783Srmacklem		LIST_INIT(&nfslockhash[i]);
2049191783Srmacklem
2050191783Srmacklem	/* and the v2 pubfh should be all zeros */
2051191783Srmacklem	NFSBZERO(nfs_v2pubfh, NFSX_V2FH);
2052191783Srmacklem}
2053191783Srmacklem
2054192121Srmacklem/*
2055192121Srmacklem * Check the v4 root exports.
2056192121Srmacklem * Return 0 if ok, 1 otherwise.
2057192121Srmacklem */
2058192121Srmacklemint
2059192121Srmacklemnfsd_checkrootexp(struct nfsrv_descript *nd)
2060192121Srmacklem{
2061192121Srmacklem
2062192121Srmacklem	if ((nd->nd_flag & (ND_GSS | ND_EXAUTHSYS)) == ND_EXAUTHSYS)
2063192121Srmacklem		return (0);
2064192121Srmacklem	if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) ==
2065192121Srmacklem	    (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY))
2066192121Srmacklem		return (0);
2067192121Srmacklem	if ((nd->nd_flag & (ND_GSSPRIVACY | ND_EXGSSPRIVACY)) ==
2068192121Srmacklem	    (ND_GSSPRIVACY | ND_EXGSSPRIVACY))
2069192121Srmacklem		return (0);
2070192121Srmacklem	if ((nd->nd_flag & (ND_GSS | ND_GSSINTEGRITY | ND_GSSPRIVACY |
2071192121Srmacklem	     ND_EXGSS)) == (ND_GSS | ND_EXGSS))
2072192121Srmacklem		return (0);
2073192121Srmacklem	return (1);
2074192121Srmacklem}
2075192121Srmacklem
2076