/* SPDX-License-Identifier: GPL-2.0 */
/*
 * NFSv4 file attributes supported by this implementation
 */

#ifndef _LINUX_NFSD_ATTR4_H
#define _LINUX_NFSD_ATTR4_H

#include <linux/types.h>
#include <linux/nfs4.h>

/*
 * The following attributes are not implemented by NFSD:
 *    ARCHIVE       (deprecated anyway)
 *    HIDDEN        (unlikely to be supported any time soon)
 *    MIMETYPE      (unlikely to be supported any time soon)
 *    QUOTA_*       (unlikely to be supported any time soon)
 *    SYSTEM        (unlikely to be supported any time soon)
 *    TIME_BACKUP   (unlikely to be supported any time soon)
 */
#define NFSD4_SUPPORTED_ATTRS_WORD0                                                         \
(FATTR4_WORD0_SUPPORTED_ATTRS   | FATTR4_WORD0_TYPE         | FATTR4_WORD0_FH_EXPIRE_TYPE   \
 | FATTR4_WORD0_CHANGE          | FATTR4_WORD0_SIZE         | FATTR4_WORD0_LINK_SUPPORT     \
 | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR   | FATTR4_WORD0_FSID             \
 | FATTR4_WORD0_UNIQUE_HANDLES  | FATTR4_WORD0_LEASE_TIME   | FATTR4_WORD0_RDATTR_ERROR     \
 | FATTR4_WORD0_ACLSUPPORT      | FATTR4_WORD0_CANSETTIME   | FATTR4_WORD0_CASE_INSENSITIVE \
 | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED                             \
 | FATTR4_WORD0_FILEHANDLE      | FATTR4_WORD0_FILEID       | FATTR4_WORD0_FILES_AVAIL      \
 | FATTR4_WORD0_FILES_FREE      | FATTR4_WORD0_FILES_TOTAL  | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS      \
 | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
 | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE     | FATTR4_WORD0_ACL)

#define NFSD4_SUPPORTED_ATTRS_WORD1                                                         \
(FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
 | FATTR4_WORD1_OWNER	        | FATTR4_WORD1_OWNER_GROUP  | FATTR4_WORD1_RAWDEV           \
 | FATTR4_WORD1_SPACE_AVAIL     | FATTR4_WORD1_SPACE_FREE   | FATTR4_WORD1_SPACE_TOTAL      \
 | FATTR4_WORD1_SPACE_USED      | FATTR4_WORD1_TIME_ACCESS  | FATTR4_WORD1_TIME_ACCESS_SET  \
 | FATTR4_WORD1_TIME_DELTA      | FATTR4_WORD1_TIME_METADATA   | FATTR4_WORD1_TIME_CREATE      \
 | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)

#define NFSD4_SUPPORTED_ATTRS_WORD2 0

/* 4.1 */
#ifdef CONFIG_NFSD_PNFS
#define PNFSD_SUPPORTED_ATTRS_WORD1	FATTR4_WORD1_FS_LAYOUT_TYPES
#define PNFSD_SUPPORTED_ATTRS_WORD2 \
(FATTR4_WORD2_LAYOUT_BLKSIZE	| FATTR4_WORD2_LAYOUT_TYPES)
#else
#define PNFSD_SUPPORTED_ATTRS_WORD1	0
#define PNFSD_SUPPORTED_ATTRS_WORD2	0
#endif /* CONFIG_NFSD_PNFS */

#define NFSD4_1_SUPPORTED_ATTRS_WORD0 \
	NFSD4_SUPPORTED_ATTRS_WORD0

#define NFSD4_1_SUPPORTED_ATTRS_WORD1 \
	(NFSD4_SUPPORTED_ATTRS_WORD1	| PNFSD_SUPPORTED_ATTRS_WORD1)

#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
	(NFSD4_SUPPORTED_ATTRS_WORD2	| PNFSD_SUPPORTED_ATTRS_WORD2 | \
	 FATTR4_WORD2_SUPPATTR_EXCLCREAT)

/* 4.2 */
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
#define NFSD4_2_SECURITY_ATTRS		FATTR4_WORD2_SECURITY_LABEL
#else
#define NFSD4_2_SECURITY_ATTRS		0
#endif

