xref: /titanic_52/usr/src/uts/common/fs/nfs/nfs_xdr.c (revision 5dfd244acc8f144280c5bc8f69ed941185fc3ccc)
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 			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 				if (rrok->rrok_count != 0) {
476 					return (xdrrdma_send_read_data(
477 					    xdrs, rrok->rrok_count,
478 					    rrok->rrok_wlist));
479 				}
480 				return (TRUE);
481 			}
482 			if (rrok->rrok_count == 0) {
483 				return (TRUE);
484 			}
485 		} else {
486 			struct clist *cl;
487 			uint32_t count;
488 
489 			XDR_CONTROL(xdrs, XDR_RDMA_GET_WLIST, &cl);
490 
491 			if (cl) {
492 				if (!xdr_u_int(xdrs, &count))
493 					return (FALSE);
494 				if (count == 0) {
495 					rrok->rrok_wlist_len = 0;
496 					rrok->rrok_count = 0;
497 				} else {
498 					rrok->rrok_wlist_len = clist_len(cl);
499 					if (rrok->rrok_wlist_len !=
500 					    roundup(count,
501 					    BYTES_PER_XDR_UNIT)) {
502 						rrok->rrok_wlist_len = 0;
503 						rrok->rrok_count = 0;
504 						return (FALSE);
505 					}
506 					rrok->rrok_count = count;
507 				}
508 				return (TRUE);
509 			}
510 		}
511 		ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data,
512 		    &rrok->rrok_count, NFS_MAXDATA);
513 
514 		return (ret);
515 	}
516 
517 	if (xdrs->x_op == XDR_ENCODE) {
518 		int i, rndup;
519 
520 		mp = rrok->rrok_mp;
521 		if (mp != NULL && xdrs->x_ops == &xdrmblk_ops) {
522 			mp->b_wptr += rrok->rrok_count;
523 			rndup = BYTES_PER_XDR_UNIT -
524 			    (rrok->rrok_count % BYTES_PER_XDR_UNIT);
525 			if (rndup != BYTES_PER_XDR_UNIT)
526 				for (i = 0; i < rndup; i++)
527 					*mp->b_wptr++ = '\0';
528 			if (xdrmblk_putmblk(xdrs, mp,
529 			    rrok->rrok_count) == TRUE) {
530 				rrok->rrok_mp = NULL;
531 				return (TRUE);
532 			}
533 		}
534 
535 		/*
536 		 * Fall thru for the xdr_bytes()
537 		 *
538 		 * Note: the mblk mp will be freed in rfs_rdfree
539 		 */
540 	}
541 
542 	ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data,
543 	    &rrok->rrok_count, NFS_MAXDATA);
544 
545 	return (ret);
546 }
547 
548 static struct xdr_discrim rdres_discrim[2] = {
549 	{ NFS_OK, xdr_rrok },
550 	{ __dontcare__, NULL_xdrproc_t }
551 };
552 
553 /*
554  * Reply from remote read
555  */
556 bool_t
557 xdr_rdresult(XDR *xdrs, struct nfsrdresult *rr)
558 {
559 	return (xdr_union(xdrs, (enum_t *)&(rr->rr_status),
560 	    (caddr_t)&(rr->rr_ok), rdres_discrim, xdr_void));
561 }
562 
563 /*
564  * File attributes which can be set
565  */
566 bool_t
567 xdr_sattr(XDR *xdrs, struct nfssattr *sa)
568 {
569 	if (xdr_u_int(xdrs, &sa->sa_mode) &&
570 	    xdr_u_int(xdrs, &sa->sa_uid) &&
571 	    xdr_u_int(xdrs, &sa->sa_gid) &&
572 	    xdr_u_int(xdrs, &sa->sa_size) &&
573 	    xdr_nfs2_timeval(xdrs, &sa->sa_atime) &&
574 	    xdr_nfs2_timeval(xdrs, &sa->sa_mtime)) {
575 		return (TRUE);
576 	}
577 	return (FALSE);
578 }
579 
580 static struct xdr_discrim attrstat_discrim[2] = {
581 	{ (int)NFS_OK, xdr_fattr },
582 	{ __dontcare__, NULL_xdrproc_t }
583 };
584 
585 /*
586  * Reply status with file attributes
587  */
588 bool_t
589 xdr_attrstat(XDR *xdrs, struct nfsattrstat *ns)
590 {
591 	return (xdr_union(xdrs, (enum_t *)&(ns->ns_status),
592 	    (caddr_t)&(ns->ns_attr), attrstat_discrim, xdr_void));
593 }
594 
595 /*
596  * Fast reply status with file attributes
597  */
598 bool_t
599 xdr_fastattrstat(XDR *xdrs, struct nfsattrstat *ns)
600 {
601 #if defined(_LITTLE_ENDIAN)
602 	/*
603 	 * we deal with the discriminator;  it's an enum
604 	 */
605 	if (!xdr_fastenum(xdrs, (enum_t *)&ns->ns_status))
606 		return (FALSE);
607 
608 	if (ns->ns_status == NFS_OK)
609 		return (xdr_fastfattr(xdrs, &ns->ns_attr));
610 #elif defined(_BIG_ENDIAN)
611 	if (ns->ns_status == NFS_OK)
612 		return (TRUE);
613 #endif
614 	return (xdr_fastshorten(xdrs, sizeof (*ns)));
615 }
616 
617 /*
618  * NFS_OK part of read sym link reply union
619  */
620 bool_t
621 xdr_srok(XDR *xdrs, struct nfssrok *srok)
622 {
623 	/*
624 	 * It is just as efficient to xdr_bytes
625 	 * an array of unknown length as to inline copy it.
626 	 */
627 	return (xdr_bytes(xdrs, &srok->srok_data, &srok->srok_count,
628 	    NFS_MAXPATHLEN));
629 }
630 
631 static struct xdr_discrim rdlnres_discrim[2] = {
632 	{ (int)NFS_OK, xdr_srok },
633 	{ __dontcare__, NULL_xdrproc_t }
634 };
635 
636 /*
637  * Result of reading symbolic link
638  */
639 bool_t
640 xdr_rdlnres(XDR *xdrs, struct nfsrdlnres *rl)
641 {
642 	return (xdr_union(xdrs, (enum_t *)&(rl->rl_status),
643 	    (caddr_t)&(rl->rl_srok), rdlnres_discrim, xdr_void));
644 }
645 
646 /*
647  * Arguments to readdir
648  */
649 bool_t
650 xdr_rddirargs(XDR *xdrs, struct nfsrddirargs *rda)
651 {
652 	int32_t *ptr;
653 	int32_t *fhp;
654 	rdma_chunkinfo_t rci;
655 	struct xdr_ops *xops = xdrrdma_xops();
656 
657 	if (xdrs->x_op == XDR_FREE)
658 		return (TRUE);
659 
660 	ptr = XDR_INLINE(xdrs,
661 	    RNDUP(sizeof (fhandle_t)) + 2 * BYTES_PER_XDR_UNIT);
662 
663 	if ((xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) &&
664 	    xdrs->x_op == XDR_ENCODE) {
665 		rci.rci_type = RCI_REPLY_CHUNK;
666 		rci.rci_len = rda->rda_count;
667 		XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci);
668 	}
669 
670 	if (ptr != NULL) {
671 		if (xdrs->x_op == XDR_DECODE) {
672 			fhp = (int32_t *)&rda->rda_fh;
673 			*fhp++ = *ptr++;
674 			*fhp++ = *ptr++;
675 			*fhp++ = *ptr++;
676 			*fhp++ = *ptr++;
677 			*fhp++ = *ptr++;
678 			*fhp++ = *ptr++;
679 			*fhp++ = *ptr++;
680 			*fhp = *ptr++;
681 			rda->rda_offset = IXDR_GET_U_INT32(ptr);
682 			rda->rda_count = IXDR_GET_U_INT32(ptr);
683 		} else {
684 			fhp = (int32_t *)&rda->rda_fh;
685 			*ptr++ = *fhp++;
686 			*ptr++ = *fhp++;
687 			*ptr++ = *fhp++;
688 			*ptr++ = *fhp++;
689 			*ptr++ = *fhp++;
690 			*ptr++ = *fhp++;
691 			*ptr++ = *fhp++;
692 			*ptr++ = *fhp;
693 			IXDR_PUT_U_INT32(ptr, rda->rda_offset);
694 			IXDR_PUT_U_INT32(ptr, rda->rda_count);
695 		}
696 		return (TRUE);
697 	}
698 
699 	if (xdr_fhandle(xdrs, &rda->rda_fh) &&
700 	    xdr_u_int(xdrs, &rda->rda_offset) &&
701 	    xdr_u_int(xdrs, &rda->rda_count)) {
702 		return (TRUE);
703 	}
704 	return (FALSE);
705 }
706 
707 
708 /*
709  * Directory read reply:
710  * union (enum status) {
711  *	NFS_OK: entlist;
712  *		boolean eof;
713  *	default:
714  * }
715  *
716  * Directory entries
717  *	struct  direct {
718  *		off_t   d_off;			* offset of next entry *
719  *		u_int	d_fileno;		* inode number of entry *
720  *		u_short d_reclen;		* length of this record *
721  *		u_short d_namlen;		* length of string in d_name *
722  *		char    d_name[MAXNAMLEN + 1];	* name no longer than this *
723  *	};
724  * are on the wire as:
725  * union entlist (boolean valid) {
726  * 	TRUE:	struct otw_dirent;
727  *		u_int nxtoffset;
728  *		union entlist;
729  *	FALSE:
730  * }
731  * where otw_dirent is:
732  * 	struct dirent {
733  *		u_int	de_fid;
734  *		string	de_name<NFS_MAXNAMELEN>;
735  *	}
736  */
737 
738 #ifdef nextdp
739 #undef	nextdp
740 #endif
741 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
742 #ifdef roundup
743 #undef	roundup
744 #endif
745 #define	roundup(x, y)	((((x) + ((y) - 1)) / (y)) * (y))
746 
747 /*
748  * ENCODE ONLY
749  */
750 bool_t
751 xdr_putrddirres(XDR *xdrs, struct nfsrddirres *rd)
752 {
753 	struct dirent64 *dp;
754 	char *name;
755 	int size;
756 	uint_t namlen;
757 	bool_t true = TRUE;
758 	bool_t false = FALSE;
759 	int entrysz;
760 	int tofit;
761 	int bufsize;
762 	uint32_t ino, off;
763 
764 	if (xdrs->x_op != XDR_ENCODE)
765 		return (FALSE);
766 	if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status))
767 		return (FALSE);
768 	if (rd->rd_status != NFS_OK)
769 		return (TRUE);
770 
771 	bufsize = 1 * BYTES_PER_XDR_UNIT;
772 	for (size = rd->rd_size, dp = rd->rd_entries;
773 	    size > 0;
774 	    size -= dp->d_reclen, dp = nextdp(dp)) {
775 		if (dp->d_reclen == 0 /* || DIRSIZ(dp) > dp->d_reclen */)
776 			return (FALSE);
777 		if (dp->d_ino == 0)
778 			continue;
779 		ino = (uint32_t)dp->d_ino; /* for LP64 we clip the bits */
780 		if (dp->d_ino != (ino64_t)ino)	/* and they better be zeros */
781 			return (FALSE);
782 		off = (uint32_t)dp->d_off;
783 		name = dp->d_name;
784 		namlen = (uint_t)strlen(name);
785 		entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
786 		    roundup(namlen, BYTES_PER_XDR_UNIT);
787 		tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
788 		if (bufsize + tofit > rd->rd_bufsize) {
789 			rd->rd_eof = FALSE;
790 			break;
791 		}
792 		if (!xdr_bool(xdrs, &true) ||
793 		    !xdr_u_int(xdrs, &ino) ||
794 		    !xdr_bytes(xdrs, &name, &namlen, NFS_MAXNAMLEN) ||
795 		    !xdr_u_int(xdrs, &off)) {
796 			return (FALSE);
797 		}
798 		bufsize += entrysz;
799 	}
800 	if (!xdr_bool(xdrs, &false))
801 		return (FALSE);
802 	if (!xdr_bool(xdrs, &rd->rd_eof))
803 		return (FALSE);
804 	return (TRUE);
805 }
806 
807 /*
808  * DECODE ONLY
809  */
810 bool_t
811 xdr_getrddirres(XDR *xdrs, struct nfsrddirres *rd)
812 {
813 	struct dirent64 *dp;
814 	uint_t namlen;
815 	int size;
816 	bool_t valid;
817 	uint32_t offset;
818 	uint_t fileid, this_reclen;
819 
820 	if (xdrs->x_op != XDR_DECODE)
821 		return (FALSE);
822 
823 	if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status))
824 		return (FALSE);
825 	if (rd->rd_status != NFS_OK)
826 		return (TRUE);
827 
828 	size = rd->rd_size;
829 	dp = rd->rd_entries;
830 	offset = rd->rd_offset;
831 	for (;;) {
832 		if (!xdr_bool(xdrs, &valid))
833 			return (FALSE);
834 		if (!valid)
835 			break;
836 		if (!xdr_u_int(xdrs, &fileid) ||
837 		    !xdr_u_int(xdrs, &namlen))
838 			return (FALSE);
839 		this_reclen = DIRENT64_RECLEN(namlen);
840 		if (this_reclen > size) {
841 			rd->rd_eof = FALSE;
842 			goto bufovflw;
843 		}
844 		if (!xdr_opaque(xdrs, dp->d_name, namlen)||
845 		    !xdr_u_int(xdrs, &offset)) {
846 			return (FALSE);
847 		}
848 		bzero(&dp->d_name[namlen],
849 		    DIRENT64_NAMELEN(this_reclen) - namlen);
850 		dp->d_ino = (ino64_t)fileid;
851 		dp->d_reclen = this_reclen;
852 		dp->d_off = (off64_t)offset;
853 		size -= dp->d_reclen;
854 		dp = nextdp(dp);
855 	}
856 	if (!xdr_bool(xdrs, &rd->rd_eof))
857 		return (FALSE);
858 bufovflw:
859 	rd->rd_size = (uint32_t)((char *)dp - (char *)(rd->rd_entries));
860 	rd->rd_offset = offset;
861 	return (TRUE);
862 }
863 
864 /*
865  * Arguments for directory operations
866  */
867 bool_t
868 xdr_diropargs(XDR *xdrs, struct nfsdiropargs *da)
869 {
870 	int32_t *ptr;
871 	int32_t *fhp;
872 	uint32_t size;
873 	uint32_t nodesize;
874 	int i;
875 	int rndup;
876 	char *cptr;
877 
878 	if (xdrs->x_op == XDR_DECODE) {
879 		da->da_fhandle = &da->da_fhandle_buf;
880 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
881 		    1 * BYTES_PER_XDR_UNIT);
882 		if (ptr != NULL) {
883 			fhp = (int32_t *)da->da_fhandle;
884 			*fhp++ = *ptr++;
885 			*fhp++ = *ptr++;
886 			*fhp++ = *ptr++;
887 			*fhp++ = *ptr++;
888 			*fhp++ = *ptr++;
889 			*fhp++ = *ptr++;
890 			*fhp++ = *ptr++;
891 			*fhp = *ptr++;
892 			size = IXDR_GET_U_INT32(ptr);
893 			if (size > NFS_MAXNAMLEN)
894 				return (FALSE);
895 			nodesize = size + 1;
896 			if (nodesize == 0)
897 				return (TRUE);
898 			if (da->da_name == NULL) {
899 				da->da_name = kmem_alloc(nodesize, KM_NOSLEEP);
900 				if (da->da_name == NULL)
901 					return (FALSE);
902 				da->da_flags |= DA_FREENAME;
903 			}
904 			ptr = XDR_INLINE(xdrs, RNDUP(size));
905 			if (ptr == NULL) {
906 				if (!xdr_opaque(xdrs, da->da_name, size)) {
907 					if (da->da_flags & DA_FREENAME) {
908 						kmem_free(da->da_name,
909 						    nodesize);
910 						da->da_name = NULL;
911 					}
912 					return (FALSE);
913 				}
914 				da->da_name[size] = '\0';
915 				if (strlen(da->da_name) != size) {
916 					if (da->da_flags & DA_FREENAME) {
917 						kmem_free(da->da_name,
918 						    nodesize);
919 						da->da_name = NULL;
920 					}
921 					return (FALSE);
922 				}
923 				return (TRUE);
924 			}
925 			bcopy(ptr, da->da_name, size);
926 			da->da_name[size] = '\0';
927 			if (strlen(da->da_name) != size) {
928 				if (da->da_flags & DA_FREENAME) {
929 					kmem_free(da->da_name, nodesize);
930 					da->da_name = NULL;
931 				}
932 				return (FALSE);
933 			}
934 			return (TRUE);
935 		}
936 		if (da->da_name == NULL)
937 			da->da_flags |= DA_FREENAME;
938 	}
939 
940 	if (xdrs->x_op == XDR_ENCODE) {
941 		size = (uint32_t)strlen(da->da_name);
942 		if (size > NFS_MAXNAMLEN)
943 			return (FALSE);
944 		ptr = XDR_INLINE(xdrs, (int)(RNDUP(sizeof (fhandle_t)) +
945 		    1 * BYTES_PER_XDR_UNIT + RNDUP(size)));
946 		if (ptr != NULL) {
947 			fhp = (int32_t *)da->da_fhandle;
948 			*ptr++ = *fhp++;
949 			*ptr++ = *fhp++;
950 			*ptr++ = *fhp++;
951 			*ptr++ = *fhp++;
952 			*ptr++ = *fhp++;
953 			*ptr++ = *fhp++;
954 			*ptr++ = *fhp++;
955 			*ptr++ = *fhp;
956 			IXDR_PUT_U_INT32(ptr, (uint32_t)size);
957 			bcopy(da->da_name, ptr, size);
958 			rndup = BYTES_PER_XDR_UNIT -
959 			    (size % BYTES_PER_XDR_UNIT);
960 			if (rndup != BYTES_PER_XDR_UNIT) {
961 				cptr = (char *)ptr + size;
962 				for (i = 0; i < rndup; i++)
963 					*cptr++ = '\0';
964 			}
965 			return (TRUE);
966 		}
967 	}
968 
969 	if (xdrs->x_op == XDR_FREE) {
970 		if (da->da_name == NULL)
971 			return (TRUE);
972 		size = (uint32_t)strlen(da->da_name);
973 		if (size > NFS_MAXNAMLEN)
974 			return (FALSE);
975 		if (da->da_flags & DA_FREENAME)
976 			kmem_free(da->da_name, size + 1);
977 		da->da_name = NULL;
978 		return (TRUE);
979 	}
980 
981 	if (xdr_fhandle(xdrs, da->da_fhandle) &&
982 	    xdr_string(xdrs, &da->da_name, NFS_MAXNAMLEN)) {
983 		return (TRUE);
984 	}
985 	return (FALSE);
986 }
987 
988 /*
989  * NFS_OK part of directory operation result
990  */
991 bool_t
992 xdr_drok(XDR *xdrs, struct nfsdrok *drok)
993 {
994 	int32_t *ptr;
995 	int32_t *fhp;
996 	struct nfsfattr *na;
997 
998 	if (xdrs->x_op == XDR_FREE)
999 		return (TRUE);
1000 
1001 	ptr = XDR_INLINE(xdrs,
1002 	    RNDUP(sizeof (fhandle_t)) + 17 * BYTES_PER_XDR_UNIT);
1003 	if (ptr != NULL) {
1004 		if (xdrs->x_op == XDR_DECODE) {
1005 			fhp = (int32_t *)&drok->drok_fhandle;
1006 			*fhp++ = *ptr++;
1007 			*fhp++ = *ptr++;
1008 			*fhp++ = *ptr++;
1009 			*fhp++ = *ptr++;
1010 			*fhp++ = *ptr++;
1011 			*fhp++ = *ptr++;
1012 			*fhp++ = *ptr++;
1013 			*fhp = *ptr++;
1014 			na = &drok->drok_attr;
1015 			na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype);
1016 			na->na_mode = IXDR_GET_U_INT32(ptr);
1017 			na->na_nlink = IXDR_GET_U_INT32(ptr);
1018 			na->na_uid = IXDR_GET_U_INT32(ptr);
1019 			na->na_gid = IXDR_GET_U_INT32(ptr);
1020 			na->na_size = IXDR_GET_U_INT32(ptr);
1021 			na->na_blocksize = IXDR_GET_U_INT32(ptr);
1022 			na->na_rdev = IXDR_GET_U_INT32(ptr);
1023 			na->na_blocks = IXDR_GET_U_INT32(ptr);
1024 			na->na_fsid = IXDR_GET_U_INT32(ptr);
1025 			na->na_nodeid = IXDR_GET_U_INT32(ptr);
1026 			na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr);
1027 			na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr);
1028 			na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
1029 			na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
1030 			na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr);
1031 			na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr);
1032 		} else {
1033 			fhp = (int32_t *)&drok->drok_fhandle;
1034 			*ptr++ = *fhp++;
1035 			*ptr++ = *fhp++;
1036 			*ptr++ = *fhp++;
1037 			*ptr++ = *fhp++;
1038 			*ptr++ = *fhp++;
1039 			*ptr++ = *fhp++;
1040 			*ptr++ = *fhp++;
1041 			*ptr++ = *fhp;
1042 			na = &drok->drok_attr;
1043 			IXDR_PUT_ENUM(ptr, na->na_type);
1044 			IXDR_PUT_U_INT32(ptr, na->na_mode);
1045 			IXDR_PUT_U_INT32(ptr, na->na_nlink);
1046 			IXDR_PUT_U_INT32(ptr, na->na_uid);
1047 			IXDR_PUT_U_INT32(ptr, na->na_gid);
1048 			IXDR_PUT_U_INT32(ptr, na->na_size);
1049 			IXDR_PUT_U_INT32(ptr, na->na_blocksize);
1050 			IXDR_PUT_U_INT32(ptr, na->na_rdev);
1051 			IXDR_PUT_U_INT32(ptr, na->na_blocks);
1052 			IXDR_PUT_U_INT32(ptr, na->na_fsid);
1053 			IXDR_PUT_U_INT32(ptr, na->na_nodeid);
1054 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec);
1055 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec);
1056 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec);
1057 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec);
1058 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec);
1059 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec);
1060 		}
1061 		return (TRUE);
1062 	}
1063 
1064 	if (xdr_fhandle(xdrs, &drok->drok_fhandle) &&
1065 	    xdr_fattr(xdrs, &drok->drok_attr)) {
1066 		return (TRUE);
1067 	}
1068 	return (FALSE);
1069 }
1070 
1071 #ifdef _LITTLE_ENDIAN
1072 bool_t
1073 xdr_fastdrok(XDR *xdrs, struct nfsdrok *drok)
1074 {
1075 	struct nfsfattr *na;
1076 
1077 	if (xdrs->x_op == XDR_FREE)
1078 		return (TRUE);
1079 	if (xdrs->x_op == XDR_DECODE)
1080 		return (FALSE);
1081 
1082 	na = &drok->drok_attr;
1083 	na->na_type = (enum nfsftype)htonl(na->na_type);
1084 	na->na_mode = (uint32_t)htonl(na->na_mode);
1085 	na->na_nlink = (uint32_t)htonl(na->na_nlink);
1086 	na->na_uid = (uint32_t)htonl(na->na_uid);
1087 	na->na_gid = (uint32_t)htonl(na->na_gid);
1088 	na->na_size = (uint32_t)htonl(na->na_size);
1089 	na->na_blocksize = (uint32_t)htonl(na->na_blocksize);
1090 	na->na_rdev = (uint32_t)htonl(na->na_rdev);
1091 	na->na_blocks = (uint32_t)htonl(na->na_blocks);
1092 	na->na_fsid = (uint32_t)htonl(na->na_fsid);
1093 	na->na_nodeid = (uint32_t)htonl(na->na_nodeid);
1094 	na->na_atime.tv_sec = htonl(na->na_atime.tv_sec);
1095 	na->na_atime.tv_usec = htonl(na->na_atime.tv_usec);
1096 	na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec);
1097 	na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec);
1098 	na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec);
1099 	na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec);
1100 	return (TRUE);
1101 }
1102 #endif
1103 
1104 static struct xdr_discrim diropres_discrim[2] = {
1105 	{ NFS_OK, xdr_drok },
1106 	{ __dontcare__, NULL_xdrproc_t }
1107 };
1108 
1109 /*
1110  * Results from directory operation
1111  */
1112 bool_t
1113 xdr_diropres(XDR *xdrs, struct nfsdiropres *dr)
1114 {
1115 	return (xdr_union(xdrs, (enum_t *)&(dr->dr_status),
1116 	    (caddr_t)&(dr->dr_drok), diropres_discrim, xdr_void));
1117 }
1118 
1119 /*
1120  * Results from directory operation
1121  */
1122 bool_t
1123 xdr_fastdiropres(XDR *xdrs, struct nfsdiropres *dr)
1124 {
1125 #if defined(_LITTLE_ENDIAN)
1126 	/*
1127 	 * we deal with the discriminator;  it's an enum
1128 	 */
1129 	if (!xdr_fastenum(xdrs, (enum_t *)&dr->dr_status))
1130 		return (FALSE);
1131 
1132 	if (dr->dr_status == NFS_OK)
1133 		return (xdr_fastdrok(xdrs, &dr->dr_drok));
1134 #elif defined(_BIG_ENDIAN)
1135 	if (dr->dr_status == NFS_OK)
1136 		return (TRUE);
1137 #endif
1138 	return (xdr_fastshorten(xdrs, sizeof (*dr)));
1139 }
1140 
1141 /*
1142  * Time Structure, unsigned
1143  */
1144 bool_t
1145 xdr_nfs2_timeval(XDR *xdrs, struct nfs2_timeval *tv)
1146 {
1147 	if (xdr_u_int(xdrs, &tv->tv_sec) &&
1148 	    xdr_u_int(xdrs, &tv->tv_usec))
1149 		return (TRUE);
1150 	return (FALSE);
1151 }
1152 
1153 /*
1154  * arguments to setattr
1155  */
1156 bool_t
1157 xdr_saargs(XDR *xdrs, struct nfssaargs *argp)
1158 {
1159 	int32_t *ptr;
1160 	int32_t *arg;
1161 	struct nfssattr *sa;
1162 
1163 	if (xdrs->x_op == XDR_FREE)
1164 		return (TRUE);
1165 
1166 	ptr = XDR_INLINE(xdrs,
1167 	    RNDUP(sizeof (fhandle_t)) + 8 * BYTES_PER_XDR_UNIT);
1168 	if (ptr != NULL) {
1169 		if (xdrs->x_op == XDR_DECODE) {
1170 			arg = (int32_t *)&argp->saa_fh;
1171 			*arg++ = *ptr++;
1172 			*arg++ = *ptr++;
1173 			*arg++ = *ptr++;
1174 			*arg++ = *ptr++;
1175 			*arg++ = *ptr++;
1176 			*arg++ = *ptr++;
1177 			*arg++ = *ptr++;
1178 			*arg = *ptr++;
1179 			sa = &argp->saa_sa;
1180 			sa->sa_mode = IXDR_GET_U_INT32(ptr);
1181 			sa->sa_uid = IXDR_GET_U_INT32(ptr);
1182 			sa->sa_gid = IXDR_GET_U_INT32(ptr);
1183 			sa->sa_size = IXDR_GET_U_INT32(ptr);
1184 			sa->sa_atime.tv_sec = IXDR_GET_U_INT32(ptr);
1185 			sa->sa_atime.tv_usec = IXDR_GET_U_INT32(ptr);
1186 			sa->sa_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
1187 			sa->sa_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
1188 		} else {
1189 			arg = (int32_t *)&argp->saa_fh;
1190 			*ptr++ = *arg++;
1191 			*ptr++ = *arg++;
1192 			*ptr++ = *arg++;
1193 			*ptr++ = *arg++;
1194 			*ptr++ = *arg++;
1195 			*ptr++ = *arg++;
1196 			*ptr++ = *arg++;
1197 			*ptr++ = *arg;
1198 			sa = &argp->saa_sa;
1199 			IXDR_PUT_U_INT32(ptr, sa->sa_mode);
1200 			IXDR_PUT_U_INT32(ptr, sa->sa_uid);
1201 			IXDR_PUT_U_INT32(ptr, sa->sa_gid);
1202 			IXDR_PUT_U_INT32(ptr, sa->sa_size);
1203 			IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_sec);
1204 			IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_usec);
1205 			IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_sec);
1206 			IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_usec);
1207 		}
1208 		return (TRUE);
1209 	}
1210 
1211 	if (xdr_fhandle(xdrs, &argp->saa_fh) &&
1212 	    xdr_sattr(xdrs, &argp->saa_sa)) {
1213 		return (TRUE);
1214 	}
1215 	return (FALSE);
1216 }
1217 
1218 
1219 /*
1220  * arguments to create and mkdir
1221  */
1222 bool_t
1223 xdr_creatargs(XDR *xdrs, struct nfscreatargs *argp)
1224 {
1225 	argp->ca_sa = &argp->ca_sa_buf;
1226 
1227 	if (xdrs->x_op == XDR_DECODE)
1228 		argp->ca_sa = &argp->ca_sa_buf;
1229 	if (xdr_diropargs(xdrs, &argp->ca_da) &&
1230 	    xdr_sattr(xdrs, argp->ca_sa)) {
1231 		return (TRUE);
1232 	}
1233 	return (FALSE);
1234 }
1235 
1236 /*
1237  * arguments to link
1238  */
1239 bool_t
1240 xdr_linkargs(XDR *xdrs, struct nfslinkargs *argp)
1241 {
1242 	if (xdrs->x_op == XDR_DECODE)
1243 		argp->la_from = &argp->la_from_buf;
1244 	if (xdr_fhandle(xdrs, argp->la_from) &&
1245 	    xdr_diropargs(xdrs, &argp->la_to)) {
1246 		return (TRUE);
1247 	}
1248 	return (FALSE);
1249 }
1250 
1251 /*
1252  * arguments to rename
1253  */
1254 bool_t
1255 xdr_rnmargs(XDR *xdrs, struct nfsrnmargs *argp)
1256 {
1257 	if (xdr_diropargs(xdrs, &argp->rna_from) &&
1258 	    xdr_diropargs(xdrs, &argp->rna_to))
1259 		return (TRUE);
1260 	return (FALSE);
1261 }
1262 
1263 
1264 /*
1265  * arguments to symlink
1266  */
1267 bool_t
1268 xdr_slargs(XDR *xdrs, struct nfsslargs *argp)
1269 {
1270 	if (xdrs->x_op == XDR_FREE) {
1271 		if (!xdr_diropargs(xdrs, &argp->sla_from))
1272 			return (FALSE);
1273 		if ((argp->sla_tnm_flags & SLA_FREETNM) &&
1274 		    !xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN))
1275 			return (FALSE);
1276 		return (TRUE);
1277 	}
1278 
1279 	if (xdrs->x_op == XDR_DECODE) {
1280 		argp->sla_sa = &argp->sla_sa_buf;
1281 		if (argp->sla_tnm == NULL)
1282 			argp->sla_tnm_flags |= SLA_FREETNM;
1283 	}
1284 
1285 	if (xdr_diropargs(xdrs, &argp->sla_from) &&
1286 	    xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN) &&
1287 	    xdr_sattr(xdrs, argp->sla_sa)) {
1288 		return (TRUE);
1289 	}
1290 	return (FALSE);
1291 }
1292 
1293 
1294 /*
1295  * NFS_OK part of statfs operation
1296  */
1297 bool_t
1298 xdr_fsok(XDR *xdrs, struct nfsstatfsok *fsok)
1299 {
1300 	int32_t *ptr;
1301 
1302 	if (xdrs->x_op == XDR_FREE)
1303 		return (TRUE);
1304 
1305 	ptr = XDR_INLINE(xdrs, 5 * BYTES_PER_XDR_UNIT);
1306 	if (ptr != NULL) {
1307 		if (xdrs->x_op == XDR_DECODE) {
1308 			fsok->fsok_tsize = IXDR_GET_INT32(ptr);
1309 			fsok->fsok_bsize = IXDR_GET_INT32(ptr);
1310 			fsok->fsok_blocks = IXDR_GET_INT32(ptr);
1311 			fsok->fsok_bfree = IXDR_GET_INT32(ptr);
1312 			fsok->fsok_bavail = IXDR_GET_INT32(ptr);
1313 		} else {
1314 			IXDR_PUT_INT32(ptr, fsok->fsok_tsize);
1315 			IXDR_PUT_INT32(ptr, fsok->fsok_bsize);
1316 			IXDR_PUT_INT32(ptr, fsok->fsok_blocks);
1317 			IXDR_PUT_INT32(ptr, fsok->fsok_bfree);
1318 			IXDR_PUT_INT32(ptr, fsok->fsok_bavail);
1319 		}
1320 		return (TRUE);
1321 	}
1322 
1323 	if (xdr_u_int(xdrs, &fsok->fsok_tsize) &&
1324 	    xdr_u_int(xdrs, &fsok->fsok_bsize) &&
1325 	    xdr_u_int(xdrs, &fsok->fsok_blocks) &&
1326 	    xdr_u_int(xdrs, &fsok->fsok_bfree) &&
1327 	    xdr_u_int(xdrs, &fsok->fsok_bavail)) {
1328 		return (TRUE);
1329 	}
1330 	return (FALSE);
1331 }
1332 
1333 #ifdef _LITTLE_ENDIAN
1334 bool_t
1335 xdr_fastfsok(XDR *xdrs, struct nfsstatfsok *fsok)
1336 {
1337 
1338 	if (xdrs->x_op == XDR_FREE)
1339 		return (TRUE);
1340 	if (xdrs->x_op == XDR_DECODE)
1341 		return (FALSE);
1342 
1343 	fsok->fsok_tsize = htonl(fsok->fsok_tsize);
1344 	fsok->fsok_bsize = htonl(fsok->fsok_bsize);
1345 	fsok->fsok_blocks = htonl(fsok->fsok_blocks);
1346 	fsok->fsok_bfree = htonl(fsok->fsok_bfree);
1347 	fsok->fsok_bavail = htonl(fsok->fsok_bavail);
1348 	return (TRUE);
1349 }
1350 #endif
1351 
1352 static struct xdr_discrim statfs_discrim[2] = {
1353 	{ NFS_OK, xdr_fsok },
1354 	{ __dontcare__, NULL_xdrproc_t }
1355 };
1356 
1357 /*
1358  * Results of statfs operation
1359  */
1360 bool_t
1361 xdr_statfs(XDR *xdrs, struct nfsstatfs *fs)
1362 {
1363 	return (xdr_union(xdrs, (enum_t *)&(fs->fs_status),
1364 	    (caddr_t)&(fs->fs_fsok), statfs_discrim, xdr_void));
1365 }
1366 
1367 /*
1368  * Results of statfs operation
1369  */
1370 bool_t
1371 xdr_faststatfs(XDR *xdrs, struct nfsstatfs *fs)
1372 {
1373 #if defined(_LITTLE_ENDIAN)
1374 	/*
1375 	 * we deal with the discriminator;  it's an enum
1376 	 */
1377 	if (!xdr_fastenum(xdrs, (enum_t *)&fs->fs_status))
1378 		return (FALSE);
1379 
1380 	if (fs->fs_status == NFS_OK)
1381 		return (xdr_fastfsok(xdrs, &fs->fs_fsok));
1382 #elif defined(_BIG_ENDIAN)
1383 	if (fs->fs_status == NFS_OK)
1384 		return (TRUE);
1385 #endif
1386 	return (xdr_fastshorten(xdrs, sizeof (*fs)));
1387 }
1388 
1389 #ifdef _LITTLE_ENDIAN
1390 /*
1391  * XDR enumerations
1392  */
1393 #ifndef lint
1394 static enum sizecheck { SIZEVAL } sizecheckvar;	/* used to find the size of */
1395 						/* an enum */
1396 #endif
1397 bool_t
1398 xdr_fastenum(XDR *xdrs, enum_t *ep)
1399 {
1400 	if (xdrs->x_op == XDR_FREE)
1401 		return (TRUE);
1402 	if (xdrs->x_op == XDR_DECODE)
1403 		return (FALSE);
1404 
1405 #ifndef lint
1406 	/*
1407 	 * enums are treated as ints
1408 	 */
1409 	if (sizeof (sizecheckvar) == sizeof (int32_t)) {
1410 		*ep = (enum_t)htonl((int32_t)(*ep));
1411 	} else if (sizeof (sizecheckvar) == sizeof (short)) {
1412 		*ep = (enum_t)htons((short)(*ep));
1413 	} else {
1414 		return (FALSE);
1415 	}
1416 	return (TRUE);
1417 #else
1418 	(void) (xdr_short(xdrs, (short *)ep));
1419 	return (xdr_int(xdrs, (int *)ep));
1420 #endif
1421 }
1422 #endif
1423 
1424 static bool_t
1425 xdr_fastshorten(XDR *xdrs, uint_t ressize)
1426 {
1427 	uint_t curpos;
1428 
1429 	curpos = XDR_GETPOS(xdrs);
1430 	ressize -= BYTES_PER_XDR_UNIT;
1431 	curpos -= ressize;
1432 	return (XDR_SETPOS(xdrs, curpos));
1433 }
1434