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