xref: /openbsd/sys/nfs/nfs_subs.c (revision fd84ef7e)
1 /*	$OpenBSD: nfs_subs.c,v 1.38 2001/12/19 08:58:06 art Exp $	*/
2 /*	$NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $	*/
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Rick Macklem at The University of Guelph.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
40  */
41 
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 #include <sys/param.h>
49 #include <sys/proc.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/mount.h>
53 #include <sys/vnode.h>
54 #include <sys/namei.h>
55 #include <sys/mbuf.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/stat.h>
59 #include <sys/malloc.h>
60 #include <sys/time.h>
61 
62 #include <uvm/uvm_extern.h>
63 
64 #include <nfs/rpcv2.h>
65 #include <nfs/nfsproto.h>
66 #include <nfs/nfsnode.h>
67 #include <nfs/nfs.h>
68 #include <nfs/xdr_subs.h>
69 #include <nfs/nfsm_subs.h>
70 #include <nfs/nfsmount.h>
71 #include <nfs/nfsrtt.h>
72 #include <nfs/nfs_var.h>
73 
74 #include <miscfs/specfs/specdev.h>
75 
76 #include <netinet/in.h>
77 #ifdef ISO
78 #include <netiso/iso.h>
79 #endif
80 
81 #include <dev/rndvar.h>
82 
83 #ifdef __GNUC__
84 #define INLINE __inline
85 #else
86 #define INLINE
87 #endif
88 
89 int	nfs_attrtimeo __P((struct nfsnode *np));
90 
91 /*
92  * Data items converted to xdr at startup, since they are constant
93  * This is kinda hokey, but may save a little time doing byte swaps
94  */
95 u_int32_t nfs_xdrneg1;
96 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
97 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
98 	rpc_auth_kerb;
99 u_int32_t nfs_prog, nfs_true, nfs_false;
100 
101 /* And other global data */
102 static u_int32_t nfs_xid = 0;
103 static u_int32_t nfs_xid_touched = 0;
104 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
105 		      NFCHR, NFNON };
106 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
107 		      NFFIFO, NFNON };
108 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
109 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
110 int nfs_ticks;
111 
112 /*
113  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
114  */
115 int nfsv3_procid[NFS_NPROCS] = {
116 	NFSPROC_NULL,
117 	NFSPROC_GETATTR,
118 	NFSPROC_SETATTR,
119 	NFSPROC_NOOP,
120 	NFSPROC_LOOKUP,
121 	NFSPROC_READLINK,
122 	NFSPROC_READ,
123 	NFSPROC_NOOP,
124 	NFSPROC_WRITE,
125 	NFSPROC_CREATE,
126 	NFSPROC_REMOVE,
127 	NFSPROC_RENAME,
128 	NFSPROC_LINK,
129 	NFSPROC_SYMLINK,
130 	NFSPROC_MKDIR,
131 	NFSPROC_RMDIR,
132 	NFSPROC_READDIR,
133 	NFSPROC_FSSTAT,
134 	NFSPROC_NOOP,
135 	NFSPROC_NOOP,
136 	NFSPROC_NOOP,
137 	NFSPROC_NOOP,
138 	NFSPROC_NOOP,
139 	NFSPROC_NOOP,
140 	NFSPROC_NOOP,
141 	NFSPROC_NOOP
142 };
143 
144 /*
145  * and the reverse mapping from generic to Version 2 procedure numbers
146  */
147 int nfsv2_procid[NFS_NPROCS] = {
148 	NFSV2PROC_NULL,
149 	NFSV2PROC_GETATTR,
150 	NFSV2PROC_SETATTR,
151 	NFSV2PROC_LOOKUP,
152 	NFSV2PROC_NOOP,
153 	NFSV2PROC_READLINK,
154 	NFSV2PROC_READ,
155 	NFSV2PROC_WRITE,
156 	NFSV2PROC_CREATE,
157 	NFSV2PROC_MKDIR,
158 	NFSV2PROC_SYMLINK,
159 	NFSV2PROC_CREATE,
160 	NFSV2PROC_REMOVE,
161 	NFSV2PROC_RMDIR,
162 	NFSV2PROC_RENAME,
163 	NFSV2PROC_LINK,
164 	NFSV2PROC_READDIR,
165 	NFSV2PROC_NOOP,
166 	NFSV2PROC_STATFS,
167 	NFSV2PROC_NOOP,
168 	NFSV2PROC_NOOP,
169 	NFSV2PROC_NOOP,
170 	NFSV2PROC_NOOP,
171 	NFSV2PROC_NOOP,
172 	NFSV2PROC_NOOP,
173 	NFSV2PROC_NOOP,
174 };
175 
176 /*
177  * Maps errno values to nfs error numbers.
178  * Use NFSERR_IO as the catch all for ones not specifically defined in
179  * RFC 1094.
180  */
181 static u_char nfsrv_v2errmap[ELAST] = {
182   NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
183   NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
184   NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
185   NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
186   NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
187   NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
188   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
189   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
190   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
191   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
192   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
193   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
194   NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
195   NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
196   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
197   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
198   NFSERR_IO,
199 };
200 
201 /*
202  * Maps errno values to nfs error numbers.
203  * Although it is not obvious whether or not NFS clients really care if
204  * a returned error value is in the specified list for the procedure, the
205  * safest thing to do is filter them appropriately. For Version 2, the
206  * X/Open XNFS document is the only specification that defines error values
207  * for each RPC (The RFC simply lists all possible error values for all RPCs),
208  * so I have decided to not do this for Version 2.
209  * The first entry is the default error return and the rest are the valid
210  * errors for that RPC in increasing numeric order.
211  */
212 static short nfsv3err_null[] = {
213 	0,
214 	0,
215 };
216 
217 static short nfsv3err_getattr[] = {
218 	NFSERR_IO,
219 	NFSERR_IO,
220 	NFSERR_STALE,
221 	NFSERR_BADHANDLE,
222 	NFSERR_SERVERFAULT,
223 	0,
224 };
225 
226 static short nfsv3err_setattr[] = {
227 	NFSERR_IO,
228 	NFSERR_PERM,
229 	NFSERR_IO,
230 	NFSERR_ACCES,
231 	NFSERR_INVAL,
232 	NFSERR_NOSPC,
233 	NFSERR_ROFS,
234 	NFSERR_DQUOT,
235 	NFSERR_STALE,
236 	NFSERR_BADHANDLE,
237 	NFSERR_NOT_SYNC,
238 	NFSERR_SERVERFAULT,
239 	0,
240 };
241 
242 static short nfsv3err_lookup[] = {
243 	NFSERR_IO,
244 	NFSERR_NOENT,
245 	NFSERR_IO,
246 	NFSERR_ACCES,
247 	NFSERR_NOTDIR,
248 	NFSERR_NAMETOL,
249 	NFSERR_STALE,
250 	NFSERR_BADHANDLE,
251 	NFSERR_SERVERFAULT,
252 	0,
253 };
254 
255 static short nfsv3err_access[] = {
256 	NFSERR_IO,
257 	NFSERR_IO,
258 	NFSERR_STALE,
259 	NFSERR_BADHANDLE,
260 	NFSERR_SERVERFAULT,
261 	0,
262 };
263 
264 static short nfsv3err_readlink[] = {
265 	NFSERR_IO,
266 	NFSERR_IO,
267 	NFSERR_ACCES,
268 	NFSERR_INVAL,
269 	NFSERR_STALE,
270 	NFSERR_BADHANDLE,
271 	NFSERR_NOTSUPP,
272 	NFSERR_SERVERFAULT,
273 	0,
274 };
275 
276 static short nfsv3err_read[] = {
277 	NFSERR_IO,
278 	NFSERR_IO,
279 	NFSERR_NXIO,
280 	NFSERR_ACCES,
281 	NFSERR_INVAL,
282 	NFSERR_STALE,
283 	NFSERR_BADHANDLE,
284 	NFSERR_SERVERFAULT,
285 	0,
286 };
287 
288 static short nfsv3err_write[] = {
289 	NFSERR_IO,
290 	NFSERR_IO,
291 	NFSERR_ACCES,
292 	NFSERR_INVAL,
293 	NFSERR_FBIG,
294 	NFSERR_NOSPC,
295 	NFSERR_ROFS,
296 	NFSERR_DQUOT,
297 	NFSERR_STALE,
298 	NFSERR_BADHANDLE,
299 	NFSERR_SERVERFAULT,
300 	0,
301 };
302 
303 static short nfsv3err_create[] = {
304 	NFSERR_IO,
305 	NFSERR_IO,
306 	NFSERR_ACCES,
307 	NFSERR_EXIST,
308 	NFSERR_NOTDIR,
309 	NFSERR_NOSPC,
310 	NFSERR_ROFS,
311 	NFSERR_NAMETOL,
312 	NFSERR_DQUOT,
313 	NFSERR_STALE,
314 	NFSERR_BADHANDLE,
315 	NFSERR_NOTSUPP,
316 	NFSERR_SERVERFAULT,
317 	0,
318 };
319 
320 static short nfsv3err_mkdir[] = {
321 	NFSERR_IO,
322 	NFSERR_IO,
323 	NFSERR_ACCES,
324 	NFSERR_EXIST,
325 	NFSERR_NOTDIR,
326 	NFSERR_NOSPC,
327 	NFSERR_ROFS,
328 	NFSERR_NAMETOL,
329 	NFSERR_DQUOT,
330 	NFSERR_STALE,
331 	NFSERR_BADHANDLE,
332 	NFSERR_NOTSUPP,
333 	NFSERR_SERVERFAULT,
334 	0,
335 };
336 
337 static short nfsv3err_symlink[] = {
338 	NFSERR_IO,
339 	NFSERR_IO,
340 	NFSERR_ACCES,
341 	NFSERR_EXIST,
342 	NFSERR_NOTDIR,
343 	NFSERR_NOSPC,
344 	NFSERR_ROFS,
345 	NFSERR_NAMETOL,
346 	NFSERR_DQUOT,
347 	NFSERR_STALE,
348 	NFSERR_BADHANDLE,
349 	NFSERR_NOTSUPP,
350 	NFSERR_SERVERFAULT,
351 	0,
352 };
353 
354 static short nfsv3err_mknod[] = {
355 	NFSERR_IO,
356 	NFSERR_IO,
357 	NFSERR_ACCES,
358 	NFSERR_EXIST,
359 	NFSERR_NOTDIR,
360 	NFSERR_NOSPC,
361 	NFSERR_ROFS,
362 	NFSERR_NAMETOL,
363 	NFSERR_DQUOT,
364 	NFSERR_STALE,
365 	NFSERR_BADHANDLE,
366 	NFSERR_NOTSUPP,
367 	NFSERR_SERVERFAULT,
368 	NFSERR_BADTYPE,
369 	0,
370 };
371 
372 static short nfsv3err_remove[] = {
373 	NFSERR_IO,
374 	NFSERR_NOENT,
375 	NFSERR_IO,
376 	NFSERR_ACCES,
377 	NFSERR_NOTDIR,
378 	NFSERR_ROFS,
379 	NFSERR_NAMETOL,
380 	NFSERR_STALE,
381 	NFSERR_BADHANDLE,
382 	NFSERR_SERVERFAULT,
383 	0,
384 };
385 
386 static short nfsv3err_rmdir[] = {
387 	NFSERR_IO,
388 	NFSERR_NOENT,
389 	NFSERR_IO,
390 	NFSERR_ACCES,
391 	NFSERR_EXIST,
392 	NFSERR_NOTDIR,
393 	NFSERR_INVAL,
394 	NFSERR_ROFS,
395 	NFSERR_NAMETOL,
396 	NFSERR_NOTEMPTY,
397 	NFSERR_STALE,
398 	NFSERR_BADHANDLE,
399 	NFSERR_NOTSUPP,
400 	NFSERR_SERVERFAULT,
401 	0,
402 };
403 
404 static short nfsv3err_rename[] = {
405 	NFSERR_IO,
406 	NFSERR_NOENT,
407 	NFSERR_IO,
408 	NFSERR_ACCES,
409 	NFSERR_EXIST,
410 	NFSERR_XDEV,
411 	NFSERR_NOTDIR,
412 	NFSERR_ISDIR,
413 	NFSERR_INVAL,
414 	NFSERR_NOSPC,
415 	NFSERR_ROFS,
416 	NFSERR_MLINK,
417 	NFSERR_NAMETOL,
418 	NFSERR_NOTEMPTY,
419 	NFSERR_DQUOT,
420 	NFSERR_STALE,
421 	NFSERR_BADHANDLE,
422 	NFSERR_NOTSUPP,
423 	NFSERR_SERVERFAULT,
424 	0,
425 };
426 
427 static short nfsv3err_link[] = {
428 	NFSERR_IO,
429 	NFSERR_IO,
430 	NFSERR_ACCES,
431 	NFSERR_EXIST,
432 	NFSERR_XDEV,
433 	NFSERR_NOTDIR,
434 	NFSERR_INVAL,
435 	NFSERR_NOSPC,
436 	NFSERR_ROFS,
437 	NFSERR_MLINK,
438 	NFSERR_NAMETOL,
439 	NFSERR_DQUOT,
440 	NFSERR_STALE,
441 	NFSERR_BADHANDLE,
442 	NFSERR_NOTSUPP,
443 	NFSERR_SERVERFAULT,
444 	0,
445 };
446 
447 static short nfsv3err_readdir[] = {
448 	NFSERR_IO,
449 	NFSERR_IO,
450 	NFSERR_ACCES,
451 	NFSERR_NOTDIR,
452 	NFSERR_STALE,
453 	NFSERR_BADHANDLE,
454 	NFSERR_BAD_COOKIE,
455 	NFSERR_TOOSMALL,
456 	NFSERR_SERVERFAULT,
457 	0,
458 };
459 
460 static short nfsv3err_readdirplus[] = {
461 	NFSERR_IO,
462 	NFSERR_IO,
463 	NFSERR_ACCES,
464 	NFSERR_NOTDIR,
465 	NFSERR_STALE,
466 	NFSERR_BADHANDLE,
467 	NFSERR_BAD_COOKIE,
468 	NFSERR_NOTSUPP,
469 	NFSERR_TOOSMALL,
470 	NFSERR_SERVERFAULT,
471 	0,
472 };
473 
474 static short nfsv3err_fsstat[] = {
475 	NFSERR_IO,
476 	NFSERR_IO,
477 	NFSERR_STALE,
478 	NFSERR_BADHANDLE,
479 	NFSERR_SERVERFAULT,
480 	0,
481 };
482 
483 static short nfsv3err_fsinfo[] = {
484 	NFSERR_STALE,
485 	NFSERR_STALE,
486 	NFSERR_BADHANDLE,
487 	NFSERR_SERVERFAULT,
488 	0,
489 };
490 
491 static short nfsv3err_pathconf[] = {
492 	NFSERR_STALE,
493 	NFSERR_STALE,
494 	NFSERR_BADHANDLE,
495 	NFSERR_SERVERFAULT,
496 	0,
497 };
498 
499 static short nfsv3err_commit[] = {
500 	NFSERR_IO,
501 	NFSERR_IO,
502 	NFSERR_STALE,
503 	NFSERR_BADHANDLE,
504 	NFSERR_SERVERFAULT,
505 	0,
506 };
507 
508 static short *nfsrv_v3errmap[] = {
509 	nfsv3err_null,
510 	nfsv3err_getattr,
511 	nfsv3err_setattr,
512 	nfsv3err_lookup,
513 	nfsv3err_access,
514 	nfsv3err_readlink,
515 	nfsv3err_read,
516 	nfsv3err_write,
517 	nfsv3err_create,
518 	nfsv3err_mkdir,
519 	nfsv3err_symlink,
520 	nfsv3err_mknod,
521 	nfsv3err_remove,
522 	nfsv3err_rmdir,
523 	nfsv3err_rename,
524 	nfsv3err_link,
525 	nfsv3err_readdir,
526 	nfsv3err_readdirplus,
527 	nfsv3err_fsstat,
528 	nfsv3err_fsinfo,
529 	nfsv3err_pathconf,
530 	nfsv3err_commit,
531 };
532 
533 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
534 extern struct nfsrtt nfsrtt;
535 extern struct nfsstats nfsstats;
536 extern nfstype nfsv2_type[9];
537 extern nfstype nfsv3_type[9];
538 extern struct nfsnodehashhead *nfsnodehashtbl;
539 extern u_long nfsnodehash;
540 
541 LIST_HEAD(nfsnodehashhead, nfsnode);
542 
543 /*
544  * Create the header for an rpc request packet
545  * The hsiz is the size of the rest of the nfs request header.
546  * (just used to decide if a cluster is a good idea)
547  */
548 struct mbuf *
549 nfsm_reqh(vp, procid, hsiz, bposp)
550 	struct vnode *vp;
551 	u_long procid;
552 	int hsiz;
553 	caddr_t *bposp;
554 {
555 	register struct mbuf *mb;
556 	register caddr_t bpos;
557 
558 	MGET(mb, M_WAIT, MT_DATA);
559 	if (hsiz >= MINCLSIZE)
560 		MCLGET(mb, M_WAIT);
561 	mb->m_len = 0;
562 	bpos = mtod(mb, caddr_t);
563 
564 	/* Finally, return values */
565 	*bposp = bpos;
566 	return (mb);
567 }
568 
569 /*
570  * Build the RPC header and fill in the authorization info.
571  * The authorization string argument is only used when the credentials
572  * come from outside of the kernel.
573  * Returns the head of the mbuf list.
574  */
575 struct mbuf *
576 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
577 	verf_str, mrest, mrest_len, mbp, xidp)
578 	register struct ucred *cr;
579 	int nmflag;
580 	int procid;
581 	int auth_type;
582 	int auth_len;
583 	char *auth_str;
584 	int verf_len;
585 	char *verf_str;
586 	struct mbuf *mrest;
587 	int mrest_len;
588 	struct mbuf **mbp;
589 	u_int32_t *xidp;
590 {
591 	register struct mbuf *mb;
592 	register u_int32_t *tl;
593 	register caddr_t bpos;
594 	register int i;
595 	struct mbuf *mreq, *mb2;
596 	int siz, grpsiz, authsiz;
597 
598 	authsiz = nfsm_rndup(auth_len);
599 	MGETHDR(mb, M_WAIT, MT_DATA);
600 	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
601 		MCLGET(mb, M_WAIT);
602 	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
603 		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
604 	} else {
605 		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
606 	}
607 	mb->m_len = 0;
608 	mreq = mb;
609 	bpos = mtod(mb, caddr_t);
610 
611 	/*
612 	 * First the RPC header.
613 	 */
614 	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
615 
616 	/* Get a new (non-zero) xid */
617 
618 	if ((nfs_xid == 0) && (nfs_xid_touched == 0)) {
619 		nfs_xid = arc4random();
620 		nfs_xid_touched = 1;
621 	} else {
622 		while ((*xidp = arc4random() % 256) == 0)
623 			;
624 		nfs_xid += *xidp;
625 	}
626 
627 	*tl++ = *xidp = txdr_unsigned(nfs_xid);
628 	*tl++ = rpc_call;
629 	*tl++ = rpc_vers;
630 	*tl++ = txdr_unsigned(NFS_PROG);
631 	if (nmflag & NFSMNT_NFSV3)
632 		*tl++ = txdr_unsigned(NFS_VER3);
633 	else
634 		*tl++ = txdr_unsigned(NFS_VER2);
635 	if (nmflag & NFSMNT_NFSV3)
636 		*tl++ = txdr_unsigned(procid);
637 	else
638 		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
639 
640 	/*
641 	 * And then the authorization cred.
642 	 */
643 	*tl++ = txdr_unsigned(auth_type);
644 	*tl = txdr_unsigned(authsiz);
645 	switch (auth_type) {
646 	case RPCAUTH_UNIX:
647 		nfsm_build(tl, u_int32_t *, auth_len);
648 		*tl++ = 0;		/* stamp ?? */
649 		*tl++ = 0;		/* NULL hostname */
650 		*tl++ = txdr_unsigned(cr->cr_uid);
651 		*tl++ = txdr_unsigned(cr->cr_gid);
652 		grpsiz = (auth_len >> 2) - 5;
653 		*tl++ = txdr_unsigned(grpsiz);
654 		for (i = 0; i < grpsiz; i++)
655 			*tl++ = txdr_unsigned(cr->cr_groups[i]);
656 		break;
657 	case RPCAUTH_KERB4:
658 		siz = auth_len;
659 		while (siz > 0) {
660 			if (M_TRAILINGSPACE(mb) == 0) {
661 				MGET(mb2, M_WAIT, MT_DATA);
662 				if (siz >= MINCLSIZE)
663 					MCLGET(mb2, M_WAIT);
664 				mb->m_next = mb2;
665 				mb = mb2;
666 				mb->m_len = 0;
667 				bpos = mtod(mb, caddr_t);
668 			}
669 			i = min(siz, M_TRAILINGSPACE(mb));
670 			bcopy(auth_str, bpos, i);
671 			mb->m_len += i;
672 			auth_str += i;
673 			bpos += i;
674 			siz -= i;
675 		}
676 		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
677 			for (i = 0; i < siz; i++)
678 				*bpos++ = '\0';
679 			mb->m_len += siz;
680 		}
681 		break;
682 	};
683 
684 	/*
685 	 * And the verifier...
686 	 */
687 	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
688 	if (verf_str) {
689 		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
690 		*tl = txdr_unsigned(verf_len);
691 		siz = verf_len;
692 		while (siz > 0) {
693 			if (M_TRAILINGSPACE(mb) == 0) {
694 				MGET(mb2, M_WAIT, MT_DATA);
695 				if (siz >= MINCLSIZE)
696 					MCLGET(mb2, M_WAIT);
697 				mb->m_next = mb2;
698 				mb = mb2;
699 				mb->m_len = 0;
700 				bpos = mtod(mb, caddr_t);
701 			}
702 			i = min(siz, M_TRAILINGSPACE(mb));
703 			bcopy(verf_str, bpos, i);
704 			mb->m_len += i;
705 			verf_str += i;
706 			bpos += i;
707 			siz -= i;
708 		}
709 		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
710 			for (i = 0; i < siz; i++)
711 				*bpos++ = '\0';
712 			mb->m_len += siz;
713 		}
714 	} else {
715 		*tl++ = txdr_unsigned(RPCAUTH_NULL);
716 		*tl = 0;
717 	}
718 	mb->m_next = mrest;
719 	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
720 	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
721 	*mbp = mb;
722 	return (mreq);
723 }
724 
725 /*
726  * copies mbuf chain to the uio scatter/gather list
727  */
728 int
729 nfsm_mbuftouio(mrep, uiop, siz, dpos)
730 	struct mbuf **mrep;
731 	register struct uio *uiop;
732 	int siz;
733 	caddr_t *dpos;
734 {
735 	register char *mbufcp, *uiocp;
736 	register int xfer, left, len;
737 	register struct mbuf *mp;
738 	long uiosiz, rem;
739 	int error = 0;
740 
741 	mp = *mrep;
742 	mbufcp = *dpos;
743 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
744 	rem = nfsm_rndup(siz)-siz;
745 	while (siz > 0) {
746 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
747 			return (EFBIG);
748 		left = uiop->uio_iov->iov_len;
749 		uiocp = uiop->uio_iov->iov_base;
750 		if (left > siz)
751 			left = siz;
752 		uiosiz = left;
753 		while (left > 0) {
754 			while (len == 0) {
755 				mp = mp->m_next;
756 				if (mp == NULL)
757 					return (EBADRPC);
758 				mbufcp = mtod(mp, caddr_t);
759 				len = mp->m_len;
760 			}
761 			xfer = (left > len) ? len : left;
762 #ifdef notdef
763 			/* Not Yet.. */
764 			if (uiop->uio_iov->iov_op != NULL)
765 				(*(uiop->uio_iov->iov_op))
766 				(mbufcp, uiocp, xfer);
767 			else
768 #endif
769 			if (uiop->uio_segflg == UIO_SYSSPACE)
770 				bcopy(mbufcp, uiocp, xfer);
771 			else
772 				copyout(mbufcp, uiocp, xfer);
773 			left -= xfer;
774 			len -= xfer;
775 			mbufcp += xfer;
776 			uiocp += xfer;
777 			uiop->uio_offset += xfer;
778 			uiop->uio_resid -= xfer;
779 		}
780 		if (uiop->uio_iov->iov_len <= siz) {
781 			uiop->uio_iovcnt--;
782 			uiop->uio_iov++;
783 		} else {
784 			uiop->uio_iov->iov_base += uiosiz;
785 			uiop->uio_iov->iov_len -= uiosiz;
786 		}
787 		siz -= uiosiz;
788 	}
789 	*dpos = mbufcp;
790 	*mrep = mp;
791 	if (rem > 0) {
792 		if (len < rem)
793 			error = nfs_adv(mrep, dpos, rem, len);
794 		else
795 			*dpos += rem;
796 	}
797 	return (error);
798 }
799 
800 /*
801  * copies a uio scatter/gather list to an mbuf chain.
802  * NOTE: can ony handle iovcnt == 1
803  */
804 int
805 nfsm_uiotombuf(uiop, mq, siz, bpos)
806 	register struct uio *uiop;
807 	struct mbuf **mq;
808 	int siz;
809 	caddr_t *bpos;
810 {
811 	register char *uiocp;
812 	register struct mbuf *mp, *mp2;
813 	register int xfer, left, mlen;
814 	int uiosiz, clflg, rem;
815 	char *cp;
816 
817 #ifdef DIAGNOSTIC
818 	if (uiop->uio_iovcnt != 1)
819 		panic("nfsm_uiotombuf: iovcnt != 1");
820 #endif
821 
822 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
823 		clflg = 1;
824 	else
825 		clflg = 0;
826 	rem = nfsm_rndup(siz)-siz;
827 	mp = mp2 = *mq;
828 	while (siz > 0) {
829 		left = uiop->uio_iov->iov_len;
830 		uiocp = uiop->uio_iov->iov_base;
831 		if (left > siz)
832 			left = siz;
833 		uiosiz = left;
834 		while (left > 0) {
835 			mlen = M_TRAILINGSPACE(mp);
836 			if (mlen == 0) {
837 				MGET(mp, M_WAIT, MT_DATA);
838 				if (clflg)
839 					MCLGET(mp, M_WAIT);
840 				mp->m_len = 0;
841 				mp2->m_next = mp;
842 				mp2 = mp;
843 				mlen = M_TRAILINGSPACE(mp);
844 			}
845 			xfer = (left > mlen) ? mlen : left;
846 #ifdef notdef
847 			/* Not Yet.. */
848 			if (uiop->uio_iov->iov_op != NULL)
849 				(*(uiop->uio_iov->iov_op))
850 				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
851 			else
852 #endif
853 			if (uiop->uio_segflg == UIO_SYSSPACE)
854 				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
855 			else
856 				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
857 			mp->m_len += xfer;
858 			left -= xfer;
859 			uiocp += xfer;
860 			uiop->uio_offset += xfer;
861 			uiop->uio_resid -= xfer;
862 		}
863 		uiop->uio_iov->iov_base += uiosiz;
864 		uiop->uio_iov->iov_len -= uiosiz;
865 		siz -= uiosiz;
866 	}
867 	if (rem > 0) {
868 		if (rem > M_TRAILINGSPACE(mp)) {
869 			MGET(mp, M_WAIT, MT_DATA);
870 			mp->m_len = 0;
871 			mp2->m_next = mp;
872 		}
873 		cp = mtod(mp, caddr_t)+mp->m_len;
874 		for (left = 0; left < rem; left++)
875 			*cp++ = '\0';
876 		mp->m_len += rem;
877 		*bpos = cp;
878 	} else
879 		*bpos = mtod(mp, caddr_t)+mp->m_len;
880 	*mq = mp;
881 	return (0);
882 }
883 
884 /*
885  * Help break down an mbuf chain by setting the first siz bytes contiguous
886  * pointed to by returned val.
887  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
888  * cases. (The macros use the vars. dpos and dpos2)
889  */
890 int
891 nfsm_disct(mdp, dposp, siz, left, cp2)
892 	struct mbuf **mdp;
893 	caddr_t *dposp;
894 	int siz;
895 	int left;
896 	caddr_t *cp2;
897 {
898 	register struct mbuf *mp, *mp2;
899 	register int siz2, xfer;
900 	register caddr_t p;
901 
902 	mp = *mdp;
903 	while (left == 0) {
904 		*mdp = mp = mp->m_next;
905 		if (mp == NULL)
906 			return (EBADRPC);
907 		left = mp->m_len;
908 		*dposp = mtod(mp, caddr_t);
909 	}
910 	if (left >= siz) {
911 		*cp2 = *dposp;
912 		*dposp += siz;
913 	} else if (mp->m_next == NULL) {
914 		return (EBADRPC);
915 	} else if (siz > MHLEN) {
916 		panic("nfs S too big");
917 	} else {
918 		MGET(mp2, M_WAIT, MT_DATA);
919 		mp2->m_next = mp->m_next;
920 		mp->m_next = mp2;
921 		mp->m_len -= left;
922 		mp = mp2;
923 		*cp2 = p = mtod(mp, caddr_t);
924 		bcopy(*dposp, p, left);		/* Copy what was left */
925 		siz2 = siz-left;
926 		p += left;
927 		mp2 = mp->m_next;
928 		/* Loop around copying up the siz2 bytes */
929 		while (siz2 > 0) {
930 			if (mp2 == NULL)
931 				return (EBADRPC);
932 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
933 			if (xfer > 0) {
934 				bcopy(mtod(mp2, caddr_t), p, xfer);
935 				NFSMADV(mp2, xfer);
936 				mp2->m_len -= xfer;
937 				p += xfer;
938 				siz2 -= xfer;
939 			}
940 			if (siz2 > 0)
941 				mp2 = mp2->m_next;
942 		}
943 		mp->m_len = siz;
944 		*mdp = mp2;
945 		*dposp = mtod(mp2, caddr_t);
946 	}
947 	return (0);
948 }
949 
950 /*
951  * Advance the position in the mbuf chain.
952  */
953 int
954 nfs_adv(mdp, dposp, offs, left)
955 	struct mbuf **mdp;
956 	caddr_t *dposp;
957 	int offs;
958 	int left;
959 {
960 	register struct mbuf *m;
961 	register int s;
962 
963 	m = *mdp;
964 	s = left;
965 	while (s < offs) {
966 		offs -= s;
967 		m = m->m_next;
968 		if (m == NULL)
969 			return (EBADRPC);
970 		s = m->m_len;
971 	}
972 	*mdp = m;
973 	*dposp = mtod(m, caddr_t)+offs;
974 	return (0);
975 }
976 
977 /*
978  * Copy a string into mbufs for the hard cases...
979  */
980 int
981 nfsm_strtmbuf(mb, bpos, cp, siz)
982 	struct mbuf **mb;
983 	char **bpos;
984 	char *cp;
985 	long siz;
986 {
987 	register struct mbuf *m1 = NULL, *m2;
988 	long left, xfer, len, tlen;
989 	u_int32_t *tl;
990 	int putsize;
991 
992 	putsize = 1;
993 	m2 = *mb;
994 	left = M_TRAILINGSPACE(m2);
995 	if (left > 0) {
996 		tl = ((u_int32_t *)(*bpos));
997 		*tl++ = txdr_unsigned(siz);
998 		putsize = 0;
999 		left -= NFSX_UNSIGNED;
1000 		m2->m_len += NFSX_UNSIGNED;
1001 		if (left > 0) {
1002 			bcopy(cp, (caddr_t) tl, left);
1003 			siz -= left;
1004 			cp += left;
1005 			m2->m_len += left;
1006 			left = 0;
1007 		}
1008 	}
1009 	/* Loop around adding mbufs */
1010 	while (siz > 0) {
1011 		MGET(m1, M_WAIT, MT_DATA);
1012 		if (siz > MLEN)
1013 			MCLGET(m1, M_WAIT);
1014 		m1->m_len = NFSMSIZ(m1);
1015 		m2->m_next = m1;
1016 		m2 = m1;
1017 		tl = mtod(m1, u_int32_t *);
1018 		tlen = 0;
1019 		if (putsize) {
1020 			*tl++ = txdr_unsigned(siz);
1021 			m1->m_len -= NFSX_UNSIGNED;
1022 			tlen = NFSX_UNSIGNED;
1023 			putsize = 0;
1024 		}
1025 		if (siz < m1->m_len) {
1026 			len = nfsm_rndup(siz);
1027 			xfer = siz;
1028 			if (xfer < len)
1029 				*(tl+(xfer>>2)) = 0;
1030 		} else {
1031 			xfer = len = m1->m_len;
1032 		}
1033 		bcopy(cp, (caddr_t) tl, xfer);
1034 		m1->m_len = len+tlen;
1035 		siz -= xfer;
1036 		cp += xfer;
1037 	}
1038 	*mb = m1;
1039 	*bpos = mtod(m1, caddr_t)+m1->m_len;
1040 	return (0);
1041 }
1042 
1043 /*
1044  * Called once to initialize data structures...
1045  */
1046 void
1047 nfs_init()
1048 {
1049 	static struct timeout nfs_timer_to;
1050 
1051 	nfsrtt.pos = 0;
1052 	rpc_vers = txdr_unsigned(RPC_VER2);
1053 	rpc_call = txdr_unsigned(RPC_CALL);
1054 	rpc_reply = txdr_unsigned(RPC_REPLY);
1055 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1056 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1057 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1058 	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1059 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1060 	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1061 	nfs_prog = txdr_unsigned(NFS_PROG);
1062 	nfs_true = txdr_unsigned(TRUE);
1063 	nfs_false = txdr_unsigned(FALSE);
1064 	nfs_xdrneg1 = txdr_unsigned(-1);
1065 	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1066 	if (nfs_ticks < 1)
1067 		nfs_ticks = 1;
1068 #ifdef NFSSERVER
1069 	nfsrv_init(0);			/* Init server data structures */
1070 	nfsrv_initcache();		/* Init the server request cache */
1071 #endif /* NFSSERVER */
1072 
1073 	/*
1074 	 * Initialize reply list and start timer
1075 	 */
1076 	TAILQ_INIT(&nfs_reqq);
1077 
1078 	timeout_set(&nfs_timer_to, nfs_timer, &nfs_timer_to);
1079 	nfs_timer(&nfs_timer_to);
1080 }
1081 
1082 #ifdef NFSCLIENT
1083 int
1084 nfs_vfs_init(vfsp)
1085 	struct vfsconf *vfsp;
1086 {
1087 	register int i;
1088 
1089 	/* Ensure async daemons disabled */
1090 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1091 		nfs_iodwant[i] = (struct proc *)0;
1092 	TAILQ_INIT(&nfs_bufq);
1093 	nfs_nhinit();			/* Init the nfsnode table */
1094 
1095 	return (0);
1096 }
1097 
1098 /*
1099  * Attribute cache routines.
1100  * nfs_loadattrcache() - loads or updates the cache contents from attributes
1101  *	that are on the mbuf list
1102  * nfs_getattrcache() - returns valid attributes if found in cache, returns
1103  *	error otherwise
1104  */
1105 
1106 /*
1107  * Load the attribute cache (that lives in the nfsnode entry) with
1108  * the values on the mbuf list and
1109  * Iff vap not NULL
1110  *    copy the attributes to *vaper
1111  */
1112 int
1113 nfs_loadattrcache(vpp, mdp, dposp, vaper)
1114 	struct vnode **vpp;
1115 	struct mbuf **mdp;
1116 	caddr_t *dposp;
1117 	struct vattr *vaper;
1118 {
1119 	register struct vnode *vp = *vpp;
1120 	register struct vattr *vap;
1121 	register struct nfs_fattr *fp;
1122 	extern int (**spec_nfsv2nodeop_p) __P((void *));
1123 	register struct nfsnode *np;
1124 	register int32_t t1;
1125 	caddr_t cp2;
1126 	int error = 0;
1127 	int32_t rdev;
1128 	struct mbuf *md;
1129 	enum vtype vtyp;
1130 	u_short vmode;
1131 	struct timespec mtime;
1132 	struct vnode *nvp;
1133 	int v3 = NFS_ISV3(vp);
1134 
1135 	md = *mdp;
1136 	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1137 	error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1138 	if (error)
1139 		return (error);
1140 	fp = (struct nfs_fattr *)cp2;
1141 	if (v3) {
1142 		vtyp = nfsv3tov_type(fp->fa_type);
1143 		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1144 		rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
1145 			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
1146 		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1147 	} else {
1148 		vtyp = nfsv2tov_type(fp->fa_type);
1149 		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1150 		if (vtyp == VNON || vtyp == VREG)
1151 			vtyp = IFTOVT(vmode);
1152 		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1153 		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1154 
1155 		/*
1156 		 * Really ugly NFSv2 kludge.
1157 		 */
1158 		if (vtyp == VCHR && rdev == 0xffffffff)
1159 			vtyp = VFIFO;
1160 	}
1161 
1162 	/*
1163 	 * If v_type == VNON it is a new node, so fill in the v_type,
1164 	 * n_mtime fields. Check to see if it represents a special
1165 	 * device, and if so, check for a possible alias. Once the
1166 	 * correct vnode has been obtained, fill in the rest of the
1167 	 * information.
1168 	 */
1169 	np = VTONFS(vp);
1170 	if (vp->v_type != vtyp) {
1171 		vp->v_type = vtyp;
1172 		if (vp->v_type == VFIFO) {
1173 #ifndef FIFO
1174 			return (EOPNOTSUPP);
1175 #else
1176 			extern int (**fifo_nfsv2nodeop_p) __P((void *));
1177 			vp->v_op = fifo_nfsv2nodeop_p;
1178 #endif /* FIFO */
1179 		}
1180 		if (vp->v_type == VCHR || vp->v_type == VBLK) {
1181 			vp->v_op = spec_nfsv2nodeop_p;
1182 			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1183 			if (nvp) {
1184 				/*
1185 				 * Discard unneeded vnode, but save its nfsnode.
1186 				 * Since the nfsnode does not have a lock, its
1187 				 * vnode lock has to be carried over.
1188 				 */
1189 
1190 				nvp->v_vnlock = vp->v_vnlock;
1191 				vp->v_vnlock = NULL;
1192 				nvp->v_data = vp->v_data;
1193 				vp->v_data = NULL;
1194 				vp->v_op = spec_vnodeop_p;
1195 				vrele(vp);
1196 				vgone(vp);
1197 				/*
1198 				 * Reinitialize aliased node.
1199 				 */
1200 				np->n_vnode = nvp;
1201 				*vpp = vp = nvp;
1202 			}
1203 		}
1204 		np->n_mtime = mtime.tv_sec;
1205 	}
1206 	vap = &np->n_vattr;
1207 	vap->va_type = vtyp;
1208 	vap->va_mode = (vmode & 07777);
1209 	vap->va_rdev = (dev_t)rdev;
1210 	vap->va_mtime = mtime;
1211 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1212 	if (v3) {
1213 		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1214 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1215 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1216 		vap->va_size = fxdr_hyper(&fp->fa3_size);
1217 		vap->va_blocksize = NFS_FABLKSIZE;
1218 		vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1219 		vap->va_fileid = fxdr_unsigned(int32_t,
1220 		    fp->fa3_fileid.nfsuquad[1]);
1221 		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1222 		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1223 		vap->va_flags = 0;
1224 		vap->va_filerev = 0;
1225 	} else {
1226 		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1227 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1228 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1229 		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1230 		vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1231 		vap->va_bytes =
1232 		    (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
1233 		    NFS_FABLKSIZE;
1234 		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1235 		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1236 		vap->va_flags = 0;
1237 		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1238 		    fp->fa2_ctime.nfsv2_sec);
1239 		vap->va_ctime.tv_nsec = 0;
1240 		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1241 		vap->va_filerev = 0;
1242 	}
1243 	if (vap->va_size != np->n_size) {
1244 		if (vap->va_type == VREG) {
1245 			if (np->n_flag & NMODIFIED) {
1246 				if (vap->va_size < np->n_size)
1247 					vap->va_size = np->n_size;
1248 				else
1249 					np->n_size = vap->va_size;
1250 			} else
1251 				np->n_size = vap->va_size;
1252 			uvm_vnp_setsize(vp, np->n_size);
1253 		} else
1254 			np->n_size = vap->va_size;
1255 	}
1256 	np->n_attrstamp = time.tv_sec;
1257 	if (vaper != NULL) {
1258 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1259 		if (np->n_flag & NCHG) {
1260 			if (np->n_flag & NACC)
1261 				vaper->va_atime = np->n_atim;
1262 			if (np->n_flag & NUPD)
1263 				vaper->va_mtime = np->n_mtim;
1264 		}
1265 	}
1266 	return (0);
1267 }
1268 
1269 INLINE int
1270 nfs_attrtimeo (np)
1271 	struct nfsnode *np;
1272 {
1273 	struct vnode *vp = np->n_vnode;
1274 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1275 	int tenthage = (time.tv_sec - np->n_mtime) / 10;
1276 	int minto, maxto;
1277 
1278 	if (vp->v_type == VDIR) {
1279 		maxto = nmp->nm_acdirmax;
1280 		minto = nmp->nm_acdirmin;
1281 	}
1282 	else {
1283 		maxto = nmp->nm_acregmax;
1284 		minto = nmp->nm_acregmin;
1285 	}
1286 
1287 	if (np->n_flag & NMODIFIED || tenthage < minto)
1288 		return minto;
1289 	else if (tenthage < maxto)
1290 		return tenthage;
1291 	else
1292 		return maxto;
1293 }
1294 
1295 /*
1296  * Check the time stamp
1297  * If the cache is valid, copy contents to *vap and return 0
1298  * otherwise return an error
1299  */
1300 int
1301 nfs_getattrcache(vp, vaper)
1302 	register struct vnode *vp;
1303 	struct vattr *vaper;
1304 {
1305 	register struct nfsnode *np = VTONFS(vp);
1306 	register struct vattr *vap;
1307 
1308 	if ((time.tv_sec - np->n_attrstamp) >= nfs_attrtimeo(np)) {
1309 		nfsstats.attrcache_misses++;
1310 		return (ENOENT);
1311 	}
1312 	nfsstats.attrcache_hits++;
1313 	vap = &np->n_vattr;
1314 	if (vap->va_size != np->n_size) {
1315 		if (vap->va_type == VREG) {
1316 			if (np->n_flag & NMODIFIED) {
1317 				if (vap->va_size < np->n_size)
1318 					vap->va_size = np->n_size;
1319 				else
1320 					np->n_size = vap->va_size;
1321 			} else
1322 				np->n_size = vap->va_size;
1323 			uvm_vnp_setsize(vp, np->n_size);
1324 		} else
1325 			np->n_size = vap->va_size;
1326 	}
1327 	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1328 	if (np->n_flag & NCHG) {
1329 		if (np->n_flag & NACC)
1330 			vaper->va_atime = np->n_atim;
1331 		if (np->n_flag & NUPD)
1332 			vaper->va_mtime = np->n_mtim;
1333 	}
1334 	return (0);
1335 }
1336 #endif /* NFSCLIENT */
1337 
1338 /*
1339  * Set up nameidata for a lookup() call and do it
1340  */
1341 int
1342 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
1343 	register struct nameidata *ndp;
1344 	fhandle_t *fhp;
1345 	int len;
1346 	struct nfssvc_sock *slp;
1347 	struct mbuf *nam;
1348 	struct mbuf **mdp;
1349 	caddr_t *dposp;
1350 	struct vnode **retdirp;
1351 	struct proc *p;
1352 	int kerbflag;
1353 {
1354 	register int i, rem;
1355 	register struct mbuf *md;
1356 	register char *fromcp, *tocp;
1357 	struct vnode *dp;
1358 	int error, rdonly;
1359 	struct componentname *cnp = &ndp->ni_cnd;
1360 
1361 	*retdirp = (struct vnode *)0;
1362 	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
1363 	/*
1364 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1365 	 * and set the various ndp fields appropriately.
1366 	 */
1367 	fromcp = *dposp;
1368 	tocp = cnp->cn_pnbuf;
1369 	md = *mdp;
1370 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1371 	cnp->cn_hash = 0;
1372 	for (i = 0; i < len; i++) {
1373 		while (rem == 0) {
1374 			md = md->m_next;
1375 			if (md == NULL) {
1376 				error = EBADRPC;
1377 				goto out;
1378 			}
1379 			fromcp = mtod(md, caddr_t);
1380 			rem = md->m_len;
1381 		}
1382 		if (*fromcp == '\0' || *fromcp == '/') {
1383 			error = EACCES;
1384 			goto out;
1385 		}
1386 		cnp->cn_hash += (u_char)*fromcp;
1387 		*tocp++ = *fromcp++;
1388 		rem--;
1389 	}
1390 	*tocp = '\0';
1391 	*mdp = md;
1392 	*dposp = fromcp;
1393 	len = nfsm_rndup(len)-len;
1394 	if (len > 0) {
1395 		if (rem >= len)
1396 			*dposp += len;
1397 		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1398 			goto out;
1399 	}
1400 	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
1401 	cnp->cn_nameptr = cnp->cn_pnbuf;
1402 	/*
1403 	 * Extract and set starting directory.
1404 	 */
1405 	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1406 	    nam, &rdonly, kerbflag);
1407 	if (error)
1408 		goto out;
1409 	if (dp->v_type != VDIR) {
1410 		vrele(dp);
1411 		error = ENOTDIR;
1412 		goto out;
1413 	}
1414 	VREF(dp);
1415 	*retdirp = dp;
1416 	ndp->ni_startdir = dp;
1417 	if (rdonly)
1418 		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
1419 	else
1420 		cnp->cn_flags |= NOCROSSMOUNT;
1421 	/*
1422 	 * And call lookup() to do the real work
1423 	 */
1424 	cnp->cn_proc = p;
1425 	error = lookup(ndp);
1426 	if (error)
1427 		goto out;
1428 	/*
1429 	 * Check for encountering a symbolic link
1430 	 */
1431 	if (cnp->cn_flags & ISSYMLINK) {
1432 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1433 			vput(ndp->ni_dvp);
1434 		else
1435 			vrele(ndp->ni_dvp);
1436 		vput(ndp->ni_vp);
1437 		ndp->ni_vp = NULL;
1438 		error = EINVAL;
1439 		goto out;
1440 	}
1441 	/*
1442 	 * Check for saved name request
1443 	 */
1444 	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1445 		cnp->cn_flags |= HASBUF;
1446 		return (0);
1447 	}
1448 out:
1449 	FREE(cnp->cn_pnbuf, M_NAMEI);
1450 	return (error);
1451 }
1452 
1453 /*
1454  * A fiddled version of m_adj() that ensures null fill to a long
1455  * boundary and only trims off the back end
1456  */
1457 void
1458 nfsm_adj(mp, len, nul)
1459 	struct mbuf *mp;
1460 	register int len;
1461 	int nul;
1462 {
1463 	register struct mbuf *m;
1464 	register int count, i;
1465 	register char *cp;
1466 
1467 	/*
1468 	 * Trim from tail.  Scan the mbuf chain,
1469 	 * calculating its length and finding the last mbuf.
1470 	 * If the adjustment only affects this mbuf, then just
1471 	 * adjust and return.  Otherwise, rescan and truncate
1472 	 * after the remaining size.
1473 	 */
1474 	count = 0;
1475 	m = mp;
1476 	for (;;) {
1477 		count += m->m_len;
1478 		if (m->m_next == (struct mbuf *)0)
1479 			break;
1480 		m = m->m_next;
1481 	}
1482 	if (m->m_len > len) {
1483 		m->m_len -= len;
1484 		if (nul > 0) {
1485 			cp = mtod(m, caddr_t)+m->m_len-nul;
1486 			for (i = 0; i < nul; i++)
1487 				*cp++ = '\0';
1488 		}
1489 		return;
1490 	}
1491 	count -= len;
1492 	if (count < 0)
1493 		count = 0;
1494 	/*
1495 	 * Correct length for chain is "count".
1496 	 * Find the mbuf with last data, adjust its length,
1497 	 * and toss data from remaining mbufs on chain.
1498 	 */
1499 	for (m = mp; m; m = m->m_next) {
1500 		if (m->m_len >= count) {
1501 			m->m_len = count;
1502 			if (nul > 0) {
1503 				cp = mtod(m, caddr_t)+m->m_len-nul;
1504 				for (i = 0; i < nul; i++)
1505 					*cp++ = '\0';
1506 			}
1507 			break;
1508 		}
1509 		count -= m->m_len;
1510 	}
1511 	for (m = m->m_next;m;m = m->m_next)
1512 		m->m_len = 0;
1513 }
1514 
1515 /*
1516  * Make these functions instead of macros, so that the kernel text size
1517  * doesn't get too big...
1518  */
1519 void
1520 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1521 	struct nfsrv_descript *nfsd;
1522 	int before_ret;
1523 	register struct vattr *before_vap;
1524 	int after_ret;
1525 	struct vattr *after_vap;
1526 	struct mbuf **mbp;
1527 	char **bposp;
1528 {
1529 	register struct mbuf *mb = *mbp, *mb2;
1530 	register char *bpos = *bposp;
1531 	register u_int32_t *tl;
1532 
1533 	if (before_ret) {
1534 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1535 		*tl = nfs_false;
1536 	} else {
1537 		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1538 		*tl++ = nfs_true;
1539 		txdr_hyper(before_vap->va_size, tl);
1540 		tl += 2;
1541 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1542 		tl += 2;
1543 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1544 	}
1545 	*bposp = bpos;
1546 	*mbp = mb;
1547 	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1548 }
1549 
1550 void
1551 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1552 	struct nfsrv_descript *nfsd;
1553 	int after_ret;
1554 	struct vattr *after_vap;
1555 	struct mbuf **mbp;
1556 	char **bposp;
1557 {
1558 	register struct mbuf *mb = *mbp, *mb2;
1559 	register char *bpos = *bposp;
1560 	register u_int32_t *tl;
1561 	register struct nfs_fattr *fp;
1562 
1563 	if (after_ret) {
1564 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1565 		*tl = nfs_false;
1566 	} else {
1567 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1568 		*tl++ = nfs_true;
1569 		fp = (struct nfs_fattr *)tl;
1570 		nfsm_srvfattr(nfsd, after_vap, fp);
1571 	}
1572 	*mbp = mb;
1573 	*bposp = bpos;
1574 }
1575 
1576 void
1577 nfsm_srvfattr(nfsd, vap, fp)
1578 	register struct nfsrv_descript *nfsd;
1579 	register struct vattr *vap;
1580 	register struct nfs_fattr *fp;
1581 {
1582 
1583 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1584 	fp->fa_uid = txdr_unsigned(vap->va_uid);
1585 	fp->fa_gid = txdr_unsigned(vap->va_gid);
1586 	if (nfsd->nd_flag & ND_NFSV3) {
1587 		fp->fa_type = vtonfsv3_type(vap->va_type);
1588 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1589 		txdr_hyper(vap->va_size, &fp->fa3_size);
1590 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1591 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1592 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1593 		fp->fa3_fsid.nfsuquad[0] = 0;
1594 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1595 		fp->fa3_fileid.nfsuquad[0] = 0;
1596 		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1597 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1598 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1599 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1600 	} else {
1601 		fp->fa_type = vtonfsv2_type(vap->va_type);
1602 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1603 		fp->fa2_size = txdr_unsigned(vap->va_size);
1604 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1605 		if (vap->va_type == VFIFO)
1606 			fp->fa2_rdev = 0xffffffff;
1607 		else
1608 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1609 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1610 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1611 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1612 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1613 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1614 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1615 	}
1616 }
1617 
1618 /*
1619  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1620  * 	- look up fsid in mount list (if not found ret error)
1621  *	- get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
1622  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1623  *	- if not lockflag unlock it with VOP_UNLOCK()
1624  */
1625 int
1626 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
1627 	fhandle_t *fhp;
1628 	int lockflag;
1629 	struct vnode **vpp;
1630 	struct ucred *cred;
1631 	struct nfssvc_sock *slp;
1632 	struct mbuf *nam;
1633 	int *rdonlyp;
1634 	int kerbflag;
1635 {
1636 	struct proc *p = curproc;	/* XXX */
1637 	register struct mount *mp;
1638 	register int i;
1639 	struct ucred *credanon;
1640 	int error, exflags;
1641 	struct sockaddr_in *saddr;
1642 
1643 	*vpp = (struct vnode *)0;
1644 	mp = vfs_getvfs(&fhp->fh_fsid);
1645 
1646 	if (!mp)
1647 		return (ESTALE);
1648 	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1649 	if (error)
1650 		return (error);
1651 	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1652 	if (error)
1653 		return (error);
1654 
1655 	saddr = mtod(nam, struct sockaddr_in *);
1656 	if (saddr->sin_family == AF_INET &&
1657 	    (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
1658 	    (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
1659 		vput(*vpp);
1660 		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1661 	}
1662 
1663 	/*
1664 	 * Check/setup credentials.
1665 	 */
1666 	if (exflags & MNT_EXKERB) {
1667 		if (!kerbflag) {
1668 			vput(*vpp);
1669 			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1670 		}
1671 	} else if (kerbflag) {
1672 		vput(*vpp);
1673 		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1674 	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1675 		cred->cr_uid = credanon->cr_uid;
1676 		cred->cr_gid = credanon->cr_gid;
1677 		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1678 			cred->cr_groups[i] = credanon->cr_groups[i];
1679 		cred->cr_ngroups = i;
1680 	}
1681 	if (exflags & MNT_EXRDONLY)
1682 		*rdonlyp = 1;
1683 	else
1684 		*rdonlyp = 0;
1685 	if (!lockflag)
1686 		VOP_UNLOCK(*vpp, 0, p);
1687 
1688 	return (0);
1689 }
1690 
1691 /*
1692  * This function compares two net addresses by family and returns TRUE
1693  * if they are the same host.
1694  * If there is any doubt, return FALSE.
1695  * The AF_INET family is handled as a special case so that address mbufs
1696  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1697  */
1698 int
1699 netaddr_match(family, haddr, nam)
1700 	int family;
1701 	union nethostaddr *haddr;
1702 	struct mbuf *nam;
1703 {
1704 	register struct sockaddr_in *inetaddr;
1705 
1706 	switch (family) {
1707 	case AF_INET:
1708 		inetaddr = mtod(nam, struct sockaddr_in *);
1709 		if (inetaddr->sin_family == AF_INET &&
1710 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1711 			return (1);
1712 		break;
1713 #ifdef ISO
1714 	case AF_ISO:
1715 	    {
1716 		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1717 
1718 		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1719 		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1720 		if (isoaddr1->siso_family == AF_ISO &&
1721 		    isoaddr1->siso_nlen > 0 &&
1722 		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1723 		    SAME_ISOADDR(isoaddr1, isoaddr2))
1724 			return (1);
1725 		break;
1726 	    }
1727 #endif	/* ISO */
1728 	default:
1729 		break;
1730 	};
1731 	return (0);
1732 }
1733 
1734 /*
1735  * The write verifier has changed (probably due to a server reboot), so all
1736  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1737  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1738  * flag. Once done the new write verifier can be set for the mount point.
1739  */
1740 void
1741 nfs_clearcommit(mp)
1742 	struct mount *mp;
1743 {
1744 	register struct vnode *vp, *nvp;
1745 	register struct buf *bp, *nbp;
1746 	int s;
1747 
1748 	s = splbio();
1749 loop:
1750 	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
1751 		if (vp->v_mount != mp)	/* Paranoia */
1752 			goto loop;
1753 		nvp = vp->v_mntvnodes.le_next;
1754 		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
1755 			nbp = bp->b_vnbufs.le_next;
1756 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1757 				== (B_DELWRI | B_NEEDCOMMIT))
1758 				bp->b_flags &= ~B_NEEDCOMMIT;
1759 		}
1760 	}
1761 	splx(s);
1762 }
1763 
1764 /*
1765  * Map errnos to NFS error numbers. For Version 3 also filter out error
1766  * numbers not specified for the associated procedure.
1767  */
1768 int
1769 nfsrv_errmap(nd, err)
1770 	struct nfsrv_descript *nd;
1771 	register int err;
1772 {
1773 	register short *defaulterrp, *errp;
1774 
1775 	if (nd->nd_flag & ND_NFSV3) {
1776 	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1777 		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1778 		while (*++errp) {
1779 			if (*errp == err)
1780 				return (err);
1781 			else if (*errp > err)
1782 				break;
1783 		}
1784 		return ((int)*defaulterrp);
1785 	    } else
1786 		return (err & 0xffff);
1787 	}
1788 	if (err <= ELAST)
1789 		return ((int)nfsrv_v2errmap[err - 1]);
1790 	return (NFSERR_IO);
1791 }
1792 
1793 /*
1794  * Sort the group list in increasing numerical order.
1795  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1796  *  that used to be here.)
1797  */
1798 void
1799 nfsrvw_sort(list, num)
1800         register gid_t *list;
1801         register int num;
1802 {
1803 	register int i, j;
1804 	gid_t v;
1805 
1806 	/* Insertion sort. */
1807 	for (i = 1; i < num; i++) {
1808 		v = list[i];
1809 		/* find correct slot for value v, moving others up */
1810 		for (j = i; --j >= 0 && v < list[j];)
1811 			list[j + 1] = list[j];
1812 		list[j + 1] = v;
1813 	}
1814 }
1815 
1816 /*
1817  * copy credentials making sure that the result can be compared with bcmp().
1818  */
1819 void
1820 nfsrv_setcred(incred, outcred)
1821 	register struct ucred *incred, *outcred;
1822 {
1823 	register int i;
1824 
1825 	bzero((caddr_t)outcred, sizeof (struct ucred));
1826 	outcred->cr_ref = 1;
1827 	outcred->cr_uid = incred->cr_uid;
1828 	outcred->cr_gid = incred->cr_gid;
1829 	outcred->cr_ngroups = incred->cr_ngroups;
1830 	for (i = 0; i < incred->cr_ngroups; i++)
1831 		outcred->cr_groups[i] = incred->cr_groups[i];
1832 	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1833 }
1834