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