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