#ifdef CONFIG_NFSD_V4_POSIX_ACLS
#define NFSD4_2_POSIX_ACL_ATTRS \
	(FATTR4_WORD2_ACL_TRUEFORM | \
	FATTR4_WORD2_ACL_TRUEFORM_SCOPE | \
	FATTR4_WORD2_POSIX_DEFAULT_ACL | \
	FATTR4_WORD2_POSIX_ACCESS_ACL)
#else
#define NFSD4_2_POSIX_ACL_ATTRS		0
#endif

#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
	(NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
	FATTR4_WORD2_MODE_UMASK | \
	FATTR4_WORD2_CLONE_BLKSIZE | \
	NFSD4_2_SECURITY_ATTRS | \
	FATTR4_WORD2_XATTR_SUPPORT | \
	FATTR4_WORD2_TIME_DELEG_ACCESS | \
	FATTR4_WORD2_TIME_DELEG_MODIFY | \
	FATTR4_WORD2_OPEN_ARGUMENTS | \
	NFSD4_2_POSIX_ACL_ATTRS)

/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
#define NFSD_WRITEONLY_ATTRS_WORD1 \
	(FATTR4_WORD1_TIME_ACCESS_SET   | FATTR4_WORD1_TIME_MODIFY_SET)

/*
 * These are the only attrs allowed in CREATE/OPEN/SETATTR. Don't add
 * a writeable attribute here without also adding code to parse it to
 * nfsd4_decode_fattr4().
 */
#define NFSD_WRITEABLE_ATTRS_WORD0 \
	(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
#define NFSD_WRITEABLE_ATTRS_WORD1 \
	(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
	| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_CREATE \
	| FATTR4_WORD1_TIME_MODIFY_SET)
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
#define MAYBE_FATTR4_WORD2_SECURITY_LABEL \
	FATTR4_WORD2_SECURITY_LABEL
#else
#define MAYBE_FATTR4_WORD2_SECURITY_LABEL 0
#endif
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
#define MAYBE_FATTR4_WORD2_POSIX_ACL_ATTRS \
	FATTR4_WORD2_POSIX_DEFAULT_ACL | FATTR4_WORD2_POSIX_ACCESS_ACL
#else
#define MAYBE_FATTR4_WORD2_POSIX_ACL_ATTRS 0
#endif
#define NFSD_WRITEABLE_ATTRS_WORD2 \
	(FATTR4_WORD2_MODE_UMASK \
	| MAYBE_FATTR4_WORD2_SECURITY_LABEL \
	| FATTR4_WORD2_TIME_DELEG_ACCESS \
	| FATTR4_WORD2_TIME_DELEG_MODIFY \
	| MAYBE_FATTR4_WORD2_POSIX_ACL_ATTRS \
	)

#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
	NFSD_WRITEABLE_ATTRS_WORD0
/*
 * we currently store the exclusive create verifier in the v_{a,m}time
 * attributes so the client can't set these at create time using EXCLUSIVE4_1
 */
#define NFSD_SUPPATTR_EXCLCREAT_WORD1 \
	(NFSD_WRITEABLE_ATTRS_WORD1 & \
	 ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET))
/*
 * The FATTR4_WORD2_TIME_DELEG attributes are not to be allowed for
 * OPEN(create) with EXCLUSIVE4_1. It doesn't make sense to set a
 * delegated timestamp on a new file.
 *
 * This mask includes NFSv4.2-only attributes (e.g., POSIX ACLs).
 * Version filtering occurs via nfsd_suppattrs[] before this mask
 * is applied, so pre-4.2 clients never see unsupported attributes.
 */
#define NFSD_SUPPATTR_EXCLCREAT_WORD2 \
	(NFSD_WRITEABLE_ATTRS_WORD2 & \
	~(FATTR4_WORD2_TIME_DELEG_ACCESS | FATTR4_WORD2_TIME_DELEG_MODIFY))

extern const u32 nfsd_suppattrs[3][3];

static inline bool bmval_is_subset(const u32 *bm1, const u32 *bm2)
{
	return !((bm1[0] & ~bm2[0]) ||
	         (bm1[1] & ~bm2[1]) ||
		 (bm1[2] & ~bm2[2]));
}

static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval)
{
	return bmval_is_subset(bmval, nfsd_suppattrs[minorversion]);
}

#endif /* _LINUX_NFSD_ATTR4_H */
