usr/src/uts/common/fs/nfs/nfs4_xdr.c
changeset 806 849fb015aa25
parent 0 68f95e015346
child 836 dfdf8a665ca9
--- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c	Mon Oct 31 22:44:43 2005 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c	Mon Oct 31 22:53:57 2005 -0800
@@ -149,14 +149,303 @@
 }
 
 /*
- * Called in nfs_acl_xdr.c
+ * XDR_INLINE encode a filehandle.
+ */
+bool_t
+xdr_inline_encode_nfs_fh4(uint32_t **ptrp, uint32_t *ptr_redzone,
+	nfs_fh4_fmt_t *fhp)
+{
+	uint32_t *ptr = *ptrp;
+	uint_t otw_len;
+	char *curp;
+	uint_t dlen;
+	uint32_t padword;
+
+	/*
+	 * First get the variable sized part of the filehandle.
+	 */
+	otw_len = fhp->fh4_len + fhp->fh4_xlen + sizeof (fhp->fh4_fsid) +
+	    sizeof (fhp->fh4_len) + sizeof (fhp->fh4_xlen);
+	/*
+	 * Round out to a full word.
+	 */
+	otw_len = RNDUP(otw_len);
+	padword = (otw_len / BYTES_PER_XDR_UNIT) - 1;
+
+	/*
+	 * Add in the fixed sized pieces.
+	 */
+	otw_len += sizeof (fhp->fh4_flag);
+
+#ifdef VOLATILE_FH_TEST
+	otw_len += sizeof (fhp->fh4_volatile_id);
+#endif
+
+	/*
+	 * Make sure we don't exceed our buffer.
+	 */
+	if ((ptr + (otw_len / BYTES_PER_XDR_UNIT) + 1) > ptr_redzone)
+		return (FALSE);
+
+	IXDR_PUT_U_INT32(ptr, otw_len);
+
+	/*
+	 * Zero out the pading.
+	 */
+	ptr[padword] = 0;
+
+	/* fh4_fsid */
+	IXDR_PUT_INT32(ptr, fhp->fh4_fsid.val[0]);
+	IXDR_PUT_INT32(ptr, fhp->fh4_fsid.val[1]);
+
+	/*
+	 * Since the next pieces are unaligned, we need to
+	 * do bytewise copies.
+	 */
+	curp = (char *)ptr;
+
+	/* fh4_len + fh4_data */
+	dlen = sizeof (fhp->fh4_len);
+	dlen += fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
+	bcopy(&fhp->fh4_len, curp, dlen);
+	curp += dlen;
+
+	/* fh4_xlen + fh4_xdata */
+	dlen = sizeof (fhp->fh4_xlen);
+	dlen += fhp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_xlen;
+	bcopy(&fhp->fh4_xlen, curp, dlen);
+	curp += dlen;
+
+	/* do necessary rounding/padding */
+	curp = (char *)RNDUP((uintptr_t)curp);
+	ptr = (uint32_t *)curp;
+
+	/*
+	 * With the above padding, we're word aligned again.
+	 */
+	ASSERT(((uintptr_t)ptr % BYTES_PER_XDR_UNIT) == 0);
+
+	/* fh4_flag */
+	IXDR_PUT_INT32(ptr, fhp->fh4_flag);
+
+#ifdef VOLATILE_FH_TEST
+	/* fh4_volatile_id */
+	IXDR_PUT_INT32(ptr, fhp->fh4_volatile_id);
+#endif
+	*ptrp = ptr;
+
+	return (TRUE);
+}
+
+static char xdr_crud[BYTES_PER_XDR_UNIT];
+
+static bool_t
+xdr_decode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
+{
+	uint32_t fhsize;		/* filehandle size */
+	uint32_t fsize;			/* fh_len size */
+	uint32_t xsize;			/* fh_xlen size */
+	uint32_t rsize;			/* bytes to round */
+	uint32_t psize;			/* pad size */
+	uint32_t dsize;			/* "data" size */
+	nfs_fh4_fmt_t *fh_fmtp;
+
+	ASSERT(xdrs->x_op == XDR_DECODE);
+
+	/*
+	 * Retrieve the filehandle length.
+	 */
+	if (!XDR_GETINT32(xdrs, (int32_t *)&fhsize))
+		return (FALSE);
+
+	/*
+	 * Check to see if what the client sent us is bigger than what
+	 * we can ever possibly send out or smaller than what we could
+	 * possibly send out.
+	 */
+	if (fhsize > sizeof (nfs_fh4_fmt_t) ||
+	    fhsize < sizeof (fsid_t) + sizeof (ushort_t) + sizeof (ushort_t))
+		return (FALSE);
+
+	rsize = fhsize % BYTES_PER_XDR_UNIT;
+	if (rsize != 0)
+		rsize = BYTES_PER_XDR_UNIT - rsize;
+
+	objp->nfs_fh4_val = kmem_zalloc(sizeof (nfs_fh4_fmt_t), KM_SLEEP);
+	objp->nfs_fh4_len = sizeof (nfs_fh4_fmt_t);
+	fh_fmtp = (nfs_fh4_fmt_t *)objp->nfs_fh4_val;
+
+	/*
+	 * Decode what should be fh4_fsid.
+	 */
+	if (!XDR_GETINT32(xdrs, (int32_t *)&fh_fmtp->fh4_fsid.val[0]))
+		return (FALSE);
+	if (!XDR_GETINT32(xdrs, (int32_t *)&fh_fmtp->fh4_fsid.val[1]))
+		return (FALSE);
+	fhsize -= sizeof (fsid_t);
+
+	/*
+	 * Decode what should be fh4_len.  fh4_len is two bytes, so we're
+	 * unaligned now, have to use XDR_GETBYTES from now on.
+	 */
+	if (!XDR_GETBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_len,
+	    sizeof (ushort_t)))
+		return (FALSE);
+	fhsize -= sizeof (ushort_t);
+
+	fsize = fh_fmtp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA :
+			fh_fmtp->fh4_len;
+	/*
+	 * Make sure the client isn't sending us a bogus length for fh4_data.
+	 */
+	if (fhsize < fsize)
+		return (FALSE);
+
+	if (!XDR_GETBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_data, fsize))
+		return (FALSE);
+	fhsize -= fsize;
+
+	/* make sure we have enough left to decode fh_xlen */
+	if (fhsize < sizeof (ushort_t))
+		return (FALSE);
+
+	if (!XDR_GETBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_xlen,
+	    sizeof (ushort_t)))
+		return (FALSE);
+	fhsize -= sizeof (ushort_t);
+
+	xsize = fh_fmtp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA :
+			fh_fmtp->fh4_xlen;
+	/*
+	 * Make sure the client isn't sending us a bogus length for fh4_xdata.
+	 */
+	if (fhsize < xsize)
+		return (FALSE);
+
+	if (!XDR_GETBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_xdata, xsize))
+		return (FALSE);
+	fhsize -= xsize;
+
+	/* we purposedly align things, so skip padding */
+	dsize = fsize + xsize + sizeof (ushort_t) + sizeof (ushort_t);
+	psize = RNDUP(dsize);
+	if (psize != dsize)
+		if (!XDR_GETBYTES(xdrs, (caddr_t)&xdr_crud, psize - dsize))
+			return (FALSE);
+
+	/* make sure we have enough left to decode fh4_flag */
+	if (fhsize < sizeof (uint32_t))
+		return (FALSE);
+
+	if (!XDR_GETBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_flag,
+	    sizeof (uint32_t)))
+		return (FALSE);
+	fhsize -= sizeof (uint32_t);
+
+#ifdef VOLATILE_FH_TEST
+	/* make sure we have enough left to decode fh4_volatile_id */
+	if (fhsize < sizeof (uint32_t))
+		return (FALSE);
+
+	if (!XDR_GETBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_volatile_id,
+	    sizeof (uint32_t)))
+		return (FALSE);
+	fhsize -= sizeof (uint32_t);
+#endif
+	/*
+	 * Make sure client didn't send request with too much padding.
+	 */
+	if (fhsize > sizeof (uint32_t))
+		return (FALSE);
+
+	if (rsize)
+		if (!XDR_GETBYTES(xdrs, (caddr_t)&xdr_crud, rsize))
+			return (FALSE);
+
+	return (TRUE);
+}
+
+static char zero_word[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
+
+static bool_t
+xdr_encode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
+{
+	uint_t otwsize, fsize, xsize;	/* otw, file, and export sizes */
+	uint_t dsize, rsize;		/* rounding sizes */
+	nfs_fh4_fmt_t *fh_fmtp;
+
+	ASSERT(xdrs->x_op == XDR_ENCODE);
+
+	fh_fmtp = (nfs_fh4_fmt_t *)objp->nfs_fh4_val;
+	fsize = fh_fmtp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA :
+			fh_fmtp->fh4_len;
+	xsize = fh_fmtp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA :
+			fh_fmtp->fh4_xlen;
+	/* fh4_i */
+	otwsize = sizeof (fsid_t) + sizeof (ushort_t) + fsize +
+			sizeof (ushort_t) + xsize;
+
+	/* round out to a full word */
+	otwsize = RNDUP(otwsize);
+
+	/* fh4_flag */
+	otwsize += sizeof (uint32_t);
+
+#ifdef VOLATILE_FH_TEST
+	/* fh4_volatile_id */
+	otwsize += sizeof (uint32_t);
+#endif
+
+	/*
+	 * XDR in filehandle size.
+	 */
+	if (!XDR_PUTINT32(xdrs, (int32_t *)&otwsize))
+		return (FALSE);
+
+	if (!XDR_PUTINT32(xdrs, (int32_t *)&fh_fmtp->fh4_fsid.val[0]))
+		return (FALSE);
+	if (!XDR_PUTINT32(xdrs, (int32_t *)&fh_fmtp->fh4_fsid.val[1]))
+		return (FALSE);
+
+	if (!XDR_PUTBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_len, fsize +
+	    sizeof (ushort_t)))
+		return (FALSE);
+
+	if (!XDR_PUTBYTES(xdrs, (caddr_t)&fh_fmtp->fh4_xlen, xsize +
+	    sizeof (ushort_t)))
+		return (FALSE);
+
+	dsize = fsize + xsize + sizeof (ushort_t) + sizeof (ushort_t);
+	rsize = RNDUP(dsize);
+
+	/*
+	 * Pad in the extra space to force alignment.
+	 */
+	if (dsize != rsize)
+		if (!XDR_PUTBYTES(xdrs, (caddr_t)&zero_word, rsize - dsize))
+			return (FALSE);
+
+	if (!XDR_PUTINT32(xdrs, (int32_t *)&fh_fmtp->fh4_flag))
+		return (FALSE);
+
+#ifdef VOLATILE_FH_TEST
+	if (!XDR_PUTINT32(xdrs, (int32_t *)&fh_fmtp->fh4_volatile_id))
+		return (FALSE);
+#endif
+
+	return (TRUE);
+}
+
+/*
+ * XDR a NFSv4 filehandle.
  */
 bool_t
 xdr_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
 {
-	if (xdrs->x_op != XDR_FREE)
-		return (xdr_bytes(xdrs, (char **)&objp->nfs_fh4_val,
-			(uint_t *)&objp->nfs_fh4_len, NFS4_FHSIZE));
+	if (xdrs->x_op == XDR_DECODE)
+		return (xdr_decode_nfs_fh4(xdrs, objp));
+	else if (xdrs->x_op == XDR_ENCODE)
+		return (xdr_encode_nfs_fh4(xdrs, objp));
 
 	if (objp->nfs_fh4_val != NULL) {
 		kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
@@ -3279,7 +3568,7 @@
 }
 
 static bool_t
-xdr_nfs_argop4_free(XDR *xdrs, nfs_argop4 **arrayp, int len)
+xdr_snfs_argop4_free(XDR *xdrs, nfs_argop4 **arrayp, int len)
 {
 	int i;
 	nfs_argop4 *array = *arrayp;
@@ -3457,9 +3746,6 @@
 static bool_t
 xdr_nfs_argop4(XDR *xdrs, nfs_argop4 *objp)
 {
-	if (!xdr_int(xdrs, (int *)&objp->argop))
-		return (FALSE);
-
 	/*
 	 * These should be ordered by frequency of use
 	 */
@@ -3614,6 +3900,30 @@
 	return (FALSE);
 }
 
+static bool_t
+xdr_cnfs_argop4_wrap(XDR *xdrs, nfs_argop4 *objp)
+{
+	if (!xdr_int(xdrs, (int *)&objp->argop))
+		return (FALSE);
+
+	return (xdr_nfs_argop4(xdrs, objp));
+}
+
+static bool_t
+xdr_snfs_argop4(XDR *xdrs, nfs_argop4 *objp)
+{
+	if (!xdr_int(xdrs, (int *)&objp->argop))
+		return (FALSE);
+
+	switch (objp->argop) {
+	case OP_PUTFH:
+		return (xdr_decode_nfs_fh4(xdrs,
+			&objp->nfs_argop4_u.opputfh.object));
+	default:
+		return (xdr_nfs_argop4(xdrs, objp));
+	}
+}
+
 /*
  * Client side encode only arg op processing
  */
@@ -3632,7 +3942,7 @@
 	 * Special case the private pseudo ops
 	 */
 	if (!(objp->argop & SUNW_PRIVATE_OP))
-		return (xdr_nfs_argop4(xdrs, objp));
+		return (xdr_cnfs_argop4_wrap(xdrs, objp));
 
 	/*
 	 * These should be ordered by frequency of use
@@ -3897,10 +4207,14 @@
 }
 
 static bool_t
+xdr_snfs_resop4_free(XDR *xdrs, nfs_resop4 **arrayp, int len, int decode_len)
+{
+	return (xdr_nfs_resop4_free(xdrs, arrayp, len, decode_len));
+}
+
+static bool_t
 xdr_nfs_resop4(XDR *xdrs, nfs_resop4 *objp)
 {
-	if (!xdr_int(xdrs, (int *)&objp->resop))
-		return (FALSE);
 	/*
 	 * These should be ordered by frequency of use
 	 */
@@ -4052,6 +4366,35 @@
 }
 
 static bool_t
+xdr_cnfs_resop4_wrap(XDR *xdrs, nfs_resop4 *objp)
+{
+	if (!xdr_int(xdrs, (int *)&objp->resop))
+		return (FALSE);
+
+	return (xdr_nfs_resop4(xdrs, objp));
+}
+
+static bool_t
+xdr_snfs_resop4(XDR *xdrs, nfs_resop4 *objp)
+{
+	if (!xdr_int(xdrs, (int *)&objp->resop))
+		return (FALSE);
+
+	switch (objp->resop) {
+	case OP_GETFH:
+		if (!XDR_PUTINT32(xdrs,
+		    (int32_t *)&objp->nfs_resop4_u.opgetfh.status))
+			return (FALSE);
+		if (objp->nfs_resop4_u.opgetfh.status != NFS4_OK)
+			return (TRUE);
+		return (xdr_encode_nfs_fh4(xdrs,
+			&objp->nfs_resop4_u.opgetfh.object));
+	default:
+		return (xdr_nfs_resop4(xdrs, objp));
+	}
+}
+
+static bool_t
 xdr_nfs_resop4_clnt(XDR *xdrs, nfs_resop4 *objp, nfs_argop4 *aobjp)
 {
 	if (!xdr_int(xdrs, (int *)&objp->resop))
@@ -4260,7 +4603,7 @@
 }
 
 bool_t
-xdr_COMPOUND4args(XDR *xdrs, COMPOUND4args *objp)
+xdr_COMPOUND4args_srv(XDR *xdrs, COMPOUND4args *objp)
 {
 	if (!xdr_bytes(xdrs, (char **)&objp->tag.utf8string_val,
 			(uint_t *)&objp->tag.utf8string_len,
@@ -4271,9 +4614,9 @@
 	if (xdrs->x_op != XDR_FREE)
 		return (xdr_array(xdrs, (char **)&objp->array,
 			(uint_t *)&objp->array_len, NFS4_COMPOUND_LIMIT,
-			sizeof (nfs_argop4), (xdrproc_t)xdr_nfs_argop4));
-
-	return (xdr_nfs_argop4_free(xdrs, &objp->array, objp->array_len));
+			sizeof (nfs_argop4), (xdrproc_t)xdr_snfs_argop4));
+
+	return (xdr_snfs_argop4_free(xdrs, &objp->array, objp->array_len));
 }
 
 bool_t
@@ -4345,7 +4688,7 @@
 }
 
 bool_t
-xdr_COMPOUND4res(XDR *xdrs, COMPOUND4res *objp)
+xdr_COMPOUND4res_srv(XDR *xdrs, COMPOUND4res *objp)
 {
 	if (!xdr_int(xdrs, (int32_t *)&objp->status))
 		return (FALSE);
@@ -4357,9 +4700,9 @@
 	if (xdrs->x_op != XDR_FREE)
 		return (xdr_array(xdrs, (char **)&objp->array,
 			(uint_t *)&objp->array_len, NFS4_COMPOUND_LIMIT,
-			sizeof (nfs_resop4), (xdrproc_t)xdr_nfs_resop4));
-
-	return (xdr_nfs_resop4_free(xdrs, &objp->array,
+			sizeof (nfs_resop4), (xdrproc_t)xdr_snfs_resop4));
+
+	return (xdr_snfs_resop4_free(xdrs, &objp->array,
 				    objp->array_len, objp->array_len));
 }