xref: /titanic_44/usr/src/uts/common/fs/nfs/nfs_xdr.c (revision f169c0eae91b2ee787cf8d6dcf8edd9159d4c9e2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/user.h>
33 #include <sys/vnode.h>
34 #include <sys/file.h>
35 #include <sys/dirent.h>
36 #include <sys/vfs.h>
37 #include <sys/stream.h>
38 #include <sys/strsubr.h>
39 #include <sys/debug.h>
40 #include <sys/t_lock.h>
41 #include <sys/sdt.h>
42 
43 #include <rpc/types.h>
44 #include <rpc/xdr.h>
45 
46 #include <nfs/nfs.h>
47 
48 #include <vm/hat.h>
49 #include <vm/as.h>
50 #include <vm/seg.h>
51 #include <vm/seg_map.h>
52 #include <vm/seg_kmem.h>
53 
54 static bool_t xdr_fastshorten(XDR *, uint_t);
55 
56 /*
57  * These are the XDR routines used to serialize and deserialize
58  * the various structures passed as parameters accross the network
59  * between NFS clients and servers.
60  */
61 
62 /*
63  * File access handle
64  * The fhandle struct is treated a opaque data on the wire
65  */
66 bool_t
67 xdr_fhandle(XDR *xdrs, fhandle_t *fh)
68 {
69 	int32_t *ptr;
70 	int32_t *fhp;
71 
72 	if (xdrs->x_op == XDR_FREE)
73 		return (TRUE);
74 
75 	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)));
76 	if (ptr != NULL) {
77 		fhp = (int32_t *)fh;
78 		if (xdrs->x_op == XDR_DECODE) {
79 			*fhp++ = *ptr++;
80 			*fhp++ = *ptr++;
81 			*fhp++ = *ptr++;
82 			*fhp++ = *ptr++;
83 			*fhp++ = *ptr++;
84 			*fhp++ = *ptr++;
85 			*fhp++ = *ptr++;
86 			*fhp = *ptr;
87 		} else {
88 			*ptr++ = *fhp++;
89 			*ptr++ = *fhp++;
90 			*ptr++ = *fhp++;
91 			*ptr++ = *fhp++;
92 			*ptr++ = *fhp++;
93 			*ptr++ = *fhp++;
94 			*ptr++ = *fhp++;
95 			*ptr = *fhp;
96 		}
97 		return (TRUE);
98 	}
99 
100 	return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
101 }
102 
103 bool_t
104 xdr_fastfhandle(XDR *xdrs, fhandle_t **fh)
105 {
106 	int32_t *ptr;
107 
108 	if (xdrs->x_op != XDR_DECODE)
109 		return (FALSE);
110 
111 	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)));
112 	if (ptr != NULL) {
113 		*fh = (fhandle_t *)ptr;
114 		return (TRUE);
115 	}
116 
117 	return (FALSE);
118 }
119 
120 /*
121  * Arguments to remote write and writecache
122  */
123 bool_t
124 xdr_writeargs(XDR *xdrs, struct nfswriteargs *wa)
125 {
126 	int32_t *ptr;
127 	int32_t *fhp;
128 
129 	switch (xdrs->x_op) {
130 	case XDR_DECODE:
131 		wa->wa_args = &wa->wa_args_buf;
132 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
133 		    3 * BYTES_PER_XDR_UNIT);
134 		if (ptr != NULL) {
135 			fhp = (int32_t *)&wa->wa_fhandle;
136 			*fhp++ = *ptr++;
137 			*fhp++ = *ptr++;
138 			*fhp++ = *ptr++;
139 			*fhp++ = *ptr++;
140 			*fhp++ = *ptr++;
141 			*fhp++ = *ptr++;
142 			*fhp++ = *ptr++;
143 			*fhp = *ptr++;
144 			wa->wa_begoff = IXDR_GET_U_INT32(ptr);
145 			wa->wa_offset = IXDR_GET_U_INT32(ptr);
146 			wa->wa_totcount = IXDR_GET_U_INT32(ptr);
147 			wa->wa_mblk = NULL;
148 			wa->wa_data = NULL;
149 			wa->wa_rlist = NULL;
150 			wa->wa_conn = NULL;
151 			if (xdrs->x_ops == &xdrmblk_ops) {
152 				return (xdrmblk_getmblk(xdrs, &wa->wa_mblk,
153 				    &wa->wa_count));
154 			} else {
155 				if (xdrs->x_ops == &xdrrdmablk_ops) {
156 					if (xdrrdma_getrdmablk(xdrs,
157 					    &wa->wa_rlist,
158 					    &wa->wa_count,
159 					    &wa->wa_conn,
160 					    NFS_MAXDATA) == TRUE)
161 					return (xdrrdma_read_from_client(
162 					    wa->wa_rlist,
163 					    &wa->wa_conn,
164 					    wa->wa_count));
165 
166 					wa->wa_rlist = NULL;
167 					wa->wa_conn = NULL;
168 				}
169 			}
170 
171 			/*
172 			 * It is just as efficient to xdr_bytes
173 			 * an array of unknown length as to inline copy it.
174 			 */
175 			return (xdr_bytes(xdrs, &wa->wa_data,
176 			    &wa->wa_count, NFS_MAXDATA));
177 		}
178 		if (xdr_fhandle(xdrs, &wa->wa_fhandle) &&
179 		    xdr_u_int(xdrs, &wa->wa_begoff) &&
180 		    xdr_u_int(xdrs, &wa->wa_offset) &&
181 		    xdr_u_int(xdrs, &wa->wa_totcount)) {
182 			/* deal with the variety of data transfer types */
183 
184 			wa->wa_mblk = NULL;
185 			wa->wa_data = NULL;
186 			wa->wa_rlist = NULL;
187 			wa->wa_conn = NULL;
188 
189 			if (xdrs->x_ops == &xdrmblk_ops) {
190 				if (xdrmblk_getmblk(xdrs, &wa->wa_mblk,
191 				    &wa->wa_count) == TRUE)
192 					return (TRUE);
193 			} else {
194 				if (xdrs->x_ops == &xdrrdmablk_ops) {
195 					if (xdrrdma_getrdmablk(xdrs,
196 					    &wa->wa_rlist,
197 					    &wa->wa_count,
198 					    &wa->wa_conn,
199 					    NFS_MAXDATA) == TRUE)
200 					return (xdrrdma_read_from_client(
201 					    wa->wa_rlist,
202 					    &wa->wa_conn,
203 					    wa->wa_count));
204 
205 					wa->wa_rlist = NULL;
206 					wa->wa_conn = NULL;
207 				}
208 			}
209 			return (xdr_bytes(xdrs, &wa->wa_data,
210 			    &wa->wa_count, NFS_MAXDATA));
211 		}
212 		return (FALSE);
213 	case XDR_ENCODE:
214 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
215 		    3 * BYTES_PER_XDR_UNIT);
216 		if (ptr != NULL) {
217 			fhp = (int32_t *)&wa->wa_fhandle;
218 			*ptr++ = *fhp++;
219 			*ptr++ = *fhp++;
220 			*ptr++ = *fhp++;
221 			*ptr++ = *fhp++;
222 			*ptr++ = *fhp++;
223 			*ptr++ = *fhp++;
224 			*ptr++ = *fhp++;
225 			*ptr++ = *fhp;
226 			IXDR_PUT_U_INT32(ptr, wa->wa_begoff);
227 			IXDR_PUT_U_INT32(ptr, wa->wa_offset);
228 			IXDR_PUT_U_INT32(ptr, wa->wa_totcount);
229 		} else {
230 			if (!(xdr_fhandle(xdrs, &wa->wa_fhandle) &&
231 			    xdr_u_int(xdrs, &wa->wa_begoff) &&
232 			    xdr_u_int(xdrs, &wa->wa_offset) &&
233 			    xdr_u_int(xdrs, &wa->wa_totcount)))
234 				return (FALSE);
235 		}
236 
237 		return (xdr_bytes(xdrs, &wa->wa_data, &wa->wa_count,
238 		    NFS_MAXDATA));
239 	case XDR_FREE:
240 		if (wa->wa_rlist) {
241 			(void) xdrrdma_free_clist(wa->wa_conn, wa->wa_rlist);
242 			wa->wa_rlist = NULL;
243 		}
244 
245 		if (wa->wa_data != NULL) {
246 			kmem_free(wa->wa_data, wa->wa_count);
247 			wa->wa_data = NULL;
248 		}
249 		return (TRUE);
250 	}
251 	return (FALSE);
252 }
253 
254 
255 /*
256  * File attributes
257  */
258 bool_t
259 xdr_fattr(XDR *xdrs, struct nfsfattr *na)
260 {
261 	int32_t *ptr;
262 
263 	if (xdrs->x_op == XDR_FREE)
264 		return (TRUE);
265 
266 	ptr = XDR_INLINE(xdrs, 17 * BYTES_PER_XDR_UNIT);
267 	if (ptr != NULL) {
268 		if (xdrs->x_op == XDR_DECODE) {
269 			na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype);
270 			na->na_mode = IXDR_GET_U_INT32(ptr);
271 			na->na_nlink = IXDR_GET_U_INT32(ptr);
272 			na->na_uid = IXDR_GET_U_INT32(ptr);
273 			na->na_gid = IXDR_GET_U_INT32(ptr);
274 			na->na_size = IXDR_GET_U_INT32(ptr);
275 			na->na_blocksize = IXDR_GET_U_INT32(ptr);
276 			na->na_rdev = IXDR_GET_U_INT32(ptr);
277 			na->na_blocks = IXDR_GET_U_INT32(ptr);
278 			na->na_fsid = IXDR_GET_U_INT32(ptr);
279 			na->na_nodeid = IXDR_GET_U_INT32(ptr);
280 			na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr);
281 			na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr);
282 			na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
283 			na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
284 			na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr);
285 			na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr);
286 		} else {
287 			IXDR_PUT_ENUM(ptr, na->na_type);
288 			IXDR_PUT_U_INT32(ptr, na->na_mode);
289 			IXDR_PUT_U_INT32(ptr, na->na_nlink);
290 			IXDR_PUT_U_INT32(ptr, na->na_uid);
291 			IXDR_PUT_U_INT32(ptr, na->na_gid);
292 			IXDR_PUT_U_INT32(ptr, na->na_size);
293 			IXDR_PUT_U_INT32(ptr, na->na_blocksize);
294 			IXDR_PUT_U_INT32(ptr, na->na_rdev);
295 			IXDR_PUT_U_INT32(ptr, na->na_blocks);
296 			IXDR_PUT_U_INT32(ptr, na->na_fsid);
297 			IXDR_PUT_U_INT32(ptr, na->na_nodeid);
298 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec);
299 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec);
300 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec);
301 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec);
302 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec);
303 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec);
304 		}
305 		return (TRUE);
306 	}
307 
308 	if (xdr_enum(xdrs, (enum_t *)&na->na_type) &&
309 	    xdr_u_int(xdrs, &na->na_mode) &&
310 	    xdr_u_int(xdrs, &na->na_nlink) &&
311 	    xdr_u_int(xdrs, &na->na_uid) &&
312 	    xdr_u_int(xdrs, &na->na_gid) &&
313 	    xdr_u_int(xdrs, &na->na_size) &&
314 	    xdr_u_int(xdrs, &na->na_blocksize) &&
315 	    xdr_u_int(xdrs, &na->na_rdev) &&
316 	    xdr_u_int(xdrs, &na->na_blocks) &&
317 	    xdr_u_int(xdrs, &na->na_fsid) &&
318 	    xdr_u_int(xdrs, &na->na_nodeid) &&
319 	    xdr_nfs2_timeval(xdrs, &na->na_atime) &&
320 	    xdr_nfs2_timeval(xdrs, &na->na_mtime) &&
321 	    xdr_nfs2_timeval(xdrs, &na->na_ctime)) {
322 		return (TRUE);
323 	}
324 	return (FALSE);
325 }
326 
327 #ifdef _LITTLE_ENDIAN
328 bool_t
329 xdr_fastfattr(XDR *xdrs, struct nfsfattr *na)
330 {
331 	if (xdrs->x_op == XDR_FREE)
332 		return (TRUE);
333 	if (xdrs->x_op == XDR_DECODE)
334 		return (FALSE);
335 
336 	na->na_type = htonl(na->na_type);
337 	na->na_mode = htonl(na->na_mode);
338 	na->na_nlink = htonl(na->na_nlink);
339 	na->na_uid = htonl(na->na_uid);
340 	na->na_gid = htonl(na->na_gid);
341 	na->na_size = htonl(na->na_size);
342 	na->na_blocksize = htonl(na->na_blocksize);
343 	na->na_rdev = htonl(na->na_rdev);
344 	na->na_blocks = htonl(na->na_blocks);
345 	na->na_fsid = htonl(na->na_fsid);
346 	na->na_nodeid = htonl(na->na_nodeid);
347 	na->na_atime.tv_sec = htonl(na->na_atime.tv_sec);
348 	na->na_atime.tv_usec = htonl(na->na_atime.tv_usec);
349 	na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec);
350 	na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec);
351 	na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec);
352 	na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec);
353 	return (TRUE);
354 }
355 #endif
356 
357 bool_t
358 xdr_readlink(XDR *xdrs, fhandle_t *fh)
359 {
360 	rdma_chunkinfo_t rci;
361 	struct xdr_ops *xops = xdrrdma_xops();
362 
363 	if (xdr_fhandle(xdrs, fh)) {
364 		if ((xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) &&
365 		    xdrs->x_op == XDR_ENCODE) {
366 			rci.rci_type = RCI_REPLY_CHUNK;
367 			rci.rci_len = MAXPATHLEN;
368 			XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci);
369 		}
370 
371 		return (TRUE);
372 	}
373 	return (FALSE);
374 }
375 
376 /*
377  * Arguments to remote read
378  */
379 bool_t
380 xdr_readargs(XDR *xdrs, struct nfsreadargs *ra)
381 {
382 	int32_t *ptr;
383 	int32_t *fhp;
384 	rdma_chunkinfo_t rci;
385 	rdma_wlist_conn_info_t rwci;
386 	struct xdr_ops *xops = xdrrdma_xops();
387 
388 	if (xdrs->x_op == XDR_FREE)
389 		return (TRUE);
390 
391 	ptr = XDR_INLINE(xdrs,
392 	    RNDUP(sizeof (fhandle_t)) + 3 * BYTES_PER_XDR_UNIT);
393 	if (ptr != NULL) {
394 		if (xdrs->x_op == XDR_DECODE) {
395 			fhp = (int32_t *)&ra->ra_fhandle;
396 			*fhp++ = *ptr++;
397 			*fhp++ = *ptr++;
398 			*fhp++ = *ptr++;
399 			*fhp++ = *ptr++;
400 			*fhp++ = *ptr++;
401 			*fhp++ = *ptr++;
402 			*fhp++ = *ptr++;
403 			*fhp = *ptr++;
404 			ra->ra_offset = IXDR_GET_INT32(ptr);
405 			ra->ra_count = IXDR_GET_INT32(ptr);
406 			ra->ra_totcount = IXDR_GET_INT32(ptr);
407 		} else {
408 			fhp = (int32_t *)&ra->ra_fhandle;
409 			*ptr++ = *fhp++;
410 			*ptr++ = *fhp++;
411 			*ptr++ = *fhp++;
412 			*ptr++ = *fhp++;
413 			*ptr++ = *fhp++;
414 			*ptr++ = *fhp++;
415 			*ptr++ = *fhp++;
416 			*ptr++ = *fhp;
417 			IXDR_PUT_INT32(ptr, ra->ra_offset);
418 			IXDR_PUT_INT32(ptr, ra->ra_count);
419 			IXDR_PUT_INT32(ptr, ra->ra_totcount);
420 		}
421 	} else {
422 		if (!xdr_fhandle(xdrs, &ra->ra_fhandle) ||
423 		    !xdr_u_int(xdrs, &ra->ra_offset) ||
424 		    !xdr_u_int(xdrs, &ra->ra_count) ||
425 		    !xdr_u_int(xdrs, &ra->ra_totcount)) {
426 			return (FALSE);
427 		}
428 	}
429 
430 	if (ra->ra_count > NFS_MAXDATA)
431 		return (FALSE);
432 
433 	ra->ra_wlist = NULL;
434 	ra->ra_conn = NULL;
435 
436 	/* If this is xdrrdma_sizeof, record the expect response size */
437 	if (xdrs->x_ops == xops && xdrs->x_op == XDR_ENCODE) {
438 		rci.rci_type = RCI_WRITE_ADDR_CHUNK;
439 		rci.rci_len = ra->ra_count;
440 		(void) XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci);
441 	}
442 	/* Nothing special to do, return */
443 	if (xdrs->x_ops != &xdrrdma_ops || xdrs->x_op == XDR_FREE)
444 		return (TRUE);
445 
446 	if (xdrs->x_op == XDR_ENCODE) {
447 		/* Place the target data location into the RDMA header */
448 		rci.rci_type = RCI_WRITE_ADDR_CHUNK;
449 		rci.rci_a.rci_addr = ra->ra_data;
450 		rci.rci_len = ra->ra_count;
451 		rci.rci_clpp = &ra->ra_wlist;
452 
453 		return (XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci));
454 	}
455 
456 	/* XDR_DECODE case */
457 	(void) XDR_CONTROL(xdrs, XDR_RDMA_GET_WCINFO, &rwci);
458 	ra->ra_wlist = rwci.rwci_wlist;
459 	ra->ra_conn = rwci.rwci_conn;
460 
461 	return (TRUE);
462 }
463 
464 
465 /*
466  * Status OK portion of remote read reply
467  */
468 bool_t
469 xdr_rrok(XDR *xdrs, struct nfsrrok *rrok)
470 {
471 	bool_t ret;
472 	mblk_t *mp;
473 	struct xdr_ops *xops = xdrrdma_xops();
474 
475 	if (xdr_fattr(xdrs, &rrok->rrok_attr) == FALSE)
476 		return (FALSE);
477 
478 	/* deal with RDMA separately */
479 	if (xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) {
480 		if (xdrs->x_op == XDR_ENCODE &&
481 		    rrok->rrok_mp != NULL) {
482 			ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data,
483 			    &rrok->rrok_count, NFS_MAXDATA);
484 			return (ret);
485 		}
486 
487 		if (xdrs->x_op == XDR_ENCODE) {
488 			if (xdr_u_int(xdrs, &rrok->rrok_count) == FALSE) {
489 				return (FALSE);
490 			}
491 			/*
492 			 * If read data sent by wlist (RDMA_WRITE), don't do
493 			 * xdr_bytes() below.   RDMA_WRITE transfers the data.
494 			 */
495 			if (rrok->rrok_wlist) {
496 				if (rrok->rrok_count != 0) {
497 					return (xdrrdma_send_read_data(
498 					    xdrs, rrok->rrok_count,
499 					    rrok->rrok_wlist));
500 				}
501 				return (TRUE);
502 			}
503 			if (rrok->rrok_count == 0) {
504 				return (TRUE);
505 			}
506 		} else {
507 			struct clist *cl;
508 			uint32_t count;
509 
510 			XDR_CONTROL(xdrs, XDR_RDMA_GET_WLIST, &cl);
511 
512 			if (cl) {
513 				if (!xdr_u_int(xdrs, &count))
514 					return (FALSE);
515 				if (count == 0) {
516 					rrok->rrok_wlist_len = 0;
517 					rrok->rrok_count = 0;
518 				} else {
519 					rrok->rrok_wlist_len = clist_len(cl);
520 					if (rrok->rrok_wlist_len !=
521 					    roundup(count,
522 					    BYTES_PER_XDR_UNIT)) {
523 						rrok->rrok_wlist_len = 0;
524 						rrok->rrok_count = 0;
525 						return (FALSE);
526 					}
527 					rrok->rrok_count = count;
528 				}
529 				return (TRUE);
530 			}
531 		}
532 		ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data,
533 		    &rrok->rrok_count, NFS_MAXDATA);
534 
535 		return (ret);
536 	}
537 
538 	if (xdrs->x_op == XDR_ENCODE) {
539 		int i, rndup;
540 
541 		mp = rrok->rrok_mp;
542 		if (mp != NULL && xdrs->x_ops == &xdrmblk_ops) {
543 			mp->b_wptr += rrok->rrok_count;
544 			rndup = BYTES_PER_XDR_UNIT -
545 			    (rrok->rrok_count % BYTES_PER_XDR_UNIT);
546 			if (rndup != BYTES_PER_XDR_UNIT)
547 				for (i = 0; i < rndup; i++)
548 					*mp->b_wptr++ = '\0';
549 			if (xdrmblk_putmblk(xdrs, mp,
550 			    rrok->rrok_count) == TRUE) {
551 				rrok->rrok_mp = NULL;
552 				return (TRUE);
553 			}
554 		}
555 
556 		/*
557 		 * Fall thru for the xdr_bytes()
558 		 *
559 		 * Note: the mblk mp will be freed in rfs_rdfree
560 		 */
561 	}
562 
563 	ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data,
564 	    &rrok->rrok_count, NFS_MAXDATA);
565 
566 	return (ret);
567 }
568 
569 static struct xdr_discrim rdres_discrim[2] = {
570 	{ NFS_OK, xdr_rrok },
571 	{ __dontcare__, NULL_xdrproc_t }
572 };
573 
574 /*
575  * Reply from remote read
576  */
577 bool_t
578 xdr_rdresult(XDR *xdrs, struct nfsrdresult *rr)
579 {
580 	return (xdr_union(xdrs, (enum_t *)&(rr->rr_status),
581 	    (caddr_t)&(rr->rr_ok), rdres_discrim, xdr_void));
582 }
583 
584 /*
585  * File attributes which can be set
586  */
587 bool_t
588 xdr_sattr(XDR *xdrs, struct nfssattr *sa)
589 {
590 	if (xdr_u_int(xdrs, &sa->sa_mode) &&
591 	    xdr_u_int(xdrs, &sa->sa_uid) &&
592 	    xdr_u_int(xdrs, &sa->sa_gid) &&
593 	    xdr_u_int(xdrs, &sa->sa_size) &&
594 	    xdr_nfs2_timeval(xdrs, &sa->sa_atime) &&
595 	    xdr_nfs2_timeval(xdrs, &sa->sa_mtime)) {
596 		return (TRUE);
597 	}
598 	return (FALSE);
599 }
600 
601 static struct xdr_discrim attrstat_discrim[2] = {
602 	{ (int)NFS_OK, xdr_fattr },
603 	{ __dontcare__, NULL_xdrproc_t }
604 };
605 
606 /*
607  * Reply status with file attributes
608  */
609 bool_t
610 xdr_attrstat(XDR *xdrs, struct nfsattrstat *ns)
611 {
612 	return (xdr_union(xdrs, (enum_t *)&(ns->ns_status),
613 	    (caddr_t)&(ns->ns_attr), attrstat_discrim, xdr_void));
614 }
615 
616 /*
617  * Fast reply status with file attributes
618  */
619 bool_t
620 xdr_fastattrstat(XDR *xdrs, struct nfsattrstat *ns)
621 {
622 #if defined(_LITTLE_ENDIAN)
623 	/*
624 	 * we deal with the discriminator;  it's an enum
625 	 */
626 	if (!xdr_fastenum(xdrs, (enum_t *)&ns->ns_status))
627 		return (FALSE);
628 
629 	if (ns->ns_status == NFS_OK)
630 		return (xdr_fastfattr(xdrs, &ns->ns_attr));
631 #elif defined(_BIG_ENDIAN)
632 	if (ns->ns_status == NFS_OK)
633 		return (TRUE);
634 #endif
635 	return (xdr_fastshorten(xdrs, sizeof (*ns)));
636 }
637 
638 /*
639  * NFS_OK part of read sym link reply union
640  */
641 bool_t
642 xdr_srok(XDR *xdrs, struct nfssrok *srok)
643 {
644 	/*
645 	 * It is just as efficient to xdr_bytes
646 	 * an array of unknown length as to inline copy it.
647 	 */
648 	return (xdr_bytes(xdrs, &srok->srok_data, &srok->srok_count,
649 	    NFS_MAXPATHLEN));
650 }
651 
652 static struct xdr_discrim rdlnres_discrim[2] = {
653 	{ (int)NFS_OK, xdr_srok },
654 	{ __dontcare__, NULL_xdrproc_t }
655 };
656 
657 /*
658  * Result of reading symbolic link
659  */
660 bool_t
661 xdr_rdlnres(XDR *xdrs, struct nfsrdlnres *rl)
662 {
663 	return (xdr_union(xdrs, (enum_t *)&(rl->rl_status),
664 	    (caddr_t)&(rl->rl_srok), rdlnres_discrim, xdr_void));
665 }
666 
667 /*
668  * Arguments to readdir
669  */
670 bool_t
671 xdr_rddirargs(XDR *xdrs, struct nfsrddirargs *rda)
672 {
673 	int32_t *ptr;
674 	int32_t *fhp;
675 	rdma_chunkinfo_t rci;
676 	struct xdr_ops *xops = xdrrdma_xops();
677 
678 	if (xdrs->x_op == XDR_FREE)
679 		return (TRUE);
680 
681 	ptr = XDR_INLINE(xdrs,
682 	    RNDUP(sizeof (fhandle_t)) + 2 * BYTES_PER_XDR_UNIT);
683 
684 	if ((xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) &&
685 	    xdrs->x_op == XDR_ENCODE) {
686 		rci.rci_type = RCI_REPLY_CHUNK;
687 		rci.rci_len = rda->rda_count;
688 		XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci);
689 	}
690 
691 	if (ptr != NULL) {
692 		if (xdrs->x_op == XDR_DECODE) {
693 			fhp = (int32_t *)&rda->rda_fh;
694 			*fhp++ = *ptr++;
695 			*fhp++ = *ptr++;
696 			*fhp++ = *ptr++;
697 			*fhp++ = *ptr++;
698 			*fhp++ = *ptr++;
699 			*fhp++ = *ptr++;
700 			*fhp++ = *ptr++;
701 			*fhp = *ptr++;
702 			rda->rda_offset = IXDR_GET_U_INT32(ptr);
703 			rda->rda_count = IXDR_GET_U_INT32(ptr);
704 		} else {
705 			fhp = (int32_t *)&rda->rda_fh;
706 			*ptr++ = *fhp++;
707 			*ptr++ = *fhp++;
708 			*ptr++ = *fhp++;
709 			*ptr++ = *fhp++;
710 			*ptr++ = *fhp++;
711 			*ptr++ = *fhp++;
712 			*ptr++ = *fhp++;
713 			*ptr++ = *fhp;
714 			IXDR_PUT_U_INT32(ptr, rda->rda_offset);
715 			IXDR_PUT_U_INT32(ptr, rda->rda_count);
716 		}
717 		return (TRUE);
718 	}
719 
720 	if (xdr_fhandle(xdrs, &rda->rda_fh) &&
721 	    xdr_u_int(xdrs, &rda->rda_offset) &&
722 	    xdr_u_int(xdrs, &rda->rda_count)) {
723 		return (TRUE);
724 	}
725 	return (FALSE);
726 }
727 
728 
729 /*
730  * Directory read reply:
731  * union (enum status) {
732  *	NFS_OK: entlist;
733  *		boolean eof;
734  *	default:
735  * }
736  *
737  * Directory entries
738  *	struct  direct {
739  *		off_t   d_off;			* offset of next entry *
740  *		u_int	d_fileno;		* inode number of entry *
741  *		u_short d_reclen;		* length of this record *
742  *		u_short d_namlen;		* length of string in d_name *
743  *		char    d_name[MAXNAMLEN + 1];	* name no longer than this *
744  *	};
745  * are on the wire as:
746  * union entlist (boolean valid) {
747  * 	TRUE:	struct otw_dirent;
748  *		u_int nxtoffset;
749  *		union entlist;
750  *	FALSE:
751  * }
752  * where otw_dirent is:
753  * 	struct dirent {
754  *		u_int	de_fid;
755  *		string	de_name<NFS_MAXNAMELEN>;
756  *	}
757  */
758 
759 #ifdef nextdp
760 #undef	nextdp
761 #endif
762 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
763 #ifdef roundup
764 #undef	roundup
765 #endif
766 #define	roundup(x, y)	((((x) + ((y) - 1)) / (y)) * (y))
767 
768 /*
769  * ENCODE ONLY
770  */
771 bool_t
772 xdr_putrddirres(XDR *xdrs, struct nfsrddirres *rd)
773 {
774 	struct dirent64 *dp;
775 	char *name;
776 	int size;
777 	uint_t namlen;
778 	bool_t true = TRUE;
779 	bool_t false = FALSE;
780 	int entrysz;
781 	int tofit;
782 	int bufsize;
783 	uint32_t ino, off;
784 
785 	if (xdrs->x_op != XDR_ENCODE)
786 		return (FALSE);
787 	if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status))
788 		return (FALSE);
789 	if (rd->rd_status != NFS_OK)
790 		return (TRUE);
791 
792 	bufsize = 1 * BYTES_PER_XDR_UNIT;
793 	for (size = rd->rd_size, dp = rd->rd_entries;
794 	    size > 0;
795 	    size -= dp->d_reclen, dp = nextdp(dp)) {
796 		if (dp->d_reclen == 0 /* || DIRSIZ(dp) > dp->d_reclen */)
797 			return (FALSE);
798 		if (dp->d_ino == 0)
799 			continue;
800 		ino = (uint32_t)dp->d_ino; /* for LP64 we clip the bits */
801 		if (dp->d_ino != (ino64_t)ino)	/* and they better be zeros */
802 			return (FALSE);
803 		off = (uint32_t)dp->d_off;
804 		name = dp->d_name;
805 		namlen = (uint_t)strlen(name);
806 		entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
807 		    roundup(namlen, BYTES_PER_XDR_UNIT);
808 		tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
809 		if (bufsize + tofit > rd->rd_bufsize) {
810 			rd->rd_eof = FALSE;
811 			break;
812 		}
813 		if (!xdr_bool(xdrs, &true) ||
814 		    !xdr_u_int(xdrs, &ino) ||
815 		    !xdr_bytes(xdrs, &name, &namlen, NFS_MAXNAMLEN) ||
816 		    !xdr_u_int(xdrs, &off)) {
817 			return (FALSE);
818 		}
819 		bufsize += entrysz;
820 	}
821 	if (!xdr_bool(xdrs, &false))
822 		return (FALSE);
823 	if (!xdr_bool(xdrs, &rd->rd_eof))
824 		return (FALSE);
825 	return (TRUE);
826 }
827 
828 /*
829  * DECODE ONLY
830  */
831 bool_t
832 xdr_getrddirres(XDR *xdrs, struct nfsrddirres *rd)
833 {
834 	struct dirent64 *dp;
835 	uint_t namlen;
836 	int size;
837 	bool_t valid;
838 	uint32_t offset;
839 	uint_t fileid, this_reclen;
840 
841 	if (xdrs->x_op != XDR_DECODE)
842 		return (FALSE);
843 
844 	if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status))
845 		return (FALSE);
846 	if (rd->rd_status != NFS_OK)
847 		return (TRUE);
848 
849 	size = rd->rd_size;
850 	dp = rd->rd_entries;
851 	offset = rd->rd_offset;
852 	for (;;) {
853 		if (!xdr_bool(xdrs, &valid))
854 			return (FALSE);
855 		if (!valid)
856 			break;
857 		if (!xdr_u_int(xdrs, &fileid) ||
858 		    !xdr_u_int(xdrs, &namlen))
859 			return (FALSE);
860 		this_reclen = DIRENT64_RECLEN(namlen);
861 		if (this_reclen > size) {
862 			rd->rd_eof = FALSE;
863 			goto bufovflw;
864 		}
865 		if (!xdr_opaque(xdrs, dp->d_name, namlen)||
866 		    !xdr_u_int(xdrs, &offset)) {
867 			return (FALSE);
868 		}
869 		bzero(&dp->d_name[namlen],
870 		    DIRENT64_NAMELEN(this_reclen) - namlen);
871 		dp->d_ino = (ino64_t)fileid;
872 		dp->d_reclen = this_reclen;
873 		dp->d_off = (off64_t)offset;
874 		size -= dp->d_reclen;
875 		dp = nextdp(dp);
876 	}
877 	if (!xdr_bool(xdrs, &rd->rd_eof))
878 		return (FALSE);
879 bufovflw:
880 	rd->rd_size = (uint32_t)((char *)dp - (char *)(rd->rd_entries));
881 	rd->rd_offset = offset;
882 	return (TRUE);
883 }
884 
885 /*
886  * Arguments for directory operations
887  */
888 bool_t
889 xdr_diropargs(XDR *xdrs, struct nfsdiropargs *da)
890 {
891 	int32_t *ptr;
892 	int32_t *fhp;
893 	uint32_t size;
894 	uint32_t nodesize;
895 	int i;
896 	int rndup;
897 	char *cptr;
898 
899 	if (xdrs->x_op == XDR_DECODE) {
900 		da->da_fhandle = &da->da_fhandle_buf;
901 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
902 		    1 * BYTES_PER_XDR_UNIT);
903 		if (ptr != NULL) {
904 			fhp = (int32_t *)da->da_fhandle;
905 			*fhp++ = *ptr++;
906 			*fhp++ = *ptr++;
907 			*fhp++ = *ptr++;
908 			*fhp++ = *ptr++;
909 			*fhp++ = *ptr++;
910 			*fhp++ = *ptr++;
911 			*fhp++ = *ptr++;
912 			*fhp = *ptr++;
913 			size = IXDR_GET_U_INT32(ptr);
914 			if (size > NFS_MAXNAMLEN)
915 				return (FALSE);
916 			nodesize = size + 1;
917 			if (nodesize == 0)
918 				return (TRUE);
919 			if (da->da_name == NULL) {
920 				da->da_name = kmem_alloc(nodesize, KM_NOSLEEP);
921 				if (da->da_name == NULL)
922 					return (FALSE);
923 				da->da_flags |= DA_FREENAME;
924 			}
925 			ptr = XDR_INLINE(xdrs, RNDUP(size));
926 			if (ptr == NULL) {
927 				if (!xdr_opaque(xdrs, da->da_name, size)) {
928 					if (da->da_flags & DA_FREENAME) {
929 						kmem_free(da->da_name,
930 						    nodesize);
931 						da->da_name = NULL;
932 					}
933 					return (FALSE);
934 				}
935 				da->da_name[size] = '\0';
936 				if (strlen(da->da_name) != size) {
937 					if (da->da_flags & DA_FREENAME) {
938 						kmem_free(da->da_name,
939 						    nodesize);
940 						da->da_name = NULL;
941 					}
942 					return (FALSE);
943 				}
944 				return (TRUE);
945 			}
946 			bcopy(ptr, da->da_name, size);
947 			da->da_name[size] = '\0';
948 			if (strlen(da->da_name) != size) {
949 				if (da->da_flags & DA_FREENAME) {
950 					kmem_free(da->da_name, nodesize);
951 					da->da_name = NULL;
952 				}
953 				return (FALSE);
954 			}
955 			return (TRUE);
956 		}
957 		if (da->da_name == NULL)
958 			da->da_flags |= DA_FREENAME;
959 	}
960 
961 	if (xdrs->x_op == XDR_ENCODE) {
962 		size = (uint32_t)strlen(da->da_name);
963 		if (size > NFS_MAXNAMLEN)
964 			return (FALSE);
965 		ptr = XDR_INLINE(xdrs, (int)(RNDUP(sizeof (fhandle_t)) +
966 		    1 * BYTES_PER_XDR_UNIT + RNDUP(size)));
967 		if (ptr != NULL) {
968 			fhp = (int32_t *)da->da_fhandle;
969 			*ptr++ = *fhp++;
970 			*ptr++ = *fhp++;
971 			*ptr++ = *fhp++;
972 			*ptr++ = *fhp++;
973 			*ptr++ = *fhp++;
974 			*ptr++ = *fhp++;
975 			*ptr++ = *fhp++;
976 			*ptr++ = *fhp;
977 			IXDR_PUT_U_INT32(ptr, (uint32_t)size);
978 			bcopy(da->da_name, ptr, size);
979 			rndup = BYTES_PER_XDR_UNIT -
980 			    (size % BYTES_PER_XDR_UNIT);
981 			if (rndup != BYTES_PER_XDR_UNIT) {
982 				cptr = (char *)ptr + size;
983 				for (i = 0; i < rndup; i++)
984 					*cptr++ = '\0';
985 			}
986 			return (TRUE);
987 		}
988 	}
989 
990 	if (xdrs->x_op == XDR_FREE) {
991 		if (da->da_name == NULL)
992 			return (TRUE);
993 		size = (uint32_t)strlen(da->da_name);
994 		if (size > NFS_MAXNAMLEN)
995 			return (FALSE);
996 		if (da->da_flags & DA_FREENAME)
997 			kmem_free(da->da_name, size + 1);
998 		da->da_name = NULL;
999 		return (TRUE);
1000 	}
1001 
1002 	if (xdr_fhandle(xdrs, da->da_fhandle) &&
1003 	    xdr_string(xdrs, &da->da_name, NFS_MAXNAMLEN)) {
1004 		return (TRUE);
1005 	}
1006 	return (FALSE);
1007 }
1008 
1009 /*
1010  * NFS_OK part of directory operation result
1011  */
1012 bool_t
1013 xdr_drok(XDR *xdrs, struct nfsdrok *drok)
1014 {
1015 	int32_t *ptr;
1016 	int32_t *fhp;
1017 	struct nfsfattr *na;
1018 
1019 	if (xdrs->x_op == XDR_FREE)
1020 		return (TRUE);
1021 
1022 	ptr = XDR_INLINE(xdrs,
1023 	    RNDUP(sizeof (fhandle_t)) + 17 * BYTES_PER_XDR_UNIT);
1024 	if (ptr != NULL) {
1025 		if (xdrs->x_op == XDR_DECODE) {
1026 			fhp = (int32_t *)&drok->drok_fhandle;
1027 			*fhp++ = *ptr++;
1028 			*fhp++ = *ptr++;
1029 			*fhp++ = *ptr++;
1030 			*fhp++ = *ptr++;
1031 			*fhp++ = *ptr++;
1032 			*fhp++ = *ptr++;
1033 			*fhp++ = *ptr++;
1034 			*fhp = *ptr++;
1035 			na = &drok->drok_attr;
1036 			na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype);
1037 			na->na_mode = IXDR_GET_U_INT32(ptr);
1038 			na->na_nlink = IXDR_GET_U_INT32(ptr);
1039 			na->na_uid = IXDR_GET_U_INT32(ptr);
1040 			na->na_gid = IXDR_GET_U_INT32(ptr);
1041 			na->na_size = IXDR_GET_U_INT32(ptr);
1042 			na->na_blocksize = IXDR_GET_U_INT32(ptr);
1043 			na->na_rdev = IXDR_GET_U_INT32(ptr);
1044 			na->na_blocks = IXDR_GET_U_INT32(ptr);
1045 			na->na_fsid = IXDR_GET_U_INT32(ptr);
1046 			na->na_nodeid = IXDR_GET_U_INT32(ptr);
1047 			na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr);
1048 			na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr);
1049 			na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
1050 			na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
1051 			na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr);
1052 			na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr);
1053 		} else {
1054 			fhp = (int32_t *)&drok->drok_fhandle;
1055 			*ptr++ = *fhp++;
1056 			*ptr++ = *fhp++;
1057 			*ptr++ = *fhp++;
1058 			*ptr++ = *fhp++;
1059 			*ptr++ = *fhp++;
1060 			*ptr++ = *fhp++;
1061 			*ptr++ = *fhp++;
1062 			*ptr++ = *fhp;
1063 			na = &drok->drok_attr;
1064 			IXDR_PUT_ENUM(ptr, na->na_type);
1065 			IXDR_PUT_U_INT32(ptr, na->na_mode);
1066 			IXDR_PUT_U_INT32(ptr, na->na_nlink);
1067 			IXDR_PUT_U_INT32(ptr, na->na_uid);
1068 			IXDR_PUT_U_INT32(ptr, na->na_gid);
1069 			IXDR_PUT_U_INT32(ptr, na->na_size);
1070 			IXDR_PUT_U_INT32(ptr, na->na_blocksize);
1071 			IXDR_PUT_U_INT32(ptr, na->na_rdev);
1072 			IXDR_PUT_U_INT32(ptr, na->na_blocks);
1073 			IXDR_PUT_U_INT32(ptr, na->na_fsid);
1074 			IXDR_PUT_U_INT32(ptr, na->na_nodeid);
1075 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec);
1076 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec);
1077 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec);
1078 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec);
1079 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec);
1080 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec);
1081 		}
1082 		return (TRUE);
1083 	}
1084 
1085 	if (xdr_fhandle(xdrs, &drok->drok_fhandle) &&
1086 	    xdr_fattr(xdrs, &drok->drok_attr)) {
1087 		return (TRUE);
1088 	}
1089 	return (FALSE);
1090 }
1091 
1092 #ifdef _LITTLE_ENDIAN
1093 bool_t
1094 xdr_fastdrok(XDR *xdrs, struct nfsdrok *drok)
1095 {
1096 	struct nfsfattr *na;
1097 
1098 	if (xdrs->x_op == XDR_FREE)
1099 		return (TRUE);
1100 	if (xdrs->x_op == XDR_DECODE)
1101 		return (FALSE);
1102 
1103 	na = &drok->drok_attr;
1104 	na->na_type = (enum nfsftype)htonl(na->na_type);
1105 	na->na_mode = (uint32_t)htonl(na->na_mode);
1106 	na->na_nlink = (uint32_t)htonl(na->na_nlink);
1107 	na->na_uid = (uint32_t)htonl(na->na_uid);
1108 	na->na_gid = (uint32_t)htonl(na->na_gid);
1109 	na->na_size = (uint32_t)htonl(na->na_size);
1110 	na->na_blocksize = (uint32_t)htonl(na->na_blocksize);
1111 	na->na_rdev = (uint32_t)htonl(na->na_rdev);
1112 	na->na_blocks = (uint32_t)htonl(na->na_blocks);
1113 	na->na_fsid = (uint32_t)htonl(na->na_fsid);
1114 	na->na_nodeid = (uint32_t)htonl(na->na_nodeid);
1115 	na->na_atime.tv_sec = htonl(na->na_atime.tv_sec);
1116 	na->na_atime.tv_usec = htonl(na->na_atime.tv_usec);
1117 	na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec);
1118 	na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec);
1119 	na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec);
1120 	na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec);
1121 	return (TRUE);
1122 }
1123 #endif
1124 
1125 static struct xdr_discrim diropres_discrim[2] = {
1126 	{ NFS_OK, xdr_drok },
1127 	{ __dontcare__, NULL_xdrproc_t }
1128 };
1129 
1130 /*
1131  * Results from directory operation
1132  */
1133 bool_t
1134 xdr_diropres(XDR *xdrs, struct nfsdiropres *dr)
1135 {
1136 	return (xdr_union(xdrs, (enum_t *)&(dr->dr_status),
1137 	    (caddr_t)&(dr->dr_drok), diropres_discrim, xdr_void));
1138 }
1139 
1140 /*
1141  * Results from directory operation
1142  */
1143 bool_t
1144 xdr_fastdiropres(XDR *xdrs, struct nfsdiropres *dr)
1145 {
1146 #if defined(_LITTLE_ENDIAN)
1147 	/*
1148 	 * we deal with the discriminator;  it's an enum
1149 	 */
1150 	if (!xdr_fastenum(xdrs, (enum_t *)&dr->dr_status))
1151 		return (FALSE);
1152 
1153 	if (dr->dr_status == NFS_OK)
1154 		return (xdr_fastdrok(xdrs, &dr->dr_drok));
1155 #elif defined(_BIG_ENDIAN)
1156 	if (dr->dr_status == NFS_OK)
1157 		return (TRUE);
1158 #endif
1159 	return (xdr_fastshorten(xdrs, sizeof (*dr)));
1160 }
1161 
1162 /*
1163  * Time Structure, unsigned
1164  */
1165 bool_t
1166 xdr_nfs2_timeval(XDR *xdrs, struct nfs2_timeval *tv)
1167 {
1168 	if (xdr_u_int(xdrs, &tv->tv_sec) &&
1169 	    xdr_u_int(xdrs, &tv->tv_usec))
1170 		return (TRUE);
1171 	return (FALSE);
1172 }
1173 
1174 /*
1175  * arguments to setattr
1176  */
1177 bool_t
1178 xdr_saargs(XDR *xdrs, struct nfssaargs *argp)
1179 {
1180 	int32_t *ptr;
1181 	int32_t *arg;
1182 	struct nfssattr *sa;
1183 
1184 	if (xdrs->x_op == XDR_FREE)
1185 		return (TRUE);
1186 
1187 	ptr = XDR_INLINE(xdrs,
1188 	    RNDUP(sizeof (fhandle_t)) + 8 * BYTES_PER_XDR_UNIT);
1189 	if (ptr != NULL) {
1190 		if (xdrs->x_op == XDR_DECODE) {
1191 			arg = (int32_t *)&argp->saa_fh;
1192 			*arg++ = *ptr++;
1193 			*arg++ = *ptr++;
1194 			*arg++ = *ptr++;
1195 			*arg++ = *ptr++;
1196 			*arg++ = *ptr++;
1197 			*arg++ = *ptr++;
1198 			*arg++ = *ptr++;
1199 			*arg = *ptr++;
1200 			sa = &argp->saa_sa;
1201 			sa->sa_mode = IXDR_GET_U_INT32(ptr);
1202 			sa->sa_uid = IXDR_GET_U_INT32(ptr);
1203 			sa->sa_gid = IXDR_GET_U_INT32(ptr);
1204 			sa->sa_size = IXDR_GET_U_INT32(ptr);
1205 			sa->sa_atime.tv_sec = IXDR_GET_U_INT32(ptr);
1206 			sa->sa_atime.tv_usec = IXDR_GET_U_INT32(ptr);
1207 			sa->sa_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
1208 			sa->sa_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
1209 		} else {
1210 			arg = (int32_t *)&argp->saa_fh;
1211 			*ptr++ = *arg++;
1212 			*ptr++ = *arg++;
1213 			*ptr++ = *arg++;
1214 			*ptr++ = *arg++;
1215 			*ptr++ = *arg++;
1216 			*ptr++ = *arg++;
1217 			*ptr++ = *arg++;
1218 			*ptr++ = *arg;
1219 			sa = &argp->saa_sa;
1220 			IXDR_PUT_U_INT32(ptr, sa->sa_mode);
1221 			IXDR_PUT_U_INT32(ptr, sa->sa_uid);
1222 			IXDR_PUT_U_INT32(ptr, sa->sa_gid);
1223 			IXDR_PUT_U_INT32(ptr, sa->sa_size);
1224 			IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_sec);
1225 			IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_usec);
1226 			IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_sec);
1227 			IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_usec);
1228 		}
1229 		return (TRUE);
1230 	}
1231 
1232 	if (xdr_fhandle(xdrs, &argp->saa_fh) &&
1233 	    xdr_sattr(xdrs, &argp->saa_sa)) {
1234 		return (TRUE);
1235 	}
1236 	return (FALSE);
1237 }
1238 
1239 
1240 /*
1241  * arguments to create and mkdir
1242  */
1243 bool_t
1244 xdr_creatargs(XDR *xdrs, struct nfscreatargs *argp)
1245 {
1246 	argp->ca_sa = &argp->ca_sa_buf;
1247 
1248 	if (xdrs->x_op == XDR_DECODE)
1249 		argp->ca_sa = &argp->ca_sa_buf;
1250 	if (xdr_diropargs(xdrs, &argp->ca_da) &&
1251 	    xdr_sattr(xdrs, argp->ca_sa)) {
1252 		return (TRUE);
1253 	}
1254 	return (FALSE);
1255 }
1256 
1257 /*
1258  * arguments to link
1259  */
1260 bool_t
1261 xdr_linkargs(XDR *xdrs, struct nfslinkargs *argp)
1262 {
1263 	if (xdrs->x_op == XDR_DECODE)
1264 		argp->la_from = &argp->la_from_buf;
1265 	if (xdr_fhandle(xdrs, argp->la_from) &&
1266 	    xdr_diropargs(xdrs, &argp->la_to)) {
1267 		return (TRUE);
1268 	}
1269 	return (FALSE);
1270 }
1271 
1272 /*
1273  * arguments to rename
1274  */
1275 bool_t
1276 xdr_rnmargs(XDR *xdrs, struct nfsrnmargs *argp)
1277 {
1278 	if (xdr_diropargs(xdrs, &argp->rna_from) &&
1279 	    xdr_diropargs(xdrs, &argp->rna_to))
1280 		return (TRUE);
1281 	return (FALSE);
1282 }
1283 
1284 
1285 /*
1286  * arguments to symlink
1287  */
1288 bool_t
1289 xdr_slargs(XDR *xdrs, struct nfsslargs *argp)
1290 {
1291 	if (xdrs->x_op == XDR_FREE) {
1292 		if (!xdr_diropargs(xdrs, &argp->sla_from))
1293 			return (FALSE);
1294 		if ((argp->sla_tnm_flags & SLA_FREETNM) &&
1295 		    !xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN))
1296 			return (FALSE);
1297 		return (TRUE);
1298 	}
1299 
1300 	if (xdrs->x_op == XDR_DECODE) {
1301 		argp->sla_sa = &argp->sla_sa_buf;
1302 		if (argp->sla_tnm == NULL)
1303 			argp->sla_tnm_flags |= SLA_FREETNM;
1304 	}
1305 
1306 	if (xdr_diropargs(xdrs, &argp->sla_from) &&
1307 	    xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN) &&
1308 	    xdr_sattr(xdrs, argp->sla_sa)) {
1309 		return (TRUE);
1310 	}
1311 	return (FALSE);
1312 }
1313 
1314 
1315 /*
1316  * NFS_OK part of statfs operation
1317  */
1318 bool_t
1319 xdr_fsok(XDR *xdrs, struct nfsstatfsok *fsok)
1320 {
1321 	int32_t *ptr;
1322 
1323 	if (xdrs->x_op == XDR_FREE)
1324 		return (TRUE);
1325 
1326 	ptr = XDR_INLINE(xdrs, 5 * BYTES_PER_XDR_UNIT);
1327 	if (ptr != NULL) {
1328 		if (xdrs->x_op == XDR_DECODE) {
1329 			fsok->fsok_tsize = IXDR_GET_INT32(ptr);
1330 			fsok->fsok_bsize = IXDR_GET_INT32(ptr);
1331 			fsok->fsok_blocks = IXDR_GET_INT32(ptr);
1332 			fsok->fsok_bfree = IXDR_GET_INT32(ptr);
1333 			fsok->fsok_bavail = IXDR_GET_INT32(ptr);
1334 		} else {
1335 			IXDR_PUT_INT32(ptr, fsok->fsok_tsize);
1336 			IXDR_PUT_INT32(ptr, fsok->fsok_bsize);
1337 			IXDR_PUT_INT32(ptr, fsok->fsok_blocks);
1338 			IXDR_PUT_INT32(ptr, fsok->fsok_bfree);
1339 			IXDR_PUT_INT32(ptr, fsok->fsok_bavail);
1340 		}
1341 		return (TRUE);
1342 	}
1343 
1344 	if (xdr_u_int(xdrs, &fsok->fsok_tsize) &&
1345 	    xdr_u_int(xdrs, &fsok->fsok_bsize) &&
1346 	    xdr_u_int(xdrs, &fsok->fsok_blocks) &&
1347 	    xdr_u_int(xdrs, &fsok->fsok_bfree) &&
1348 	    xdr_u_int(xdrs, &fsok->fsok_bavail)) {
1349 		return (TRUE);
1350 	}
1351 	return (FALSE);
1352 }
1353 
1354 #ifdef _LITTLE_ENDIAN
1355 bool_t
1356 xdr_fastfsok(XDR *xdrs, struct nfsstatfsok *fsok)
1357 {
1358 
1359 	if (xdrs->x_op == XDR_FREE)
1360 		return (TRUE);
1361 	if (xdrs->x_op == XDR_DECODE)
1362 		return (FALSE);
1363 
1364 	fsok->fsok_tsize = htonl(fsok->fsok_tsize);
1365 	fsok->fsok_bsize = htonl(fsok->fsok_bsize);
1366 	fsok->fsok_blocks = htonl(fsok->fsok_blocks);
1367 	fsok->fsok_bfree = htonl(fsok->fsok_bfree);
1368 	fsok->fsok_bavail = htonl(fsok->fsok_bavail);
1369 	return (TRUE);
1370 }
1371 #endif
1372 
1373 static struct xdr_discrim statfs_discrim[2] = {
1374 	{ NFS_OK, xdr_fsok },
1375 	{ __dontcare__, NULL_xdrproc_t }
1376 };
1377 
1378 /*
1379  * Results of statfs operation
1380  */
1381 bool_t
1382 xdr_statfs(XDR *xdrs, struct nfsstatfs *fs)
1383 {
1384 	return (xdr_union(xdrs, (enum_t *)&(fs->fs_status),
1385 	    (caddr_t)&(fs->fs_fsok), statfs_discrim, xdr_void));
1386 }
1387 
1388 /*
1389  * Results of statfs operation
1390  */
1391 bool_t
1392 xdr_faststatfs(XDR *xdrs, struct nfsstatfs *fs)
1393 {
1394 #if defined(_LITTLE_ENDIAN)
1395 	/*
1396 	 * we deal with the discriminator;  it's an enum
1397 	 */
1398 	if (!xdr_fastenum(xdrs, (enum_t *)&fs->fs_status))
1399 		return (FALSE);
1400 
1401 	if (fs->fs_status == NFS_OK)
1402 		return (xdr_fastfsok(xdrs, &fs->fs_fsok));
1403 #elif defined(_BIG_ENDIAN)
1404 	if (fs->fs_status == NFS_OK)
1405 		return (TRUE);
1406 #endif
1407 	return (xdr_fastshorten(xdrs, sizeof (*fs)));
1408 }
1409 
1410 #ifdef _LITTLE_ENDIAN
1411 /*
1412  * XDR enumerations
1413  */
1414 #ifndef lint
1415 static enum sizecheck { SIZEVAL } sizecheckvar;	/* used to find the size of */
1416 						/* an enum */
1417 #endif
1418 bool_t
1419 xdr_fastenum(XDR *xdrs, enum_t *ep)
1420 {
1421 	if (xdrs->x_op == XDR_FREE)
1422 		return (TRUE);
1423 	if (xdrs->x_op == XDR_DECODE)
1424 		return (FALSE);
1425 
1426 #ifndef lint
1427 	/*
1428 	 * enums are treated as ints
1429 	 */
1430 	if (sizeof (sizecheckvar) == sizeof (int32_t)) {
1431 		*ep = (enum_t)htonl((int32_t)(*ep));
1432 	} else if (sizeof (sizecheckvar) == sizeof (short)) {
1433 		*ep = (enum_t)htons((short)(*ep));
1434 	} else {
1435 		return (FALSE);
1436 	}
1437 	return (TRUE);
1438 #else
1439 	(void) (xdr_short(xdrs, (short *)ep));
1440 	return (xdr_int(xdrs, (int *)ep));
1441 #endif
1442 }
1443 #endif
1444 
1445 static bool_t
1446 xdr_fastshorten(XDR *xdrs, uint_t ressize)
1447 {
1448 	uint_t curpos;
1449 
1450 	curpos = XDR_GETPOS(xdrs);
1451 	ressize -= BYTES_PER_XDR_UNIT;
1452 	curpos -= ressize;
1453 	return (XDR_SETPOS(xdrs, curpos));
1454 }
1455