1 /*
2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34 /*
35 * Copyright (c) 1989, 1993
36 * The Regents of the University of California. All rights reserved.
37 *
38 * This code is derived from software contributed to Berkeley by
39 * Rick Macklem at The University of Guelph.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 /*
67 * These functions support the macros and help fiddle mbuf chains for
68 * the nfs op functions. They do things like create the rpc header and
69 * copy data between mbuf chains and uio lists.
70 */
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/buf.h>
75 #include <sys/proc.h>
76 #include <sys/mount.h>
77 #include <sys/vnode.h>
78 #include <sys/mbuf.h>
79 #include <sys/socket.h>
80 #include <sys/stat.h>
81 #include <sys/malloc.h>
82 #include <sys/sysent.h>
83 #include <sys/syscall.h>
84 #include <sys/conf.h>
85 #include <sys/objcache.h>
86
87 #include <vm/vm.h>
88 #include <vm/vm_object.h>
89 #include <vm/vm_extern.h>
90
91 #include <sys/buf2.h>
92
93 #include "rpcv2.h"
94 #include "nfsproto.h"
95 #include "nfs.h"
96 #include "nfsmount.h"
97 #include "nfsnode.h"
98 #include "xdr_subs.h"
99 #include "nfsm_subs.h"
100 #include "nfsrtt.h"
101
102 #include <netinet/in.h>
103
104 static u_int32_t nfs_xid = 0;
105
106 /*
107 * Create the header for an rpc request packet
108 * The hsiz is the size of the rest of the nfs request header.
109 * (just used to decide if a cluster is a good idea)
110 */
111 void
nfsm_reqhead(nfsm_info_t info,struct vnode * vp,u_long procid,int hsiz)112 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
113 {
114 info->mb = m_getl(hsiz, M_WAITOK, MT_DATA, 0, NULL);
115 info->mb->m_len = 0;
116 info->mreq = info->mb;
117 info->bpos = mtod(info->mb, caddr_t);
118 }
119
120 /*
121 * Build the RPC header and fill in the authorization info.
122 * The authorization string argument is only used when the credentials
123 * come from outside of the kernel.
124 * Returns the head of the mbuf list.
125 */
126 struct mbuf *
nfsm_rpchead(struct ucred * cr,int nmflag,int procid,int auth_type,int auth_len,char * auth_str,int verf_len,char * verf_str,struct mbuf * mrest,int mrest_len,struct mbuf ** mbp,u_int32_t * xidp)127 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
128 int auth_len, char *auth_str, int verf_len, char *verf_str,
129 struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
130 u_int32_t *xidp)
131 {
132 struct nfsm_info info;
133 struct mbuf *mb2;
134 u_int32_t *tl;
135 u_int32_t xid;
136 int siz, grpsiz, authsiz, dsiz;
137 int i;
138
139 authsiz = nfsm_rndup(auth_len);
140 dsiz = authsiz + 10 * NFSX_UNSIGNED;
141 info.mb = m_getl(dsiz, M_WAITOK, MT_DATA, M_PKTHDR, NULL);
142 if (dsiz < MINCLSIZE) {
143 if (dsiz < MHLEN)
144 MH_ALIGN(info.mb, dsiz);
145 else
146 MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
147 }
148 info.mb->m_len = info.mb->m_pkthdr.len = 0;
149 info.mreq = info.mb;
150 info.bpos = mtod(info.mb, caddr_t);
151
152 /*
153 * First the RPC header.
154 */
155 tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
156
157 /* Get a pretty random xid to start with */
158 if (!nfs_xid)
159 nfs_xid = krandom();
160
161 do {
162 xid = atomic_fetchadd_int(&nfs_xid, 1);
163 } while (xid == 0);
164
165 *tl++ = *xidp = txdr_unsigned(xid);
166 *tl++ = rpc_call;
167 *tl++ = rpc_vers;
168 *tl++ = txdr_unsigned(NFS_PROG);
169 if (nmflag & NFSMNT_NFSV3)
170 *tl++ = txdr_unsigned(NFS_VER3);
171 else
172 *tl++ = txdr_unsigned(NFS_VER2);
173 if (nmflag & NFSMNT_NFSV3)
174 *tl++ = txdr_unsigned(procid);
175 else
176 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
177
178 /*
179 * And then the authorization cred.
180 */
181 *tl++ = txdr_unsigned(auth_type);
182 *tl = txdr_unsigned(authsiz);
183 switch (auth_type) {
184 case RPCAUTH_UNIX:
185 tl = nfsm_build(&info, auth_len);
186 *tl++ = 0; /* stamp ?? */
187 *tl++ = 0; /* NULL hostname */
188 *tl++ = txdr_unsigned(cr->cr_uid);
189 *tl++ = txdr_unsigned(cr->cr_groups[0]);
190 grpsiz = (auth_len >> 2) - 5;
191 *tl++ = txdr_unsigned(grpsiz);
192 for (i = 1; i <= grpsiz; i++)
193 *tl++ = txdr_unsigned(cr->cr_groups[i]);
194 break;
195 case RPCAUTH_KERB4:
196 siz = auth_len;
197 while (siz > 0) {
198 if (M_TRAILINGSPACE(info.mb) == 0) {
199 mb2 = m_getl(siz, M_WAITOK, MT_DATA, 0, NULL);
200 mb2->m_len = 0;
201 info.mb->m_next = mb2;
202 info.mb = mb2;
203 info.bpos = mtod(info.mb, caddr_t);
204 }
205 i = min(siz, M_TRAILINGSPACE(info.mb));
206 bcopy(auth_str, info.bpos, i);
207 info.mb->m_len += i;
208 auth_str += i;
209 info.bpos += i;
210 siz -= i;
211 }
212 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
213 for (i = 0; i < siz; i++)
214 *info.bpos++ = '\0';
215 info.mb->m_len += siz;
216 }
217 break;
218 }
219
220 /*
221 * And the verifier...
222 */
223 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
224 if (verf_str) {
225 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
226 *tl = txdr_unsigned(verf_len);
227 siz = verf_len;
228 while (siz > 0) {
229 if (M_TRAILINGSPACE(info.mb) == 0) {
230 mb2 = m_getl(siz, M_WAITOK, MT_DATA,
231 0, NULL);
232 mb2->m_len = 0;
233 info.mb->m_next = mb2;
234 info.mb = mb2;
235 info.bpos = mtod(info.mb, caddr_t);
236 }
237 i = min(siz, M_TRAILINGSPACE(info.mb));
238 bcopy(verf_str, info.bpos, i);
239 info.mb->m_len += i;
240 verf_str += i;
241 info.bpos += i;
242 siz -= i;
243 }
244 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
245 for (i = 0; i < siz; i++)
246 *info.bpos++ = '\0';
247 info.mb->m_len += siz;
248 }
249 } else {
250 *tl++ = txdr_unsigned(RPCAUTH_NULL);
251 *tl = 0;
252 }
253 info.mb->m_next = mrest;
254 info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
255 info.mreq->m_pkthdr.rcvif = NULL;
256 *mbp = info.mb;
257 return (info.mreq);
258 }
259
260 void *
nfsm_build(nfsm_info_t info,int bytes)261 nfsm_build(nfsm_info_t info, int bytes)
262 {
263 struct mbuf *mb2;
264 void *ptr;
265
266 if (bytes > M_TRAILINGSPACE(info->mb)) {
267 MGET(mb2, M_WAITOK, MT_DATA);
268 if (bytes > MLEN)
269 panic("build > MLEN");
270 info->mb->m_next = mb2;
271 info->mb = mb2;
272 info->mb->m_len = 0;
273 info->bpos = mtod(info->mb, caddr_t);
274 }
275 ptr = info->bpos;
276 info->mb->m_len += bytes;
277 info->bpos += bytes;
278 return (ptr);
279 }
280
281 /*
282 *
283 * If NULL returned caller is expected to abort with an EBADRPC error.
284 * Caller will usually use the NULLOUT macro.
285 */
286 void *
nfsm_dissect(nfsm_info_t info,int bytes)287 nfsm_dissect(nfsm_info_t info, int bytes)
288 {
289 caddr_t cp2;
290 void *ptr;
291 int error;
292 int n;
293
294 /*
295 * Check for missing reply packet. This typically occurs if there
296 * is a soft termination w/too many retries.
297 */
298 if (info->md == NULL) {
299 if (info->mrep) {
300 m_freem(info->mrep);
301 info->mrep = NULL;
302 }
303 return NULL;
304 }
305
306 /*
307 * Otherwise any error will be due to the packet format
308 */
309 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
310 if (bytes <= n) {
311 ptr = info->dpos;
312 info->dpos += bytes;
313 } else {
314 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
315 if (error) {
316 m_freem(info->mrep);
317 info->mrep = NULL;
318 ptr = NULL;
319 } else {
320 ptr = cp2;
321 }
322 }
323 return (ptr);
324 }
325
326 /*
327 *
328 * Caller is expected to abort if non-zero error is returned.
329 */
330 int
nfsm_fhtom(nfsm_info_t info,struct vnode * vp)331 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
332 {
333 u_int32_t *tl;
334 caddr_t cp;
335 int error;
336 int n;
337
338 if (info->v3) {
339 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
340 if (n <= M_TRAILINGSPACE(info->mb)) {
341 tl = nfsm_build(info, n);
342 *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
343 *(tl + ((n >> 2) - 2)) = 0;
344 bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
345 VTONFS(vp)->n_fhsize);
346 error = 0;
347 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
348 (caddr_t)VTONFS(vp)->n_fhp,
349 VTONFS(vp)->n_fhsize)) != 0) {
350 m_freem(info->mreq);
351 info->mreq = NULL;
352 }
353 } else {
354 cp = nfsm_build(info, NFSX_V2FH);
355 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
356 error = 0;
357 }
358 return (error);
359 }
360
361 void
nfsm_srvfhtom(nfsm_info_t info,fhandle_t * fhp)362 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
363 {
364 u_int32_t *tl;
365
366 if (info->v3) {
367 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
368 *tl++ = txdr_unsigned(NFSX_V3FH);
369 bcopy(fhp, tl, NFSX_V3FH);
370 } else {
371 tl = nfsm_build(info, NFSX_V2FH);
372 bcopy(fhp, tl, NFSX_V2FH);
373 }
374 }
375
376 void
nfsm_srvpostop_fh(nfsm_info_t info,fhandle_t * fhp)377 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
378 {
379 u_int32_t *tl;
380
381 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
382 *tl++ = nfs_true;
383 *tl++ = txdr_unsigned(NFSX_V3FH);
384 bcopy(fhp, tl, NFSX_V3FH);
385 }
386
387 /*
388 * Caller is expected to abort if non-zero error is returned.
389 *
390 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
391 * winds up 0. The caller is responsible for dealing with (*vpp).
392 */
393 int
nfsm_mtofh(nfsm_info_t info,struct vnode * dvp,struct vnode ** vpp,int * gotvpp)394 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
395 {
396 struct nfsnode *ttnp;
397 nfsfh_t *ttfhp;
398 u_int32_t *tl;
399 int ttfhsize;
400 int error = 0;
401
402 if (info->v3) {
403 tl = nfsm_dissect(info, NFSX_UNSIGNED);
404 if (tl == NULL)
405 return(EBADRPC);
406 *gotvpp = fxdr_unsigned(int, *tl);
407 } else {
408 *gotvpp = 1;
409 }
410 if (*gotvpp) {
411 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
412 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp, NULL);
413 if (error) {
414 m_freem(info->mrep);
415 info->mrep = NULL;
416 return (error);
417 }
418 *vpp = NFSTOV(ttnp);
419 }
420 if (info->v3) {
421 tl = nfsm_dissect(info, NFSX_UNSIGNED);
422 if (tl == NULL)
423 return (EBADRPC);
424 if (*gotvpp) {
425 *gotvpp = fxdr_unsigned(int, *tl);
426 } else if (fxdr_unsigned(int, *tl)) {
427 error = nfsm_adv(info, NFSX_V3FATTR);
428 if (error)
429 return (error);
430 }
431 }
432 if (*gotvpp)
433 error = nfsm_loadattr(info, *vpp, NULL);
434 nfsmout:
435 return (error);
436 }
437
438 /*
439 *
440 * Caller is expected to abort with EBADRPC if a negative length is returned.
441 */
442 int
nfsm_getfh(nfsm_info_t info,nfsfh_t ** fhpp)443 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
444 {
445 u_int32_t *tl;
446 int n;
447
448 *fhpp = NULL;
449 if (info->v3) {
450 tl = nfsm_dissect(info, NFSX_UNSIGNED);
451 if (tl == NULL)
452 return(-1);
453 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
454 m_freem(info->mrep);
455 info->mrep = NULL;
456 return(-1);
457 }
458 } else {
459 n = NFSX_V2FH;
460 }
461 *fhpp = nfsm_dissect(info, nfsm_rndup(n));
462 if (*fhpp == NULL)
463 return(-1);
464 return(n);
465 }
466
467 /*
468 * Caller is expected to abort if a non-zero error is returned.
469 */
470 int
nfsm_loadattr(nfsm_info_t info,struct vnode * vp,struct vattr * vap)471 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
472 {
473 int error;
474
475 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
476 if (error) {
477 m_freem(info->mrep);
478 info->mrep = NULL;
479 return (error);
480 }
481 return (0);
482 }
483
484 /*
485 * Caller is expected to abort if a non-zero error is returned.
486 */
487 int
nfsm_postop_attr(nfsm_info_t info,struct vnode * vp,int * attrp,int lflags)488 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
489 {
490 u_int32_t *tl;
491 int error;
492
493 tl = nfsm_dissect(info, NFSX_UNSIGNED);
494 if (tl == NULL)
495 return(EBADRPC);
496 *attrp = fxdr_unsigned(int, *tl);
497 if (*attrp) {
498 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
499 NULL, lflags);
500 if (error) {
501 *attrp = 0;
502 m_freem(info->mrep);
503 info->mrep = NULL;
504 return (error);
505 }
506 }
507 return (0);
508 }
509
510 /*
511 * Caller is expected to abort if a non-zero error is returned.
512 */
513 int
nfsm_wcc_data(nfsm_info_t info,struct vnode * vp,int * attrp)514 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
515 {
516 u_int32_t *tl;
517 int error;
518 int ttattrf;
519 int ttretf = 0;
520
521 tl = nfsm_dissect(info, NFSX_UNSIGNED);
522 if (tl == NULL)
523 return (EBADRPC);
524 if (*tl == nfs_true) {
525 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
526 if (tl == NULL)
527 return (EBADRPC);
528 if (*attrp) {
529 ttretf = (VTONFS(vp)->n_mtime ==
530 fxdr_unsigned(u_int32_t, *(tl + 2)));
531 if (ttretf == 0)
532 VTONFS(vp)->n_flag |= NRMODIFIED;
533 }
534 error = nfsm_postop_attr(info, vp, &ttattrf,
535 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
536 if (error)
537 return(error);
538 } else {
539 error = nfsm_postop_attr(info, vp, &ttattrf,
540 NFS_LATTR_NOSHRINK);
541 if (error)
542 return(error);
543 }
544 if (*attrp)
545 *attrp = ttretf;
546 else
547 *attrp = ttattrf;
548 return(0);
549 }
550
551 /*
552 * This function updates the attribute cache based on data returned in the
553 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
554 * a 'before' and 'after' mtime is returned that allows us to determine if
555 * the new mtime attribute represents our modification or someone else's
556 * modification.
557 *
558 * The flag argument returns non-0 if the original times matched, zero if
559 * they did not match. NRMODIFIED is automatically set if the before time
560 * does not match the original n_mtime, and n_mtime is automatically updated
561 * to the new after time (by nfsm_postop_attr()).
562 *
563 * If full is true, set all fields, otherwise just set mode and time fields
564 */
565 void
nfsm_v3attrbuild(nfsm_info_t info,struct vattr * vap,int full)566 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
567 {
568 u_int32_t *tl;
569
570 if (vap->va_mode != (mode_t)VNOVAL) {
571 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
572 *tl++ = nfs_true;
573 *tl = txdr_unsigned(vap->va_mode);
574 } else {
575 tl = nfsm_build(info, NFSX_UNSIGNED);
576 *tl = nfs_false;
577 }
578 if (full && vap->va_uid != (uid_t)VNOVAL) {
579 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
580 *tl++ = nfs_true;
581 *tl = txdr_unsigned(vap->va_uid);
582 } else {
583 tl = nfsm_build(info, NFSX_UNSIGNED);
584 *tl = nfs_false;
585 }
586 if (full && vap->va_gid != (gid_t)VNOVAL) {
587 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
588 *tl++ = nfs_true;
589 *tl = txdr_unsigned(vap->va_gid);
590 } else {
591 tl = nfsm_build(info, NFSX_UNSIGNED);
592 *tl = nfs_false;
593 }
594 if (full && vap->va_size != VNOVAL) {
595 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
596 *tl++ = nfs_true;
597 txdr_hyper(vap->va_size, tl);
598 } else {
599 tl = nfsm_build(info, NFSX_UNSIGNED);
600 *tl = nfs_false;
601 }
602 if (vap->va_atime.tv_sec != VNOVAL) {
603 if (vap->va_atime.tv_sec != time_second) {
604 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
605 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
606 txdr_nfsv3time(&vap->va_atime, tl);
607 } else {
608 tl = nfsm_build(info, NFSX_UNSIGNED);
609 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
610 }
611 } else {
612 tl = nfsm_build(info, NFSX_UNSIGNED);
613 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
614 }
615 if (vap->va_mtime.tv_sec != VNOVAL) {
616 if (vap->va_mtime.tv_sec != time_second) {
617 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
618 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
619 txdr_nfsv3time(&vap->va_mtime, tl);
620 } else {
621 tl = nfsm_build(info, NFSX_UNSIGNED);
622 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
623 }
624 } else {
625 tl = nfsm_build(info, NFSX_UNSIGNED);
626 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
627 }
628 }
629
630 /*
631 * Caller is expected to abort with EBADRPC if a negative length is returned.
632 */
633 int
nfsm_strsiz(nfsm_info_t info,int maxlen)634 nfsm_strsiz(nfsm_info_t info, int maxlen)
635 {
636 u_int32_t *tl;
637 int len;
638
639 tl = nfsm_dissect(info, NFSX_UNSIGNED);
640 if (tl == NULL)
641 return(-1);
642 len = fxdr_unsigned(int32_t, *tl);
643 if (len < 0 || len > maxlen)
644 return(-1);
645 return (len);
646 }
647
648 /*
649 * Caller is expected to abort if a negative length is returned, but also
650 * call nfsm_reply(0) if -2 is returned.
651 *
652 * This function sets *errorp. Caller should not modify the error code.
653 */
654 int
nfsm_srvstrsiz(nfsm_info_t info,int maxlen,int * errorp)655 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
656 {
657 u_int32_t *tl;
658 int len;
659
660 tl = nfsm_dissect(info, NFSX_UNSIGNED);
661 if (tl == NULL) {
662 *errorp = EBADRPC;
663 return(-1);
664 }
665 len = fxdr_unsigned(int32_t,*tl);
666 if (len > maxlen || len <= 0) {
667 *errorp = EBADRPC;
668 return(-2);
669 }
670 return(len);
671 }
672
673 /*
674 * Caller is expected to abort if a negative length is returned, but also
675 * call nfsm_reply(0) if -2 is returned.
676 *
677 * This function sets *errorp. Caller should not modify the error code.
678 */
679 int
nfsm_srvnamesiz(nfsm_info_t info,int * errorp)680 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
681 {
682 u_int32_t *tl;
683 int len;
684
685 tl = nfsm_dissect(info, NFSX_UNSIGNED);
686 if (tl == NULL) {
687 *errorp = EBADRPC;
688 return(-1);
689 }
690
691 /*
692 * In this case if *errorp is not EBADRPC and we are NFSv3,
693 * nfsm_reply() will not return a negative number. But all
694 * call cases assume len is valid so we really do want
695 * to return -1.
696 */
697 len = fxdr_unsigned(int32_t,*tl);
698 if (len > NFS_MAXNAMLEN)
699 *errorp = NFSERR_NAMETOL;
700 if (len <= 0)
701 *errorp = EBADRPC;
702 if (*errorp)
703 return(-2);
704 return (len);
705 }
706
707 /*
708 * Caller is expected to abort if a non-zero error is returned.
709 */
710 int
nfsm_mtouio(nfsm_info_t info,struct uio * uiop,int len)711 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
712 {
713 int error;
714
715 if (len > 0 &&
716 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
717 m_freem(info->mrep);
718 info->mrep = NULL;
719 return(error);
720 }
721 return(0);
722 }
723
724 /*
725 * Caller is expected to abort if a non-zero error is returned.
726 */
727 int
nfsm_mtobio(nfsm_info_t info,struct bio * bio,int len)728 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
729 {
730 int error;
731
732 if (len > 0 &&
733 (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
734 m_freem(info->mrep);
735 info->mrep = NULL;
736 return(error);
737 }
738 return (0);
739 }
740
741 /*
742 * Caller is expected to abort if a non-zero error is returned.
743 */
744 int
nfsm_uiotom(nfsm_info_t info,struct uio * uiop,int len)745 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
746 {
747 int error;
748
749 error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
750 if (error) {
751 m_freem(info->mreq);
752 info->mreq = NULL;
753 return (error);
754 }
755 return(0);
756 }
757
758 int
nfsm_biotom(nfsm_info_t info,struct bio * bio,int off,int len)759 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
760 {
761 int error;
762
763 error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
764 if (error) {
765 m_freem(info->mreq);
766 info->mreq = NULL;
767 return (error);
768 }
769 return(0);
770 }
771
772 /*
773 * Caller is expected to abort if a negative value is returned. This
774 * function sets *errorp. Caller should not modify the error code.
775 *
776 * We load up the remaining info fields and run the request state
777 * machine until it is done.
778 *
779 * This call runs the entire state machine and does not return until
780 * the command is complete.
781 */
782 int
nfsm_request(nfsm_info_t info,struct vnode * vp,int procnum,thread_t td,struct ucred * cred,int * errorp)783 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
784 thread_t td, struct ucred *cred, int *errorp)
785 {
786 info->state = NFSM_STATE_SETUP;
787 info->procnum = procnum;
788 info->vp = vp;
789 info->td = td;
790 info->cred = cred;
791 info->bio = NULL;
792 info->nmp = VFSTONFS(vp->v_mount);
793
794 *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
795 if (*errorp) {
796 if ((*errorp & NFSERR_RETERR) == 0)
797 return(-1);
798 *errorp &= ~NFSERR_RETERR;
799 }
800 return(0);
801 }
802
803 /*
804 * This call starts the state machine through the initial transmission.
805 * Completion is via the bio. The info structure must have installed
806 * a 'done' callback.
807 *
808 * If we are unable to do the initial tx we generate the bio completion
809 * ourselves.
810 */
811 void
nfsm_request_bio(nfsm_info_t info,struct vnode * vp,int procnum,thread_t td,struct ucred * cred)812 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
813 thread_t td, struct ucred *cred)
814 {
815 struct buf *bp;
816 int error;
817
818 info->state = NFSM_STATE_SETUP;
819 info->procnum = procnum;
820 info->vp = vp;
821 info->td = td;
822 info->cred = cred;
823 info->nmp = VFSTONFS(vp->v_mount);
824
825 error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY);
826 if (error != EINPROGRESS) {
827 kprintf("nfsm_request_bio: early abort %d\n", error);
828 bp = info->bio->bio_buf;
829 if (error) {
830 bp->b_flags |= B_ERROR;
831 if (error == EIO) /* unrecoverable */
832 bp->b_flags |= B_INVAL;
833 }
834 bp->b_error = error;
835 biodone(info->bio);
836 }
837 }
838
839 /*
840 * Caller is expected to abort if a non-zero error is returned.
841 */
842 int
nfsm_strtom(nfsm_info_t info,const void * data,int len,int maxlen)843 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
844 {
845 u_int32_t *tl;
846 int error;
847 int n;
848
849 if (len > maxlen) {
850 m_freem(info->mreq);
851 info->mreq = NULL;
852 return(ENAMETOOLONG);
853 }
854 n = nfsm_rndup(len) + NFSX_UNSIGNED;
855 if (n <= M_TRAILINGSPACE(info->mb)) {
856 tl = nfsm_build(info, n);
857 *tl++ = txdr_unsigned(len);
858 *(tl + ((n >> 2) - 2)) = 0;
859 bcopy(data, tl, len);
860 error = 0;
861 } else {
862 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
863 if (error) {
864 m_freem(info->mreq);
865 info->mreq = NULL;
866 }
867 }
868 return (error);
869 }
870
871 /*
872 * Caller is expected to abort if a negative value is returned. This
873 * function sets *errorp. Caller should not modify the error code.
874 */
875 int
nfsm_reply(nfsm_info_t info,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,int siz,int * errorp)876 nfsm_reply(nfsm_info_t info,
877 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
878 int siz, int *errorp)
879 {
880 nfsd->nd_repstat = *errorp;
881 if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
882 siz = 0;
883 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
884 &info->mb, &info->bpos);
885 if (info->mrep != NULL) {
886 m_freem(info->mrep);
887 info->mrep = NULL;
888 }
889 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
890 *errorp = 0;
891 return(-1);
892 }
893 return(0);
894 }
895
896 void
nfsm_writereply(nfsm_info_t info,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,int error,int siz)897 nfsm_writereply(nfsm_info_t info,
898 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
899 int error, int siz)
900 {
901 nfsd->nd_repstat = error;
902 if (error && !(info->v3))
903 siz = 0;
904 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
905 }
906
907 /*
908 * Caller is expected to abort if a non-zero error is returned.
909 */
910 int
nfsm_adv(nfsm_info_t info,int len)911 nfsm_adv(nfsm_info_t info, int len)
912 {
913 int error;
914 int n;
915
916 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
917 if (n >= len) {
918 info->dpos += len;
919 error = 0;
920 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
921 m_freem(info->mrep);
922 info->mrep = NULL;
923 }
924 return (error);
925 }
926
927 /*
928 * Caller is expected to abort if a negative length is returned, but also
929 * call nfsm_reply(0) if -2 is returned.
930 *
931 * This function sets *errorp. Caller should not modify the error code.
932 */
933 int
nfsm_srvmtofh(nfsm_info_t info,struct nfsrv_descript * nfsd,fhandle_t * fhp,int * errorp)934 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
935 fhandle_t *fhp, int *errorp)
936 {
937 u_int32_t *tl;
938 int fhlen;
939
940 if (nfsd->nd_flag & ND_NFSV3) {
941 tl = nfsm_dissect(info, NFSX_UNSIGNED);
942 if (tl == NULL) {
943 *errorp = EBADRPC;
944 return(-1);
945 }
946 fhlen = fxdr_unsigned(int, *tl);
947 if (fhlen != 0 && fhlen != NFSX_V3FH) {
948 *errorp = EBADRPC;
949 return(-2);
950 }
951 } else {
952 fhlen = NFSX_V2FH;
953 }
954 if (fhlen != 0) {
955 tl = nfsm_dissect(info, fhlen);
956 if (tl == NULL) {
957 *errorp = EBADRPC;
958 return(-1);
959 }
960 bcopy(tl, fhp, fhlen);
961 } else {
962 bzero(fhp, NFSX_V3FH);
963 }
964 return(0);
965 }
966
967 void *
_nfsm_clget(nfsm_info_t info,struct mbuf ** mp1,struct mbuf ** mp2,char ** bp,char ** be)968 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
969 char **bp, char **be)
970 {
971 if (*bp >= *be) {
972 if (*mp1 == info->mb)
973 (*mp1)->m_len += *bp - info->bpos;
974 *mp1 = m_getcl(M_WAITOK, MT_DATA, 0);
975 (*mp1)->m_len = MCLBYTES;
976 (*mp2)->m_next = *mp1;
977 *mp2 = *mp1;
978 *bp = mtod(*mp1, caddr_t);
979 *be = *bp + (*mp1)->m_len;
980 }
981 return(*bp);
982 }
983
984 int
nfsm_srvsattr(nfsm_info_t info,struct vattr * vap)985 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
986 {
987 u_int32_t *tl;
988 int error = 0;
989
990 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
991 if (*tl == nfs_true) {
992 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
993 vap->va_mode = nfstov_mode(*tl);
994 }
995 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
996 if (*tl == nfs_true) {
997 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
998 vap->va_uid = fxdr_unsigned(uid_t, *tl);
999 }
1000 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1001 if (*tl == nfs_true) {
1002 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1003 vap->va_gid = fxdr_unsigned(gid_t, *tl);
1004 }
1005 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1006 if (*tl == nfs_true) {
1007 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1008 vap->va_size = fxdr_hyper(tl);
1009 }
1010 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1011 switch (fxdr_unsigned(int, *tl)) {
1012 case NFSV3SATTRTIME_TOCLIENT:
1013 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1014 fxdr_nfsv3time(tl, &vap->va_atime);
1015 break;
1016 case NFSV3SATTRTIME_TOSERVER:
1017 getnanotime(&vap->va_atime);
1018 break;
1019 }
1020 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1021 switch (fxdr_unsigned(int, *tl)) {
1022 case NFSV3SATTRTIME_TOCLIENT:
1023 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1024 fxdr_nfsv3time(tl, &vap->va_mtime);
1025 break;
1026 case NFSV3SATTRTIME_TOSERVER:
1027 getnanotime(&vap->va_mtime);
1028 break;
1029 }
1030 nfsmout:
1031 return (error);
1032 }
1033
1034 /*
1035 * copies mbuf chain to the uio scatter/gather list
1036 */
1037 int
nfsm_mbuftouio(struct mbuf ** mrep,struct uio * uiop,int siz,caddr_t * dpos)1038 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1039 {
1040 char *mbufcp, *uiocp;
1041 int xfer, left, len;
1042 struct mbuf *mp;
1043 long uiosiz, rem;
1044 int error = 0;
1045
1046 mp = *mrep;
1047 mbufcp = *dpos;
1048 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1049 rem = nfsm_rndup(siz)-siz;
1050 while (siz > 0) {
1051 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1052 return (EFBIG);
1053 left = uiop->uio_iov->iov_len;
1054 uiocp = uiop->uio_iov->iov_base;
1055 if (left > siz)
1056 left = siz;
1057 uiosiz = left;
1058 while (left > 0) {
1059 while (len == 0) {
1060 mp = mp->m_next;
1061 if (mp == NULL)
1062 return (EBADRPC);
1063 mbufcp = mtod(mp, caddr_t);
1064 len = mp->m_len;
1065 }
1066 xfer = (left > len) ? len : left;
1067 #ifdef notdef
1068 /* Not Yet.. */
1069 if (uiop->uio_iov->iov_op != NULL)
1070 (*(uiop->uio_iov->iov_op))
1071 (mbufcp, uiocp, xfer);
1072 else
1073 #endif
1074 if (uiop->uio_segflg == UIO_SYSSPACE)
1075 bcopy(mbufcp, uiocp, xfer);
1076 else
1077 copyout(mbufcp, uiocp, xfer);
1078 left -= xfer;
1079 len -= xfer;
1080 mbufcp += xfer;
1081 uiocp += xfer;
1082 uiop->uio_offset += xfer;
1083 uiop->uio_resid -= xfer;
1084 }
1085 if (uiop->uio_iov->iov_len <= siz) {
1086 uiop->uio_iovcnt--;
1087 uiop->uio_iov++;
1088 } else {
1089 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1090 uiop->uio_iov->iov_len -= uiosiz;
1091 }
1092 siz -= uiosiz;
1093 }
1094 *dpos = mbufcp;
1095 *mrep = mp;
1096 if (rem > 0) {
1097 if (len < rem)
1098 error = nfs_adv(mrep, dpos, rem, len);
1099 else
1100 *dpos += rem;
1101 }
1102 return (error);
1103 }
1104
1105 /*
1106 * copies mbuf chain to the bio buffer
1107 */
1108 int
nfsm_mbuftobio(struct mbuf ** mrep,struct bio * bio,int size,caddr_t * dpos)1109 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1110 {
1111 struct buf *bp = bio->bio_buf;
1112 char *mbufcp;
1113 char *bio_cp;
1114 int xfer, len;
1115 struct mbuf *mp;
1116 long rem;
1117 int error = 0;
1118 int bio_left;
1119
1120 mp = *mrep;
1121 mbufcp = *dpos;
1122 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1123 rem = nfsm_rndup(size) - size;
1124
1125 bio_left = bp->b_bcount;
1126 bio_cp = bp->b_data;
1127
1128 while (size > 0) {
1129 while (len == 0) {
1130 mp = mp->m_next;
1131 if (mp == NULL)
1132 return (EBADRPC);
1133 mbufcp = mtod(mp, caddr_t);
1134 len = mp->m_len;
1135 }
1136 if ((xfer = len) > size)
1137 xfer = size;
1138 if (bio_left) {
1139 if (xfer > bio_left)
1140 xfer = bio_left;
1141 bcopy(mbufcp, bio_cp, xfer);
1142 } else {
1143 /*
1144 * Not enough buffer space in the bio.
1145 */
1146 return(EFBIG);
1147 }
1148 size -= xfer;
1149 bio_left -= xfer;
1150 bio_cp += xfer;
1151 len -= xfer;
1152 mbufcp += xfer;
1153 }
1154 *dpos = mbufcp;
1155 *mrep = mp;
1156 if (rem > 0) {
1157 if (len < rem)
1158 error = nfs_adv(mrep, dpos, rem, len);
1159 else
1160 *dpos += rem;
1161 }
1162 return (error);
1163 }
1164
1165 /*
1166 * copies a uio scatter/gather list to an mbuf chain.
1167 * NOTE: can ony handle iovcnt == 1
1168 */
1169 int
nfsm_uiotombuf(struct uio * uiop,struct mbuf ** mq,int siz,caddr_t * bpos)1170 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1171 {
1172 char *uiocp;
1173 struct mbuf *mp, *mp2;
1174 int xfer, left, mlen;
1175 int uiosiz, rem;
1176 boolean_t getcluster;
1177 char *cp;
1178
1179 #ifdef DIAGNOSTIC
1180 if (uiop->uio_iovcnt != 1)
1181 panic("nfsm_uiotombuf: iovcnt != 1");
1182 #endif
1183
1184 if (siz >= MINCLSIZE)
1185 getcluster = TRUE;
1186 else
1187 getcluster = FALSE;
1188 rem = nfsm_rndup(siz) - siz;
1189 mp = mp2 = *mq;
1190 while (siz > 0) {
1191 left = uiop->uio_iov->iov_len;
1192 uiocp = uiop->uio_iov->iov_base;
1193 if (left > siz)
1194 left = siz;
1195 uiosiz = left;
1196 while (left > 0) {
1197 mlen = M_TRAILINGSPACE(mp);
1198 if (mlen == 0) {
1199 if (getcluster)
1200 mp = m_getcl(M_WAITOK, MT_DATA, 0);
1201 else
1202 mp = m_get(M_WAITOK, MT_DATA);
1203 mp->m_len = 0;
1204 mp2->m_next = mp;
1205 mp2 = mp;
1206 mlen = M_TRAILINGSPACE(mp);
1207 }
1208 xfer = (left > mlen) ? mlen : left;
1209 #ifdef notdef
1210 /* Not Yet.. */
1211 if (uiop->uio_iov->iov_op != NULL)
1212 (*(uiop->uio_iov->iov_op))
1213 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1214 else
1215 #endif
1216 if (uiop->uio_segflg == UIO_SYSSPACE)
1217 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1218 else
1219 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1220 mp->m_len += xfer;
1221 left -= xfer;
1222 uiocp += xfer;
1223 uiop->uio_offset += xfer;
1224 uiop->uio_resid -= xfer;
1225 }
1226 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1227 uiop->uio_iov->iov_len -= uiosiz;
1228 siz -= uiosiz;
1229 }
1230 if (rem > 0) {
1231 if (rem > M_TRAILINGSPACE(mp)) {
1232 MGET(mp, M_WAITOK, MT_DATA);
1233 mp->m_len = 0;
1234 mp2->m_next = mp;
1235 }
1236 cp = mtod(mp, caddr_t)+mp->m_len;
1237 for (left = 0; left < rem; left++)
1238 *cp++ = '\0';
1239 mp->m_len += rem;
1240 *bpos = cp;
1241 } else
1242 *bpos = mtod(mp, caddr_t)+mp->m_len;
1243 *mq = mp;
1244 return (0);
1245 }
1246
1247 int
nfsm_biotombuf(struct bio * bio,struct mbuf ** mq,int off,int siz,caddr_t * bpos)1248 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1249 int siz, caddr_t *bpos)
1250 {
1251 struct buf *bp = bio->bio_buf;
1252 struct mbuf *mp, *mp2;
1253 char *bio_cp;
1254 int bio_left;
1255 int xfer, mlen;
1256 int rem;
1257 boolean_t getcluster;
1258 char *cp;
1259
1260 if (siz >= MINCLSIZE)
1261 getcluster = TRUE;
1262 else
1263 getcluster = FALSE;
1264 rem = nfsm_rndup(siz) - siz;
1265 mp = mp2 = *mq;
1266
1267 bio_cp = bp->b_data + off;
1268 bio_left = siz;
1269
1270 while (bio_left) {
1271 mlen = M_TRAILINGSPACE(mp);
1272 if (mlen == 0) {
1273 if (getcluster)
1274 mp = m_getcl(M_WAITOK, MT_DATA, 0);
1275 else
1276 mp = m_get(M_WAITOK, MT_DATA);
1277 mp->m_len = 0;
1278 mp2->m_next = mp;
1279 mp2 = mp;
1280 mlen = M_TRAILINGSPACE(mp);
1281 }
1282 xfer = (bio_left < mlen) ? bio_left : mlen;
1283 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1284 mp->m_len += xfer;
1285 bio_left -= xfer;
1286 bio_cp += xfer;
1287 }
1288 if (rem > 0) {
1289 if (rem > M_TRAILINGSPACE(mp)) {
1290 MGET(mp, M_WAITOK, MT_DATA);
1291 mp->m_len = 0;
1292 mp2->m_next = mp;
1293 }
1294 cp = mtod(mp, caddr_t) + mp->m_len;
1295 for (mlen = 0; mlen < rem; mlen++)
1296 *cp++ = '\0';
1297 mp->m_len += rem;
1298 *bpos = cp;
1299 } else {
1300 *bpos = mtod(mp, caddr_t) + mp->m_len;
1301 }
1302 *mq = mp;
1303 return(0);
1304 }
1305
1306 /*
1307 * Help break down an mbuf chain by setting the first siz bytes contiguous
1308 * pointed to by returned val.
1309 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1310 * cases. (The macros use the vars. dpos and dpos2)
1311 */
1312 int
nfsm_disct(struct mbuf ** mdp,caddr_t * dposp,int siz,int left,caddr_t * cp2)1313 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1314 {
1315 struct mbuf *mp, *mp2;
1316 int siz2, xfer;
1317 caddr_t p;
1318
1319 mp = *mdp;
1320 while (left == 0) {
1321 *mdp = mp = mp->m_next;
1322 if (mp == NULL)
1323 return (EBADRPC);
1324 left = mp->m_len;
1325 *dposp = mtod(mp, caddr_t);
1326 }
1327 if (left >= siz) {
1328 *cp2 = *dposp;
1329 *dposp += siz;
1330 } else if (mp->m_next == NULL) {
1331 return (EBADRPC);
1332 } else if (siz > MHLEN) {
1333 panic("nfs S too big");
1334 } else {
1335 MGET(mp2, M_WAITOK, MT_DATA);
1336 mp2->m_next = mp->m_next;
1337 mp->m_next = mp2;
1338 mp->m_len -= left;
1339 mp = mp2;
1340 *cp2 = p = mtod(mp, caddr_t);
1341 bcopy(*dposp, p, left); /* Copy what was left */
1342 siz2 = siz-left;
1343 p += left;
1344 mp2 = mp->m_next;
1345 /* Loop around copying up the siz2 bytes */
1346 while (siz2 > 0) {
1347 if (mp2 == NULL)
1348 return (EBADRPC);
1349 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1350 if (xfer > 0) {
1351 bcopy(mtod(mp2, caddr_t), p, xfer);
1352 mp2->m_len -= xfer;
1353 mp2->m_data += xfer;
1354 p += xfer;
1355 siz2 -= xfer;
1356 }
1357 if (siz2 > 0)
1358 mp2 = mp2->m_next;
1359 }
1360 mp->m_len = siz;
1361 *mdp = mp2;
1362 *dposp = mtod(mp2, caddr_t);
1363 }
1364 return (0);
1365 }
1366
1367 /*
1368 * Advance the position in the mbuf chain.
1369 */
1370 int
nfs_adv(struct mbuf ** mdp,caddr_t * dposp,int offs,int left)1371 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1372 {
1373 struct mbuf *m;
1374 int s;
1375
1376 m = *mdp;
1377 s = left;
1378 while (s < offs) {
1379 offs -= s;
1380 m = m->m_next;
1381 if (m == NULL)
1382 return (EBADRPC);
1383 s = m->m_len;
1384 }
1385 *mdp = m;
1386 *dposp = mtod(m, caddr_t)+offs;
1387 return (0);
1388 }
1389
1390 /*
1391 * Copy a string into mbufs for the hard cases...
1392 */
1393 int
nfsm_strtmbuf(struct mbuf ** mb,char ** bpos,const char * cp,long siz)1394 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1395 {
1396 struct mbuf *m1 = NULL, *m2;
1397 long left, xfer, len, tlen;
1398 u_int32_t *tl;
1399 int putsize;
1400
1401 putsize = 1;
1402 m2 = *mb;
1403 left = M_TRAILINGSPACE(m2);
1404 if (left > 0) {
1405 tl = ((u_int32_t *)(*bpos));
1406 *tl++ = txdr_unsigned(siz);
1407 putsize = 0;
1408 left -= NFSX_UNSIGNED;
1409 m2->m_len += NFSX_UNSIGNED;
1410 if (left > 0) {
1411 bcopy(cp, (caddr_t) tl, left);
1412 siz -= left;
1413 cp += left;
1414 m2->m_len += left;
1415 left = 0;
1416 }
1417 }
1418 /* Loop around adding mbufs */
1419 while (siz > 0) {
1420 int msize;
1421
1422 m1 = m_getl(siz, M_WAITOK, MT_DATA, 0, &msize);
1423 m1->m_len = msize;
1424 m2->m_next = m1;
1425 m2 = m1;
1426 tl = mtod(m1, u_int32_t *);
1427 tlen = 0;
1428 if (putsize) {
1429 *tl++ = txdr_unsigned(siz);
1430 m1->m_len -= NFSX_UNSIGNED;
1431 tlen = NFSX_UNSIGNED;
1432 putsize = 0;
1433 }
1434 if (siz < m1->m_len) {
1435 len = nfsm_rndup(siz);
1436 xfer = siz;
1437 if (xfer < len)
1438 *(tl+(xfer>>2)) = 0;
1439 } else {
1440 xfer = len = m1->m_len;
1441 }
1442 bcopy(cp, (caddr_t) tl, xfer);
1443 m1->m_len = len+tlen;
1444 siz -= xfer;
1445 cp += xfer;
1446 }
1447 *mb = m1;
1448 *bpos = mtod(m1, caddr_t)+m1->m_len;
1449 return (0);
1450 }
1451
1452 /*
1453 * A fiddled version of m_adj() that ensures null fill to a long
1454 * boundary and only trims off the back end
1455 */
1456 void
nfsm_adj(struct mbuf * mp,int len,int nul)1457 nfsm_adj(struct mbuf *mp, int len, int nul)
1458 {
1459 struct mbuf *m;
1460 int count, i;
1461 char *cp;
1462
1463 /*
1464 * Trim from tail. Scan the mbuf chain,
1465 * calculating its length and finding the last mbuf.
1466 * If the adjustment only affects this mbuf, then just
1467 * adjust and return. Otherwise, rescan and truncate
1468 * after the remaining size.
1469 */
1470 count = 0;
1471 m = mp;
1472 for (;;) {
1473 count += m->m_len;
1474 if (m->m_next == NULL)
1475 break;
1476 m = m->m_next;
1477 }
1478 if (m->m_len > len) {
1479 m->m_len -= len;
1480 if (nul > 0) {
1481 cp = mtod(m, caddr_t)+m->m_len-nul;
1482 for (i = 0; i < nul; i++)
1483 *cp++ = '\0';
1484 }
1485 return;
1486 }
1487 count -= len;
1488 if (count < 0)
1489 count = 0;
1490 /*
1491 * Correct length for chain is "count".
1492 * Find the mbuf with last data, adjust its length,
1493 * and toss data from remaining mbufs on chain.
1494 */
1495 for (m = mp; m; m = m->m_next) {
1496 if (m->m_len >= count) {
1497 m->m_len = count;
1498 if (nul > 0) {
1499 cp = mtod(m, caddr_t)+m->m_len-nul;
1500 for (i = 0; i < nul; i++)
1501 *cp++ = '\0';
1502 }
1503 break;
1504 }
1505 count -= m->m_len;
1506 }
1507 for (m = m->m_next;m;m = m->m_next)
1508 m->m_len = 0;
1509 }
1510
1511 /*
1512 * Make these functions instead of macros, so that the kernel text size
1513 * doesn't get too big...
1514 */
1515 void
nfsm_srvwcc_data(nfsm_info_t info,struct nfsrv_descript * nfsd,int before_ret,struct vattr * before_vap,int after_ret,struct vattr * after_vap)1516 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1517 int before_ret, struct vattr *before_vap,
1518 int after_ret, struct vattr *after_vap)
1519 {
1520 u_int32_t *tl;
1521
1522 /*
1523 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1524 */
1525 if (before_ret) {
1526 tl = nfsm_build(info, NFSX_UNSIGNED);
1527 *tl = nfs_false;
1528 } else {
1529 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1530 *tl++ = nfs_true;
1531 txdr_hyper(before_vap->va_size, tl);
1532 tl += 2;
1533 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1534 tl += 2;
1535 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1536 }
1537 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1538 }
1539
1540 void
nfsm_srvpostop_attr(nfsm_info_t info,struct nfsrv_descript * nfsd,int after_ret,struct vattr * after_vap)1541 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1542 int after_ret, struct vattr *after_vap)
1543 {
1544 struct nfs_fattr *fp;
1545 u_int32_t *tl;
1546
1547 if (after_ret) {
1548 tl = nfsm_build(info, NFSX_UNSIGNED);
1549 *tl = nfs_false;
1550 } else {
1551 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1552 *tl++ = nfs_true;
1553 fp = (struct nfs_fattr *)tl;
1554 nfsm_srvfattr(nfsd, after_vap, fp);
1555 }
1556 }
1557
1558 void
nfsm_srvfattr(struct nfsrv_descript * nfsd,struct vattr * vap,struct nfs_fattr * fp)1559 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1560 struct nfs_fattr *fp)
1561 {
1562 /*
1563 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1564 */
1565 if (vap->va_nlink > 65535)
1566 fp->fa_nlink = 65535;
1567 else
1568 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1569 fp->fa_uid = txdr_unsigned(vap->va_uid);
1570 fp->fa_gid = txdr_unsigned(vap->va_gid);
1571 if (nfsd->nd_flag & ND_NFSV3) {
1572 fp->fa_type = vtonfsv3_type(vap->va_type);
1573 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1574 txdr_hyper(vap->va_size, &fp->fa3_size);
1575 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1576 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1577 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1578 fp->fa3_fsid.nfsuquad[0] = 0;
1579 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1580 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1581 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1582 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1583 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1584 } else {
1585 fp->fa_type = vtonfsv2_type(vap->va_type);
1586 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1587 fp->fa2_size = txdr_unsigned(vap->va_size);
1588 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1589 if (vap->va_type == VFIFO)
1590 fp->fa2_rdev = 0xffffffff;
1591 else
1592 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1593 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1594 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1595 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1596 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1597 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1598 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1599 }
1600 }
1601