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