nfs_nfsdsubs.c revision 191783
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 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/fs/nfsserver/nfs_nfsdsubs.c 191783 2009-05-04 15:23:58Z rmacklem $");
36
37#ifndef APPLEKEXT
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#include <fs/nfs/nfsport.h>
44
45extern u_int32_t newnfs_true, newnfs_false;
46extern int nfs_pubfhset;
47extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
48extern struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE];
49extern int nfsrv_useacl;
50extern uid_t nfsrv_defaultuid;
51extern gid_t nfsrv_defaultgid;
52
53char nfs_v2pubfh[NFSX_V2FH];
54static nfstype newnfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
55    NFNON, NFCHR, NFNON };
56extern nfstype nfsv34_type[9];
57#endif	/* !APPLEKEXT */
58
59static char nfsrv_hexdigit(char, int *);
60
61/*
62 * Maps errno values to nfs error numbers.
63 * Use NFSERR_IO as the catch all for ones not specifically defined in
64 * RFC 1094.
65 */
66static u_char nfsrv_v2errmap[ELAST] = {
67  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
68  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
69  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
70  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
71  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
72  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
73  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
74  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
75  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
76  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
77  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
78  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
79  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
80  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
81  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
82  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
83  NFSERR_IO,
84};
85
86/*
87 * Maps errno values to nfs error numbers.
88 * Although it is not obvious whether or not NFS clients really care if
89 * a returned error value is in the specified list for the procedure, the
90 * safest thing to do is filter them appropriately. For Version 2, the
91 * X/Open XNFS document is the only specification that defines error values
92 * for each RPC (The RFC simply lists all possible error values for all RPCs),
93 * so I have decided to not do this for Version 2.
94 * The first entry is the default error return and the rest are the valid
95 * errors for that RPC in increasing numeric order.
96 */
97static short nfsv3err_null[] = {
98	0,
99	0,
100};
101
102static short nfsv3err_getattr[] = {
103	NFSERR_IO,
104	NFSERR_IO,
105	NFSERR_STALE,
106	NFSERR_BADHANDLE,
107	NFSERR_SERVERFAULT,
108	NFSERR_DELAY,
109	0,
110};
111
112static short nfsv3err_setattr[] = {
113	NFSERR_IO,
114	NFSERR_ACCES,
115	NFSERR_PERM,
116	NFSERR_IO,
117	NFSERR_INVAL,
118	NFSERR_NOSPC,
119	NFSERR_ROFS,
120	NFSERR_DQUOT,
121	NFSERR_STALE,
122	NFSERR_BADHANDLE,
123	NFSERR_NOT_SYNC,
124	NFSERR_SERVERFAULT,
125	NFSERR_DELAY,
126	0,
127};
128
129static short nfsv3err_lookup[] = {
130	NFSERR_IO,
131	NFSERR_NOENT,
132	NFSERR_ACCES,
133	NFSERR_NAMETOL,
134	NFSERR_IO,
135	NFSERR_NOTDIR,
136	NFSERR_STALE,
137	NFSERR_BADHANDLE,
138	NFSERR_SERVERFAULT,
139	NFSERR_DELAY,
140	0,
141};
142
143static short nfsv3err_access[] = {
144	NFSERR_IO,
145	NFSERR_IO,
146	NFSERR_STALE,
147	NFSERR_BADHANDLE,
148	NFSERR_SERVERFAULT,
149	NFSERR_DELAY,
150	0,
151};
152
153static short nfsv3err_readlink[] = {
154	NFSERR_IO,
155	NFSERR_IO,
156	NFSERR_ACCES,
157	NFSERR_INVAL,
158	NFSERR_STALE,
159	NFSERR_BADHANDLE,
160	NFSERR_NOTSUPP,
161	NFSERR_SERVERFAULT,
162	NFSERR_DELAY,
163	0,
164};
165
166static short nfsv3err_read[] = {
167	NFSERR_IO,
168	NFSERR_IO,
169	NFSERR_NXIO,
170	NFSERR_ACCES,
171	NFSERR_INVAL,
172	NFSERR_STALE,
173	NFSERR_BADHANDLE,
174	NFSERR_SERVERFAULT,
175	NFSERR_DELAY,
176	0,
177};
178
179static short nfsv3err_write[] = {
180	NFSERR_IO,
181	NFSERR_IO,
182	NFSERR_ACCES,
183	NFSERR_NOSPC,
184	NFSERR_INVAL,
185	NFSERR_FBIG,
186	NFSERR_ROFS,
187	NFSERR_DQUOT,
188	NFSERR_STALE,
189	NFSERR_BADHANDLE,
190	NFSERR_SERVERFAULT,
191	NFSERR_DELAY,
192	0,
193};
194
195static short nfsv3err_create[] = {
196	NFSERR_IO,
197	NFSERR_EXIST,
198	NFSERR_NAMETOL,
199	NFSERR_ACCES,
200	NFSERR_IO,
201	NFSERR_NOTDIR,
202	NFSERR_NOSPC,
203	NFSERR_ROFS,
204	NFSERR_DQUOT,
205	NFSERR_STALE,
206	NFSERR_BADHANDLE,
207	NFSERR_NOTSUPP,
208	NFSERR_SERVERFAULT,
209	NFSERR_DELAY,
210	0,
211};
212
213static short nfsv3err_mkdir[] = {
214	NFSERR_IO,
215	NFSERR_EXIST,
216	NFSERR_ACCES,
217	NFSERR_NAMETOL,
218	NFSERR_IO,
219	NFSERR_NOTDIR,
220	NFSERR_NOSPC,
221	NFSERR_ROFS,
222	NFSERR_DQUOT,
223	NFSERR_STALE,
224	NFSERR_BADHANDLE,
225	NFSERR_NOTSUPP,
226	NFSERR_SERVERFAULT,
227	NFSERR_DELAY,
228	0,
229};
230
231static short nfsv3err_symlink[] = {
232	NFSERR_IO,
233	NFSERR_ACCES,
234	NFSERR_EXIST,
235	NFSERR_NAMETOL,
236	NFSERR_NOSPC,
237	NFSERR_IO,
238	NFSERR_NOTDIR,
239	NFSERR_ROFS,
240	NFSERR_DQUOT,
241	NFSERR_STALE,
242	NFSERR_BADHANDLE,
243	NFSERR_NOTSUPP,
244	NFSERR_SERVERFAULT,
245	NFSERR_DELAY,
246	0,
247};
248
249static short nfsv3err_mknod[] = {
250	NFSERR_IO,
251	NFSERR_ACCES,
252	NFSERR_EXIST,
253	NFSERR_NAMETOL,
254	NFSERR_NOSPC,
255	NFSERR_IO,
256	NFSERR_NOTDIR,
257	NFSERR_ROFS,
258	NFSERR_DQUOT,
259	NFSERR_STALE,
260	NFSERR_BADHANDLE,
261	NFSERR_NOTSUPP,
262	NFSERR_SERVERFAULT,
263	NFSERR_DELAY,
264	NFSERR_BADTYPE,
265	0,
266};
267
268static short nfsv3err_remove[] = {
269	NFSERR_IO,
270	NFSERR_NOENT,
271	NFSERR_ACCES,
272	NFSERR_NAMETOL,
273	NFSERR_IO,
274	NFSERR_NOTDIR,
275	NFSERR_ROFS,
276	NFSERR_STALE,
277	NFSERR_BADHANDLE,
278	NFSERR_SERVERFAULT,
279	NFSERR_DELAY,
280	0,
281};
282
283static short nfsv3err_rmdir[] = {
284	NFSERR_IO,
285	NFSERR_NOENT,
286	NFSERR_ACCES,
287	NFSERR_NOTDIR,
288	NFSERR_NAMETOL,
289	NFSERR_IO,
290	NFSERR_EXIST,
291	NFSERR_INVAL,
292	NFSERR_ROFS,
293	NFSERR_NOTEMPTY,
294	NFSERR_STALE,
295	NFSERR_BADHANDLE,
296	NFSERR_NOTSUPP,
297	NFSERR_SERVERFAULT,
298	NFSERR_DELAY,
299	0,
300};
301
302static short nfsv3err_rename[] = {
303	NFSERR_IO,
304	NFSERR_NOENT,
305	NFSERR_ACCES,
306	NFSERR_EXIST,
307	NFSERR_NAMETOL,
308	NFSERR_XDEV,
309	NFSERR_IO,
310	NFSERR_NOTDIR,
311	NFSERR_ISDIR,
312	NFSERR_INVAL,
313	NFSERR_NOSPC,
314	NFSERR_ROFS,
315	NFSERR_MLINK,
316	NFSERR_NOTEMPTY,
317	NFSERR_DQUOT,
318	NFSERR_STALE,
319	NFSERR_BADHANDLE,
320	NFSERR_NOTSUPP,
321	NFSERR_SERVERFAULT,
322	NFSERR_DELAY,
323	0,
324};
325
326static short nfsv3err_link[] = {
327	NFSERR_IO,
328	NFSERR_ACCES,
329	NFSERR_EXIST,
330	NFSERR_NAMETOL,
331	NFSERR_IO,
332	NFSERR_XDEV,
333	NFSERR_NOTDIR,
334	NFSERR_INVAL,
335	NFSERR_NOSPC,
336	NFSERR_ROFS,
337	NFSERR_MLINK,
338	NFSERR_DQUOT,
339	NFSERR_STALE,
340	NFSERR_BADHANDLE,
341	NFSERR_NOTSUPP,
342	NFSERR_SERVERFAULT,
343	NFSERR_DELAY,
344	0,
345};
346
347static short nfsv3err_readdir[] = {
348	NFSERR_IO,
349	NFSERR_ACCES,
350	NFSERR_NOTDIR,
351	NFSERR_IO,
352	NFSERR_STALE,
353	NFSERR_BADHANDLE,
354	NFSERR_BAD_COOKIE,
355	NFSERR_TOOSMALL,
356	NFSERR_SERVERFAULT,
357	NFSERR_DELAY,
358	0,
359};
360
361static short nfsv3err_readdirplus[] = {
362	NFSERR_IO,
363	NFSERR_ACCES,
364	NFSERR_NOTDIR,
365	NFSERR_IO,
366	NFSERR_STALE,
367	NFSERR_BADHANDLE,
368	NFSERR_BAD_COOKIE,
369	NFSERR_NOTSUPP,
370	NFSERR_TOOSMALL,
371	NFSERR_SERVERFAULT,
372	NFSERR_DELAY,
373	0,
374};
375
376static short nfsv3err_fsstat[] = {
377	NFSERR_IO,
378	NFSERR_IO,
379	NFSERR_STALE,
380	NFSERR_BADHANDLE,
381	NFSERR_SERVERFAULT,
382	NFSERR_DELAY,
383	0,
384};
385
386static short nfsv3err_fsinfo[] = {
387	NFSERR_STALE,
388	NFSERR_STALE,
389	NFSERR_BADHANDLE,
390	NFSERR_SERVERFAULT,
391	NFSERR_DELAY,
392	0,
393};
394
395static short nfsv3err_pathconf[] = {
396	NFSERR_STALE,
397	NFSERR_STALE,
398	NFSERR_BADHANDLE,
399	NFSERR_SERVERFAULT,
400	NFSERR_DELAY,
401	0,
402};
403
404static short nfsv3err_commit[] = {
405	NFSERR_IO,
406	NFSERR_IO,
407	NFSERR_STALE,
408	NFSERR_BADHANDLE,
409	NFSERR_SERVERFAULT,
410	NFSERR_DELAY,
411	0,
412};
413
414static short *nfsrv_v3errmap[] = {
415	nfsv3err_null,
416	nfsv3err_getattr,
417	nfsv3err_setattr,
418	nfsv3err_lookup,
419	nfsv3err_access,
420	nfsv3err_readlink,
421	nfsv3err_read,
422	nfsv3err_write,
423	nfsv3err_create,
424	nfsv3err_mkdir,
425	nfsv3err_symlink,
426	nfsv3err_mknod,
427	nfsv3err_remove,
428	nfsv3err_rmdir,
429	nfsv3err_rename,
430	nfsv3err_link,
431	nfsv3err_readdir,
432	nfsv3err_readdirplus,
433	nfsv3err_fsstat,
434	nfsv3err_fsinfo,
435	nfsv3err_pathconf,
436	nfsv3err_commit,
437};
438
439/*
440 * And the same for V4.
441 */
442static short nfsv4err_null[] = {
443	0,
444	0,
445};
446
447static short nfsv4err_access[] = {
448	NFSERR_IO,
449	NFSERR_ACCES,
450	NFSERR_BADHANDLE,
451	NFSERR_BADXDR,
452	NFSERR_DELAY,
453	NFSERR_FHEXPIRED,
454	NFSERR_INVAL,
455	NFSERR_IO,
456	NFSERR_MOVED,
457	NFSERR_NOFILEHANDLE,
458	NFSERR_RESOURCE,
459	NFSERR_SERVERFAULT,
460	NFSERR_STALE,
461	0,
462};
463
464static short nfsv4err_close[] = {
465	NFSERR_EXPIRED,
466	NFSERR_ADMINREVOKED,
467	NFSERR_BADHANDLE,
468	NFSERR_BADSEQID,
469	NFSERR_BADSTATEID,
470	NFSERR_BADXDR,
471	NFSERR_DELAY,
472	NFSERR_EXPIRED,
473	NFSERR_FHEXPIRED,
474	NFSERR_INVAL,
475	NFSERR_ISDIR,
476	NFSERR_LEASEMOVED,
477	NFSERR_LOCKSHELD,
478	NFSERR_MOVED,
479	NFSERR_NOFILEHANDLE,
480	NFSERR_OLDSTATEID,
481	NFSERR_RESOURCE,
482	NFSERR_SERVERFAULT,
483	NFSERR_STALE,
484	NFSERR_STALESTATEID,
485	0,
486};
487
488static short nfsv4err_commit[] = {
489	NFSERR_IO,
490	NFSERR_ACCES,
491	NFSERR_BADHANDLE,
492	NFSERR_BADXDR,
493	NFSERR_FHEXPIRED,
494	NFSERR_INVAL,
495	NFSERR_IO,
496	NFSERR_ISDIR,
497	NFSERR_MOVED,
498	NFSERR_NOFILEHANDLE,
499	NFSERR_RESOURCE,
500	NFSERR_ROFS,
501	NFSERR_SERVERFAULT,
502	NFSERR_STALE,
503	0,
504};
505
506static short nfsv4err_create[] = {
507	NFSERR_IO,
508	NFSERR_ACCES,
509	NFSERR_ATTRNOTSUPP,
510	NFSERR_BADCHAR,
511	NFSERR_BADHANDLE,
512	NFSERR_BADNAME,
513	NFSERR_BADOWNER,
514	NFSERR_BADTYPE,
515	NFSERR_BADXDR,
516	NFSERR_DELAY,
517	NFSERR_DQUOT,
518	NFSERR_EXIST,
519	NFSERR_FHEXPIRED,
520	NFSERR_INVAL,
521	NFSERR_IO,
522	NFSERR_MOVED,
523	NFSERR_NAMETOL,
524	NFSERR_NOFILEHANDLE,
525	NFSERR_NOSPC,
526	NFSERR_NOTDIR,
527	NFSERR_PERM,
528	NFSERR_RESOURCE,
529	NFSERR_ROFS,
530	NFSERR_SERVERFAULT,
531	NFSERR_STALE,
532	0,
533};
534
535static short nfsv4err_delegpurge[] = {
536	NFSERR_SERVERFAULT,
537	NFSERR_BADXDR,
538	NFSERR_NOTSUPP,
539	NFSERR_LEASEMOVED,
540	NFSERR_MOVED,
541	NFSERR_RESOURCE,
542	NFSERR_SERVERFAULT,
543	NFSERR_STALECLIENTID,
544	0,
545};
546
547static short nfsv4err_delegreturn[] = {
548	NFSERR_SERVERFAULT,
549	NFSERR_ADMINREVOKED,
550	NFSERR_BADSTATEID,
551	NFSERR_BADXDR,
552	NFSERR_EXPIRED,
553	NFSERR_INVAL,
554	NFSERR_LEASEMOVED,
555	NFSERR_MOVED,
556	NFSERR_NOFILEHANDLE,
557	NFSERR_NOTSUPP,
558	NFSERR_OLDSTATEID,
559	NFSERR_RESOURCE,
560	NFSERR_SERVERFAULT,
561	NFSERR_STALE,
562	NFSERR_STALESTATEID,
563	0,
564};
565
566static short nfsv4err_getattr[] = {
567	NFSERR_IO,
568	NFSERR_ACCES,
569	NFSERR_BADHANDLE,
570	NFSERR_BADXDR,
571	NFSERR_DELAY,
572	NFSERR_FHEXPIRED,
573	NFSERR_INVAL,
574	NFSERR_IO,
575	NFSERR_MOVED,
576	NFSERR_NOFILEHANDLE,
577	NFSERR_RESOURCE,
578	NFSERR_SERVERFAULT,
579	NFSERR_STALE,
580	0,
581};
582
583static short nfsv4err_getfh[] = {
584	NFSERR_BADHANDLE,
585	NFSERR_BADHANDLE,
586	NFSERR_FHEXPIRED,
587	NFSERR_MOVED,
588	NFSERR_NOFILEHANDLE,
589	NFSERR_RESOURCE,
590	NFSERR_SERVERFAULT,
591	NFSERR_STALE,
592	0,
593};
594
595static short nfsv4err_link[] = {
596	NFSERR_IO,
597	NFSERR_ACCES,
598	NFSERR_BADCHAR,
599	NFSERR_BADHANDLE,
600	NFSERR_BADNAME,
601	NFSERR_BADXDR,
602	NFSERR_DELAY,
603	NFSERR_DQUOT,
604	NFSERR_EXIST,
605	NFSERR_FHEXPIRED,
606	NFSERR_FILEOPEN,
607	NFSERR_INVAL,
608	NFSERR_IO,
609	NFSERR_ISDIR,
610	NFSERR_MLINK,
611	NFSERR_MOVED,
612	NFSERR_NAMETOL,
613	NFSERR_NOENT,
614	NFSERR_NOFILEHANDLE,
615	NFSERR_NOSPC,
616	NFSERR_NOTDIR,
617	NFSERR_NOTSUPP,
618	NFSERR_RESOURCE,
619	NFSERR_ROFS,
620	NFSERR_SERVERFAULT,
621	NFSERR_STALE,
622	NFSERR_WRONGSEC,
623	NFSERR_XDEV,
624	0,
625};
626
627static short nfsv4err_lock[] = {
628	NFSERR_SERVERFAULT,
629	NFSERR_ACCES,
630	NFSERR_ADMINREVOKED,
631	NFSERR_BADHANDLE,
632	NFSERR_BADRANGE,
633	NFSERR_BADSEQID,
634	NFSERR_BADSTATEID,
635	NFSERR_BADXDR,
636	NFSERR_DEADLOCK,
637	NFSERR_DELAY,
638	NFSERR_DENIED,
639	NFSERR_EXPIRED,
640	NFSERR_FHEXPIRED,
641	NFSERR_GRACE,
642	NFSERR_INVAL,
643	NFSERR_ISDIR,
644	NFSERR_LEASEMOVED,
645	NFSERR_LOCKNOTSUPP,
646	NFSERR_LOCKRANGE,
647	NFSERR_MOVED,
648	NFSERR_NOFILEHANDLE,
649	NFSERR_NOGRACE,
650	NFSERR_OLDSTATEID,
651	NFSERR_OPENMODE,
652	NFSERR_RECLAIMBAD,
653	NFSERR_RECLAIMCONFLICT,
654	NFSERR_RESOURCE,
655	NFSERR_SERVERFAULT,
656	NFSERR_STALE,
657	NFSERR_STALECLIENTID,
658	NFSERR_STALESTATEID,
659	0,
660};
661
662static short nfsv4err_lockt[] = {
663	NFSERR_SERVERFAULT,
664	NFSERR_ACCES,
665	NFSERR_BADHANDLE,
666	NFSERR_BADRANGE,
667	NFSERR_BADXDR,
668	NFSERR_DELAY,
669	NFSERR_DENIED,
670	NFSERR_FHEXPIRED,
671	NFSERR_GRACE,
672	NFSERR_INVAL,
673	NFSERR_ISDIR,
674	NFSERR_LEASEMOVED,
675	NFSERR_LOCKRANGE,
676	NFSERR_MOVED,
677	NFSERR_NOFILEHANDLE,
678	NFSERR_RESOURCE,
679	NFSERR_SERVERFAULT,
680	NFSERR_STALE,
681	NFSERR_STALECLIENTID,
682	0,
683};
684
685static short nfsv4err_locku[] = {
686	NFSERR_SERVERFAULT,
687	NFSERR_ACCES,
688	NFSERR_ADMINREVOKED,
689	NFSERR_BADHANDLE,
690	NFSERR_BADRANGE,
691	NFSERR_BADSEQID,
692	NFSERR_BADSTATEID,
693	NFSERR_BADXDR,
694	NFSERR_EXPIRED,
695	NFSERR_FHEXPIRED,
696	NFSERR_GRACE,
697	NFSERR_INVAL,
698	NFSERR_ISDIR,
699	NFSERR_LEASEMOVED,
700	NFSERR_LOCKRANGE,
701	NFSERR_MOVED,
702	NFSERR_NOFILEHANDLE,
703	NFSERR_OLDSTATEID,
704	NFSERR_RESOURCE,
705	NFSERR_SERVERFAULT,
706	NFSERR_STALE,
707	NFSERR_STALESTATEID,
708	0,
709};
710
711static short nfsv4err_lookup[] = {
712	NFSERR_IO,
713	NFSERR_ACCES,
714	NFSERR_BADCHAR,
715	NFSERR_BADHANDLE,
716	NFSERR_BADNAME,
717	NFSERR_BADXDR,
718	NFSERR_FHEXPIRED,
719	NFSERR_INVAL,
720	NFSERR_IO,
721	NFSERR_MOVED,
722	NFSERR_NAMETOL,
723	NFSERR_NOENT,
724	NFSERR_NOFILEHANDLE,
725	NFSERR_NOTDIR,
726	NFSERR_RESOURCE,
727	NFSERR_SERVERFAULT,
728	NFSERR_STALE,
729	NFSERR_SYMLINK,
730	NFSERR_WRONGSEC,
731	0,
732};
733
734static short nfsv4err_lookupp[] = {
735	NFSERR_IO,
736	NFSERR_ACCES,
737	NFSERR_BADHANDLE,
738	NFSERR_FHEXPIRED,
739	NFSERR_IO,
740	NFSERR_MOVED,
741	NFSERR_NOENT,
742	NFSERR_NOFILEHANDLE,
743	NFSERR_NOTDIR,
744	NFSERR_RESOURCE,
745	NFSERR_SERVERFAULT,
746	NFSERR_STALE,
747	0,
748};
749
750static short nfsv4err_nverify[] = {
751	NFSERR_IO,
752	NFSERR_ACCES,
753	NFSERR_ATTRNOTSUPP,
754	NFSERR_BADCHAR,
755	NFSERR_BADHANDLE,
756	NFSERR_BADXDR,
757	NFSERR_DELAY,
758	NFSERR_FHEXPIRED,
759	NFSERR_INVAL,
760	NFSERR_IO,
761	NFSERR_MOVED,
762	NFSERR_NOFILEHANDLE,
763	NFSERR_RESOURCE,
764	NFSERR_SAME,
765	NFSERR_SERVERFAULT,
766	NFSERR_STALE,
767	0,
768};
769
770static short nfsv4err_open[] = {
771	NFSERR_IO,
772	NFSERR_ACCES,
773	NFSERR_ADMINREVOKED,
774	NFSERR_ATTRNOTSUPP,
775	NFSERR_BADCHAR,
776	NFSERR_BADHANDLE,
777	NFSERR_BADNAME,
778	NFSERR_BADOWNER,
779	NFSERR_BADSEQID,
780	NFSERR_BADXDR,
781	NFSERR_DELAY,
782	NFSERR_DQUOT,
783	NFSERR_EXIST,
784	NFSERR_EXPIRED,
785	NFSERR_FHEXPIRED,
786	NFSERR_GRACE,
787	NFSERR_IO,
788	NFSERR_INVAL,
789	NFSERR_ISDIR,
790	NFSERR_LEASEMOVED,
791	NFSERR_MOVED,
792	NFSERR_NAMETOL,
793	NFSERR_NOENT,
794	NFSERR_NOFILEHANDLE,
795	NFSERR_NOGRACE,
796	NFSERR_NOSPC,
797	NFSERR_NOTDIR,
798	NFSERR_NOTSUPP,
799	NFSERR_PERM,
800	NFSERR_RECLAIMBAD,
801	NFSERR_RECLAIMCONFLICT,
802	NFSERR_RESOURCE,
803	NFSERR_ROFS,
804	NFSERR_SERVERFAULT,
805	NFSERR_SHAREDENIED,
806	NFSERR_STALE,
807	NFSERR_STALECLIENTID,
808	NFSERR_SYMLINK,
809	NFSERR_WRONGSEC,
810	0,
811};
812
813static short nfsv4err_openattr[] = {
814	NFSERR_IO,
815	NFSERR_ACCES,
816	NFSERR_BADHANDLE,
817	NFSERR_BADXDR,
818	NFSERR_DELAY,
819	NFSERR_DQUOT,
820	NFSERR_FHEXPIRED,
821	NFSERR_IO,
822	NFSERR_MOVED,
823	NFSERR_NOENT,
824	NFSERR_NOFILEHANDLE,
825	NFSERR_NOSPC,
826	NFSERR_NOTSUPP,
827	NFSERR_RESOURCE,
828	NFSERR_ROFS,
829	NFSERR_SERVERFAULT,
830	NFSERR_STALE,
831	0,
832};
833
834static short nfsv4err_openconfirm[] = {
835	NFSERR_SERVERFAULT,
836	NFSERR_ADMINREVOKED,
837	NFSERR_BADHANDLE,
838	NFSERR_BADSEQID,
839	NFSERR_BADSTATEID,
840	NFSERR_BADXDR,
841	NFSERR_EXPIRED,
842	NFSERR_FHEXPIRED,
843	NFSERR_INVAL,
844	NFSERR_ISDIR,
845	NFSERR_MOVED,
846	NFSERR_NOFILEHANDLE,
847	NFSERR_OLDSTATEID,
848	NFSERR_RESOURCE,
849	NFSERR_SERVERFAULT,
850	NFSERR_STALE,
851	NFSERR_STALESTATEID,
852	0,
853};
854
855static short nfsv4err_opendowngrade[] = {
856	NFSERR_SERVERFAULT,
857	NFSERR_ADMINREVOKED,
858	NFSERR_BADHANDLE,
859	NFSERR_BADSEQID,
860	NFSERR_BADSTATEID,
861	NFSERR_BADXDR,
862	NFSERR_EXPIRED,
863	NFSERR_FHEXPIRED,
864	NFSERR_INVAL,
865	NFSERR_MOVED,
866	NFSERR_NOFILEHANDLE,
867	NFSERR_OLDSTATEID,
868	NFSERR_RESOURCE,
869	NFSERR_SERVERFAULT,
870	NFSERR_STALE,
871	NFSERR_STALESTATEID,
872	0,
873};
874
875static short nfsv4err_putfh[] = {
876	NFSERR_SERVERFAULT,
877	NFSERR_BADHANDLE,
878	NFSERR_BADXDR,
879	NFSERR_FHEXPIRED,
880	NFSERR_MOVED,
881	NFSERR_RESOURCE,
882	NFSERR_SERVERFAULT,
883	NFSERR_STALE,
884	NFSERR_WRONGSEC,
885	0,
886};
887
888static short nfsv4err_putpubfh[] = {
889	NFSERR_SERVERFAULT,
890	NFSERR_RESOURCE,
891	NFSERR_SERVERFAULT,
892	NFSERR_WRONGSEC,
893	0,
894};
895
896static short nfsv4err_putrootfh[] = {
897	NFSERR_SERVERFAULT,
898	NFSERR_RESOURCE,
899	NFSERR_SERVERFAULT,
900	NFSERR_WRONGSEC,
901	0,
902};
903
904static short nfsv4err_read[] = {
905	NFSERR_IO,
906	NFSERR_ACCES,
907	NFSERR_ADMINREVOKED,
908	NFSERR_BADHANDLE,
909	NFSERR_BADSTATEID,
910	NFSERR_BADXDR,
911	NFSERR_DELAY,
912	NFSERR_EXPIRED,
913	NFSERR_FHEXPIRED,
914	NFSERR_GRACE,
915	NFSERR_IO,
916	NFSERR_INVAL,
917	NFSERR_ISDIR,
918	NFSERR_LEASEMOVED,
919	NFSERR_LOCKED,
920	NFSERR_MOVED,
921	NFSERR_NOFILEHANDLE,
922	NFSERR_NXIO,
923	NFSERR_OLDSTATEID,
924	NFSERR_OPENMODE,
925	NFSERR_RESOURCE,
926	NFSERR_SERVERFAULT,
927	NFSERR_STALE,
928	NFSERR_STALESTATEID,
929	0,
930};
931
932static short nfsv4err_readdir[] = {
933	NFSERR_IO,
934	NFSERR_ACCES,
935	NFSERR_BADHANDLE,
936	NFSERR_BAD_COOKIE,
937	NFSERR_BADXDR,
938	NFSERR_DELAY,
939	NFSERR_FHEXPIRED,
940	NFSERR_INVAL,
941	NFSERR_IO,
942	NFSERR_MOVED,
943	NFSERR_NOFILEHANDLE,
944	NFSERR_NOTDIR,
945	NFSERR_NOTSAME,
946	NFSERR_RESOURCE,
947	NFSERR_SERVERFAULT,
948	NFSERR_STALE,
949	NFSERR_TOOSMALL,
950	0,
951};
952
953static short nfsv4err_readlink[] = {
954	NFSERR_IO,
955	NFSERR_ACCES,
956	NFSERR_BADHANDLE,
957	NFSERR_DELAY,
958	NFSERR_FHEXPIRED,
959	NFSERR_INVAL,
960	NFSERR_IO,
961	NFSERR_ISDIR,
962	NFSERR_MOVED,
963	NFSERR_NOFILEHANDLE,
964	NFSERR_NOTSUPP,
965	NFSERR_RESOURCE,
966	NFSERR_SERVERFAULT,
967	NFSERR_STALE,
968	0,
969};
970
971static short nfsv4err_remove[] = {
972	NFSERR_IO,
973	NFSERR_ACCES,
974	NFSERR_BADCHAR,
975	NFSERR_BADHANDLE,
976	NFSERR_BADNAME,
977	NFSERR_BADXDR,
978	NFSERR_DELAY,
979	NFSERR_FHEXPIRED,
980	NFSERR_FILEOPEN,
981	NFSERR_INVAL,
982	NFSERR_IO,
983	NFSERR_MOVED,
984	NFSERR_NAMETOL,
985	NFSERR_NOENT,
986	NFSERR_NOFILEHANDLE,
987	NFSERR_NOTDIR,
988	NFSERR_NOTEMPTY,
989	NFSERR_RESOURCE,
990	NFSERR_ROFS,
991	NFSERR_SERVERFAULT,
992	NFSERR_STALE,
993	0,
994};
995
996static short nfsv4err_rename[] = {
997	NFSERR_IO,
998	NFSERR_ACCES,
999	NFSERR_BADCHAR,
1000	NFSERR_BADHANDLE,
1001	NFSERR_BADNAME,
1002	NFSERR_BADXDR,
1003	NFSERR_DELAY,
1004	NFSERR_DQUOT,
1005	NFSERR_EXIST,
1006	NFSERR_FHEXPIRED,
1007	NFSERR_FILEOPEN,
1008	NFSERR_INVAL,
1009	NFSERR_IO,
1010	NFSERR_MOVED,
1011	NFSERR_NAMETOL,
1012	NFSERR_NOENT,
1013	NFSERR_NOFILEHANDLE,
1014	NFSERR_NOSPC,
1015	NFSERR_NOTDIR,
1016	NFSERR_NOTEMPTY,
1017	NFSERR_RESOURCE,
1018	NFSERR_ROFS,
1019	NFSERR_SERVERFAULT,
1020	NFSERR_STALE,
1021	NFSERR_WRONGSEC,
1022	NFSERR_XDEV,
1023	0,
1024};
1025
1026static short nfsv4err_renew[] = {
1027	NFSERR_SERVERFAULT,
1028	NFSERR_ACCES,
1029	NFSERR_ADMINREVOKED,
1030	NFSERR_BADXDR,
1031	NFSERR_CBPATHDOWN,
1032	NFSERR_EXPIRED,
1033	NFSERR_LEASEMOVED,
1034	NFSERR_RESOURCE,
1035	NFSERR_SERVERFAULT,
1036	NFSERR_STALECLIENTID,
1037	0,
1038};
1039
1040static short nfsv4err_restorefh[] = {
1041	NFSERR_SERVERFAULT,
1042	NFSERR_BADHANDLE,
1043	NFSERR_FHEXPIRED,
1044	NFSERR_MOVED,
1045	NFSERR_RESOURCE,
1046	NFSERR_RESTOREFH,
1047	NFSERR_SERVERFAULT,
1048	NFSERR_STALE,
1049	NFSERR_WRONGSEC,
1050	0,
1051};
1052
1053static short nfsv4err_savefh[] = {
1054	NFSERR_SERVERFAULT,
1055	NFSERR_BADHANDLE,
1056	NFSERR_FHEXPIRED,
1057	NFSERR_MOVED,
1058	NFSERR_NOFILEHANDLE,
1059	NFSERR_RESOURCE,
1060	NFSERR_SERVERFAULT,
1061	NFSERR_STALE,
1062	0,
1063};
1064
1065static short nfsv4err_secinfo[] = {
1066	NFSERR_SERVERFAULT,
1067	NFSERR_ACCES,
1068	NFSERR_BADCHAR,
1069	NFSERR_BADHANDLE,
1070	NFSERR_BADNAME,
1071	NFSERR_BADXDR,
1072	NFSERR_FHEXPIRED,
1073	NFSERR_INVAL,
1074	NFSERR_MOVED,
1075	NFSERR_NAMETOL,
1076	NFSERR_NOENT,
1077	NFSERR_NOFILEHANDLE,
1078	NFSERR_NOTDIR,
1079	NFSERR_RESOURCE,
1080	NFSERR_SERVERFAULT,
1081	NFSERR_STALE,
1082	0,
1083};
1084
1085static short nfsv4err_setattr[] = {
1086	NFSERR_IO,
1087	NFSERR_ACCES,
1088	NFSERR_ADMINREVOKED,
1089	NFSERR_ATTRNOTSUPP,
1090	NFSERR_BADCHAR,
1091	NFSERR_BADHANDLE,
1092	NFSERR_BADOWNER,
1093	NFSERR_BADSTATEID,
1094	NFSERR_BADXDR,
1095	NFSERR_DELAY,
1096	NFSERR_DQUOT,
1097	NFSERR_EXPIRED,
1098	NFSERR_FBIG,
1099	NFSERR_FHEXPIRED,
1100	NFSERR_GRACE,
1101	NFSERR_INVAL,
1102	NFSERR_IO,
1103	NFSERR_ISDIR,
1104	NFSERR_LOCKED,
1105	NFSERR_MOVED,
1106	NFSERR_NOFILEHANDLE,
1107	NFSERR_NOSPC,
1108	NFSERR_OLDSTATEID,
1109	NFSERR_OPENMODE,
1110	NFSERR_PERM,
1111	NFSERR_RESOURCE,
1112	NFSERR_ROFS,
1113	NFSERR_SERVERFAULT,
1114	NFSERR_STALE,
1115	NFSERR_STALESTATEID,
1116	0,
1117};
1118
1119static short nfsv4err_setclientid[] = {
1120	NFSERR_SERVERFAULT,
1121	NFSERR_BADXDR,
1122	NFSERR_CLIDINUSE,
1123	NFSERR_INVAL,
1124	NFSERR_RESOURCE,
1125	NFSERR_SERVERFAULT,
1126	0,
1127};
1128
1129static short nfsv4err_setclientidconfirm[] = {
1130	NFSERR_SERVERFAULT,
1131	NFSERR_BADXDR,
1132	NFSERR_CLIDINUSE,
1133	NFSERR_RESOURCE,
1134	NFSERR_SERVERFAULT,
1135	NFSERR_STALECLIENTID,
1136	0,
1137};
1138
1139static short nfsv4err_verify[] = {
1140	NFSERR_SERVERFAULT,
1141	NFSERR_ACCES,
1142	NFSERR_ATTRNOTSUPP,
1143	NFSERR_BADCHAR,
1144	NFSERR_BADHANDLE,
1145	NFSERR_BADXDR,
1146	NFSERR_DELAY,
1147	NFSERR_FHEXPIRED,
1148	NFSERR_INVAL,
1149	NFSERR_MOVED,
1150	NFSERR_NOFILEHANDLE,
1151	NFSERR_NOTSAME,
1152	NFSERR_RESOURCE,
1153	NFSERR_SERVERFAULT,
1154	NFSERR_STALE,
1155	0,
1156};
1157
1158static short nfsv4err_write[] = {
1159	NFSERR_IO,
1160	NFSERR_ACCES,
1161	NFSERR_ADMINREVOKED,
1162	NFSERR_BADHANDLE,
1163	NFSERR_BADSTATEID,
1164	NFSERR_BADXDR,
1165	NFSERR_DELAY,
1166	NFSERR_DQUOT,
1167	NFSERR_EXPIRED,
1168	NFSERR_FBIG,
1169	NFSERR_FHEXPIRED,
1170	NFSERR_GRACE,
1171	NFSERR_INVAL,
1172	NFSERR_IO,
1173	NFSERR_ISDIR,
1174	NFSERR_LEASEMOVED,
1175	NFSERR_LOCKED,
1176	NFSERR_MOVED,
1177	NFSERR_NOFILEHANDLE,
1178	NFSERR_NOSPC,
1179	NFSERR_NXIO,
1180	NFSERR_OLDSTATEID,
1181	NFSERR_OPENMODE,
1182	NFSERR_RESOURCE,
1183	NFSERR_ROFS,
1184	NFSERR_SERVERFAULT,
1185	NFSERR_STALE,
1186	NFSERR_STALESTATEID,
1187	0,
1188};
1189
1190static short nfsv4err_releaselockowner[] = {
1191	NFSERR_SERVERFAULT,
1192	NFSERR_ADMINREVOKED,
1193	NFSERR_BADXDR,
1194	NFSERR_EXPIRED,
1195	NFSERR_LEASEMOVED,
1196	NFSERR_LOCKSHELD,
1197	NFSERR_RESOURCE,
1198	NFSERR_SERVERFAULT,
1199	NFSERR_STALECLIENTID,
1200	0,
1201};
1202
1203static short *nfsrv_v4errmap[] = {
1204	nfsv4err_null,
1205	nfsv4err_null,
1206	nfsv4err_null,
1207	nfsv4err_access,
1208	nfsv4err_close,
1209	nfsv4err_commit,
1210	nfsv4err_create,
1211	nfsv4err_delegpurge,
1212	nfsv4err_delegreturn,
1213	nfsv4err_getattr,
1214	nfsv4err_getfh,
1215	nfsv4err_link,
1216	nfsv4err_lock,
1217	nfsv4err_lockt,
1218	nfsv4err_locku,
1219	nfsv4err_lookup,
1220	nfsv4err_lookupp,
1221	nfsv4err_nverify,
1222	nfsv4err_open,
1223	nfsv4err_openattr,
1224	nfsv4err_openconfirm,
1225	nfsv4err_opendowngrade,
1226	nfsv4err_putfh,
1227	nfsv4err_putpubfh,
1228	nfsv4err_putrootfh,
1229	nfsv4err_read,
1230	nfsv4err_readdir,
1231	nfsv4err_readlink,
1232	nfsv4err_remove,
1233	nfsv4err_rename,
1234	nfsv4err_renew,
1235	nfsv4err_restorefh,
1236	nfsv4err_savefh,
1237	nfsv4err_secinfo,
1238	nfsv4err_setattr,
1239	nfsv4err_setclientid,
1240	nfsv4err_setclientidconfirm,
1241	nfsv4err_verify,
1242	nfsv4err_write,
1243	nfsv4err_releaselockowner,
1244};
1245
1246/*
1247 * A fiddled version of m_adj() that ensures null fill to a long
1248 * boundary and only trims off the back end
1249 */
1250APPLESTATIC void
1251nfsrv_adj(mbuf_t mp, int len, int nul)
1252{
1253	mbuf_t m;
1254	int count, i;
1255	char *cp;
1256
1257	/*
1258	 * Trim from tail.  Scan the mbuf chain,
1259	 * calculating its length and finding the last mbuf.
1260	 * If the adjustment only affects this mbuf, then just
1261	 * adjust and return.  Otherwise, rescan and truncate
1262	 * after the remaining size.
1263	 */
1264	count = 0;
1265	m = mp;
1266	for (;;) {
1267		count += mbuf_len(m);
1268		if (mbuf_next(m) == NULL)
1269			break;
1270		m = mbuf_next(m);
1271	}
1272	if (mbuf_len(m) > len) {
1273		mbuf_setlen(m, mbuf_len(m) - len);
1274		if (nul > 0) {
1275			cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1276			for (i = 0; i < nul; i++)
1277				*cp++ = '\0';
1278		}
1279		return;
1280	}
1281	count -= len;
1282	if (count < 0)
1283		count = 0;
1284	/*
1285	 * Correct length for chain is "count".
1286	 * Find the mbuf with last data, adjust its length,
1287	 * and toss data from remaining mbufs on chain.
1288	 */
1289	for (m = mp; m; m = mbuf_next(m)) {
1290		if (mbuf_len(m) >= count) {
1291			mbuf_setlen(m, count);
1292			if (nul > 0) {
1293				cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1294				for (i = 0; i < nul; i++)
1295					*cp++ = '\0';
1296			}
1297			break;
1298		}
1299		count -= mbuf_len(m);
1300	}
1301	for (m = mbuf_next(m); m; m = mbuf_next(m))
1302		mbuf_setlen(m, 0);
1303}
1304
1305/*
1306 * Make these functions instead of macros, so that the kernel text size
1307 * doesn't get too big...
1308 */
1309APPLESTATIC void
1310nfsrv_wcc(struct nfsrv_descript *nd, int before_ret,
1311    struct nfsvattr *before_nvap, int after_ret, struct nfsvattr *after_nvap)
1312{
1313	u_int32_t *tl;
1314
1315	if (before_ret) {
1316		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1317		*tl = newnfs_false;
1318	} else {
1319		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1320		*tl++ = newnfs_true;
1321		txdr_hyper(before_nvap->na_size, tl);
1322		tl += 2;
1323		txdr_nfsv3time(&(before_nvap->na_mtime), tl);
1324		tl += 2;
1325		txdr_nfsv3time(&(before_nvap->na_ctime), tl);
1326	}
1327	nfsrv_postopattr(nd, after_ret, after_nvap);
1328}
1329
1330APPLESTATIC void
1331nfsrv_postopattr(struct nfsrv_descript *nd, int after_ret,
1332    struct nfsvattr *after_nvap)
1333{
1334	u_int32_t *tl;
1335
1336	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1337	if (after_ret)
1338		*tl = newnfs_false;
1339	else {
1340		*tl = newnfs_true;
1341		nfsrv_fillattr(nd, after_nvap);
1342	}
1343}
1344
1345/*
1346 * Fill in file attributes for V2 and 3. For V4, call a separate
1347 * routine that sifts through all the attribute bits.
1348 */
1349APPLESTATIC void
1350nfsrv_fillattr(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1351{
1352	struct nfs_fattr *fp;
1353	int fattr_size;
1354
1355	/*
1356	 * Build space for the attribute structure.
1357	 */
1358	if (nd->nd_flag & ND_NFSV3)
1359		fattr_size = NFSX_V3FATTR;
1360	else
1361		fattr_size = NFSX_V2FATTR;
1362	NFSM_BUILD(fp, struct nfs_fattr *, fattr_size);
1363
1364	/*
1365	 * Now just fill it all in.
1366	 */
1367	fp->fa_nlink = txdr_unsigned(nvap->na_nlink);
1368	fp->fa_uid = txdr_unsigned(nvap->na_uid);
1369	fp->fa_gid = txdr_unsigned(nvap->na_gid);
1370	if (nd->nd_flag & ND_NFSV3) {
1371		fp->fa_type = vtonfsv34_type(nvap->na_type);
1372		fp->fa_mode = vtonfsv34_mode(nvap->na_mode);
1373		txdr_hyper(nvap->na_size, &fp->fa3_size);
1374		txdr_hyper(nvap->na_bytes, &fp->fa3_used);
1375		fp->fa3_rdev.specdata1 = txdr_unsigned(NFSMAJOR(nvap->na_rdev));
1376		fp->fa3_rdev.specdata2 = txdr_unsigned(NFSMINOR(nvap->na_rdev));
1377		fp->fa3_fsid.nfsuquad[0] = 0;
1378		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(nvap->na_fsid);
1379		fp->fa3_fileid.nfsuquad[0] = 0;
1380		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(nvap->na_fileid);
1381		txdr_nfsv3time(&nvap->na_atime, &fp->fa3_atime);
1382		txdr_nfsv3time(&nvap->na_mtime, &fp->fa3_mtime);
1383		txdr_nfsv3time(&nvap->na_ctime, &fp->fa3_ctime);
1384	} else {
1385		fp->fa_type = vtonfsv2_type(nvap->na_type);
1386		fp->fa_mode = vtonfsv2_mode(nvap->na_type, nvap->na_mode);
1387		fp->fa2_size = txdr_unsigned(nvap->na_size);
1388		fp->fa2_blocksize = txdr_unsigned(nvap->na_blocksize);
1389		if (nvap->na_type == VFIFO)
1390			fp->fa2_rdev = 0xffffffff;
1391		else
1392			fp->fa2_rdev = txdr_unsigned(nvap->na_rdev);
1393		fp->fa2_blocks = txdr_unsigned(nvap->na_bytes / NFS_FABLKSIZE);
1394		fp->fa2_fsid = txdr_unsigned(nvap->na_fsid);
1395		fp->fa2_fileid = txdr_unsigned(nvap->na_fileid);
1396		txdr_nfsv2time(&nvap->na_atime, &fp->fa2_atime);
1397		txdr_nfsv2time(&nvap->na_mtime, &fp->fa2_mtime);
1398		txdr_nfsv2time(&nvap->na_ctime, &fp->fa2_ctime);
1399	}
1400}
1401
1402/*
1403 * This function gets a file handle out of an mbuf list.
1404 * It returns 0 for success, EBADRPC otherwise.
1405 * If sets the third flagp argument to 1 if the file handle is
1406 * the public file handle.
1407 * For NFSv4, if the length is incorrect, set nd_repstat == NFSERR_BADHANDLE
1408 */
1409APPLESTATIC int
1410nfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
1411{
1412	u_int32_t *tl;
1413	int error = 0, len, copylen;
1414
1415	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1416		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1417		len = fxdr_unsigned(int, *tl);
1418		if (len == 0 && nfs_pubfhset && (nd->nd_flag & ND_NFSV3) &&
1419		    nd->nd_procnum == NFSPROC_LOOKUP) {
1420			nd->nd_flag |= ND_PUBLOOKUP;
1421			return (0);
1422		}
1423		if (len < NFSRV_MINFH || len > NFSRV_MAXFH) {
1424			if (nd->nd_flag & ND_NFSV4) {
1425			    if (len > 0 && len <= NFSX_V4FHMAX) {
1426				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1427				if (error)
1428					return (error);
1429				nd->nd_repstat = NFSERR_BADHANDLE;
1430				return (0);
1431			    } else {
1432				return (EBADRPC);
1433			    }
1434			} else {
1435				return (EBADRPC);
1436			}
1437		}
1438		copylen = len;
1439	} else {
1440		/*
1441		 * For NFSv2, the file handle is always 32 bytes on the
1442		 * wire, but this server only cares about the first
1443		 * NFSRV_MAXFH bytes.
1444		 */
1445		len = NFSX_V2FH;
1446		copylen = NFSRV_MAXFH;
1447	}
1448	NFSM_DISSECT(tl, u_int32_t *, len);
1449	if ((nd->nd_flag & ND_NFSV2) && nfs_pubfhset &&
1450	    nd->nd_procnum == NFSPROC_LOOKUP &&
1451	    !NFSBCMP((caddr_t)tl, nfs_v2pubfh, NFSX_V2FH)) {
1452		nd->nd_flag |= ND_PUBLOOKUP;
1453		return (0);
1454	}
1455	NFSBCOPY(tl, (caddr_t)fhp->nfsrvfh_data, copylen);
1456	fhp->nfsrvfh_len = copylen;
1457nfsmout:
1458	return (error);
1459}
1460
1461/*
1462 * Map errnos to NFS error numbers. For Version 3 and 4 also filter out error
1463 * numbers not specified for the associated procedure.
1464 * NFSPROC_NOOP is a special case, where the high order bits of nd_repstat
1465 * should be cleared. NFSPROC_NOOP is used to return errors when a valid
1466 * RPC procedure is not involved.
1467 * Returns the error number in XDR.
1468 */
1469APPLESTATIC int
1470nfsd_errmap(struct nfsrv_descript *nd)
1471{
1472	short *defaulterrp, *errp;
1473
1474	if (!nd->nd_repstat)
1475		return (0);
1476	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1477		if (nd->nd_procnum == NFSPROC_NOOP)
1478			return (txdr_unsigned(nd->nd_repstat & 0xffff));
1479		if (nd->nd_flag & ND_NFSV3)
1480		    errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1481		else if (nd->nd_repstat == EBADRPC)
1482			return (txdr_unsigned(NFSERR_BADXDR));
1483		else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
1484			 nd->nd_repstat == NFSERR_OPILLEGAL)
1485			return (txdr_unsigned(nd->nd_repstat));
1486		else
1487		    errp = defaulterrp = nfsrv_v4errmap[nd->nd_procnum];
1488		while (*++errp)
1489			if (*errp == nd->nd_repstat)
1490				return (txdr_unsigned(nd->nd_repstat));
1491		return (txdr_unsigned(*defaulterrp));
1492	}
1493	if (nd->nd_repstat <= ELAST)
1494		return (txdr_unsigned(nfsrv_v2errmap[nd->nd_repstat - 1]));
1495	return (txdr_unsigned(NFSERR_IO));
1496}
1497
1498/*
1499 * Check to see if setting a uid/gid is permitted when creating a new
1500 * file object. (Called when uid and/or gid is specified in the
1501 * settable attributes for V4.
1502 */
1503APPLESTATIC int
1504nfsrv_checkuidgid(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1505{
1506
1507	/*
1508	 * If not setting either uid nor gid, it's OK.
1509	 */
1510	if (NFSVNO_NOTSETUID(nvap) && NFSVNO_NOTSETGID(nvap))
1511		return (0);
1512	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid == nfsrv_defaultuid)
1513	    || (NFSVNO_ISSETGID(nvap) && nvap->na_gid == nfsrv_defaultgid))
1514		return (NFSERR_BADOWNER);
1515	if (nd->nd_cred->cr_uid == 0)
1516		return (0);
1517	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid != nd->nd_cred->cr_uid) ||
1518	    (NFSVNO_ISSETGID(nvap) && nvap->na_gid != nd->nd_cred->cr_gid &&
1519	    !groupmember(nvap->na_gid, nd->nd_cred)))
1520		return (NFSERR_PERM);
1521	return (0);
1522}
1523
1524/*
1525 * and this routine fixes up the settable attributes for V4 if allowed
1526 * by nfsrv_checkuidgid().
1527 */
1528APPLESTATIC void
1529nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
1530    struct nfsvattr *nvap, NFSACL_T *aclp, NFSPROC_T *p, nfsattrbit_t *attrbitp,
1531    struct nfsexstuff *exp)
1532{
1533	int change = 0;
1534	struct nfsvattr nva;
1535	uid_t tuid;
1536	int error;
1537	nfsattrbit_t nattrbits;
1538
1539	/*
1540	 * Maybe this should be done for V2 and 3 but it never has been
1541	 * and nobody seems to be upset, so I think it's best not to change
1542	 * the V2 and 3 semantics.
1543	 */
1544	if ((nd->nd_flag & ND_NFSV4) == 0)
1545		return;
1546	NFSVNO_ATTRINIT(&nva);
1547	NFSZERO_ATTRBIT(&nattrbits);
1548	tuid = nd->nd_cred->cr_uid;
1549	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) &&
1550	    NFSVNO_ISSETUID(nvap) &&
1551	    nvap->na_uid != nd->nd_cred->cr_uid) {
1552		if (nd->nd_cred->cr_uid == 0) {
1553			nva.na_uid = nvap->na_uid;
1554			change++;
1555			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNER);
1556		} else {
1557			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNER);
1558		}
1559	}
1560	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESSSET) &&
1561	    NFSVNO_ISSETATIME(nvap)) {
1562		nva.na_atime = nvap->na_atime;
1563		change++;
1564		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEACCESSSET);
1565	}
1566	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFYSET) &&
1567	    NFSVNO_ISSETMTIME(nvap)) {
1568		nva.na_mtime = nvap->na_mtime;
1569		change++;
1570		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEMODIFYSET);
1571	}
1572	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) &&
1573	    NFSVNO_ISSETGID(nvap)) {
1574		if (nvap->na_gid == nd->nd_cred->cr_gid ||
1575		    groupmember(nvap->na_gid, nd->nd_cred)) {
1576			nd->nd_cred->cr_uid = 0;
1577			nva.na_gid = nvap->na_gid;
1578			change++;
1579			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNERGROUP);
1580		} else {
1581			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP);
1582		}
1583	}
1584	if (change) {
1585		error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
1586		if (error) {
1587			NFSCLRALL_ATTRBIT(attrbitp, &nattrbits);
1588		}
1589	}
1590	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) &&
1591	    NFSVNO_ISSETSIZE(nvap) && nvap->na_size != (u_quad_t)0) {
1592		NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_SIZE);
1593	}
1594#ifdef NFS4_ACL_EXTATTR_NAME
1595	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL) &&
1596	    nfsrv_useacl != 0 && aclp != NULL) {
1597		if (aclp->acl_cnt > 0) {
1598			error = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
1599			if (error) {
1600				NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1601			}
1602		}
1603	} else
1604#endif
1605	NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1606	nd->nd_cred->cr_uid = tuid;
1607}
1608
1609/*
1610 * Translate an ASCII hex digit to it's binary value. Return -1 if the
1611 * char isn't a hex digit.
1612 */
1613static char
1614nfsrv_hexdigit(char c, int *err)
1615{
1616
1617	*err = 0;
1618	if (c >= '0' && c <= '9')
1619		return (c - '0');
1620	if (c >= 'a' && c <= 'f')
1621		return (c - 'a' + ((char)10));
1622	if (c >= 'A' && c <= 'F')
1623		return (c - 'A' + ((char)10));
1624	/* Not valid ! */
1625	*err = 1;
1626	return (1);	/* BOGUS */
1627}
1628
1629/*
1630 * Check to see if NFSERR_MOVED can be returned for this op. Return 1 iff
1631 * it can be.
1632 */
1633APPLESTATIC int
1634nfsrv_errmoved(int op)
1635{
1636	short *errp;
1637
1638	errp = nfsrv_v4errmap[op];
1639	while (*errp != 0) {
1640		if (*errp == NFSERR_MOVED)
1641			return (1);
1642		errp++;
1643	}
1644	return (0);
1645}
1646
1647/*
1648 * Fill in attributes for a Referral.
1649 * (Return the number of bytes of XDR created.)
1650 */
1651APPLESTATIC int
1652nfsrv_putreferralattr(struct nfsrv_descript *nd, nfsattrbit_t *retbitp,
1653    struct nfsreferral *refp, int getattr, int *reterrp)
1654{
1655	u_int32_t *tl, *retnump;
1656	u_char *cp, *cp2;
1657	int prefixnum, retnum = 0, i, len, bitpos, rderrbit = 0, nonrefbit = 0;
1658	int fslocationsbit = 0;
1659	nfsattrbit_t tmpbits, refbits;
1660
1661	NFSREFERRAL_ATTRBIT(&refbits);
1662	if (getattr)
1663		NFSCLRBIT_ATTRBIT(&refbits, NFSATTRBIT_RDATTRERROR);
1664	else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_RDATTRERROR))
1665		rderrbit = 1;
1666	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_FSLOCATIONS))
1667		fslocationsbit = 1;
1668
1669	/*
1670	 * Check for the case where unsupported referral attributes are
1671	 * requested.
1672	 */
1673	NFSSET_ATTRBIT(&tmpbits, retbitp);
1674	NFSCLRALL_ATTRBIT(&tmpbits, &refbits);
1675	if (NFSNONZERO_ATTRBIT(&tmpbits))
1676		nonrefbit = 1;
1677
1678	if (nonrefbit && !fslocationsbit && (getattr || !rderrbit)) {
1679		*reterrp = NFSERR_MOVED;
1680		return (0);
1681	}
1682
1683	/*
1684	 * Now we can fill in the attributes.
1685	 */
1686	NFSSET_ATTRBIT(&tmpbits, retbitp);
1687	NFSCLRNOT_ATTRBIT(&tmpbits, &refbits);
1688
1689	/*
1690	 * Put out the attribute bitmap for the ones being filled in
1691	 * and get the field for the number of attributes returned.
1692	 */
1693	prefixnum = nfsrv_putattrbit(nd, &tmpbits);
1694	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1695	prefixnum += NFSX_UNSIGNED;
1696
1697	/*
1698	 * Now, loop around filling in the attributes for each bit set.
1699	 */
1700	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1701	    if (NFSISSET_ATTRBIT(&tmpbits, bitpos)) {
1702		switch (bitpos) {
1703		case NFSATTRBIT_TYPE:
1704			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1705			*tl = txdr_unsigned(NFDIR);
1706			retnum += NFSX_UNSIGNED;
1707			break;
1708		case NFSATTRBIT_FSID:
1709			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
1710			*tl++ = 0;
1711			*tl++ = txdr_unsigned(NFSV4ROOT_FSID0);
1712			*tl++ = 0;
1713			*tl = txdr_unsigned(NFSV4ROOT_REFERRAL);
1714			retnum += NFSX_V4FSID;
1715			break;
1716		case NFSATTRBIT_RDATTRERROR:
1717			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1718			if (nonrefbit)
1719				*tl = txdr_unsigned(NFSERR_MOVED);
1720			else
1721				*tl = 0;
1722			retnum += NFSX_UNSIGNED;
1723			break;
1724		case NFSATTRBIT_FSLOCATIONS:
1725			retnum += nfsm_strtom(nd, "/", 1);
1726			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1727			*tl = txdr_unsigned(refp->nfr_srvcnt);
1728			retnum += NFSX_UNSIGNED;
1729			cp = refp->nfr_srvlist;
1730			for (i = 0; i < refp->nfr_srvcnt; i++) {
1731				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1732				*tl = txdr_unsigned(1);
1733				retnum += NFSX_UNSIGNED;
1734				cp2 = STRCHR(cp, ':');
1735				if (cp2 != NULL)
1736					len = cp2 - cp;
1737				else
1738					len = 1;
1739				retnum += nfsm_strtom(nd, cp, len);
1740				if (cp2 != NULL)
1741					cp = cp2 + 1;
1742				cp2 = STRCHR(cp, ',');
1743				if (cp2 != NULL)
1744					len = cp2 - cp;
1745				else
1746					len = strlen(cp);
1747				retnum += nfsm_strtom(nd, cp, len);
1748				if (cp2 != NULL)
1749					cp = cp2 + 1;
1750			}
1751			break;
1752		case NFSATTRBIT_MOUNTEDONFILEID:
1753			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
1754			*tl++ = 0;
1755			*tl = txdr_unsigned(refp->nfr_dfileno);
1756			retnum += NFSX_HYPER;
1757			break;
1758		default:
1759			printf("EEK! Bad V4 refattr bitpos=%d\n", bitpos);
1760		};
1761	    }
1762	}
1763	*retnump = txdr_unsigned(retnum);
1764	return (retnum + prefixnum);
1765}
1766
1767/*
1768 * Parse a file name out of a request.
1769 */
1770APPLESTATIC int
1771nfsrv_parsename(struct nfsrv_descript *nd, char *bufp, u_long *hashp,
1772    NFSPATHLEN_T *outlenp)
1773{
1774	char *fromcp, *tocp, val = '\0';
1775	mbuf_t md;
1776	int i;
1777	int rem, len, error = 0, pubtype = 0, outlen = 0, percent = 0;
1778	char digit;
1779	u_int32_t *tl;
1780	u_long hash = 0;
1781
1782	if (hashp != NULL)
1783		*hashp = 0;
1784	tocp = bufp;
1785	/*
1786	 * For V4, check for lookup parent.
1787	 * Otherwise, get the component name.
1788	 */
1789	if ((nd->nd_flag & ND_NFSV4) && nd->nd_procnum == NFSV4OP_LOOKUPP) {
1790	    *tocp++ = '.';
1791	    hash += ((u_char)'.');
1792	    *tocp++ = '.';
1793	    hash += ((u_char)'.');
1794	    outlen = 2;
1795	} else {
1796	    /*
1797	     * First, get the name length.
1798	     */
1799	    NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1800	    len = fxdr_unsigned(int, *tl);
1801	    if (len > NFS_MAXNAMLEN) {
1802		nd->nd_repstat = NFSERR_NAMETOL;
1803		return (0);
1804	    } else if (len <= 0) {
1805		nd->nd_repstat = NFSERR_INVAL;
1806		return (0);
1807	    }
1808
1809	    /*
1810	     * Now, copy the component name into the buffer.
1811	     */
1812	    fromcp = nd->nd_dpos;
1813	    md = nd->nd_md;
1814	    rem = NFSMTOD(md, caddr_t) + mbuf_len(md) - fromcp;
1815	    for (i = 0; i < len; i++) {
1816		while (rem == 0) {
1817			md = mbuf_next(md);
1818			if (md == NULL)
1819				return (EBADRPC);
1820			fromcp = NFSMTOD(md, caddr_t);
1821			rem = mbuf_len(md);
1822		}
1823		if (*fromcp == '\0') {
1824			nd->nd_repstat = EACCES;
1825			return (0);
1826		}
1827		/*
1828		 * For lookups on the public filehandle, do some special
1829		 * processing on the name. (The public file handle is the
1830		 * root of the public file system for this server.)
1831		 */
1832		if (nd->nd_flag & ND_PUBLOOKUP) {
1833			/*
1834			 * If the first char is ASCII, it is a canonical
1835			 * path, otherwise it is a native path. (RFC2054
1836			 * doesn't actually state what it is if the first
1837			 * char isn't ASCII or 0x80, so I assume native.)
1838			 * pubtype == 1 -> native path
1839			 * pubtype == 2 -> canonical path
1840			 */
1841			if (i == 0) {
1842				if (*fromcp & 0x80) {
1843					/*
1844					 * Since RFC2054 doesn't indicate
1845					 * that a native path of just 0x80
1846					 * isn't allowed, I'll replace the
1847					 * 0x80 with '/' instead of just
1848					 * throwing it away.
1849					 */
1850					*fromcp = '/';
1851					pubtype = 1;
1852				} else {
1853					pubtype = 2;
1854				}
1855			}
1856			/*
1857			 * '/' only allowed in a native path
1858			 */
1859			if (*fromcp == '/' && pubtype != 1) {
1860				nd->nd_repstat = EACCES;
1861				return (0);
1862			}
1863
1864			/*
1865			 * For the special case of 2 hex digits after a
1866			 * '%' in an absolute path, calculate the value.
1867			 * percent == 1 -> indicates "get first hex digit"
1868			 * percent == 2 -> indicates "get second hex digit"
1869			 */
1870			if (percent > 0) {
1871				digit = nfsrv_hexdigit(*fromcp, &error);
1872				if (error) {
1873					nd->nd_repstat = EACCES;
1874					return (0);
1875				}
1876				if (percent == 1) {
1877					val = (digit << 4);
1878					percent = 2;
1879				} else {
1880					val += digit;
1881					percent = 0;
1882					*tocp++ = val;
1883					hash += ((u_char)val);
1884					outlen++;
1885				}
1886			} else {
1887				if (*fromcp == '%' && pubtype == 2) {
1888					/*
1889					 * Must be followed by 2 hex digits
1890					 */
1891					if ((len - i) < 3) {
1892						nd->nd_repstat = EACCES;
1893						return (0);
1894					}
1895					percent = 1;
1896				} else {
1897					*tocp++ = *fromcp;
1898					hash += ((u_char)*fromcp);
1899					outlen++;
1900				}
1901			}
1902		} else {
1903			/*
1904			 * Normal, non lookup on public, name.
1905			 */
1906			if (*fromcp == '/') {
1907				if (nd->nd_flag & ND_NFSV4)
1908					nd->nd_repstat = NFSERR_BADNAME;
1909				else
1910					nd->nd_repstat = EACCES;
1911				return (0);
1912			}
1913			hash += ((u_char)*fromcp);
1914			*tocp++ = *fromcp;
1915			outlen++;
1916		}
1917		fromcp++;
1918		rem--;
1919	    }
1920	    nd->nd_md = md;
1921	    nd->nd_dpos = fromcp;
1922	    i = NFSM_RNDUP(len) - len;
1923	    if (i > 0) {
1924		if (rem >= i) {
1925			nd->nd_dpos += i;
1926		} else {
1927			error = nfsm_advance(nd, i, rem);
1928			if (error)
1929				return (error);
1930		}
1931	    }
1932
1933	    /*
1934	     * For v4, don't allow lookups of '.' or '..' and
1935	     * also check for non-utf8 strings.
1936	     */
1937	    if (nd->nd_flag & ND_NFSV4) {
1938		if ((outlen == 1 && bufp[0] == '.') ||
1939		    (outlen == 2 && bufp[0] == '.' &&
1940		     bufp[1] == '.')) {
1941		    nd->nd_repstat = NFSERR_BADNAME;
1942		    return (0);
1943		}
1944		if (nfsrv_checkutf8((u_int8_t *)bufp, outlen)) {
1945		    nd->nd_repstat = NFSERR_INVAL;
1946		    return (0);
1947		}
1948	    }
1949	}
1950	*tocp = '\0';
1951	*outlenp = (size_t)outlen;
1952	if (hashp != NULL)
1953		*hashp = hash;
1954nfsmout:
1955	return (error);
1956}
1957
1958/*
1959 * Check the tcp socket sequence number has been acknowledged.
1960 */
1961int
1962nfsrv_checksockseqnum(struct socket *so, tcp_seq tcpseqval)
1963{
1964	tcp_seq maxseq, unaseq;
1965	int error, ret;
1966
1967	error = nfsrv_getsocksndseq(so, &maxseq, &unaseq);
1968	if (error)
1969		return (0);
1970	ret = SEQ_GEQ(unaseq, tcpseqval);
1971	return (ret);
1972}
1973
1974/*
1975 * Get the tcp sequence number to be acknowledged.
1976 */
1977int
1978nfsrv_getsockseqnum(struct socket *so, tcp_seq *tcpseqp)
1979{
1980	tcp_seq maxseq, unaseq;
1981	u_int sbcc;
1982	int error;
1983
1984	sbcc = so->so_snd.sb_cc;
1985	error = nfsrv_getsocksndseq(so, &maxseq, &unaseq);
1986	if (error)
1987		return (0);
1988	/*
1989	 * Set the seq# to a value that will
1990	 * be at least the end of the reply.
1991	 * When this sequence# is acknowledged
1992	 * by the client, the client has received
1993	 * the reply.
1994	 */
1995	*tcpseqp = sbcc + maxseq;
1996	return (1);
1997}
1998
1999void
2000nfsd_init(void)
2001{
2002	int i;
2003	static int inited = 0;
2004
2005	if (inited)
2006		return;
2007	inited = 1;
2008
2009	/*
2010	 * Initialize client queues. Don't free/reinitialize
2011	 * them when nfsds are restarted.
2012	 */
2013	for (i = 0; i < NFSCLIENTHASHSIZE; i++)
2014		LIST_INIT(&nfsclienthash[i]);
2015	for (i = 0; i < NFSLOCKHASHSIZE; i++)
2016		LIST_INIT(&nfslockhash[i]);
2017
2018	/* and the v2 pubfh should be all zeros */
2019	NFSBZERO(nfs_v2pubfh, NFSX_V2FH);
2020}
2021
2022