nfs_srvsubs.c revision 55934
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: head/sys/nfsserver/nfs_srvsubs.c 55934 2000-01-13 20:18:25Z dillon $
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/buf.h>
49#include <sys/proc.h>
50#include <sys/mount.h>
51#include <sys/vnode.h>
52#include <sys/namei.h>
53#include <sys/mbuf.h>
54#include <sys/socket.h>
55#include <sys/stat.h>
56#include <sys/malloc.h>
57#include <sys/sysent.h>
58#include <sys/syscall.h>
59#include <sys/conf.h>
60
61#include <vm/vm.h>
62#include <vm/vm_object.h>
63#include <vm/vm_extern.h>
64#include <vm/vm_zone.h>
65
66#include <nfs/rpcv2.h>
67#include <nfs/nfsproto.h>
68#include <nfs/nfs.h>
69#include <nfs/nfsnode.h>
70#include <nfs/xdr_subs.h>
71#include <nfs/nfsm_subs.h>
72#include <nfs/nfsmount.h>
73#include <nfs/nqnfs.h>
74#include <nfs/nfsrtt.h>
75
76#include <netinet/in.h>
77#ifdef ISO
78#include <netiso/iso.h>
79#endif
80
81/*
82 * Data items converted to xdr at startup, since they are constant
83 * This is kinda hokey, but may save a little time doing byte swaps
84 */
85u_int32_t nfs_xdrneg1;
86u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
87	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
88	rpc_auth_kerb;
89u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
90
91/* And other global data */
92static u_int32_t nfs_xid = 0;
93static enum vtype nv2tov_type[8]= {
94	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
95};
96enum vtype nv3tov_type[8]= {
97	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
98};
99
100int nfs_ticks;
101int nfs_pbuf_freecnt = -1;	/* start out unlimited */
102
103struct nfs_reqq nfs_reqq;
104struct nfssvc_sockhead nfssvc_sockhead;
105int nfssvc_sockhead_flag;
106struct nfsd_head nfsd_head;
107int nfsd_head_flag;
108struct nfs_bufq nfs_bufq;
109struct nqtimerhead nqtimerhead;
110struct nqfhhashhead *nqfhhashtbl;
111u_long nqfhhash;
112
113static void (*nfs_prev_lease_updatetime) __P((int));
114static int nfs_prev_nfssvc_sy_narg;
115static sy_call_t *nfs_prev_nfssvc_sy_call;
116
117#ifndef NFS_NOSERVER
118
119static vop_t *nfs_prev_vop_lease_check;
120
121/*
122 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
123 */
124int nfsv3_procid[NFS_NPROCS] = {
125	NFSPROC_NULL,
126	NFSPROC_GETATTR,
127	NFSPROC_SETATTR,
128	NFSPROC_NOOP,
129	NFSPROC_LOOKUP,
130	NFSPROC_READLINK,
131	NFSPROC_READ,
132	NFSPROC_NOOP,
133	NFSPROC_WRITE,
134	NFSPROC_CREATE,
135	NFSPROC_REMOVE,
136	NFSPROC_RENAME,
137	NFSPROC_LINK,
138	NFSPROC_SYMLINK,
139	NFSPROC_MKDIR,
140	NFSPROC_RMDIR,
141	NFSPROC_READDIR,
142	NFSPROC_FSSTAT,
143	NFSPROC_NOOP,
144	NFSPROC_NOOP,
145	NFSPROC_NOOP,
146	NFSPROC_NOOP,
147	NFSPROC_NOOP,
148	NFSPROC_NOOP,
149	NFSPROC_NOOP,
150	NFSPROC_NOOP
151};
152
153#endif /* NFS_NOSERVER */
154/*
155 * and the reverse mapping from generic to Version 2 procedure numbers
156 */
157int nfsv2_procid[NFS_NPROCS] = {
158	NFSV2PROC_NULL,
159	NFSV2PROC_GETATTR,
160	NFSV2PROC_SETATTR,
161	NFSV2PROC_LOOKUP,
162	NFSV2PROC_NOOP,
163	NFSV2PROC_READLINK,
164	NFSV2PROC_READ,
165	NFSV2PROC_WRITE,
166	NFSV2PROC_CREATE,
167	NFSV2PROC_MKDIR,
168	NFSV2PROC_SYMLINK,
169	NFSV2PROC_CREATE,
170	NFSV2PROC_REMOVE,
171	NFSV2PROC_RMDIR,
172	NFSV2PROC_RENAME,
173	NFSV2PROC_LINK,
174	NFSV2PROC_READDIR,
175	NFSV2PROC_NOOP,
176	NFSV2PROC_STATFS,
177	NFSV2PROC_NOOP,
178	NFSV2PROC_NOOP,
179	NFSV2PROC_NOOP,
180	NFSV2PROC_NOOP,
181	NFSV2PROC_NOOP,
182	NFSV2PROC_NOOP,
183	NFSV2PROC_NOOP,
184};
185
186#ifndef NFS_NOSERVER
187/*
188 * Maps errno values to nfs error numbers.
189 * Use NFSERR_IO as the catch all for ones not specifically defined in
190 * RFC 1094.
191 */
192static u_char nfsrv_v2errmap[ELAST] = {
193  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
194  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
195  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
196  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
197  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
198  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
199  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
200  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
201  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
202  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
203  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
204  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
205  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
206  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
207  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
208  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
209  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
210  NFSERR_IO /* << Last is 86 */
211};
212
213/*
214 * Maps errno values to nfs error numbers.
215 * Although it is not obvious whether or not NFS clients really care if
216 * a returned error value is in the specified list for the procedure, the
217 * safest thing to do is filter them appropriately. For Version 2, the
218 * X/Open XNFS document is the only specification that defines error values
219 * for each RPC (The RFC simply lists all possible error values for all RPCs),
220 * so I have decided to not do this for Version 2.
221 * The first entry is the default error return and the rest are the valid
222 * errors for that RPC in increasing numeric order.
223 */
224static short nfsv3err_null[] = {
225	0,
226	0,
227};
228
229static short nfsv3err_getattr[] = {
230	NFSERR_IO,
231	NFSERR_IO,
232	NFSERR_STALE,
233	NFSERR_BADHANDLE,
234	NFSERR_SERVERFAULT,
235	0,
236};
237
238static short nfsv3err_setattr[] = {
239	NFSERR_IO,
240	NFSERR_PERM,
241	NFSERR_IO,
242	NFSERR_ACCES,
243	NFSERR_INVAL,
244	NFSERR_NOSPC,
245	NFSERR_ROFS,
246	NFSERR_DQUOT,
247	NFSERR_STALE,
248	NFSERR_BADHANDLE,
249	NFSERR_NOT_SYNC,
250	NFSERR_SERVERFAULT,
251	0,
252};
253
254static short nfsv3err_lookup[] = {
255	NFSERR_IO,
256	NFSERR_NOENT,
257	NFSERR_IO,
258	NFSERR_ACCES,
259	NFSERR_NOTDIR,
260	NFSERR_NAMETOL,
261	NFSERR_STALE,
262	NFSERR_BADHANDLE,
263	NFSERR_SERVERFAULT,
264	0,
265};
266
267static short nfsv3err_access[] = {
268	NFSERR_IO,
269	NFSERR_IO,
270	NFSERR_STALE,
271	NFSERR_BADHANDLE,
272	NFSERR_SERVERFAULT,
273	0,
274};
275
276static short nfsv3err_readlink[] = {
277	NFSERR_IO,
278	NFSERR_IO,
279	NFSERR_ACCES,
280	NFSERR_INVAL,
281	NFSERR_STALE,
282	NFSERR_BADHANDLE,
283	NFSERR_NOTSUPP,
284	NFSERR_SERVERFAULT,
285	0,
286};
287
288static short nfsv3err_read[] = {
289	NFSERR_IO,
290	NFSERR_IO,
291	NFSERR_NXIO,
292	NFSERR_ACCES,
293	NFSERR_INVAL,
294	NFSERR_STALE,
295	NFSERR_BADHANDLE,
296	NFSERR_SERVERFAULT,
297	0,
298};
299
300static short nfsv3err_write[] = {
301	NFSERR_IO,
302	NFSERR_IO,
303	NFSERR_ACCES,
304	NFSERR_INVAL,
305	NFSERR_FBIG,
306	NFSERR_NOSPC,
307	NFSERR_ROFS,
308	NFSERR_DQUOT,
309	NFSERR_STALE,
310	NFSERR_BADHANDLE,
311	NFSERR_SERVERFAULT,
312	0,
313};
314
315static short nfsv3err_create[] = {
316	NFSERR_IO,
317	NFSERR_IO,
318	NFSERR_ACCES,
319	NFSERR_EXIST,
320	NFSERR_NOTDIR,
321	NFSERR_NOSPC,
322	NFSERR_ROFS,
323	NFSERR_NAMETOL,
324	NFSERR_DQUOT,
325	NFSERR_STALE,
326	NFSERR_BADHANDLE,
327	NFSERR_NOTSUPP,
328	NFSERR_SERVERFAULT,
329	0,
330};
331
332static short nfsv3err_mkdir[] = {
333	NFSERR_IO,
334	NFSERR_IO,
335	NFSERR_ACCES,
336	NFSERR_EXIST,
337	NFSERR_NOTDIR,
338	NFSERR_NOSPC,
339	NFSERR_ROFS,
340	NFSERR_NAMETOL,
341	NFSERR_DQUOT,
342	NFSERR_STALE,
343	NFSERR_BADHANDLE,
344	NFSERR_NOTSUPP,
345	NFSERR_SERVERFAULT,
346	0,
347};
348
349static short nfsv3err_symlink[] = {
350	NFSERR_IO,
351	NFSERR_IO,
352	NFSERR_ACCES,
353	NFSERR_EXIST,
354	NFSERR_NOTDIR,
355	NFSERR_NOSPC,
356	NFSERR_ROFS,
357	NFSERR_NAMETOL,
358	NFSERR_DQUOT,
359	NFSERR_STALE,
360	NFSERR_BADHANDLE,
361	NFSERR_NOTSUPP,
362	NFSERR_SERVERFAULT,
363	0,
364};
365
366static short nfsv3err_mknod[] = {
367	NFSERR_IO,
368	NFSERR_IO,
369	NFSERR_ACCES,
370	NFSERR_EXIST,
371	NFSERR_NOTDIR,
372	NFSERR_NOSPC,
373	NFSERR_ROFS,
374	NFSERR_NAMETOL,
375	NFSERR_DQUOT,
376	NFSERR_STALE,
377	NFSERR_BADHANDLE,
378	NFSERR_NOTSUPP,
379	NFSERR_SERVERFAULT,
380	NFSERR_BADTYPE,
381	0,
382};
383
384static short nfsv3err_remove[] = {
385	NFSERR_IO,
386	NFSERR_NOENT,
387	NFSERR_IO,
388	NFSERR_ACCES,
389	NFSERR_NOTDIR,
390	NFSERR_ROFS,
391	NFSERR_NAMETOL,
392	NFSERR_STALE,
393	NFSERR_BADHANDLE,
394	NFSERR_SERVERFAULT,
395	0,
396};
397
398static short nfsv3err_rmdir[] = {
399	NFSERR_IO,
400	NFSERR_NOENT,
401	NFSERR_IO,
402	NFSERR_ACCES,
403	NFSERR_EXIST,
404	NFSERR_NOTDIR,
405	NFSERR_INVAL,
406	NFSERR_ROFS,
407	NFSERR_NAMETOL,
408	NFSERR_NOTEMPTY,
409	NFSERR_STALE,
410	NFSERR_BADHANDLE,
411	NFSERR_NOTSUPP,
412	NFSERR_SERVERFAULT,
413	0,
414};
415
416static short nfsv3err_rename[] = {
417	NFSERR_IO,
418	NFSERR_NOENT,
419	NFSERR_IO,
420	NFSERR_ACCES,
421	NFSERR_EXIST,
422	NFSERR_XDEV,
423	NFSERR_NOTDIR,
424	NFSERR_ISDIR,
425	NFSERR_INVAL,
426	NFSERR_NOSPC,
427	NFSERR_ROFS,
428	NFSERR_MLINK,
429	NFSERR_NAMETOL,
430	NFSERR_NOTEMPTY,
431	NFSERR_DQUOT,
432	NFSERR_STALE,
433	NFSERR_BADHANDLE,
434	NFSERR_NOTSUPP,
435	NFSERR_SERVERFAULT,
436	0,
437};
438
439static short nfsv3err_link[] = {
440	NFSERR_IO,
441	NFSERR_IO,
442	NFSERR_ACCES,
443	NFSERR_EXIST,
444	NFSERR_XDEV,
445	NFSERR_NOTDIR,
446	NFSERR_INVAL,
447	NFSERR_NOSPC,
448	NFSERR_ROFS,
449	NFSERR_MLINK,
450	NFSERR_NAMETOL,
451	NFSERR_DQUOT,
452	NFSERR_STALE,
453	NFSERR_BADHANDLE,
454	NFSERR_NOTSUPP,
455	NFSERR_SERVERFAULT,
456	0,
457};
458
459static short nfsv3err_readdir[] = {
460	NFSERR_IO,
461	NFSERR_IO,
462	NFSERR_ACCES,
463	NFSERR_NOTDIR,
464	NFSERR_STALE,
465	NFSERR_BADHANDLE,
466	NFSERR_BAD_COOKIE,
467	NFSERR_TOOSMALL,
468	NFSERR_SERVERFAULT,
469	0,
470};
471
472static short nfsv3err_readdirplus[] = {
473	NFSERR_IO,
474	NFSERR_IO,
475	NFSERR_ACCES,
476	NFSERR_NOTDIR,
477	NFSERR_STALE,
478	NFSERR_BADHANDLE,
479	NFSERR_BAD_COOKIE,
480	NFSERR_NOTSUPP,
481	NFSERR_TOOSMALL,
482	NFSERR_SERVERFAULT,
483	0,
484};
485
486static short nfsv3err_fsstat[] = {
487	NFSERR_IO,
488	NFSERR_IO,
489	NFSERR_STALE,
490	NFSERR_BADHANDLE,
491	NFSERR_SERVERFAULT,
492	0,
493};
494
495static short nfsv3err_fsinfo[] = {
496	NFSERR_STALE,
497	NFSERR_STALE,
498	NFSERR_BADHANDLE,
499	NFSERR_SERVERFAULT,
500	0,
501};
502
503static short nfsv3err_pathconf[] = {
504	NFSERR_STALE,
505	NFSERR_STALE,
506	NFSERR_BADHANDLE,
507	NFSERR_SERVERFAULT,
508	0,
509};
510
511static short nfsv3err_commit[] = {
512	NFSERR_IO,
513	NFSERR_IO,
514	NFSERR_STALE,
515	NFSERR_BADHANDLE,
516	NFSERR_SERVERFAULT,
517	0,
518};
519
520static short *nfsrv_v3errmap[] = {
521	nfsv3err_null,
522	nfsv3err_getattr,
523	nfsv3err_setattr,
524	nfsv3err_lookup,
525	nfsv3err_access,
526	nfsv3err_readlink,
527	nfsv3err_read,
528	nfsv3err_write,
529	nfsv3err_create,
530	nfsv3err_mkdir,
531	nfsv3err_symlink,
532	nfsv3err_mknod,
533	nfsv3err_remove,
534	nfsv3err_rmdir,
535	nfsv3err_rename,
536	nfsv3err_link,
537	nfsv3err_readdir,
538	nfsv3err_readdirplus,
539	nfsv3err_fsstat,
540	nfsv3err_fsinfo,
541	nfsv3err_pathconf,
542	nfsv3err_commit,
543};
544
545#endif /* NFS_NOSERVER */
546
547extern struct nfsrtt nfsrtt;
548extern time_t nqnfsstarttime;
549extern int nqsrv_clockskew;
550extern int nqsrv_writeslack;
551extern int nqsrv_maxlease;
552extern struct nfsstats nfsstats;
553extern int nqnfs_piggy[NFS_NPROCS];
554extern nfstype nfsv2_type[9];
555extern nfstype nfsv3_type[9];
556extern struct nfsnodehashhead *nfsnodehashtbl;
557extern u_long nfsnodehash;
558
559struct nfssvc_args;
560extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
561
562LIST_HEAD(nfsnodehashhead, nfsnode);
563
564int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
565
566u_quad_t
567nfs_curusec()
568{
569	struct timeval tv;
570
571	getmicrotime(&tv);
572	return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
573}
574
575/*
576 * Create the header for an rpc request packet
577 * The hsiz is the size of the rest of the nfs request header.
578 * (just used to decide if a cluster is a good idea)
579 */
580struct mbuf *
581nfsm_reqh(vp, procid, hsiz, bposp)
582	struct vnode *vp;
583	u_long procid;
584	int hsiz;
585	caddr_t *bposp;
586{
587	register struct mbuf *mb;
588	register u_int32_t *tl;
589	register caddr_t bpos;
590	struct mbuf *mb2;
591	struct nfsmount *nmp;
592	int nqflag;
593
594	MGET(mb, M_WAIT, MT_DATA);
595	if (hsiz >= MINCLSIZE)
596		MCLGET(mb, M_WAIT);
597	mb->m_len = 0;
598	bpos = mtod(mb, caddr_t);
599
600	/*
601	 * For NQNFS, add lease request.
602	 */
603	if (vp) {
604		nmp = VFSTONFS(vp->v_mount);
605		if (nmp->nm_flag & NFSMNT_NQNFS) {
606			nqflag = NQNFS_NEEDLEASE(vp, procid);
607			if (nqflag) {
608				nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
609				*tl++ = txdr_unsigned(nqflag);
610				*tl = txdr_unsigned(nmp->nm_leaseterm);
611			} else {
612				nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
613				*tl = 0;
614			}
615		}
616	}
617	/* Finally, return values */
618	*bposp = bpos;
619	return (mb);
620}
621
622/*
623 * Build the RPC header and fill in the authorization info.
624 * The authorization string argument is only used when the credentials
625 * come from outside of the kernel.
626 * Returns the head of the mbuf list.
627 */
628struct mbuf *
629nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
630	verf_str, mrest, mrest_len, mbp, xidp)
631	register struct ucred *cr;
632	int nmflag;
633	int procid;
634	int auth_type;
635	int auth_len;
636	char *auth_str;
637	int verf_len;
638	char *verf_str;
639	struct mbuf *mrest;
640	int mrest_len;
641	struct mbuf **mbp;
642	u_int32_t *xidp;
643{
644	register struct mbuf *mb;
645	register u_int32_t *tl;
646	register caddr_t bpos;
647	register int i;
648	struct mbuf *mreq, *mb2;
649	int siz, grpsiz, authsiz;
650
651	authsiz = nfsm_rndup(auth_len);
652	MGETHDR(mb, M_WAIT, MT_DATA);
653	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
654		MCLGET(mb, M_WAIT);
655	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
656		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
657	} else {
658		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
659	}
660	mb->m_len = 0;
661	mreq = mb;
662	bpos = mtod(mb, caddr_t);
663
664	/*
665	 * First the RPC header.
666	 */
667	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
668
669	/* Get a pretty random xid to start with */
670	if (!nfs_xid)
671		nfs_xid = random();
672	/*
673	 * Skip zero xid if it should ever happen.
674	 */
675	if (++nfs_xid == 0)
676		nfs_xid++;
677
678	*tl++ = *xidp = txdr_unsigned(nfs_xid);
679	*tl++ = rpc_call;
680	*tl++ = rpc_vers;
681	if (nmflag & NFSMNT_NQNFS) {
682		*tl++ = txdr_unsigned(NQNFS_PROG);
683		*tl++ = txdr_unsigned(NQNFS_VER3);
684	} else {
685		*tl++ = txdr_unsigned(NFS_PROG);
686		if (nmflag & NFSMNT_NFSV3)
687			*tl++ = txdr_unsigned(NFS_VER3);
688		else
689			*tl++ = txdr_unsigned(NFS_VER2);
690	}
691	if (nmflag & NFSMNT_NFSV3)
692		*tl++ = txdr_unsigned(procid);
693	else
694		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
695
696	/*
697	 * And then the authorization cred.
698	 */
699	*tl++ = txdr_unsigned(auth_type);
700	*tl = txdr_unsigned(authsiz);
701	switch (auth_type) {
702	case RPCAUTH_UNIX:
703		nfsm_build(tl, u_int32_t *, auth_len);
704		*tl++ = 0;		/* stamp ?? */
705		*tl++ = 0;		/* NULL hostname */
706		*tl++ = txdr_unsigned(cr->cr_uid);
707		*tl++ = txdr_unsigned(cr->cr_groups[0]);
708		grpsiz = (auth_len >> 2) - 5;
709		*tl++ = txdr_unsigned(grpsiz);
710		for (i = 1; i <= grpsiz; i++)
711			*tl++ = txdr_unsigned(cr->cr_groups[i]);
712		break;
713	case RPCAUTH_KERB4:
714		siz = auth_len;
715		while (siz > 0) {
716			if (M_TRAILINGSPACE(mb) == 0) {
717				MGET(mb2, M_WAIT, MT_DATA);
718				if (siz >= MINCLSIZE)
719					MCLGET(mb2, M_WAIT);
720				mb->m_next = mb2;
721				mb = mb2;
722				mb->m_len = 0;
723				bpos = mtod(mb, caddr_t);
724			}
725			i = min(siz, M_TRAILINGSPACE(mb));
726			bcopy(auth_str, bpos, i);
727			mb->m_len += i;
728			auth_str += i;
729			bpos += i;
730			siz -= i;
731		}
732		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
733			for (i = 0; i < siz; i++)
734				*bpos++ = '\0';
735			mb->m_len += siz;
736		}
737		break;
738	};
739
740	/*
741	 * And the verifier...
742	 */
743	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
744	if (verf_str) {
745		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
746		*tl = txdr_unsigned(verf_len);
747		siz = verf_len;
748		while (siz > 0) {
749			if (M_TRAILINGSPACE(mb) == 0) {
750				MGET(mb2, M_WAIT, MT_DATA);
751				if (siz >= MINCLSIZE)
752					MCLGET(mb2, M_WAIT);
753				mb->m_next = mb2;
754				mb = mb2;
755				mb->m_len = 0;
756				bpos = mtod(mb, caddr_t);
757			}
758			i = min(siz, M_TRAILINGSPACE(mb));
759			bcopy(verf_str, bpos, i);
760			mb->m_len += i;
761			verf_str += i;
762			bpos += i;
763			siz -= i;
764		}
765		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
766			for (i = 0; i < siz; i++)
767				*bpos++ = '\0';
768			mb->m_len += siz;
769		}
770	} else {
771		*tl++ = txdr_unsigned(RPCAUTH_NULL);
772		*tl = 0;
773	}
774	mb->m_next = mrest;
775	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
776	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
777	*mbp = mb;
778	return (mreq);
779}
780
781/*
782 * copies mbuf chain to the uio scatter/gather list
783 */
784int
785nfsm_mbuftouio(mrep, uiop, siz, dpos)
786	struct mbuf **mrep;
787	register struct uio *uiop;
788	int siz;
789	caddr_t *dpos;
790{
791	register char *mbufcp, *uiocp;
792	register int xfer, left, len;
793	register struct mbuf *mp;
794	long uiosiz, rem;
795	int error = 0;
796
797	mp = *mrep;
798	mbufcp = *dpos;
799	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
800	rem = nfsm_rndup(siz)-siz;
801	while (siz > 0) {
802		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
803			return (EFBIG);
804		left = uiop->uio_iov->iov_len;
805		uiocp = uiop->uio_iov->iov_base;
806		if (left > siz)
807			left = siz;
808		uiosiz = left;
809		while (left > 0) {
810			while (len == 0) {
811				mp = mp->m_next;
812				if (mp == NULL)
813					return (EBADRPC);
814				mbufcp = mtod(mp, caddr_t);
815				len = mp->m_len;
816			}
817			xfer = (left > len) ? len : left;
818#ifdef notdef
819			/* Not Yet.. */
820			if (uiop->uio_iov->iov_op != NULL)
821				(*(uiop->uio_iov->iov_op))
822				(mbufcp, uiocp, xfer);
823			else
824#endif
825			if (uiop->uio_segflg == UIO_SYSSPACE)
826				bcopy(mbufcp, uiocp, xfer);
827			else
828				copyout(mbufcp, uiocp, xfer);
829			left -= xfer;
830			len -= xfer;
831			mbufcp += xfer;
832			uiocp += xfer;
833			uiop->uio_offset += xfer;
834			uiop->uio_resid -= xfer;
835		}
836		if (uiop->uio_iov->iov_len <= siz) {
837			uiop->uio_iovcnt--;
838			uiop->uio_iov++;
839		} else {
840			uiop->uio_iov->iov_base += uiosiz;
841			uiop->uio_iov->iov_len -= uiosiz;
842		}
843		siz -= uiosiz;
844	}
845	*dpos = mbufcp;
846	*mrep = mp;
847	if (rem > 0) {
848		if (len < rem)
849			error = nfs_adv(mrep, dpos, rem, len);
850		else
851			*dpos += rem;
852	}
853	return (error);
854}
855
856/*
857 * copies a uio scatter/gather list to an mbuf chain.
858 * NOTE: can ony handle iovcnt == 1
859 */
860int
861nfsm_uiotombuf(uiop, mq, siz, bpos)
862	register struct uio *uiop;
863	struct mbuf **mq;
864	int siz;
865	caddr_t *bpos;
866{
867	register char *uiocp;
868	register struct mbuf *mp, *mp2;
869	register int xfer, left, mlen;
870	int uiosiz, clflg, rem;
871	char *cp;
872
873#ifdef DIAGNOSTIC
874	if (uiop->uio_iovcnt != 1)
875		panic("nfsm_uiotombuf: iovcnt != 1");
876#endif
877
878	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
879		clflg = 1;
880	else
881		clflg = 0;
882	rem = nfsm_rndup(siz)-siz;
883	mp = mp2 = *mq;
884	while (siz > 0) {
885		left = uiop->uio_iov->iov_len;
886		uiocp = uiop->uio_iov->iov_base;
887		if (left > siz)
888			left = siz;
889		uiosiz = left;
890		while (left > 0) {
891			mlen = M_TRAILINGSPACE(mp);
892			if (mlen == 0) {
893				MGET(mp, M_WAIT, MT_DATA);
894				if (clflg)
895					MCLGET(mp, M_WAIT);
896				mp->m_len = 0;
897				mp2->m_next = mp;
898				mp2 = mp;
899				mlen = M_TRAILINGSPACE(mp);
900			}
901			xfer = (left > mlen) ? mlen : left;
902#ifdef notdef
903			/* Not Yet.. */
904			if (uiop->uio_iov->iov_op != NULL)
905				(*(uiop->uio_iov->iov_op))
906				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
907			else
908#endif
909			if (uiop->uio_segflg == UIO_SYSSPACE)
910				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
911			else
912				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
913			mp->m_len += xfer;
914			left -= xfer;
915			uiocp += xfer;
916			uiop->uio_offset += xfer;
917			uiop->uio_resid -= xfer;
918		}
919		uiop->uio_iov->iov_base += uiosiz;
920		uiop->uio_iov->iov_len -= uiosiz;
921		siz -= uiosiz;
922	}
923	if (rem > 0) {
924		if (rem > M_TRAILINGSPACE(mp)) {
925			MGET(mp, M_WAIT, MT_DATA);
926			mp->m_len = 0;
927			mp2->m_next = mp;
928		}
929		cp = mtod(mp, caddr_t)+mp->m_len;
930		for (left = 0; left < rem; left++)
931			*cp++ = '\0';
932		mp->m_len += rem;
933		*bpos = cp;
934	} else
935		*bpos = mtod(mp, caddr_t)+mp->m_len;
936	*mq = mp;
937	return (0);
938}
939
940/*
941 * Help break down an mbuf chain by setting the first siz bytes contiguous
942 * pointed to by returned val.
943 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
944 * cases. (The macros use the vars. dpos and dpos2)
945 */
946int
947nfsm_disct(mdp, dposp, siz, left, cp2)
948	struct mbuf **mdp;
949	caddr_t *dposp;
950	int siz;
951	int left;
952	caddr_t *cp2;
953{
954	register struct mbuf *mp, *mp2;
955	register int siz2, xfer;
956	register caddr_t p;
957
958	mp = *mdp;
959	while (left == 0) {
960		*mdp = mp = mp->m_next;
961		if (mp == NULL)
962			return (EBADRPC);
963		left = mp->m_len;
964		*dposp = mtod(mp, caddr_t);
965	}
966	if (left >= siz) {
967		*cp2 = *dposp;
968		*dposp += siz;
969	} else if (mp->m_next == NULL) {
970		return (EBADRPC);
971	} else if (siz > MHLEN) {
972		panic("nfs S too big");
973	} else {
974		MGET(mp2, M_WAIT, MT_DATA);
975		mp2->m_next = mp->m_next;
976		mp->m_next = mp2;
977		mp->m_len -= left;
978		mp = mp2;
979		*cp2 = p = mtod(mp, caddr_t);
980		bcopy(*dposp, p, left);		/* Copy what was left */
981		siz2 = siz-left;
982		p += left;
983		mp2 = mp->m_next;
984		/* Loop around copying up the siz2 bytes */
985		while (siz2 > 0) {
986			if (mp2 == NULL)
987				return (EBADRPC);
988			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
989			if (xfer > 0) {
990				bcopy(mtod(mp2, caddr_t), p, xfer);
991				NFSMADV(mp2, xfer);
992				mp2->m_len -= xfer;
993				p += xfer;
994				siz2 -= xfer;
995			}
996			if (siz2 > 0)
997				mp2 = mp2->m_next;
998		}
999		mp->m_len = siz;
1000		*mdp = mp2;
1001		*dposp = mtod(mp2, caddr_t);
1002	}
1003	return (0);
1004}
1005
1006/*
1007 * Advance the position in the mbuf chain.
1008 */
1009int
1010nfs_adv(mdp, dposp, offs, left)
1011	struct mbuf **mdp;
1012	caddr_t *dposp;
1013	int offs;
1014	int left;
1015{
1016	register struct mbuf *m;
1017	register int s;
1018
1019	m = *mdp;
1020	s = left;
1021	while (s < offs) {
1022		offs -= s;
1023		m = m->m_next;
1024		if (m == NULL)
1025			return (EBADRPC);
1026		s = m->m_len;
1027	}
1028	*mdp = m;
1029	*dposp = mtod(m, caddr_t)+offs;
1030	return (0);
1031}
1032
1033/*
1034 * Copy a string into mbufs for the hard cases...
1035 */
1036int
1037nfsm_strtmbuf(mb, bpos, cp, siz)
1038	struct mbuf **mb;
1039	char **bpos;
1040	const char *cp;
1041	long siz;
1042{
1043	register struct mbuf *m1 = NULL, *m2;
1044	long left, xfer, len, tlen;
1045	u_int32_t *tl;
1046	int putsize;
1047
1048	putsize = 1;
1049	m2 = *mb;
1050	left = M_TRAILINGSPACE(m2);
1051	if (left > 0) {
1052		tl = ((u_int32_t *)(*bpos));
1053		*tl++ = txdr_unsigned(siz);
1054		putsize = 0;
1055		left -= NFSX_UNSIGNED;
1056		m2->m_len += NFSX_UNSIGNED;
1057		if (left > 0) {
1058			bcopy(cp, (caddr_t) tl, left);
1059			siz -= left;
1060			cp += left;
1061			m2->m_len += left;
1062			left = 0;
1063		}
1064	}
1065	/* Loop around adding mbufs */
1066	while (siz > 0) {
1067		MGET(m1, M_WAIT, MT_DATA);
1068		if (siz > MLEN)
1069			MCLGET(m1, M_WAIT);
1070		m1->m_len = NFSMSIZ(m1);
1071		m2->m_next = m1;
1072		m2 = m1;
1073		tl = mtod(m1, u_int32_t *);
1074		tlen = 0;
1075		if (putsize) {
1076			*tl++ = txdr_unsigned(siz);
1077			m1->m_len -= NFSX_UNSIGNED;
1078			tlen = NFSX_UNSIGNED;
1079			putsize = 0;
1080		}
1081		if (siz < m1->m_len) {
1082			len = nfsm_rndup(siz);
1083			xfer = siz;
1084			if (xfer < len)
1085				*(tl+(xfer>>2)) = 0;
1086		} else {
1087			xfer = len = m1->m_len;
1088		}
1089		bcopy(cp, (caddr_t) tl, xfer);
1090		m1->m_len = len+tlen;
1091		siz -= xfer;
1092		cp += xfer;
1093	}
1094	*mb = m1;
1095	*bpos = mtod(m1, caddr_t)+m1->m_len;
1096	return (0);
1097}
1098
1099/*
1100 * Called once to initialize data structures...
1101 */
1102int
1103nfs_init(vfsp)
1104	struct vfsconf *vfsp;
1105{
1106	register int i;
1107
1108	nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1);
1109
1110	nfs_mount_type = vfsp->vfc_typenum;
1111	nfsrtt.pos = 0;
1112	rpc_vers = txdr_unsigned(RPC_VER2);
1113	rpc_call = txdr_unsigned(RPC_CALL);
1114	rpc_reply = txdr_unsigned(RPC_REPLY);
1115	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1116	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1117	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1118	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1119	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1120	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1121	nfs_prog = txdr_unsigned(NFS_PROG);
1122	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1123	nfs_true = txdr_unsigned(TRUE);
1124	nfs_false = txdr_unsigned(FALSE);
1125	nfs_xdrneg1 = txdr_unsigned(-1);
1126	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1127	if (nfs_ticks < 1)
1128		nfs_ticks = 1;
1129	/* Ensure async daemons disabled */
1130	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1131		nfs_iodwant[i] = (struct proc *)0;
1132		nfs_iodmount[i] = (struct nfsmount *)0;
1133	}
1134	nfs_nhinit();			/* Init the nfsnode table */
1135#ifndef NFS_NOSERVER
1136	nfsrv_init(0);			/* Init server data structures */
1137	nfsrv_initcache();		/* Init the server request cache */
1138#endif
1139
1140	/*
1141	 * Initialize the nqnfs server stuff.
1142	 */
1143	if (nqnfsstarttime == 0) {
1144		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1145			+ nqsrv_clockskew + nqsrv_writeslack;
1146		NQLOADNOVRAM(nqnfsstarttime);
1147		CIRCLEQ_INIT(&nqtimerhead);
1148		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1149	}
1150
1151	/*
1152	 * Initialize reply list and start timer
1153	 */
1154	TAILQ_INIT(&nfs_reqq);
1155
1156	nfs_timer(0);
1157
1158	/*
1159	 * Set up lease_check and lease_updatetime so that other parts
1160	 * of the system can call us, if we are loadable.
1161	 */
1162#ifndef NFS_NOSERVER
1163	nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)];
1164	default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
1165#endif
1166	nfs_prev_lease_updatetime = lease_updatetime;
1167	lease_updatetime = nfs_lease_updatetime;
1168	nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
1169	sysent[SYS_nfssvc].sy_narg = 2;
1170	nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
1171	sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
1172
1173	nfs_pbuf_freecnt = nswbuf / 2 + 1;
1174
1175	return (0);
1176}
1177
1178int
1179nfs_uninit(vfsp)
1180	struct vfsconf *vfsp;
1181{
1182
1183	untimeout(nfs_timer, (void *)NULL, nfs_timer_handle);
1184	nfs_mount_type = -1;
1185#ifndef NFS_NOSERVER
1186	default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check;
1187#endif
1188	lease_updatetime = nfs_prev_lease_updatetime;
1189	sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
1190	sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
1191	return (0);
1192}
1193
1194/*
1195 * Attribute cache routines.
1196 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1197 *	that are on the mbuf list
1198 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1199 *	error otherwise
1200 */
1201
1202/*
1203 * Load the attribute cache (that lives in the nfsnode entry) with
1204 * the values on the mbuf list and
1205 * Iff vap not NULL
1206 *    copy the attributes to *vaper
1207 */
1208int
1209nfs_loadattrcache(vpp, mdp, dposp, vaper)
1210	struct vnode **vpp;
1211	struct mbuf **mdp;
1212	caddr_t *dposp;
1213	struct vattr *vaper;
1214{
1215	register struct vnode *vp = *vpp;
1216	register struct vattr *vap;
1217	register struct nfs_fattr *fp;
1218	register struct nfsnode *np;
1219	register int32_t t1;
1220	caddr_t cp2;
1221	int error = 0, rdev;
1222	struct mbuf *md;
1223	enum vtype vtyp;
1224	u_short vmode;
1225	struct timespec mtime;
1226	int v3 = NFS_ISV3(vp);
1227
1228	md = *mdp;
1229	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1230	if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0)
1231		return (error);
1232	fp = (struct nfs_fattr *)cp2;
1233	if (v3) {
1234		vtyp = nfsv3tov_type(fp->fa_type);
1235		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1236		rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1237			fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1238		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1239	} else {
1240		vtyp = nfsv2tov_type(fp->fa_type);
1241		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1242		/*
1243		 * XXX
1244		 *
1245		 * The duplicate information returned in fa_type and fa_mode
1246		 * is an ambiguity in the NFS version 2 protocol.
1247		 *
1248		 * VREG should be taken literally as a regular file.  If a
1249		 * server intents to return some type information differently
1250		 * in the upper bits of the mode field (e.g. for sockets, or
1251		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
1252		 * leave the examination of the mode bits even in the VREG
1253		 * case to avoid breakage for bogus servers, but we make sure
1254		 * that there are actually type bits set in the upper part of
1255		 * fa_mode (and failing that, trust the va_type field).
1256		 *
1257		 * NFSv3 cleared the issue, and requires fa_mode to not
1258		 * contain any type information (while also introduing sockets
1259		 * and FIFOs for fa_type).
1260		 */
1261		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
1262			vtyp = IFTOVT(vmode);
1263		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1264		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1265
1266		/*
1267		 * Really ugly NFSv2 kludge.
1268		 */
1269		if (vtyp == VCHR && rdev == 0xffffffff)
1270			vtyp = VFIFO;
1271	}
1272
1273	/*
1274	 * If v_type == VNON it is a new node, so fill in the v_type,
1275	 * n_mtime fields. Check to see if it represents a special
1276	 * device, and if so, check for a possible alias. Once the
1277	 * correct vnode has been obtained, fill in the rest of the
1278	 * information.
1279	 */
1280	np = VTONFS(vp);
1281	if (vp->v_type != vtyp) {
1282		vp->v_type = vtyp;
1283		if (vp->v_type == VFIFO) {
1284			vp->v_op = fifo_nfsv2nodeop_p;
1285		}
1286		if (vp->v_type == VCHR || vp->v_type == VBLK) {
1287			vp->v_op = spec_nfsv2nodeop_p;
1288			addaliasu(vp, rdev);
1289		}
1290		np->n_mtime = mtime.tv_sec;
1291	}
1292	vap = &np->n_vattr;
1293	vap->va_type = vtyp;
1294	vap->va_mode = (vmode & 07777);
1295	vap->va_rdev = rdev;
1296	vap->va_mtime = mtime;
1297	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1298	if (v3) {
1299		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1300		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1301		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1302		vap->va_size = fxdr_hyper(&fp->fa3_size);
1303		vap->va_blocksize = NFS_FABLKSIZE;
1304		vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1305		vap->va_fileid = fxdr_unsigned(int32_t,
1306		    fp->fa3_fileid.nfsuquad[1]);
1307		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1308		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1309		vap->va_flags = 0;
1310		vap->va_filerev = 0;
1311	} else {
1312		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1313		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1314		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1315		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1316		vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1317		vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
1318		    * NFS_FABLKSIZE;
1319		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1320		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1321		vap->va_flags = 0;
1322		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1323		    fp->fa2_ctime.nfsv2_sec);
1324		vap->va_ctime.tv_nsec = 0;
1325		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1326		vap->va_filerev = 0;
1327	}
1328	if (vap->va_size != np->n_size) {
1329		if (vap->va_type == VREG) {
1330			if (np->n_flag & NMODIFIED) {
1331				if (vap->va_size < np->n_size)
1332					vap->va_size = np->n_size;
1333				else
1334					np->n_size = vap->va_size;
1335			} else {
1336				np->n_size = vap->va_size;
1337			}
1338			vnode_pager_setsize(vp, np->n_size);
1339		} else {
1340			np->n_size = vap->va_size;
1341		}
1342	}
1343	np->n_attrstamp = time_second;
1344	if (vaper != NULL) {
1345		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1346		if (np->n_flag & NCHG) {
1347			if (np->n_flag & NACC)
1348				vaper->va_atime = np->n_atim;
1349			if (np->n_flag & NUPD)
1350				vaper->va_mtime = np->n_mtim;
1351		}
1352	}
1353	return (0);
1354}
1355
1356#ifdef NFS_ACDEBUG
1357#include <sys/sysctl.h>
1358SYSCTL_DECL(_vfs_nfs);
1359static int nfs_acdebug;
1360SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
1361#endif
1362
1363/*
1364 * Check the time stamp
1365 * If the cache is valid, copy contents to *vap and return 0
1366 * otherwise return an error
1367 */
1368int
1369nfs_getattrcache(vp, vaper)
1370	register struct vnode *vp;
1371	struct vattr *vaper;
1372{
1373	register struct nfsnode *np;
1374	register struct vattr *vap;
1375	struct nfsmount *nmp;
1376	int timeo;
1377
1378	np = VTONFS(vp);
1379	vap = &np->n_vattr;
1380	nmp = VFSTONFS(vp->v_mount);
1381	/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
1382	timeo = (time_second - np->n_mtime) / 10;
1383
1384#ifdef NFS_ACDEBUG
1385	if (nfs_acdebug>1)
1386		printf("nfs_getattrcache: initial timeo = %d\n", timeo);
1387#endif
1388
1389	if (vap->va_type == VDIR) {
1390		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
1391			timeo = nmp->nm_acdirmin;
1392		else if (timeo > nmp->nm_acdirmax)
1393			timeo = nmp->nm_acdirmax;
1394	} else {
1395		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
1396			timeo = nmp->nm_acregmin;
1397		else if (timeo > nmp->nm_acregmax)
1398			timeo = nmp->nm_acregmax;
1399	}
1400
1401#ifdef NFS_ACDEBUG
1402	if (nfs_acdebug > 2)
1403		printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
1404			nmp->nm_acregmin, nmp->nm_acregmax,
1405			nmp->nm_acdirmin, nmp->nm_acdirmax);
1406
1407	if (nfs_acdebug)
1408		printf("nfs_getattrcache: age = %d; final timeo = %d\n",
1409			(time_second - np->n_attrstamp), timeo);
1410#endif
1411
1412	if ((time_second - np->n_attrstamp) >= timeo) {
1413		nfsstats.attrcache_misses++;
1414		return (ENOENT);
1415	}
1416	nfsstats.attrcache_hits++;
1417	if (vap->va_size != np->n_size) {
1418		if (vap->va_type == VREG) {
1419			if (np->n_flag & NMODIFIED) {
1420				if (vap->va_size < np->n_size)
1421					vap->va_size = np->n_size;
1422				else
1423					np->n_size = vap->va_size;
1424			} else {
1425				np->n_size = vap->va_size;
1426			}
1427			vnode_pager_setsize(vp, np->n_size);
1428		} else {
1429			np->n_size = vap->va_size;
1430		}
1431	}
1432	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1433	if (np->n_flag & NCHG) {
1434		if (np->n_flag & NACC)
1435			vaper->va_atime = np->n_atim;
1436		if (np->n_flag & NUPD)
1437			vaper->va_mtime = np->n_mtim;
1438	}
1439	return (0);
1440}
1441
1442#ifndef NFS_NOSERVER
1443/*
1444 * Set up nameidata for a lookup() call and do it.
1445 *
1446 * If pubflag is set, this call is done for a lookup operation on the
1447 * public filehandle. In that case we allow crossing mountpoints and
1448 * absolute pathnames. However, the caller is expected to check that
1449 * the lookup result is within the public fs, and deny access if
1450 * it is not.
1451 *
1452 * nfs_namei() clears out garbage fields that namei() might leave garbage.
1453 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
1454 * error occurs but the parent was not requested.
1455 *
1456 * dirp may be set whether an error is returned or not, and must be
1457 * released by the caller.
1458 */
1459int
1460nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1461	register struct nameidata *ndp;
1462	fhandle_t *fhp;
1463	int len;
1464	struct nfssvc_sock *slp;
1465	struct sockaddr *nam;
1466	struct mbuf **mdp;
1467	caddr_t *dposp;
1468	struct vnode **retdirp;
1469	struct proc *p;
1470	int kerbflag, pubflag;
1471{
1472	register int i, rem;
1473	register struct mbuf *md;
1474	register char *fromcp, *tocp, *cp;
1475	struct iovec aiov;
1476	struct uio auio;
1477	struct vnode *dp;
1478	int error, rdonly, linklen;
1479	struct componentname *cnp = &ndp->ni_cnd;
1480
1481	*retdirp = (struct vnode *)0;
1482	cnp->cn_pnbuf = zalloc(namei_zone);
1483
1484	/*
1485	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1486	 * and set the various ndp fields appropriately.
1487	 */
1488	fromcp = *dposp;
1489	tocp = cnp->cn_pnbuf;
1490	md = *mdp;
1491	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1492	for (i = 0; i < len; i++) {
1493		while (rem == 0) {
1494			md = md->m_next;
1495			if (md == NULL) {
1496				error = EBADRPC;
1497				goto out;
1498			}
1499			fromcp = mtod(md, caddr_t);
1500			rem = md->m_len;
1501		}
1502		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1503			error = EACCES;
1504			goto out;
1505		}
1506		*tocp++ = *fromcp++;
1507		rem--;
1508	}
1509	*tocp = '\0';
1510	*mdp = md;
1511	*dposp = fromcp;
1512	len = nfsm_rndup(len)-len;
1513	if (len > 0) {
1514		if (rem >= len)
1515			*dposp += len;
1516		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1517			goto out;
1518	}
1519
1520	/*
1521	 * Extract and set starting directory.
1522	 */
1523	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1524	    nam, &rdonly, kerbflag, pubflag);
1525	if (error)
1526		goto out;
1527	if (dp->v_type != VDIR) {
1528		vrele(dp);
1529		error = ENOTDIR;
1530		goto out;
1531	}
1532
1533	if (rdonly)
1534		cnp->cn_flags |= RDONLY;
1535
1536	/*
1537	 * Set return directory.  Reference to dp is implicitly transfered
1538	 * to the returned pointer
1539	 */
1540	*retdirp = dp;
1541
1542	if (pubflag) {
1543		/*
1544		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1545		 * and the 'native path' indicator.
1546		 */
1547		cp = zalloc(namei_zone);
1548		fromcp = cnp->cn_pnbuf;
1549		tocp = cp;
1550		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
1551			switch ((unsigned char)*fromcp) {
1552			case WEBNFS_NATIVE_CHAR:
1553				/*
1554				 * 'Native' path for us is the same
1555				 * as a path according to the NFS spec,
1556				 * just skip the escape char.
1557				 */
1558				fromcp++;
1559				break;
1560			/*
1561			 * More may be added in the future, range 0x80-0xff
1562			 */
1563			default:
1564				error = EIO;
1565				zfree(namei_zone, cp);
1566				goto out;
1567			}
1568		}
1569		/*
1570		 * Translate the '%' escapes, URL-style.
1571		 */
1572		while (*fromcp != '\0') {
1573			if (*fromcp == WEBNFS_ESC_CHAR) {
1574				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
1575					fromcp++;
1576					*tocp++ = HEXSTRTOI(fromcp);
1577					fromcp += 2;
1578					continue;
1579				} else {
1580					error = ENOENT;
1581					zfree(namei_zone, cp);
1582					goto out;
1583				}
1584			} else
1585				*tocp++ = *fromcp++;
1586		}
1587		*tocp = '\0';
1588		zfree(namei_zone, cnp->cn_pnbuf);
1589		cnp->cn_pnbuf = cp;
1590	}
1591
1592	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
1593	ndp->ni_segflg = UIO_SYSSPACE;
1594
1595	if (pubflag) {
1596		ndp->ni_rootdir = rootvnode;
1597		ndp->ni_loopcnt = 0;
1598		if (cnp->cn_pnbuf[0] == '/')
1599			dp = rootvnode;
1600	} else {
1601		cnp->cn_flags |= NOCROSSMOUNT;
1602	}
1603
1604	/*
1605	 * Initialize for scan, set ni_startdir and bump ref on dp again
1606	 * becuase lookup() will dereference ni_startdir.
1607	 */
1608
1609	cnp->cn_proc = p;
1610	VREF(dp);
1611	ndp->ni_startdir = dp;
1612
1613	for (;;) {
1614		cnp->cn_nameptr = cnp->cn_pnbuf;
1615		/*
1616		 * Call lookup() to do the real work.  If an error occurs,
1617		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
1618		 * we do not have to dereference anything before returning.
1619		 * In either case ni_startdir will be dereferenced and NULLed
1620		 * out.
1621		 */
1622		error = lookup(ndp);
1623		if (error)
1624			break;
1625
1626		/*
1627		 * Check for encountering a symbolic link.  Trivial
1628		 * termination occurs if no symlink encountered.
1629		 * Note: zfree is safe because error is 0, so we will
1630		 * not zfree it again when we break.
1631		 */
1632		if ((cnp->cn_flags & ISSYMLINK) == 0) {
1633			nfsrv_object_create(ndp->ni_vp);
1634			if (cnp->cn_flags & (SAVENAME | SAVESTART))
1635				cnp->cn_flags |= HASBUF;
1636			else
1637				zfree(namei_zone, cnp->cn_pnbuf);
1638			break;
1639		}
1640
1641		/*
1642		 * Validate symlink
1643		 */
1644		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1645			VOP_UNLOCK(ndp->ni_dvp, 0, p);
1646		if (!pubflag) {
1647			error = EINVAL;
1648			goto badlink2;
1649		}
1650
1651		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1652			error = ELOOP;
1653			goto badlink2;
1654		}
1655		if (ndp->ni_pathlen > 1)
1656			cp = zalloc(namei_zone);
1657		else
1658			cp = cnp->cn_pnbuf;
1659		aiov.iov_base = cp;
1660		aiov.iov_len = MAXPATHLEN;
1661		auio.uio_iov = &aiov;
1662		auio.uio_iovcnt = 1;
1663		auio.uio_offset = 0;
1664		auio.uio_rw = UIO_READ;
1665		auio.uio_segflg = UIO_SYSSPACE;
1666		auio.uio_procp = (struct proc *)0;
1667		auio.uio_resid = MAXPATHLEN;
1668		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
1669		if (error) {
1670		badlink1:
1671			if (ndp->ni_pathlen > 1)
1672				zfree(namei_zone, cp);
1673		badlink2:
1674			vrele(ndp->ni_dvp);
1675			vput(ndp->ni_vp);
1676			break;
1677		}
1678		linklen = MAXPATHLEN - auio.uio_resid;
1679		if (linklen == 0) {
1680			error = ENOENT;
1681			goto badlink1;
1682		}
1683		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1684			error = ENAMETOOLONG;
1685			goto badlink1;
1686		}
1687
1688		/*
1689		 * Adjust or replace path
1690		 */
1691		if (ndp->ni_pathlen > 1) {
1692			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1693			zfree(namei_zone, cnp->cn_pnbuf);
1694			cnp->cn_pnbuf = cp;
1695		} else
1696			cnp->cn_pnbuf[linklen] = '\0';
1697		ndp->ni_pathlen += linklen;
1698
1699		/*
1700		 * Cleanup refs for next loop and check if root directory
1701		 * should replace current directory.  Normally ni_dvp
1702		 * becomes the new base directory and is cleaned up when
1703		 * we loop.  Explicitly null pointers after invalidation
1704		 * to clarify operation.
1705		 */
1706		vput(ndp->ni_vp);
1707		ndp->ni_vp = NULL;
1708
1709		if (cnp->cn_pnbuf[0] == '/') {
1710			vrele(ndp->ni_dvp);
1711			ndp->ni_dvp = ndp->ni_rootdir;
1712			VREF(ndp->ni_dvp);
1713		}
1714		ndp->ni_startdir = ndp->ni_dvp;
1715		ndp->ni_dvp = NULL;
1716	}
1717
1718	/*
1719	 * nfs_namei() guarentees that fields will not contain garbage
1720	 * whether an error occurs or not.  This allows the caller to track
1721	 * cleanup state trivially.
1722	 */
1723out:
1724	if (error) {
1725		zfree(namei_zone, cnp->cn_pnbuf);
1726		ndp->ni_vp = NULL;
1727		ndp->ni_dvp = NULL;
1728		ndp->ni_startdir = NULL;
1729		cnp->cn_flags &= ~HASBUF;
1730	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
1731		ndp->ni_dvp = NULL;
1732	}
1733	return (error);
1734}
1735
1736/*
1737 * A fiddled version of m_adj() that ensures null fill to a long
1738 * boundary and only trims off the back end
1739 */
1740void
1741nfsm_adj(mp, len, nul)
1742	struct mbuf *mp;
1743	register int len;
1744	int nul;
1745{
1746	register struct mbuf *m;
1747	register int count, i;
1748	register char *cp;
1749
1750	/*
1751	 * Trim from tail.  Scan the mbuf chain,
1752	 * calculating its length and finding the last mbuf.
1753	 * If the adjustment only affects this mbuf, then just
1754	 * adjust and return.  Otherwise, rescan and truncate
1755	 * after the remaining size.
1756	 */
1757	count = 0;
1758	m = mp;
1759	for (;;) {
1760		count += m->m_len;
1761		if (m->m_next == (struct mbuf *)0)
1762			break;
1763		m = m->m_next;
1764	}
1765	if (m->m_len > len) {
1766		m->m_len -= len;
1767		if (nul > 0) {
1768			cp = mtod(m, caddr_t)+m->m_len-nul;
1769			for (i = 0; i < nul; i++)
1770				*cp++ = '\0';
1771		}
1772		return;
1773	}
1774	count -= len;
1775	if (count < 0)
1776		count = 0;
1777	/*
1778	 * Correct length for chain is "count".
1779	 * Find the mbuf with last data, adjust its length,
1780	 * and toss data from remaining mbufs on chain.
1781	 */
1782	for (m = mp; m; m = m->m_next) {
1783		if (m->m_len >= count) {
1784			m->m_len = count;
1785			if (nul > 0) {
1786				cp = mtod(m, caddr_t)+m->m_len-nul;
1787				for (i = 0; i < nul; i++)
1788					*cp++ = '\0';
1789			}
1790			break;
1791		}
1792		count -= m->m_len;
1793	}
1794	for (m = m->m_next;m;m = m->m_next)
1795		m->m_len = 0;
1796}
1797
1798/*
1799 * Make these functions instead of macros, so that the kernel text size
1800 * doesn't get too big...
1801 */
1802void
1803nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1804	struct nfsrv_descript *nfsd;
1805	int before_ret;
1806	register struct vattr *before_vap;
1807	int after_ret;
1808	struct vattr *after_vap;
1809	struct mbuf **mbp;
1810	char **bposp;
1811{
1812	register struct mbuf *mb = *mbp, *mb2;
1813	register char *bpos = *bposp;
1814	register u_int32_t *tl;
1815
1816	if (before_ret) {
1817		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1818		*tl = nfs_false;
1819	} else {
1820		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1821		*tl++ = nfs_true;
1822		txdr_hyper(before_vap->va_size, tl);
1823		tl += 2;
1824		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1825		tl += 2;
1826		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1827	}
1828	*bposp = bpos;
1829	*mbp = mb;
1830	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1831}
1832
1833void
1834nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1835	struct nfsrv_descript *nfsd;
1836	int after_ret;
1837	struct vattr *after_vap;
1838	struct mbuf **mbp;
1839	char **bposp;
1840{
1841	register struct mbuf *mb = *mbp, *mb2;
1842	register char *bpos = *bposp;
1843	register u_int32_t *tl;
1844	register struct nfs_fattr *fp;
1845
1846	if (after_ret) {
1847		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1848		*tl = nfs_false;
1849	} else {
1850		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1851		*tl++ = nfs_true;
1852		fp = (struct nfs_fattr *)tl;
1853		nfsm_srvfattr(nfsd, after_vap, fp);
1854	}
1855	*mbp = mb;
1856	*bposp = bpos;
1857}
1858
1859void
1860nfsm_srvfattr(nfsd, vap, fp)
1861	register struct nfsrv_descript *nfsd;
1862	register struct vattr *vap;
1863	register struct nfs_fattr *fp;
1864{
1865
1866	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1867	fp->fa_uid = txdr_unsigned(vap->va_uid);
1868	fp->fa_gid = txdr_unsigned(vap->va_gid);
1869	if (nfsd->nd_flag & ND_NFSV3) {
1870		fp->fa_type = vtonfsv3_type(vap->va_type);
1871		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1872		txdr_hyper(vap->va_size, &fp->fa3_size);
1873		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1874		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1875		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1876		fp->fa3_fsid.nfsuquad[0] = 0;
1877		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1878		fp->fa3_fileid.nfsuquad[0] = 0;
1879		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1880		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1881		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1882		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1883	} else {
1884		fp->fa_type = vtonfsv2_type(vap->va_type);
1885		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1886		fp->fa2_size = txdr_unsigned(vap->va_size);
1887		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1888		if (vap->va_type == VFIFO)
1889			fp->fa2_rdev = 0xffffffff;
1890		else
1891			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1892		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1893		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1894		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1895		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1896		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1897		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1898	}
1899}
1900
1901/*
1902 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1903 * 	- look up fsid in mount list (if not found ret error)
1904 *	- get vp and export rights by calling VFS_FHTOVP()
1905 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1906 *	- if not lockflag unlock it with VOP_UNLOCK()
1907 */
1908int
1909nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1910	fhandle_t *fhp;
1911	int lockflag;
1912	struct vnode **vpp;
1913	struct ucred *cred;
1914	struct nfssvc_sock *slp;
1915	struct sockaddr *nam;
1916	int *rdonlyp;
1917	int kerbflag;
1918	int pubflag;
1919{
1920	struct proc *p = curproc; /* XXX */
1921	register struct mount *mp;
1922	register int i;
1923	struct ucred *credanon;
1924	int error, exflags;
1925#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1926	struct sockaddr_int *saddr;
1927#endif
1928
1929	*vpp = (struct vnode *)0;
1930
1931	if (nfs_ispublicfh(fhp)) {
1932		if (!pubflag || !nfs_pub.np_valid)
1933			return (ESTALE);
1934		fhp = &nfs_pub.np_handle;
1935	}
1936
1937	mp = vfs_getvfs(&fhp->fh_fsid);
1938	if (!mp)
1939		return (ESTALE);
1940	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1941	if (error)
1942		return (error);
1943	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1944	if (error)
1945		return (error);
1946#ifdef MNT_EXNORESPORT
1947	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1948		saddr = (struct sockaddr_in *)nam;
1949		if (saddr->sin_family == AF_INET &&
1950		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1951			vput(*vpp);
1952			*vpp = NULL;
1953			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1954		}
1955	}
1956#endif
1957	/*
1958	 * Check/setup credentials.
1959	 */
1960	if (exflags & MNT_EXKERB) {
1961		if (!kerbflag) {
1962			vput(*vpp);
1963			*vpp = NULL;
1964			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1965		}
1966	} else if (kerbflag) {
1967		vput(*vpp);
1968		*vpp = NULL;
1969		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1970	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1971		cred->cr_uid = credanon->cr_uid;
1972		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1973			cred->cr_groups[i] = credanon->cr_groups[i];
1974		cred->cr_ngroups = i;
1975	}
1976	if (exflags & MNT_EXRDONLY)
1977		*rdonlyp = 1;
1978	else
1979		*rdonlyp = 0;
1980
1981	nfsrv_object_create(*vpp);
1982
1983	if (!lockflag)
1984		VOP_UNLOCK(*vpp, 0, p);
1985	return (0);
1986}
1987
1988
1989/*
1990 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1991 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1992 * transformed this to all zeroes in both cases, so check for it.
1993 */
1994int
1995nfs_ispublicfh(fhp)
1996	fhandle_t *fhp;
1997{
1998	char *cp = (char *)fhp;
1999	int i;
2000
2001	for (i = 0; i < NFSX_V3FH; i++)
2002		if (*cp++ != 0)
2003			return (FALSE);
2004	return (TRUE);
2005}
2006
2007#endif /* NFS_NOSERVER */
2008/*
2009 * This function compares two net addresses by family and returns TRUE
2010 * if they are the same host.
2011 * If there is any doubt, return FALSE.
2012 * The AF_INET family is handled as a special case so that address mbufs
2013 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2014 */
2015int
2016netaddr_match(family, haddr, nam)
2017	int family;
2018	union nethostaddr *haddr;
2019	struct sockaddr *nam;
2020{
2021	register struct sockaddr_in *inetaddr;
2022
2023	switch (family) {
2024	case AF_INET:
2025		inetaddr = (struct sockaddr_in *)nam;
2026		if (inetaddr->sin_family == AF_INET &&
2027		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2028			return (1);
2029		break;
2030#ifdef ISO
2031	case AF_ISO:
2032	    {
2033		register struct sockaddr_iso *isoaddr1, *isoaddr2;
2034
2035		isoaddr1 = (struct sockaddr_iso *)nam;
2036		isoaddr2 = (struct sockaddr_iso *)haddr->had_nam;
2037		if (isoaddr1->siso_family == AF_ISO &&
2038		    isoaddr1->siso_nlen > 0 &&
2039		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
2040		    SAME_ISOADDR(isoaddr1, isoaddr2))
2041			return (1);
2042		break;
2043	    }
2044#endif	/* ISO */
2045	default:
2046		break;
2047	};
2048	return (0);
2049}
2050
2051static nfsuint64 nfs_nullcookie = { { 0, 0 } };
2052/*
2053 * This function finds the directory cookie that corresponds to the
2054 * logical byte offset given.
2055 */
2056nfsuint64 *
2057nfs_getcookie(np, off, add)
2058	register struct nfsnode *np;
2059	off_t off;
2060	int add;
2061{
2062	register struct nfsdmap *dp, *dp2;
2063	register int pos;
2064
2065	pos = (uoff_t)off / NFS_DIRBLKSIZ;
2066	if (pos == 0 || off < 0) {
2067#ifdef DIAGNOSTIC
2068		if (add)
2069			panic("nfs getcookie add at <= 0");
2070#endif
2071		return (&nfs_nullcookie);
2072	}
2073	pos--;
2074	dp = np->n_cookies.lh_first;
2075	if (!dp) {
2076		if (add) {
2077			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
2078				M_NFSDIROFF, M_WAITOK);
2079			dp->ndm_eocookie = 0;
2080			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2081		} else
2082			return ((nfsuint64 *)0);
2083	}
2084	while (pos >= NFSNUMCOOKIES) {
2085		pos -= NFSNUMCOOKIES;
2086		if (dp->ndm_list.le_next) {
2087			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2088				pos >= dp->ndm_eocookie)
2089				return ((nfsuint64 *)0);
2090			dp = dp->ndm_list.le_next;
2091		} else if (add) {
2092			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
2093				M_NFSDIROFF, M_WAITOK);
2094			dp2->ndm_eocookie = 0;
2095			LIST_INSERT_AFTER(dp, dp2, ndm_list);
2096			dp = dp2;
2097		} else
2098			return ((nfsuint64 *)0);
2099	}
2100	if (pos >= dp->ndm_eocookie) {
2101		if (add)
2102			dp->ndm_eocookie = pos + 1;
2103		else
2104			return ((nfsuint64 *)0);
2105	}
2106	return (&dp->ndm_cookies[pos]);
2107}
2108
2109/*
2110 * Invalidate cached directory information, except for the actual directory
2111 * blocks (which are invalidated separately).
2112 * Done mainly to avoid the use of stale offset cookies.
2113 */
2114void
2115nfs_invaldir(vp)
2116	register struct vnode *vp;
2117{
2118	register struct nfsnode *np = VTONFS(vp);
2119
2120#ifdef DIAGNOSTIC
2121	if (vp->v_type != VDIR)
2122		panic("nfs: invaldir not dir");
2123#endif
2124	np->n_direofoffset = 0;
2125	np->n_cookieverf.nfsuquad[0] = 0;
2126	np->n_cookieverf.nfsuquad[1] = 0;
2127	if (np->n_cookies.lh_first)
2128		np->n_cookies.lh_first->ndm_eocookie = 0;
2129}
2130
2131/*
2132 * The write verifier has changed (probably due to a server reboot), so all
2133 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2134 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2135 * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
2136 * mount point.
2137 *
2138 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
2139 * writes are not clusterable.
2140 */
2141void
2142nfs_clearcommit(mp)
2143	struct mount *mp;
2144{
2145	register struct vnode *vp, *nvp;
2146	register struct buf *bp, *nbp;
2147	int s;
2148
2149	s = splbio();
2150loop:
2151	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
2152		if (vp->v_mount != mp)	/* Paranoia */
2153			goto loop;
2154		nvp = vp->v_mntvnodes.le_next;
2155		for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2156			nbp = TAILQ_NEXT(bp, b_vnbufs);
2157			if (BUF_REFCNT(bp) == 0 &&
2158			    (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
2159				== (B_DELWRI | B_NEEDCOMMIT))
2160				bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
2161		}
2162	}
2163	splx(s);
2164}
2165
2166#ifndef NFS_NOSERVER
2167/*
2168 * Map errnos to NFS error numbers. For Version 3 also filter out error
2169 * numbers not specified for the associated procedure.
2170 */
2171int
2172nfsrv_errmap(nd, err)
2173	struct nfsrv_descript *nd;
2174	register int err;
2175{
2176	register short *defaulterrp, *errp;
2177
2178	if (nd->nd_flag & ND_NFSV3) {
2179	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
2180		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2181		while (*++errp) {
2182			if (*errp == err)
2183				return (err);
2184			else if (*errp > err)
2185				break;
2186		}
2187		return ((int)*defaulterrp);
2188	    } else
2189		return (err & 0xffff);
2190	}
2191	if (err <= ELAST)
2192		return ((int)nfsrv_v2errmap[err - 1]);
2193	return (NFSERR_IO);
2194}
2195
2196int
2197nfsrv_object_create(vp)
2198	struct vnode *vp;
2199{
2200
2201	if (vp == NULL || vp->v_type != VREG)
2202		return (1);
2203	return (vfs_object_create(vp, curproc,
2204				  curproc ? curproc->p_ucred : NULL));
2205}
2206
2207/*
2208 * Sort the group list in increasing numerical order.
2209 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
2210 *  that used to be here.)
2211 */
2212void
2213nfsrvw_sort(list, num)
2214        register gid_t *list;
2215        register int num;
2216{
2217	register int i, j;
2218	gid_t v;
2219
2220	/* Insertion sort. */
2221	for (i = 1; i < num; i++) {
2222		v = list[i];
2223		/* find correct slot for value v, moving others up */
2224		for (j = i; --j >= 0 && v < list[j];)
2225			list[j + 1] = list[j];
2226		list[j + 1] = v;
2227	}
2228}
2229
2230/*
2231 * copy credentials making sure that the result can be compared with bcmp().
2232 */
2233void
2234nfsrv_setcred(incred, outcred)
2235	register struct ucred *incred, *outcred;
2236{
2237	register int i;
2238
2239	bzero((caddr_t)outcred, sizeof (struct ucred));
2240	outcred->cr_ref = 1;
2241	outcred->cr_uid = incred->cr_uid;
2242	outcred->cr_ngroups = incred->cr_ngroups;
2243	for (i = 0; i < incred->cr_ngroups; i++)
2244		outcred->cr_groups[i] = incred->cr_groups[i];
2245	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
2246}
2247#endif /* NFS_NOSERVER */
2248