xref: /dragonfly/sys/vfs/nfs/nfsm_subs.c (revision b1999ea8)
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