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
54static 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 */
66bool_t
67xdr_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
103bool_t
104xdr_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 */
123bool_t
124xdr_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 */
258bool_t
259xdr_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
328bool_t
329xdr_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
357bool_t
358xdr_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 */
379bool_t
380xdr_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 */
468bool_t
469xdr_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
569static 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 */
577bool_t
578xdr_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 */
587bool_t
588xdr_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
601static 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 */
609bool_t
610xdr_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 */
619bool_t
620xdr_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 */
641bool_t
642xdr_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
652static 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 */
660bool_t
661xdr_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 */
670bool_t
671xdr_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 */
771bool_t
772xdr_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 */
831bool_t
832xdr_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);
879bufovflw:
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 */
888bool_t
889xdr_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 */
1012bool_t
1013xdr_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
1093bool_t
1094xdr_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
1125static 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 */
1133bool_t
1134xdr_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 */
1143bool_t
1144xdr_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 */
1165bool_t
1166xdr_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 */
1177bool_t
1178xdr_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 */
1243bool_t
1244xdr_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 */
1260bool_t
1261xdr_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 */
1275bool_t
1276xdr_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 */
1288bool_t
1289xdr_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 */
1318bool_t
1319xdr_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
1355bool_t
1356xdr_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
1373static 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 */
1381bool_t
1382xdr_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 */
1391bool_t
1392xdr_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
1415static enum sizecheck { SIZEVAL } sizecheckvar;	/* used to find the size of */
1416						/* an enum */
1417#endif
1418bool_t
1419xdr_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
1445static bool_t
1446xdr_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