/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#include <rpc/rpc_rdma.h>
/*
* These are the XDR routines used to serialize and deserialize
* the various structures passed as parameters across the network
* between NFS clients and servers.
*/
/*
* XDR null terminated ASCII strings
* xdr_string3 deals with "C strings" - arrays of bytes that are
* terminated by a NULL character. The parameter cpp references a
* pointer to storage; If the pointer is null, then the necessary
* storage is allocated. The last parameter is the max allowed length
* of the string as allowed by the system. The NFS Version 3 protocol
* does not place limits on strings, but the implementation needs to
* place a reasonable limit to avoid problems.
*/
{
char *sp;
/*
* first deal with the length since xdr strings are counted-strings
*/
case XDR_FREE:
return (TRUE); /* already free */
/* FALLTHROUGH */
case XDR_ENCODE:
break;
case XDR_DECODE:
break;
}
return (FALSE);
/*
* now deal with the actual bytes
*/
case XDR_DECODE:
*cpp = nfs3nametoolong;
return (FALSE);
return (TRUE);
}
if (nodesize == 0)
return (TRUE);
return (FALSE);
mem_alloced = TRUE;
}
if (mem_alloced)
return (FALSE);
}
} else {
if (mem_alloced)
return (FALSE);
}
return (TRUE);
case XDR_ENCODE:
case XDR_FREE:
return (TRUE);
}
return (FALSE);
}
/*
* XDR_INLINE decode a filehandle.
*/
{
/*
* Check to see if what the client sent us is bigger or smaller
* than what we can ever possibly send out. NFS_FHMAXDATA is
* unfortunately badly named as it is no longer the max and is
* really the min of what is sent over the wire.
*/
sizeof (ushort_t) + NFS_FHMAXDATA +
sizeof (ushort_t) + NFS_FHMAXDATA)) {
return (FALSE);
}
/*
* All internal parts of a filehandle are in native byte order.
*
* Decode what should be fh3_fsid, it is aligned.
*/
bp += BYTES_PER_XDR_UNIT;
bp += BYTES_PER_XDR_UNIT;
/*
* Decode what should be fh3_len. fh3_len is two bytes, so we're
* unaligned now.
*/
/*
* For backwards compatability, the fid length may be less than
* NFS_FHMAXDATA, but it was always encoded as NFS_FHMAXDATA bytes.
*/
/*
* Make sure the client isn't sending us a bogus length for fh3x_data.
*/
return (FALSE);
return (FALSE);
/*
* Make sure the client isn't sending us a bogus length for fh3x_xdata.
*/
return (FALSE);
/*
* We realign things on purpose, so skip any padding
*/
if (resid != 0) {
return (FALSE);
}
/*
* Make sure client didn't send extra bytes
*/
if (fhsize != 0)
return (FALSE);
return (TRUE);
}
static bool_t
{
/*
* Retrieve the filehandle length.
*/
return (FALSE);
objp->fh3_length = 0;
/*
* Check to see if what the client sent us is bigger or smaller
* than what we can ever possibly send out. NFS_FHMAXDATA is
* unfortunately badly named as it is no longer the max and is
* really the min of what is sent over the wire.
*/
sizeof (ushort_t) + NFS_FHMAXDATA +
sizeof (ushort_t) + NFS_FHMAXDATA)) {
return (FALSE);
return (TRUE);
}
/*
* bring in fhsize plus any padding
*/
return (FALSE);
}
}
/*
* If in the process of decoding we find the file handle
* is not correctly formed, we need to continue decoding
* and trigger an NFS layer error. Set the nfs_fh3_len to
* zero so it gets caught as a bad length.
*/
objp->fh3_length = 0;
}
return (TRUE);
}
/*
* XDR_INLINE encode a filehandle.
*/
{
/*
* First get the initial and variable sized part of the filehandle.
*/
/*
* Round out to a full word.
*/
/*
* Make sure we don't exceed our buffer.
*/
return (FALSE);
/*
* Zero out the pading.
*/
/*
* The rest of the filehandle is in native byteorder
*/
/* fh3_fsid */
/*
* Since the next pieces are unaligned, we need to
* do bytewise copies.
*/
/* fh3_len + fh3_data */
/* fh3_xlen + fh3_xdata */
/*
* With the above padding, we're word aligned again.
*/
return (TRUE);
}
static bool_t
{
/*
* First get the over the wire size, it is the 4 bytes
* for the length, plus the combined size of the
* file handle components.
*/
/*
* Round out to a full word.
*/
/*
* Next try to inline the XDR stream, if that fails (rare)
* allocate a buffer to encode the file handle and then
* copy it using xdr_opaque and free the buffer.
*/
}
return (ret);
}
/*
* XDR a NFSv3 filehandle the naive way.
*/
{
return (TRUE);
return (FALSE);
return (FALSE);
}
/*
* XDR a NFSv3 filehandle with intelligence on the server.
* Encoding goes from our in-memory structure to wire format.
* Decoding goes from wire format to our in-memory structure.
*/
{
case XDR_ENCODE:
else
case XDR_DECODE:
case XDR_FREE:
return (TRUE);
}
return (FALSE);
}
{
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
}
static bool_t
{
return (TRUE);
} else {
}
return (TRUE);
}
return (FALSE);
return (TRUE);
}
/*
* Fast decode of an fattr3 to a vattr
* Only return FALSE on decode error, all other fattr to vattr translation
* failures set status.
*
* Callers must catch the following errors:
* EFBIG - file size will not fit in va_size
* EOVERFLOW - time will not fit in va_*time
*/
static bool_t
{
/*
* DECODE only
*/
/* On success, all attributes will be decoded */
/*
* Common case
*/
else
/*
* If invalid size, stop decode, set status, and
* return TRUE, x_handy will be correct, caller must ignore vap.
*/
return (TRUE);
}
/* fsid is ignored */
ptr += 2;
/*
* nfs protocol defines times as unsigned so don't
* extend sign, unless sysadmin set nfs_allow_preepoch_time.
* The inline macros do the equivilant of NFS_TIME_T_CONVERT
*/
if (nfs_allow_preepoch_time) {
} else {
/*
* Check if the time would overflow on 32-bit
*/
/*CONSTCOND*/
if (NFS3_TIME_OVERFLOW(ntime)) {
return (TRUE);
}
/*CONSTCOND*/
if (NFS3_TIME_OVERFLOW(ntime)) {
return (TRUE);
}
/*CONSTCOND*/
if (NFS3_TIME_OVERFLOW(ntime)) {
return (TRUE);
}
}
} else {
/*
* Slow path
*/
return (FALSE);
if (nfs_allow_preepoch_time) {
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
} else {
/*
* Check if the time would overflow on 32-bit
* Set status and keep decoding stream.
*/
return (FALSE);
/*CONSTCOND*/
if (NFS3_TIME_OVERFLOW(ntime)) {
}
return (FALSE);
return (FALSE);
/*CONSTCOND*/
if (NFS3_TIME_OVERFLOW(ntime)) {
}
return (FALSE);
return (FALSE);
/*CONSTCOND*/
if (NFS3_TIME_OVERFLOW(ntime)) {
}
return (FALSE);
}
/*
* Fixup as needed
*/
else
/*
* If invalid size, set status, and
* return TRUE, caller must ignore vap.
*/
return (TRUE);
}
}
/*
* Fill in derived fields
*/
/*
* Common case values
*/
vap->va_nblocks = 0;
case VREG:
case VDIR:
case VLNK:
break;
case VBLK:
/* FALLTHRU */
case VCHR:
break;
case VSOCK:
case VFIFO:
default:
break;
}
return (TRUE);
}
static bool_t
{
/*
* DECODE only
*/
return (FALSE);
return (TRUE);
return (FALSE);
return (FALSE);
/*
* The file size may cause an EFBIG or the time values
* may cause EOVERFLOW, if so simply drop the attributes.
*/
return (TRUE);
}
{
return (FALSE);
return (TRUE);
return (FALSE);
return (FALSE);
/*
* Check that we don't get a file we can't handle through
* existing interfaces (especially stat64()).
* Decode only check since on encode the data has
* been dealt with in the above call to xdr_fattr3().
*/
/* Set attrs to false if invalid size or time */
return (TRUE);
}
#ifndef _LP64
#endif
}
return (TRUE);
}
static bool_t
{
return (TRUE);
/* pre_op_attr */
return (FALSE);
case TRUE:
} else {
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
}
#ifndef _LP64
/*
* check time overflow.
*/
#endif
break;
case FALSE:
break;
default:
return (FALSE);
}
}
/* pre_op_attr */
return (FALSE);
case TRUE:
} else {
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
}
break;
case FALSE:
break;
default:
return (FALSE);
}
}
}
{
return (FALSE);
switch (objp->handle_follows) {
case TRUE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_FREE:
case XDR_DECODE:
return (FALSE);
break;
}
return (TRUE);
case FALSE:
return (TRUE);
default:
return (FALSE);
}
}
static bool_t
{
/* set_mode3 */
return (FALSE);
return (FALSE);
/* set_uid3 */
return (FALSE);
return (FALSE);
/* set_gid3 */
return (FALSE);
return (FALSE);
/* set_size3 */
return (FALSE);
return (FALSE);
/* set_atime */
return (FALSE);
return (FALSE);
return (FALSE);
}
/* set_mtime */
return (FALSE);
return (FALSE);
return (FALSE);
}
return (TRUE);
}
{
return (FALSE);
return (TRUE);
/* xdr_GETATTR3resok */
}
{
/*
* DECODE or FREE only
*/
return (TRUE);
return (FALSE);
return (FALSE);
return (TRUE);
}
{
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
return (FALSE);
/* sattrguard3 */
return (FALSE);
case TRUE:
return (FALSE);
case FALSE:
return (TRUE);
default:
return (FALSE);
}
}
{
return (FALSE);
case NFS3_OK:
default:
}
}
{
return (FALSE);
/* xdr_LOOKUP3resok */
case XDR_ENCODE:
return (FALSE);
break;
case XDR_FREE:
case XDR_DECODE:
return (FALSE);
break;
}
return (FALSE);
}
{
/*
* DECODE or FREE only
*/
return (TRUE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
}
{
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
}
{
return (FALSE);
/* xdr_ACCESS3resok */
return (FALSE);
}
{
}
return (FALSE);
return (TRUE);
}
{
return (FALSE);
return (xdr_post_op_attr(xdrs,
/* xdr_READLINK3resok */
return (FALSE);
}
{
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
return (FALSE);
return (FALSE);
/* if xdrrdma_sizeof in progress, then store the size */
}
return (TRUE);
} else {
}
}
/* XDR_DECODE case */
return (TRUE);
}
{
return (FALSE);
return (FALSE);
}
return (TRUE);
} else {
return (FALSE);
}
/*
* We have read results in an mblk chain, but
* the encoding operations don't handle mblks
* (they'll operate on data.data_val rather
* than data.mp). Because data_val can only
* point at a single data buffer, we need to
* pullup the read results into a single data
* block and reset data_val to point to it.
*
* This happens with RPC GSS where the wrapping
* function does XDR serialization into a
* temporary buffer prior to applying GSS.
* Because we're not in a performance sensitive
* path, the pullupmsg() here shouldn't hurt us
* too badly.
*/
return (FALSE);
}
} else {
return (FALSE);
}
/*
* If read data sent by wlist (RDMA_WRITE), don't do
* xdr_bytes() below. RDMA_WRITE transfers the data.
* Note: this is encode-only because the client code
* uses xdr_READ3vres/xdr_READ3uiores to decode results.
*/
return (xdrrdma_send_read_data(
}
return (TRUE);
}
}
/*
* Fall thru for the xdr_bytes()
*
* note: the mblk will be freed in
* rfs3_read_free.
*/
}
/* no RDMA_WRITE transfer -- send data inline */
return (ret);
}
{
/*
* DECODE or FREE only
*/
return (TRUE);
return (FALSE);
return (FALSE);
return (FALSE);
return (TRUE);
return (FALSE);
return (FALSE);
/*
* If read data received via RDMA_WRITE, don't do xdr_bytes().
* RDMA_WRITE already moved the data so decode length of RDMA_WRITE.
*/
if (cl) {
return (FALSE);
}
return (FALSE);
}
int, ocount,
return (FALSE);
}
return (TRUE);
}
}
}
{
size_t n;
int error;
/*
* DECODE or FREE only
*/
return (TRUE);
return (FALSE);
return (FALSE);
return (FALSE);
/*
* For directio we just skip over attributes if present
*/
switch (attributes) {
case TRUE:
return (FALSE);
break;
case FALSE:
break;
default:
return (FALSE);
}
return (TRUE);
return (FALSE);
return (FALSE);
return (FALSE);
return (TRUE);
return (FALSE);
do {
uiop);
if (error)
return (FALSE);
size -= n;
}
return (TRUE);
}
return (FALSE);
}
return (FALSE);
}
/*
* XXX: Assume 1 iov, needs to be changed.
*/
return (TRUE);
}
}
/*
* This isn't an xdrmblk stream nor RDMA.
* Handle the likely case that it can be
* inlined (ex. xdrmem).
*/
return (FALSE);
return (TRUE);
return (FALSE);
/*
* Handle some other (unlikely) stream type that will need a copy.
*/
return (FALSE);
return (FALSE);
}
}
{
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
return (FALSE);
return (FALSE);
return (FALSE);
return (TRUE);
}
}
return (FALSE);
}
return (TRUE);
}
}
/* Else fall thru for the xdr_bytes(). */
}
return (TRUE);
}
}
}
{
return (FALSE);
/* xdr_WRITE3resok */
return (FALSE);
return (FALSE);
return (FALSE);
/*
* writeverf3 is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
}
{
return (FALSE);
/* xdr_createhow3 */
return (FALSE);
case UNCHECKED:
case GUARDED:
case EXCLUSIVE:
/*
* createverf3 is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
default:
return (FALSE);
}
}
{
return (FALSE);
case NFS3_OK:
/* xdr_CREATE3resok */
return (FALSE);
return (FALSE);
default:
/* xdr_CREATE3resfail */
}
}
{
return (FALSE);
}
{
return (FALSE);
case NFS3_OK:
/* xdr_MKDIR3resok */
return (FALSE);
return (FALSE);
default:
}
}
{
return (FALSE);
return (FALSE);
}
{
return (FALSE);
case NFS3_OK:
/* xdr_SYMLINK3resok */
return (FALSE);
return (FALSE);
default:
}
}
{
return (FALSE);
return (FALSE);
case NF3CHR:
case NF3BLK:
/* xdr_devicedata3 */
return (FALSE);
return (FALSE);
case NF3SOCK:
case NF3FIFO:
default:
break;
}
return (TRUE);
}
{
return (FALSE);
case NFS3_OK:
/* xdr_MKNOD3resok */
return (FALSE);
return (FALSE);
default:
}
}
{
return (FALSE);
case NFS3_OK:
default:
}
}
{
return (FALSE);
case NFS3_OK:
default:
}
}
{
return (FALSE);
}
{
return (FALSE);
case NFS3_OK:
/* xdr_RENAME3resok */
return (FALSE);
default:
/* xdr_RENAME3resfail */
return (FALSE);
}
}
{
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
}
{
return (FALSE);
case NFS3_OK:
/* xdr_LINK3resok */
return (FALSE);
default:
/* xdr_LINK3resfail */
return (FALSE);
}
}
{
return (TRUE);
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
}
return (FALSE);
/*
* cookieverf is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
return (FALSE);
}
#ifdef nextdp
#endif
#ifdef roundup
#endif
/*
* ENCODE ONLY
*/
static bool_t
{
char *name;
int size;
int bufsize;
int entrysz;
int tofit;
return (FALSE);
/*
* bufsize is used to keep track of the size of the response.
* It is primed with:
* 1 for the status +
* 1 for the dir_attributes.attributes boolean +
* 2 for the cookie verifier
* all times BYTES_PER_XDR_UNIT to convert from XDR units
* to bytes. If there are directory attributes to be
* returned, then:
* NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
* time BYTES_PER_XDR_UNIT is added to account for them.
*/
size > 0;
return (FALSE);
continue;
/*
* An entry is composed of:
* 2 for the fileid +
* 1 for the length of the name +
* 2 for the cookie +
* all times BYTES_PER_XDR_UNIT to convert from
* XDR units to bytes, plus the length of the name
* rounded up to the nearest BYTES_PER_XDR_UNIT.
*/
/*
* We need to check to see if the number of bytes left
* to go into the buffer will actually fit into the
* buffer. This is calculated as the size of this
* entry plus:
* 1 for the eof indicator
* times BYTES_PER_XDR_UNIT to convert from from
* XDR units to bytes.
*/
break;
}
return (FALSE);
}
}
return (FALSE);
return (FALSE);
return (TRUE);
}
{
/*
* ENCODE or FREE only
*/
return (FALSE);
return (FALSE);
/* xdr_READDIR3resok */
return (FALSE);
return (TRUE);
/*
* cookieverf is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
return (FALSE);
}
{
int outcount = 0;
/*
* DECODE or FREE only
*/
return (TRUE);
return (FALSE);
return (FALSE);
return (FALSE);
return (TRUE);
/*
* cookieverf is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
return (FALSE);
for (;;) {
return (FALSE);
if (!valid) {
/*
* We have run out of entries, decode eof.
*/
return (FALSE);
break;
}
/*
* fileid3 fileid
*/
return (FALSE);
/*
* filename3 name
*/
return (FALSE);
/*
* If this will overflow buffer, stop decoding
*/
break;
}
return (FALSE);
/*
* cookie3 cookie
*/
return (FALSE);
outcount += this_reclen;
}
return (TRUE);
}
{
return (TRUE);
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
}
return (FALSE);
/*
* cookieverf is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
return (FALSE);
return (FALSE);
}
/*
* ENCODE ONLY
*/
static bool_t
{
char *name;
int nents;
return (FALSE);
while (nents > 0) {
return (FALSE);
return (FALSE);
}
}
infop++;
nents--;
}
return (FALSE);
return (FALSE);
return (TRUE);
}
{
/*
* ENCODE or FREE only
*/
return (FALSE);
return (FALSE);
case NFS3_OK:
/* xdr_READDIRPLUS3resok */
return (FALSE);
/*
* cookieverf is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
return (FALSE);
return (FALSE);
}
break;
default:
}
return (TRUE);
}
/*
* Decode readdirplus directly into a dirent64_t and do the DNLC caching.
*/
{
int outcount = 0;
/*
* DECODE or FREE only
*/
return (TRUE);
return (FALSE);
return (FALSE);
return (FALSE);
return (TRUE);
/*
* cookieverf is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
return (FALSE);
for (;;) {
int va_valid;
int fh_valid;
return (FALSE);
if (!valid) {
/*
* We have run out of entries, decode eof.
*/
return (FALSE);
break;
}
/*
* fileid3 fileid
*/
return (FALSE);
/*
* filename3 name
*/
return (FALSE);
/*
* If this will overflow buffer, stop decoding
*/
break;
}
return (FALSE);
/*
* cookie3 cookie
*/
return (FALSE);
/*
* post_op_attr name_attributes
*/
return (FALSE);
else
/*
* post_op_fh3 name_handle
*/
return (FALSE);
/*
* By definition of the standard fh_valid can be 0 (FALSE) or
* 1 (TRUE), but we have to account for it being anything else
* in case some other system didn't follow the standard. Note
* that this is why the else checks if the fh_valid variable
* is != FALSE.
*/
return (FALSE);
} else {
return (FALSE);
}
/*
* If the name is "." or there are no attributes,
* don't polute the DNLC with "." entries or files
* we cannot determine the type for.
*/
/*
* Do the DNLC caching
*/
}
outcount += this_reclen;
}
return (TRUE);
}
{
return (FALSE);
/* xdr_FSSTAT3resok */
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
}
{
return (FALSE);
/* xdr_FSINFO3resok */
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
}
{
return (FALSE);
/* xdr_PATHCONF3resok */
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
return (FALSE);
}
{
return (TRUE);
case XDR_FREE:
case XDR_ENCODE:
return (FALSE);
break;
case XDR_DECODE:
return (FALSE);
break;
}
return (FALSE);
}
{
return (FALSE);
/* xdr_COMMIT3resok */
return (FALSE);
/*
* writeverf3 is really an opaque 8 byte
* quantity, but we will treat it as a
* hyper for efficiency, the cost of
* a byteswap here saves bcopys elsewhere
*/
}