summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfs')
-rw-r--r--sys/fs/nfs/nfs.h704
-rw-r--r--sys/fs/nfs/nfs_commonacl.c750
-rw-r--r--sys/fs/nfs/nfs_commonkrpc.c901
-rw-r--r--sys/fs/nfs/nfs_commonport.c486
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c3404
-rw-r--r--sys/fs/nfs/nfs_var.h604
-rw-r--r--sys/fs/nfs/nfscl.h71
-rw-r--r--sys/fs/nfs/nfsclstate.h175
-rw-r--r--sys/fs/nfs/nfsdport.h105
-rw-r--r--sys/fs/nfs/nfskpiport.h73
-rw-r--r--sys/fs/nfs/nfsm_subs.h129
-rw-r--r--sys/fs/nfs/nfsport.h751
-rw-r--r--sys/fs/nfs/nfsproto.h1129
-rw-r--r--sys/fs/nfs/nfsrvcache.h107
-rw-r--r--sys/fs/nfs/nfsrvstate.h235
-rw-r--r--sys/fs/nfs/nfsv4_errstr.h101
-rw-r--r--sys/fs/nfs/rpcv2.h207
-rw-r--r--sys/fs/nfs/xdr_subs.h99
18 files changed, 10031 insertions, 0 deletions
diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h
new file mode 100644
index 0000000..8a341ac
--- /dev/null
+++ b/sys/fs/nfs/nfs.h
@@ -0,0 +1,704 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFS_H_
+#define _NFS_NFS_H_
+/*
+ * Tunable constants for nfs
+ */
+
+#define NFS_MAXIOVEC 34
+#define NFS_TICKINTVL 10 /* Desired time for a tick (msec) */
+#define NFS_HZ (hz / nfscl_ticks) /* Ticks/sec */
+#define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */
+#define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */
+#define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */
+#define NFS_TCPTIMEO 300 /* TCP timeout */
+#define NFS_MAXRCVTIMEO 60 /* 1 minute in seconds */
+#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/
+#define NFS_MAXREXMIT 100 /* Stop counting after this many */
+#define NFSV4_CALLBACKTIMEO (2 * NFS_HZ) /* Timeout in ticks */
+#define NFSV4_CALLBACKRETRY 5 /* Number of retries before failure */
+#define NFSV4_CBRETRYCNT 4 /* # of CBRecall retries upon err */
+#define NFSV4_UPCALLTIMEO (15 * NFS_HZ) /* Timeout in ticks for upcalls */
+ /* to gssd or nfsuserd */
+#define NFSV4_UPCALLRETRY 4 /* Number of retries before failure */
+#define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */
+#define NFS_RETRANS 10 /* Num of retrans for soft mounts */
+#define NFS_MAXGRPS 16 /* Max. size of groups list */
+#define NFS_TRYLATERDEL 15 /* Maximum delay timeout (sec) */
+#ifndef NFS_REMOVETIMEO
+#define NFS_REMOVETIMEO 15 /* # sec to wait for delegret in local syscall */
+#endif
+#ifndef NFS_MINATTRTIMO
+#define NFS_MINATTRTIMO 5 /* Attribute cache timeout in sec */
+#endif
+#ifndef NFS_MAXATTRTIMO
+#define NFS_MAXATTRTIMO 60
+#endif
+#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */
+#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */
+#define NFS_READDIRSIZE 8192 /* Def. readdir size */
+#define NFS_DEFRAHEAD 0 /* Def. read ahead # blocks */
+#define NFS_MAXRAHEAD 32 /* Max. read ahead # blocks */
+#define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */
+#ifndef NFSRV_LEASE
+#define NFSRV_LEASE 120 /* Lease time in seconds for V4 */
+#endif /* assigned to nfsrv_lease */
+#ifndef NFSRV_STALELEASE
+#define NFSRV_STALELEASE (5 * nfsrv_lease)
+#endif
+#ifndef NFSRV_MOULDYLEASE
+#define NFSRV_MOULDYLEASE 604800 /* One week (in sec) */
+#endif
+#ifndef NFSCLIENTHASHSIZE
+#define NFSCLIENTHASHSIZE 20 /* Size of server client hash table */
+#endif
+#ifndef NFSLOCKHASHSIZE
+#define NFSLOCKHASHSIZE 20 /* Size of server nfslock hash table */
+#endif
+#define NFSSTATEHASHSIZE 10 /* Size of server stateid hash table */
+#ifndef NFSUSERHASHSIZE
+#define NFSUSERHASHSIZE 30 /* Size of user id hash table */
+#endif
+#ifndef NFSGROUPHASHSIZE
+#define NFSGROUPHASHSIZE 5 /* Size of group id hash table */
+#endif
+#ifndef NFSCLDELEGHIGHWATER
+#define NFSCLDELEGHIGHWATER 10000 /* limit for client delegations */
+#endif
+#ifndef NFSNOOPEN /* Inactive open owner (sec) */
+#define NFSNOOPEN 120
+#endif
+#define NFSRV_LEASEDELTA 15 /* # of seconds to delay beyond lease */
+#define NFS_IDMAXSIZE 4 /* max sizeof (in_addr_t) */
+#ifndef NFSRVCACHE_UDPTIMEOUT
+#define NFSRVCACHE_UDPTIMEOUT 30 /* # of sec to hold cached rpcs(udp) */
+#endif
+#ifndef NFSRVCACHE_UDPHIGHWATER
+#define NFSRVCACHE_UDPHIGHWATER 500 /* Max # of udp cache entries */
+#endif
+#ifndef NFSRVCACHE_TCPTIMEOUT
+#define NFSRVCACHE_TCPTIMEOUT (3600*12) /*#of sec to hold cached rpcs(tcp) */
+#endif
+#ifndef NFSRVCACHE_FLOODLEVEL
+#define NFSRVCACHE_FLOODLEVEL 16384 /* Very high water mark for cache */
+#endif
+#ifndef NFSRV_CLIENTHIGHWATER
+#define NFSRV_CLIENTHIGHWATER 1000
+#endif
+#ifndef NFSRV_MAXDUMPLIST
+#define NFSRV_MAXDUMPLIST 10000
+#endif
+#ifndef NFS_ACCESSCACHESIZE
+#define NFS_ACCESSCACHESIZE 8
+#endif
+#define NFSV4_CBPORT 7745 /* Callback port for testing */
+
+/*
+ * This macro defines the high water mark for issuing V4 delegations.
+ * (It is currently set at a conservative 20% of NFSRV_V4STATELIMIT. This
+ * may want to increase when clients can make more effective use of
+ * delegations.)
+ */
+#define NFSRV_V4DELEGLIMIT(c) (((c) * 5) > NFSRV_V4STATELIMIT)
+
+#define NFS_READDIRBLKSIZ DIRBLKSIZ /* Minimal nm_readdirsize */
+
+/*
+ * Oddballs
+ */
+#define NFS_CMPFH(n, f, s) \
+ ((n)->n_fhp->nfh_len == (s) && !NFSBCMP((n)->n_fhp->nfh_fh, (caddr_t)(f), (s)))
+#define NFSRV_CMPFH(nf, ns, f, s) \
+ ((ns) == (s) && !NFSBCMP((caddr_t)(nf), (caddr_t)(f), (s)))
+#define NFS_CMPTIME(t1, t2) \
+ ((t1).tv_sec == (t2).tv_sec && (t1).tv_nsec == (t2).tv_nsec)
+#define NFS_SETTIME(t) do { \
+ (t).tv_sec = time.tv_sec; (t).tv_nsec = 1000 * time.tv_usec; } while (0)
+#define NFS_SRVMAXDATA(n) \
+ (((n)->nd_flag & (ND_NFSV3 | ND_NFSV4)) ? \
+ NFS_MAXDATA : NFS_V2MAXDATA)
+#define NFS64BITSSET 0xffffffffffffffffull
+#define NFS64BITSMINUS1 0xfffffffffffffffeull
+
+/*
+ * Structures for the nfssvc(2) syscall. Not that anyone but nfsd, mount_nfs
+ * and nfsloaduser should ever try and use it.
+ */
+struct nfsd_args {
+ int sock; /* Socket to serve */
+ caddr_t name; /* Client addr for connection based sockets */
+ int namelen; /* Length of name */
+};
+
+/*
+ * nfsd argument for new krpc.
+ */
+struct nfsd_nfsd_args {
+ const char *principal; /* GSS-API service principal name */
+ int minthreads; /* minimum service thread count */
+ int maxthreads; /* maximum service thread count */
+};
+
+/*
+ * Arguments for use by the callback daemon.
+ */
+struct nfsd_nfscbd_args {
+ const char *principal; /* GSS-API service principal name */
+};
+
+struct nfscbd_args {
+ int sock; /* Socket to serve */
+ caddr_t name; /* Client addr for connection based sockets */
+ int namelen; /* Length of name */
+ u_short port; /* Port# for callbacks */
+};
+
+struct nfsd_idargs {
+ int nid_flag; /* Flags (see below) */
+ uid_t nid_uid; /* user/group id */
+ gid_t nid_gid;
+ int nid_usermax; /* Upper bound on user name cache */
+ int nid_usertimeout;/* User name timeout (minutes) */
+ u_char *nid_name; /* Name */
+ int nid_namelen; /* and its length */
+};
+
+struct nfsd_clid {
+ int nclid_idlen; /* Length of client id */
+ u_char nclid_id[NFSV4_OPAQUELIMIT]; /* and name */
+};
+
+struct nfsd_dumplist {
+ int ndl_size; /* Number of elements */
+ void *ndl_list; /* and the list of elements */
+};
+
+struct nfsd_dumpclients {
+ u_int32_t ndcl_flags; /* LCL_xxx flags */
+ u_int32_t ndcl_nopenowners; /* Number of openowners */
+ u_int32_t ndcl_nopens; /* and opens */
+ u_int32_t ndcl_nlockowners; /* and of lockowners */
+ u_int32_t ndcl_nlocks; /* and of locks */
+ u_int32_t ndcl_ndelegs; /* and of delegations */
+ u_int32_t ndcl_nolddelegs; /* and old delegations */
+ sa_family_t ndcl_addrfam; /* Callback address */
+ union {
+ struct in_addr sin_addr;
+ struct in6_addr sin6_addr;
+ } ndcl_cbaddr;
+ struct nfsd_clid ndcl_clid; /* and client id */
+};
+
+struct nfsd_dumplocklist {
+ char *ndllck_fname; /* File Name */
+ int ndllck_size; /* Number of elements */
+ void *ndllck_list; /* and the list of elements */
+};
+
+struct nfsd_dumplocks {
+ u_int32_t ndlck_flags; /* state flags NFSLCK_xxx */
+ nfsv4stateid_t ndlck_stateid; /* stateid */
+ u_int64_t ndlck_first; /* lock byte range */
+ u_int64_t ndlck_end;
+ struct nfsd_clid ndlck_owner; /* Owner of open/lock */
+ sa_family_t ndlck_addrfam; /* Callback address */
+ union {
+ struct in_addr sin_addr;
+ struct in6_addr sin6_addr;
+ } ndlck_cbaddr;
+ struct nfsd_clid ndlck_clid; /* and client id */
+};
+
+/*
+ * Structure for referral information.
+ */
+struct nfsreferral {
+ u_char *nfr_srvlist; /* List of servers */
+ int nfr_srvcnt; /* number of servers */
+ vnode_t nfr_vp; /* vnode for referral */
+ u_int32_t nfr_dfileno; /* assigned dir inode# */
+};
+
+/*
+ * Flags for lc_flags and opsflags for nfsrv_getclient().
+ */
+#define LCL_NEEDSCONFIRM 0x00000001
+#define LCL_DONTCLEAN 0x00000002
+#define LCL_WAKEUPWANTED 0x00000004
+#define LCL_TCPCALLBACK 0x00000008
+#define LCL_CALLBACKSON 0x00000010
+#define LCL_INDEXNOTOK 0x00000020
+#define LCL_STAMPEDSTABLE 0x00000040
+#define LCL_EXPIREIT 0x00000080
+#define LCL_CBDOWN 0x00000100
+#define LCL_KERBV 0x00000400
+#define LCL_NAME 0x00000800
+#define LCL_NEEDSCBNULL 0x00001000
+#define LCL_GSSINTEGRITY 0x00002000
+#define LCL_GSSPRIVACY 0x00004000
+#define LCL_ADMINREVOKED 0x00008000
+
+#define LCL_GSS LCL_KERBV /* Or of all mechs */
+
+/*
+ * Bits for flags in nfslock and nfsstate.
+ * The access, deny, NFSLCK_READ and NFSLCK_WRITE bits must be defined as
+ * below, in the correct order, so the shifts work for tests.
+ */
+#define NFSLCK_READACCESS 0x00000001
+#define NFSLCK_WRITEACCESS 0x00000002
+#define NFSLCK_ACCESSBITS (NFSLCK_READACCESS | NFSLCK_WRITEACCESS)
+#define NFSLCK_SHIFT 2
+#define NFSLCK_READDENY 0x00000004
+#define NFSLCK_WRITEDENY 0x00000008
+#define NFSLCK_DENYBITS (NFSLCK_READDENY | NFSLCK_WRITEDENY)
+#define NFSLCK_SHAREBITS \
+ (NFSLCK_READACCESS|NFSLCK_WRITEACCESS|NFSLCK_READDENY|NFSLCK_WRITEDENY)
+#define NFSLCK_LOCKSHIFT 4
+#define NFSLCK_READ 0x00000010
+#define NFSLCK_WRITE 0x00000020
+#define NFSLCK_BLOCKING 0x00000040
+#define NFSLCK_RECLAIM 0x00000080
+#define NFSLCK_OPENTOLOCK 0x00000100
+#define NFSLCK_TEST 0x00000200
+#define NFSLCK_LOCK 0x00000400
+#define NFSLCK_UNLOCK 0x00000800
+#define NFSLCK_OPEN 0x00001000
+#define NFSLCK_CLOSE 0x00002000
+#define NFSLCK_CHECK 0x00004000
+#define NFSLCK_RELEASE 0x00008000
+#define NFSLCK_NEEDSCONFIRM 0x00010000
+#define NFSLCK_CONFIRM 0x00020000
+#define NFSLCK_DOWNGRADE 0x00040000
+#define NFSLCK_DELEGREAD 0x00080000
+#define NFSLCK_DELEGWRITE 0x00100000
+#define NFSLCK_DELEGCUR 0x00200000
+#define NFSLCK_DELEGPREV 0x00400000
+#define NFSLCK_OLDDELEG 0x00800000
+#define NFSLCK_DELEGRECALL 0x01000000
+#define NFSLCK_SETATTR 0x02000000
+#define NFSLCK_DELEGPURGE 0x04000000
+#define NFSLCK_DELEGRETURN 0x08000000
+
+/* And bits for nid_flag */
+#define NFSID_INITIALIZE 0x0001
+#define NFSID_ADDUID 0x0002
+#define NFSID_DELUID 0x0004
+#define NFSID_ADDUSERNAME 0x0008
+#define NFSID_DELUSERNAME 0x0010
+#define NFSID_ADDGID 0x0020
+#define NFSID_DELGID 0x0040
+#define NFSID_ADDGROUPNAME 0x0080
+#define NFSID_DELGROUPNAME 0x0100
+
+/*
+ * Stats structure
+ */
+struct nfsstats {
+ int attrcache_hits;
+ int attrcache_misses;
+ int lookupcache_hits;
+ int lookupcache_misses;
+ int direofcache_hits;
+ int direofcache_misses;
+ int accesscache_hits;
+ int accesscache_misses;
+ int biocache_reads;
+ int read_bios;
+ int read_physios;
+ int biocache_writes;
+ int write_bios;
+ int write_physios;
+ int biocache_readlinks;
+ int readlink_bios;
+ int biocache_readdirs;
+ int readdir_bios;
+ int rpccnt[NFS_NPROCS];
+ int rpcretries;
+ int srvrpccnt[NFSV4OP_NOPS + NFSV4OP_FAKENOPS];
+ int srvrpc_errs;
+ int srv_errs;
+ int rpcrequests;
+ int rpctimeouts;
+ int rpcunexpected;
+ int rpcinvalid;
+ int srvcache_inproghits;
+ int srvcache_idemdonehits;
+ int srvcache_nonidemdonehits;
+ int srvcache_misses;
+ int srvcache_tcppeak;
+ int srvcache_size;
+ int srvclients;
+ int srvopenowners;
+ int srvopens;
+ int srvlockowners;
+ int srvlocks;
+ int srvdelegates;
+ int cbrpccnt[NFSV4OP_CBNOPS];
+ int clopenowners;
+ int clopens;
+ int cllockowners;
+ int cllocks;
+ int cldelegates;
+ int cllocalopenowners;
+ int cllocalopens;
+ int cllocallockowners;
+ int cllocallocks;
+};
+
+/*
+ * fs.nfs sysctl(3) identifiers
+ */
+#define NFS_NFSSTATS 1 /* struct: struct nfsstats */
+
+#define FS_NFS_NAMES { \
+ { 0, 0 }, \
+ { "nfsstats", CTLTYPE_STRUCT }, \
+}
+
+/*
+ * Here is the definition of the attribute bits array and macros that
+ * manipulate it.
+ * THE MACROS MUST BE MANUALLY MODIFIED IF NFSATTRBIT_MAXWORDS CHANGES!!
+ * It is (NFSATTRBIT_MAX + 31) / 32.
+ */
+#define NFSATTRBIT_MAXWORDS 2
+
+typedef struct {
+ u_int32_t bits[NFSATTRBIT_MAXWORDS];
+} nfsattrbit_t;
+
+#define NFSZERO_ATTRBIT(b) do { (b)->bits[0] = 0; (b)->bits[1] = 0; } while (0)
+#define NFSSET_ATTRBIT(t, f) do { (t)->bits[0] = (f)->bits[0]; \
+ (t)->bits[1] = (f)->bits[1]; } while (0)
+#define NFSSETSUPP_ATTRBIT(b) do { \
+ (b)->bits[0] = NFSATTRBIT_SUPP0; \
+ (b)->bits[1] = (NFSATTRBIT_SUPP1 | NFSATTRBIT_SUPPSETONLY); } while (0)
+#define NFSISSET_ATTRBIT(b, p) ((b)->bits[(p) / 32] & (1 << ((p) % 32)))
+#define NFSSETBIT_ATTRBIT(b, p) ((b)->bits[(p) / 32] |= (1 << ((p) % 32)))
+#define NFSCLRBIT_ATTRBIT(b, p) ((b)->bits[(p) / 32] &= ~(1 << ((p) % 32)))
+#define NFSCLRALL_ATTRBIT(b, a) do { \
+ (b)->bits[0] &= ~((a)->bits[0]); \
+ (b)->bits[1] &= ~((a)->bits[1]); \
+ } while (0)
+#define NFSCLRNOT_ATTRBIT(b, a) do { \
+ (b)->bits[0] &= ((a)->bits[0]); \
+ (b)->bits[1] &= ((a)->bits[1]); \
+ } while (0)
+#define NFSCLRNOTFILLABLE_ATTRBIT(b) do { \
+ (b)->bits[0] &= NFSATTRBIT_SUPP0; \
+ (b)->bits[1] &= NFSATTRBIT_SUPP1; } while (0)
+#define NFSCLRNOTSETABLE_ATTRBIT(b) do { \
+ (b)->bits[0] &= NFSATTRBIT_SETABLE0; \
+ (b)->bits[1] &= NFSATTRBIT_SETABLE1; } while (0)
+#define NFSNONZERO_ATTRBIT(b) ((b)->bits[0] || (b)->bits[1])
+#define NFSEQUAL_ATTRBIT(b, p) \
+ ((b)->bits[0] == (p)->bits[0] && (b)->bits[1] == (p)->bits[1])
+#define NFSGETATTR_ATTRBIT(b) do { \
+ (b)->bits[0] = NFSATTRBIT_GETATTR0; \
+ (b)->bits[1] = NFSATTRBIT_GETATTR1; } while (0)
+#define NFSWCCATTR_ATTRBIT(b) do { \
+ (b)->bits[0] = NFSATTRBIT_WCCATTR0; \
+ (b)->bits[1] = NFSATTRBIT_WCCATTR1; } while (0)
+#define NFSWRITEGETATTR_ATTRBIT(b) do { \
+ (b)->bits[0] = NFSATTRBIT_WRITEGETATTR0; \
+ (b)->bits[1] = NFSATTRBIT_WRITEGETATTR1; } while (0)
+#define NFSCBGETATTR_ATTRBIT(b, c) do { \
+ (c)->bits[0] = ((b)->bits[0] & NFSATTRBIT_CBGETATTR0); \
+ (c)->bits[1] = ((b)->bits[1] & NFSATTRBIT_CBGETATTR1); } while (0)
+#define NFSPATHCONF_GETATTRBIT(b) do { \
+ (b)->bits[0] = NFSGETATTRBIT_PATHCONF0; \
+ (b)->bits[1] = NFSGETATTRBIT_PATHCONF1; } while (0)
+#define NFSSTATFS_GETATTRBIT(b) do { \
+ (b)->bits[0] = NFSGETATTRBIT_STATFS0; \
+ (b)->bits[1] = NFSGETATTRBIT_STATFS1; } while (0)
+#define NFSISSETSTATFS_ATTRBIT(b) \
+ (((b)->bits[0] & NFSATTRBIT_STATFS0) || \
+ ((b)->bits[1] & NFSATTRBIT_STATFS1))
+#define NFSCLRSTATFS_ATTRBIT(b) do { \
+ (b)->bits[0] &= ~NFSATTRBIT_STATFS0; \
+ (b)->bits[1] &= ~NFSATTRBIT_STATFS1; } while (0)
+#define NFSREADDIRPLUS_ATTRBIT(b) do { \
+ (b)->bits[0] = NFSATTRBIT_READDIRPLUS0; \
+ (b)->bits[1] = NFSATTRBIT_READDIRPLUS1; } while (0)
+#define NFSREFERRAL_ATTRBIT(b) do { \
+ (b)->bits[0] = NFSATTRBIT_REFERRAL0; \
+ (b)->bits[1] = NFSATTRBIT_REFERRAL1; } while (0)
+
+/*
+ * Store uid, gid creds that handle maps to.
+ * Since some BSDen define cr_gid as cr_groups[0], I'll just keep them
+ * all in nfsc_groups[NGROUPS + 1].
+ */
+struct nfscred {
+ uid_t nfsc_uid;
+ gid_t nfsc_groups[NGROUPS + 1];
+ int nfsc_ngroups;
+};
+
+/*
+ * Constants that define the file handle for the V4 root directory.
+ * (The FSID must never be used by other file systems that are exported.)
+ */
+#define NFSV4ROOT_FSID0 ((int32_t) -1)
+#define NFSV4ROOT_FSID1 ((int32_t) -1)
+#define NFSV4ROOT_REFERRAL ((int32_t) -2)
+#define NFSV4ROOT_INO 2 /* It's traditional */
+#define NFSV4ROOT_GEN 1
+
+/*
+ * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts.
+ * What should be in this set is open to debate, but I believe that since
+ * I/O system calls on ufs are never interrupted by signals the set should
+ * be minimal. My reasoning is that many current programs that use signals
+ * such as SIGALRM will not expect file I/O system calls to be interrupted
+ * by them and break.
+ */
+#if defined(_KERNEL) || defined(KERNEL)
+
+struct uio; struct buf; struct vattr; struct nameidata; /* XXX */
+
+/*
+ * Socket errors ignored for connectionless sockets?
+ * For now, ignore them all
+ */
+#define NFSIGNORE_SOERROR(s, e) \
+ ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK && \
+ ((s) & PR_CONNREQUIRED) == 0)
+
+
+/*
+ * This structure holds socket information for a connection. Used by the
+ * client and the server for callbacks.
+ */
+struct nfssockreq {
+ NFSSOCKADDR_T nr_nam;
+ int nr_sotype;
+ int nr_soproto;
+ int nr_soflags;
+ struct ucred *nr_cred;
+ int nr_lock;
+ NFSMUTEX_T nr_mtx;
+ u_int32_t nr_prog;
+ u_int32_t nr_vers;
+ struct __rpc_client *nr_client;
+};
+
+/*
+ * And associated nr_lock bits.
+ */
+#define NFSR_SNDLOCK 0x01
+#define NFSR_WANTSND 0x02
+#define NFSR_RCVLOCK 0x04
+#define NFSR_WANTRCV 0x08
+#define NFSR_RESERVEDPORT 0x10
+#define NFSR_LOCALHOST 0x20
+
+/*
+ * Queue head for nfsreq's
+ */
+TAILQ_HEAD(nfsreqhead, nfsreq);
+
+/* First 8 R_xxx flags defined in rpc/rpcclnt.h, the rest are here */
+#define R_DONTRECOVER 0x00000100 /* don't initiate recovery when this
+ rpc gets a stale state reply */
+
+/*
+ * Network address hash list element
+ */
+union nethostaddr {
+ struct in_addr had_inet;
+ struct in6_addr had_inet6;
+};
+
+/*
+ * Structure of list of mechanisms.
+ */
+struct nfsgss_mechlist {
+ int len;
+ const u_char *str;
+ int totlen;
+};
+#define KERBV_MECH 0 /* position in list */
+
+/*
+ * This structure is used by the server for describing each request.
+ */
+struct nfsrv_descript {
+ mbuf_t nd_mrep; /* Request mbuf list */
+ mbuf_t nd_md; /* Current dissect mbuf */
+ mbuf_t nd_mreq; /* Reply mbuf list */
+ mbuf_t nd_mb; /* Current build mbuf */
+ NFSSOCKADDR_T nd_nam; /* and socket addr */
+ NFSSOCKADDR_T nd_nam2; /* return socket addr */
+ caddr_t nd_dpos; /* Current dissect pos */
+ caddr_t nd_bpos; /* Current build pos */
+ u_int16_t nd_procnum; /* RPC # */
+ u_int32_t nd_flag; /* nd_flag */
+ u_int32_t nd_repstat; /* Reply status */
+ int *nd_errp; /* Pointer to ret status */
+ u_int32_t nd_retxid; /* Reply xid */
+ struct nfsrvcache *nd_rp; /* Assoc. cache entry */
+ struct timeval nd_starttime; /* Time RPC initiated */
+ fhandle_t nd_fh; /* File handle */
+ struct ucred *nd_cred; /* Credentials */
+ uid_t nd_saveduid; /* Saved uid */
+ u_int64_t nd_sockref; /* Rcv socket ref# */
+ u_int64_t nd_compref; /* Compound RPC ref# */
+ time_t nd_tcpconntime; /* Time TCP connection est. */
+ nfsquad_t nd_clientid; /* Implied clientid */
+ int nd_credflavor; /* credential flavor */
+ int nd_gssnamelen; /* principal name length */
+ char *nd_gssname; /* principal name */
+};
+
+#define nd_princlen nd_gssnamelen
+#define nd_principal nd_gssname
+
+/* Bits for "nd_flag" */
+#define ND_DONTSAVEREPLY 0x00000001
+#define ND_SAVEREPLY 0x00000002
+#define ND_NFSV2 0x00000004
+#define ND_NFSV3 0x00000008
+#define ND_NFSV4 0x00000010
+#define ND_KERBV 0x00000020
+#define ND_GSSINTEGRITY 0x00000040
+#define ND_GSSPRIVACY 0x00000080
+#define ND_WINDOWVERF 0x00000100
+#define ND_GSSINITREPLY 0x00000200
+#define ND_STREAMSOCK 0x00000400
+#define ND_PUBLOOKUP 0x00000800
+#define ND_USEGSSNAME 0x00001000
+#define ND_SAMETCPCONN 0x00002000
+#define ND_IMPLIEDCLID 0x00004000
+#define ND_NOMOREDATA 0x00008000
+#define ND_V4WCCATTR 0x00010000
+#define ND_NFSCB 0x00020000
+#define ND_AUTHNONE 0x00040000
+#define ND_EXGSSONLY 0x00080000
+#define ND_INCRSEQID 0x00100000
+
+/*
+ * ND_GSS should be the "or" of all GSS type authentications.
+ */
+#define ND_GSS (ND_KERBV)
+
+struct nfsv4_opflag {
+ int retfh;
+ int needscfh;
+ int savereply;
+ int modifyfs;
+};
+
+/*
+ * Flags used to indicate what to do w.r.t. seqid checking.
+ */
+#define NFSRVSEQID_FIRST 0x01
+#define NFSRVSEQID_LAST 0x02
+#define NFSRVSEQID_OPEN 0x04
+
+/*
+ * MNT_EXGSSONLY is the Or of all the EXGSS bits.
+ */
+#define MNT_EXGSSONLY MNT_EXGSSKRB5
+
+/*
+ * assign a doubly linked list to a new head
+ * and prepend one list into another.
+ */
+#define LIST_NEWHEAD(nhead, ohead, field) do { \
+ if (((nhead)->lh_first = (ohead)->lh_first) != NULL) \
+ (ohead)->lh_first->field.le_prev = &(nhead)->lh_first; \
+ (ohead)->lh_first = NULL; \
+ } while (0)
+
+#define LIST_PREPEND(head, phead, lelm, field) do { \
+ if ((head)->lh_first != NULL) { \
+ (lelm)->field.le_next = (head)->lh_first; \
+ (lelm)->field.le_next->field.le_prev = \
+ &(lelm)->field.le_next; \
+ } \
+ (head)->lh_first = (phead)->lh_first; \
+ (head)->lh_first->field.le_prev = &(head)->lh_first; \
+ } while (0)
+
+/*
+ * File handle structure for client. Malloc'd to the correct length with
+ * malloc type M_NFSFH.
+ */
+struct nfsfh {
+ u_int16_t nfh_len; /* Length of file handle */
+ u_int8_t nfh_fh[1]; /* and the file handle */
+};
+
+/*
+ * File handle structure for server. The NFSRV_MAXFH constant is
+ * set in nfsdport.h. I use a 32bit length, so that alignment is
+ * preserved.
+ */
+struct nfsrvfh {
+ u_int32_t nfsrvfh_len;
+ u_int8_t nfsrvfh_data[NFSRV_MAXFH];
+};
+
+/*
+ * This structure is used for sleep locks on the NFSv4 nfsd threads and
+ * NFSv4 client data structures.
+ */
+struct nfsv4lock {
+ u_int32_t nfslock_usecnt;
+ u_int8_t nfslock_lock;
+};
+#define NFSV4LOCK_LOCK 0x01
+#define NFSV4LOCK_LOCKWANTED 0x02
+#define NFSV4LOCK_WANTED 0x04
+
+/*
+ * Values for the override argument for nfsvno_accchk().
+ */
+#define NFSACCCHK_NOOVERRIDE 0
+#define NFSACCCHK_ALLOWROOT 1
+#define NFSACCCHK_ALLOWOWNER 2
+
+/*
+ * and values for the vpislocked argument for nfsvno_accchk().
+ */
+#define NFSACCCHK_VPNOTLOCKED 0
+#define NFSACCCHK_VPISLOCKED 1
+
+#endif /* _KERNEL */
+
+#endif /* _NFS_NFS_H */
diff --git a/sys/fs/nfs/nfs_commonacl.c b/sys/fs/nfs/nfs_commonacl.c
new file mode 100644
index 0000000..9ebfd32
--- /dev/null
+++ b/sys/fs/nfs/nfs_commonacl.c
@@ -0,0 +1,750 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef APPLEKEXT
+#include <fs/nfs/nfsport.h>
+
+extern int nfsrv_useacl;
+#endif
+
+static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
+ enum vtype type, acl_perm_t *permp);
+
+#if defined(NFS4_ACL_EXTATTR_NAME)
+/*
+ * Handle xdr for an ace.
+ */
+APPLESTATIC int
+nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
+ int *aceerrp, int *acesizep, NFSPROC_T *p)
+{
+ u_int32_t *tl;
+ int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
+ u_char *name, namestr[NFSV4_SMALLSTR + 1];
+ u_int32_t flag, mask, acetype;
+ gid_t gid;
+ uid_t uid;
+
+ *aceerrp = 0;
+ acep->ae_flags = 0;
+ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
+ acetype = fxdr_unsigned(u_int32_t, *tl++);
+ flag = fxdr_unsigned(u_int32_t, *tl++);
+ mask = fxdr_unsigned(u_int32_t, *tl++);
+ len = fxdr_unsigned(int, *tl);
+ if (len < 0) {
+ return (NFSERR_BADXDR);
+ } else if (len == 0) {
+ /* Netapp filers return a 0 length who for nil users */
+ acep->ae_tag = ACL_UNDEFINED_TAG;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ acep->ae_perm = (acl_perm_t)0;
+ acep->ae_extended = ACL_EXTENDED_DENY;
+ if (acesizep)
+ *acesizep = 4 * NFSX_UNSIGNED;
+ return (0);
+ }
+ if (len > NFSV4_SMALLSTR)
+ name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
+ else
+ name = namestr;
+ error = nfsrv_mtostr(nd, name, len);
+ if (error) {
+ if (len > NFSV4_SMALLSTR)
+ free(name, M_NFSSTRING);
+ return (error);
+ }
+ if (len == 6) {
+ if (!NFSBCMP(name, "OWNER@", 6)) {
+ acep->ae_tag = ACL_USER_OBJ;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ owner = 1;
+ gotid = 1;
+ } else if (!NFSBCMP(name, "GROUP@", 6)) {
+ acep->ae_tag = ACL_GROUP_OBJ;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ gotid = 1;
+ }
+ } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) {
+ acep->ae_tag = ACL_EVERYONE;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ gotid = 1;
+ }
+ if (gotid == 0) {
+ if (flag & NFSV4ACE_IDENTIFIERGROUP) {
+ acep->ae_tag = ACL_GROUP;
+ aceerr = nfsv4_strtogid(name, len, &gid, p);
+ if (aceerr == 0)
+ acep->ae_id = (uid_t)gid;
+ } else {
+ acep->ae_tag = ACL_USER;
+ aceerr = nfsv4_strtouid(name, len, &uid, p);
+ if (aceerr == 0)
+ acep->ae_id = uid;
+ }
+ }
+ if (len > NFSV4_SMALLSTR)
+ free(name, M_NFSSTRING);
+
+ if (aceerr == 0) {
+ /*
+ * Handle the flags.
+ */
+ flag &= ~NFSV4ACE_IDENTIFIERGROUP;
+ if (flag & NFSV4ACE_FILEINHERIT) {
+ flag &= ~NFSV4ACE_FILEINHERIT;
+ acep->ae_flags |= ACL_ENTRY_FILE_INHERIT;
+ }
+ if (flag & NFSV4ACE_DIRECTORYINHERIT) {
+ flag &= ~NFSV4ACE_DIRECTORYINHERIT;
+ acep->ae_flags |= ACL_ENTRY_DIRECTORY_INHERIT;
+ }
+ if (flag & NFSV4ACE_NOPROPAGATEINHERIT) {
+ flag &= ~NFSV4ACE_NOPROPAGATEINHERIT;
+ acep->ae_flags |= ACL_ENTRY_LIMIT_INHERIT;
+ }
+ if (flag & NFSV4ACE_INHERITONLY) {
+ flag &= ~NFSV4ACE_INHERITONLY;
+ acep->ae_flags |= ACL_ENTRY_ONLY_INHERIT;
+ }
+ if (flag & NFSV4ACE_SUCCESSFULACCESS) {
+ flag &= ~NFSV4ACE_SUCCESSFULACCESS;
+ acep->ae_flags |= ACL_ENTRY_SUCCESSFUL_ACCESS;
+ }
+ if (flag & NFSV4ACE_FAILEDACCESS) {
+ flag &= ~NFSV4ACE_FAILEDACCESS;
+ acep->ae_flags |= ACL_ENTRY_FAILED_ACCESS;
+ }
+ /*
+ * Set ae_extended.
+ */
+ if (acetype == NFSV4ACE_ALLOWEDTYPE)
+ acep->ae_extended = ACL_EXTENDED_ALLOW;
+ else if (acetype == NFSV4ACE_DENIEDTYPE)
+ acep->ae_extended = ACL_EXTENDED_DENY;
+ else if (acetype == NFSV4ACE_AUDITTYPE)
+ acep->ae_extended = ACL_EXTENDED_AUDIT;
+ else if (acetype == NFSV4ACE_ALARMTYPE)
+ acep->ae_extended = ACL_EXTENDED_ALARM;
+ else
+ aceerr = NFSERR_ATTRNOTSUPP;
+ }
+
+ /*
+ * Now, check for unsupported flag bits.
+ */
+ if (aceerr == 0 && flag != 0)
+ aceerr = NFSERR_ATTRNOTSUPP;
+
+ /*
+ * And turn the mask into perm bits.
+ */
+ if (aceerr == 0)
+ aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG,
+ &acep->ae_perm);
+ *aceerrp = aceerr;
+ if (acesizep)
+ *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
+ return (0);
+nfsmout:
+ return (error);
+}
+
+/*
+ * Turn an NFSv4 ace mask into R/W/X flag bits.
+ */
+static int
+nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
+ enum vtype type, acl_perm_t *permp)
+{
+ acl_perm_t perm = 0x0;
+
+ if (mask & NFSV4ACE_READDATA) {
+ mask &= ~NFSV4ACE_READDATA;
+ perm |= ACL_READ_DATA;
+ }
+ if (mask & NFSV4ACE_LISTDIRECTORY) {
+ mask &= ~NFSV4ACE_LISTDIRECTORY;
+ perm |= ACL_LIST_DIRECTORY;
+ }
+ if (mask & NFSV4ACE_WRITEDATA) {
+ mask &= ~NFSV4ACE_WRITEDATA;
+ perm |= ACL_WRITE_DATA;
+ }
+ if (mask & NFSV4ACE_ADDFILE) {
+ mask &= ~NFSV4ACE_ADDFILE;
+ perm |= ACL_ADD_FILE;
+ }
+ if (mask & NFSV4ACE_APPENDDATA) {
+ mask &= ~NFSV4ACE_APPENDDATA;
+ perm |= ACL_APPEND_DATA;
+ }
+ if (mask & NFSV4ACE_ADDSUBDIRECTORY) {
+ mask &= ~NFSV4ACE_ADDSUBDIRECTORY;
+ perm |= ACL_ADD_SUBDIRECTORY;
+ }
+ if (mask & NFSV4ACE_READNAMEDATTR) {
+ mask &= ~NFSV4ACE_READNAMEDATTR;
+ perm |= ACL_READ_NAMED_ATTRS;
+ }
+ if (mask & NFSV4ACE_WRITENAMEDATTR) {
+ mask &= ~NFSV4ACE_WRITENAMEDATTR;
+ perm |= ACL_WRITE_NAMED_ATTRS;
+ }
+ if (mask & NFSV4ACE_EXECUTE) {
+ mask &= ~NFSV4ACE_EXECUTE;
+ perm |= ACL_EXECUTE;
+ }
+ if (mask & NFSV4ACE_SEARCH) {
+ mask &= ~NFSV4ACE_SEARCH;
+ perm |= ACL_SEARCH;
+ }
+ if (mask & NFSV4ACE_DELETECHILD) {
+ mask &= ~NFSV4ACE_DELETECHILD;
+ perm |= ACL_DELETE_CHILD;
+ }
+ if (mask & NFSV4ACE_READATTRIBUTES) {
+ mask &= ~NFSV4ACE_READATTRIBUTES;
+ perm |= ACL_READ_ATTRIBUTES;
+ }
+ if (mask & NFSV4ACE_WRITEATTRIBUTES) {
+ mask &= ~NFSV4ACE_WRITEATTRIBUTES;
+ perm |= ACL_WRITE_ATTRIBUTES;
+ }
+ if (mask & NFSV4ACE_DELETE) {
+ mask &= ~NFSV4ACE_DELETE;
+ perm |= ACL_DELETE;
+ }
+ if (mask & NFSV4ACE_READACL) {
+ mask &= ~NFSV4ACE_READACL;
+ perm |= ACL_READ_ACL;
+ }
+ if (mask & NFSV4ACE_WRITEACL) {
+ mask &= ~NFSV4ACE_WRITEACL;
+ perm |= ACL_WRITE_ACL;
+ }
+ if (mask & NFSV4ACE_WRITEOWNER) {
+ mask &= ~NFSV4ACE_WRITEOWNER;
+ perm |= ACL_WRITE_OWNER;
+ }
+ if (mask & NFSV4ACE_SYNCHRONIZE) {
+ mask &= ~NFSV4ACE_SYNCHRONIZE;
+ perm |= ACL_SYNCHRONIZE;
+ }
+ if (mask != 0)
+ return (NFSERR_ATTRNOTSUPP);
+ *permp = perm;
+ return (0);
+}
+#else
+/*
+ * Handle xdr for an ace.
+ */
+APPLESTATIC int
+nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
+ int *aceerrp, int *acesizep, NFSPROC_T *p)
+{
+ u_int32_t *tl;
+ int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
+ u_char *name, namestr[NFSV4_SMALLSTR + 1];
+ u_int32_t flag, mask, acetype;
+ gid_t gid;
+ uid_t uid;
+
+ *aceerrp = 0;
+ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
+ acetype = fxdr_unsigned(u_int32_t, *tl++);
+ flag = fxdr_unsigned(u_int32_t, *tl++);
+ mask = fxdr_unsigned(u_int32_t, *tl++);
+ len = fxdr_unsigned(int, *tl);
+ if (len < 0) {
+ return (NFSERR_BADXDR);
+ } else if (len == 0) {
+ /* Netapp filers return a 0 length who for nil users */
+ acep->ae_tag = ACL_UNDEFINED_TAG;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ acep->ae_perm = (acl_perm_t)0;
+ if (acesizep)
+ *acesizep = 4 * NFSX_UNSIGNED;
+ return (0);
+ }
+ if (len > NFSV4_SMALLSTR)
+ name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
+ else
+ name = namestr;
+ error = nfsrv_mtostr(nd, name, len);
+ if (error) {
+ if (len > NFSV4_SMALLSTR)
+ free(name, M_NFSSTRING);
+ return (error);
+ }
+ if (len == 6) {
+ if (!NFSBCMP(name, "OWNER@", 6)) {
+ acep->ae_tag = ACL_USER_OBJ;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ owner = 1;
+ gotid = 1;
+ } else if (!NFSBCMP(name, "GROUP@", 6)) {
+ acep->ae_tag = ACL_GROUP_OBJ;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ gotid = 1;
+ flag &= ~NFSV4ACE_IDENTIFIERGROUP;
+ }
+ } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) {
+ acep->ae_tag = ACL_OTHER;
+ acep->ae_id = ACL_UNDEFINED_ID;
+ gotid = 1;
+ }
+ if (!gotid) {
+ if (flag & NFSV4ACE_IDENTIFIERGROUP) {
+ flag &= ~NFSV4ACE_IDENTIFIERGROUP;
+ acep->ae_tag = ACL_GROUP;
+ aceerr = nfsv4_strtogid(name, len, &gid, p);
+ if (!aceerr)
+ acep->ae_id = (uid_t)gid;
+ } else {
+ acep->ae_tag = ACL_USER;
+ aceerr = nfsv4_strtouid(name, len, &uid, p);
+ if (!aceerr)
+ acep->ae_id = uid;
+ }
+ }
+ if (len > NFSV4_SMALLSTR)
+ free(name, M_NFSSTRING);
+
+ /*
+ * Now, check for unsupported types or flag bits.
+ */
+ if (!aceerr && ((acetype != NFSV4ACE_ALLOWEDTYPE &&
+ acetype != NFSV4ACE_AUDITTYPE && acetype != NFSV4ACE_ALARMTYPE
+ && acetype != NFSV4ACE_DENIEDTYPE) || flag))
+ aceerr = NFSERR_ATTRNOTSUPP;
+
+ /*
+ * And turn the mask into perm bits.
+ */
+ if (!aceerr)
+ aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG,
+ &acep->ae_perm);
+ *aceerrp = aceerr;
+ if (acesizep)
+ *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
+ return (0);
+nfsmout:
+ return (error);
+}
+
+/*
+ * Turn an NFSv4 ace mask into R/W/X flag bits.
+ */
+static int
+nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
+ enum vtype type, acl_perm_t *permp)
+{
+ acl_perm_t perm = 0x0;
+
+ if (acetype != NFSV4ACE_ALLOWEDTYPE && acetype != NFSV4ACE_DENIEDTYPE){
+ if (mask & ~NFSV4ACE_AUDITMASK)
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ if (mask & NFSV4ACE_DELETE) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ if (acetype == NFSV4ACE_DENIEDTYPE) {
+ if (mask & NFSV4ACE_ALLFILESMASK) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ if (owner) {
+ if (mask & NFSV4ACE_OWNERMASK) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ } else {
+ if ((mask & NFSV4ACE_OWNERMASK) != NFSV4ACE_OWNERMASK) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ mask &= ~NFSV4ACE_OWNERMASK;
+ }
+ } else if (acetype == NFSV4ACE_ALLOWEDTYPE) {
+ if ((mask & NFSV4ACE_ALLFILESMASK) != NFSV4ACE_ALLFILESMASK) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ mask &= ~NFSV4ACE_ALLFILESMASK;
+ if (owner) {
+ if ((mask & NFSV4ACE_OWNERMASK) != NFSV4ACE_OWNERMASK) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ mask &= ~NFSV4ACE_OWNERMASK;
+ } else if (mask & NFSV4ACE_OWNERMASK) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ }
+ if (type == VDIR) {
+ if ((mask & NFSV4ACE_DIRREADMASK) == NFSV4ACE_DIRREADMASK) {
+ perm |= ACL_READ;
+ mask &= ~NFSV4ACE_DIRREADMASK;
+ }
+ if ((mask & NFSV4ACE_DIRWRITEMASK) == NFSV4ACE_DIRWRITEMASK) {
+ perm |= ACL_WRITE;
+ mask &= ~NFSV4ACE_DIRWRITEMASK;
+ }
+ if ((mask & NFSV4ACE_DIREXECUTEMASK)==NFSV4ACE_DIREXECUTEMASK){
+ perm |= ACL_EXECUTE;
+ mask &= ~NFSV4ACE_DIREXECUTEMASK;
+ }
+ } else {
+ if (acetype == NFSV4ACE_DENIEDTYPE &&
+ (mask & NFSV4ACE_SYNCHRONIZE)) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ mask &= ~(NFSV4ACE_SYNCHRONIZE | NFSV4ACE_DELETECHILD);
+ if ((mask & NFSV4ACE_READMASK) == NFSV4ACE_READMASK) {
+ perm |= ACL_READ;
+ mask &= ~NFSV4ACE_READMASK;
+ }
+ if ((mask & NFSV4ACE_WRITEMASK) == NFSV4ACE_WRITEMASK) {
+ perm |= ACL_WRITE;
+ mask &= ~NFSV4ACE_WRITEMASK;
+ }
+ if ((mask & NFSV4ACE_EXECUTEMASK) == NFSV4ACE_EXECUTEMASK) {
+ perm |= ACL_EXECUTE;
+ mask &= ~NFSV4ACE_EXECUTEMASK;
+ }
+ }
+ if (mask) {
+ return (NFSERR_ATTRNOTSUPP);
+ }
+ *permp = perm;
+ return (0);
+}
+#endif /* !NFS4_ACL_EXTATTR_NAME */
+
+#ifdef NFS4_ACL_EXTATTR_NAME
+/* local functions */
+static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int,
+ enum vtype, int, int, struct acl_entry *);
+
+/*
+ * This function builds an NFS ace.
+ */
+static int
+nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen,
+ enum vtype type, int group, int owner, struct acl_entry *ace)
+{
+ u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype;
+ int full_len;
+
+ full_len = NFSM_RNDUP(namelen);
+ NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len);
+
+ /*
+ * Fill in the ace type.
+ */
+ if (ace->ae_extended & ACL_EXTENDED_ALLOW)
+ acetype = NFSV4ACE_ALLOWEDTYPE;
+ else if (ace->ae_extended & ACL_EXTENDED_DENY)
+ acetype = NFSV4ACE_DENIEDTYPE;
+ else if (ace->ae_extended & ACL_EXTENDED_AUDIT)
+ acetype = NFSV4ACE_AUDITTYPE;
+ else
+ acetype = NFSV4ACE_ALARMTYPE;
+ *tl++ = txdr_unsigned(acetype);
+
+ /*
+ * Set the flag bits from the ACL.
+ */
+ if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT)
+ aceflag |= NFSV4ACE_FILEINHERIT;
+ if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT)
+ aceflag |= NFSV4ACE_DIRECTORYINHERIT;
+ if (ace->ae_flags & ACL_ENTRY_LIMIT_INHERIT)
+ aceflag |= NFSV4ACE_NOPROPAGATEINHERIT;
+ if (ace->ae_flags & ACL_ENTRY_ONLY_INHERIT)
+ aceflag |= NFSV4ACE_INHERITONLY;
+ if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS)
+ aceflag |= NFSV4ACE_SUCCESSFULACCESS;
+ if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS)
+ aceflag |= NFSV4ACE_FAILEDACCESS;
+ if (group)
+ aceflag |= NFSV4ACE_IDENTIFIERGROUP;
+ *tl++ = txdr_unsigned(aceflag);
+ if (type == VDIR) {
+ if (ace->ae_perm & ACL_LIST_DIRECTORY)
+ acemask |= NFSV4ACE_LISTDIRECTORY;
+ if (ace->ae_perm & ACL_ADD_FILE)
+ acemask |= NFSV4ACE_ADDFILE;
+ if (ace->ae_perm & ACL_ADD_SUBDIRECTORY)
+ acemask |= NFSV4ACE_ADDSUBDIRECTORY;
+ if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
+ acemask |= NFSV4ACE_READNAMEDATTR;
+ if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
+ acemask |= NFSV4ACE_WRITENAMEDATTR;
+ if (ace->ae_perm & ACL_SEARCH)
+ acemask |= NFSV4ACE_SEARCH;
+ if (ace->ae_perm & ACL_DELETE_CHILD)
+ acemask |= NFSV4ACE_DELETECHILD;
+ if (ace->ae_perm & ACL_READ_ATTRIBUTES)
+ acemask |= NFSV4ACE_READATTRIBUTES;
+ if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
+ acemask |= NFSV4ACE_WRITEATTRIBUTES;
+ if (ace->ae_perm & ACL_DELETE)
+ acemask |= NFSV4ACE_DELETE;
+ if (ace->ae_perm & ACL_READ_ACL)
+ acemask |= NFSV4ACE_READACL;
+ if (ace->ae_perm & ACL_WRITE_ACL)
+ acemask |= NFSV4ACE_WRITEACL;
+ if (ace->ae_perm & ACL_WRITE_OWNER)
+ acemask |= NFSV4ACE_WRITEOWNER;
+ } else {
+ if (ace->ae_perm & ACL_READ_DATA)
+ acemask |= NFSV4ACE_READDATA;
+ if (ace->ae_perm & ACL_WRITE_DATA)
+ acemask |= NFSV4ACE_WRITEDATA;
+ if (ace->ae_perm & ACL_APPEND_DATA)
+ acemask |= NFSV4ACE_APPENDDATA;
+ if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
+ acemask |= NFSV4ACE_READNAMEDATTR;
+ if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
+ acemask |= NFSV4ACE_WRITENAMEDATTR;
+ if (ace->ae_perm & ACL_EXECUTE)
+ acemask |= NFSV4ACE_EXECUTE;
+ if (ace->ae_perm & ACL_READ_ATTRIBUTES)
+ acemask |= NFSV4ACE_READATTRIBUTES;
+ if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
+ acemask |= NFSV4ACE_WRITEATTRIBUTES;
+ if (ace->ae_perm & ACL_DELETE)
+ acemask |= NFSV4ACE_DELETE;
+ if (ace->ae_perm & ACL_READ_ACL)
+ acemask |= NFSV4ACE_READACL;
+ if (ace->ae_perm & ACL_WRITE_ACL)
+ acemask |= NFSV4ACE_WRITEACL;
+ if (ace->ae_perm & ACL_WRITE_OWNER)
+ acemask |= NFSV4ACE_WRITEOWNER;
+ if (ace->ae_perm & ACL_SYNCHRONIZE)
+ acemask |= NFSV4ACE_SYNCHRONIZE;
+ }
+ *tl++ = txdr_unsigned(acemask);
+ *tl++ = txdr_unsigned(namelen);
+ if (full_len - namelen)
+ *(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
+ NFSBCOPY(name, (caddr_t)tl, namelen);
+ return (full_len + 4 * NFSX_UNSIGNED);
+}
+
+/*
+ * Build an NFSv4 ACL.
+ */
+APPLESTATIC int
+nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type,
+ NFSPROC_T *p)
+{
+ int i, entrycnt = 0, retlen;
+ u_int32_t *entrycntp;
+ int isowner, isgroup, namelen, malloced;
+ u_char *name, namestr[NFSV4_SMALLSTR];
+
+ NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED);
+ retlen = NFSX_UNSIGNED;
+ /*
+ * Loop through the acl entries, building each one.
+ */
+ for (i = 0; i < aclp->acl_cnt; i++) {
+ isowner = isgroup = malloced = 0;
+ switch (aclp->acl_entry[i].ae_tag) {
+ case ACL_USER_OBJ:
+ isowner = 1;
+ name = "OWNER@";
+ namelen = 6;
+ break;
+ case ACL_GROUP_OBJ:
+ isgroup = 1;
+ name = "GROUP@";
+ namelen = 6;
+ break;
+ case ACL_EVERYONE:
+ name = "EVERYONE@";
+ namelen = 9;
+ break;
+ case ACL_USER:
+ name = namestr;
+ nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
+ &namelen, p);
+ if (name != namestr)
+ malloced = 1;
+ break;
+ case ACL_GROUP:
+ isgroup = 1;
+ name = namestr;
+ nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
+ &namelen, p);
+ if (name != namestr)
+ malloced = 1;
+ break;
+ default:
+ continue;
+ };
+ retlen += nfsrv_buildace(nd, name, namelen, type, isgroup,
+ isowner, &aclp->acl_entry[i]);
+ entrycnt++;
+ if (malloced)
+ free(name, M_NFSSTRING);
+ }
+ *entrycntp = txdr_unsigned(entrycnt);
+ return (retlen);
+}
+
+/*
+ * Check access for an NFSv4 acl.
+ * The vflags are the basic VREAD, VWRITE, VEXEC. The mask is the NFSV4ACE
+ * mask bits for the more detailed check.
+ * If the more detailed check fails, due to no acl, do a basic one.
+ */
+APPLESTATIC int
+nfsrv_aclaccess(vnode_t vp, accmode_t vflags, u_int32_t mask,
+ struct ucred *cred, NFSPROC_T *p)
+{
+ int error = 0;
+ accmode_t access;
+
+ if (nfsrv_useacl == 0) {
+ error = VOP_ACCESS(vp, vflags, cred, p);
+ return (error);
+ }
+
+ /* Convert NFSV4ACE mask to vaccess_t */
+ access = 0;
+ if (mask & NFSV4ACE_READDATA)
+ access |= VREAD;
+ if (mask & NFSV4ACE_LISTDIRECTORY)
+ access |= VREAD;
+ if (mask & NFSV4ACE_WRITEDATA)
+ access |= VWRITE;
+ if (mask & NFSV4ACE_ADDFILE)
+ access |= VWRITE;
+ if (mask & NFSV4ACE_APPENDDATA)
+ access |= VAPPEND;
+ if (mask & NFSV4ACE_ADDSUBDIRECTORY)
+ access |= VAPPEND;
+ if (mask & NFSV4ACE_READNAMEDATTR)
+ access |= VREAD_NAMED_ATTRS;
+ if (mask & NFSV4ACE_WRITENAMEDATTR)
+ access |= VWRITE_NAMED_ATTRS;
+ if (mask & NFSV4ACE_EXECUTE)
+ access |= VEXEC;
+ if (mask & NFSV4ACE_SEARCH)
+ access |= VEXEC;
+ if (mask & NFSV4ACE_DELETECHILD)
+ access |= VDELETE_CHILD;
+ if (mask & NFSV4ACE_READATTRIBUTES)
+ access |= VREAD_ATTRIBUTES;
+ if (mask & NFSV4ACE_WRITEATTRIBUTES)
+ access |= VWRITE_ATTRIBUTES;
+ if (mask & NFSV4ACE_DELETE)
+ access |= VDELETE;
+ if (mask & NFSV4ACE_READACL)
+ access |= VREAD_ACL;
+ if (mask & NFSV4ACE_WRITEACL)
+ access |= VWRITE_ACL;
+ if (mask & NFSV4ACE_WRITEOWNER)
+ access |= VWRITE_OWNER;
+ if (mask & NFSV4ACE_SYNCHRONIZE)
+ access |= VSYNCHRONIZE;
+
+ if (access != 0)
+ error = VOP_ACCESS(vp, access, cred, p);
+ else
+ error = VOP_ACCESS(vp, vflags, cred, p);
+ return (error);
+}
+
+/*
+ * Set an NFSv4 acl.
+ */
+APPLESTATIC int
+nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred,
+ NFSPROC_T *p)
+{
+ int error;
+
+ if (nfsrv_useacl == 0 || !NFSHASNFS4ACL(vnode_mount(vp)))
+ return (NFSERR_ATTRNOTSUPP);
+ /*
+ * With NFS4 ACLs, chmod(2) may need to add additional entries.
+ * Make sure it has enough room for that - splitting every entry
+ * into two and appending "canonical six" entries at the end.
+ * Cribbed out of kern/vfs_acl.c - Rick M.
+ */
+ if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
+ return (NFSERR_ATTRNOTSUPP);
+ error = VOP_ACLCHECK(vp, ACL_TYPE_NFS4, aclp, cred, p);
+#ifdef MAC
+ if (!error)
+ error = mac_check_vnode_setacl(cred, vp, ACL_TYPE_NFS4, aclp);
+#endif
+ if (!error)
+ error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p);
+ return (error);
+}
+
+/*
+ * Compare two NFSv4 acls.
+ * Return 0 if they are the same, 1 if not the same.
+ */
+APPLESTATIC int
+nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
+{
+ int i;
+ struct acl_entry *acep1, *acep2;
+
+ if (aclp1->acl_cnt != aclp2->acl_cnt)
+ return (1);
+ acep1 = aclp1->acl_entry;
+ acep2 = aclp2->acl_entry;
+ for (i = 0; i < aclp1->acl_cnt; i++) {
+ if (acep1->ae_tag != acep2->ae_tag)
+ return (1);
+ switch (acep1->ae_tag) {
+ case ACL_GROUP:
+ case ACL_USER:
+ if (acep1->ae_id != acep2->ae_id)
+ return (1);
+ /* fall through */
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_OTHER:
+ if (acep1->ae_perm != acep2->ae_perm)
+ return (1);
+ };
+ acep1++;
+ acep2++;
+ }
+ return (0);
+}
+
+#endif /* NFS4_ACL_EXTATTR_NAME */
diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
new file mode 100644
index 0000000..429eed2
--- /dev/null
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -0,0 +1,901 @@
+/*-
+ * Copyright (c) 1989, 1991, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Socket operations for use by nfs
+ */
+
+#include "opt_inet6.h"
+#include "opt_kgssapi.h"
+#include "opt_nfs.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/vnode.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpcclnt.h>
+
+#include <kgssapi/krb5/kcrypto.h>
+
+#include <fs/nfs/nfsport.h>
+
+NFSSTATESPINLOCK;
+NFSREQSPINLOCK;
+extern struct nfsstats newnfsstats;
+extern struct nfsreqhead nfsd_reqq;
+extern int nfscl_ticks;
+extern void (*ncl_call_invalcaches)(struct vnode *);
+
+static int nfsrv_gsscallbackson = 0;
+static int nfs_bufpackets = 4;
+static int nfs_reconnects;
+static int nfs3_jukebox_delay = 10;
+static int nfs_skip_wcc_data_onerr = 1;
+static int nfs_keytab_enctype = ETYPE_DES_CBC_CRC;
+
+SYSCTL_DECL(_vfs_newnfs);
+
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0,
+ "Buffer reservation size 2 < x < 64");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0,
+ "Number of times the nfs client has had to reconnect");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0,
+ "Number of seconds to delay a retry after receiving EJUKEBOX");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0,
+ "Disable weak cache consistency checking when server returns an error");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, keytab_enctype, CTLFLAG_RW, &nfs_keytab_enctype, 0,
+ "Encryption type for the keytab entry used by nfs");
+
+static void nfs_down(struct nfsmount *, struct thread *, const char *,
+ int, int);
+static void nfs_up(struct nfsmount *, struct thread *, const char *,
+ int, int);
+static int nfs_msg(struct thread *, const char *, const char *, int);
+
+extern int nfsv2_procid[];
+
+struct nfs_cached_auth {
+ int ca_refs; /* refcount, including 1 from the cache */
+ uid_t ca_uid; /* uid that corresponds to this auth */
+ AUTH *ca_auth; /* RPC auth handle */
+};
+
+/*
+ * Initialize sockets and congestion for a new NFS connection.
+ * We do not free the sockaddr if error.
+ */
+int
+newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
+ struct ucred *cred, NFSPROC_T *p, int callback_retry_mult)
+{
+ int rcvreserve, sndreserve;
+ int pktscale;
+ struct sockaddr *saddr;
+ struct ucred *origcred;
+ CLIENT *client;
+ struct netconfig *nconf;
+ struct socket *so;
+ int one = 1, retries, error, printsbmax = 0;
+ struct thread *td = curthread;
+
+ /*
+ * We need to establish the socket using the credentials of
+ * the mountpoint. Some parts of this process (such as
+ * sobind() and soconnect()) will use the curent thread's
+ * credential instead of the socket credential. To work
+ * around this, temporarily change the current thread's
+ * credential to that of the mountpoint.
+ *
+ * XXX: It would be better to explicitly pass the correct
+ * credential to sobind() and soconnect().
+ */
+ origcred = td->td_ucred;
+
+ /*
+ * Use the credential in nr_cred, if not NULL.
+ */
+ if (nrp->nr_cred != NULL)
+ td->td_ucred = nrp->nr_cred;
+ else
+ td->td_ucred = cred;
+ saddr = nrp->nr_nam;
+
+ if (saddr->sa_family == AF_INET)
+ if (nrp->nr_sotype == SOCK_DGRAM)
+ nconf = getnetconfigent("udp");
+ else
+ nconf = getnetconfigent("tcp");
+ else
+ if (nrp->nr_sotype == SOCK_DGRAM)
+ nconf = getnetconfigent("udp6");
+ else
+ nconf = getnetconfigent("tcp6");
+
+ pktscale = nfs_bufpackets;
+ if (pktscale < 2)
+ pktscale = 2;
+ if (pktscale > 64)
+ pktscale = 64;
+ /*
+ * soreserve() can fail if sb_max is too small, so shrink pktscale
+ * and try again if there is an error.
+ * Print a log message suggesting increasing sb_max.
+ * Creating a socket and doing this is necessary since, if the
+ * reservation sizes are too large and will make soreserve() fail,
+ * the connection will work until a large send is attempted and
+ * then it will loop in the krpc code.
+ */
+ so = NULL;
+ saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *);
+ error = socreate(saddr->sa_family, &so, nrp->nr_sotype,
+ nrp->nr_soproto, td->td_ucred, td);
+ if (error) {
+ td->td_ucred = origcred;
+ return (error);
+ }
+ do {
+ if (error != 0 && pktscale > 2) {
+ pktscale--;
+ if (printsbmax == 0) {
+ printf("nfscl: consider increasing kern.ipc.maxsockbuf\n");
+ printsbmax = 1;
+ }
+ }
+ if (nrp->nr_sotype == SOCK_DGRAM) {
+ if (nmp != NULL) {
+ sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
+ pktscale;
+ rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
+ pktscale;
+ } else {
+ sndreserve = rcvreserve = 1024 * pktscale;
+ }
+ } else {
+ if (nrp->nr_sotype != SOCK_STREAM)
+ panic("nfscon sotype");
+ if (nmp != NULL) {
+ sndreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR +
+ sizeof (u_int32_t)) * pktscale;
+ rcvreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR +
+ sizeof (u_int32_t)) * pktscale;
+ } else {
+ sndreserve = rcvreserve = 1024 * pktscale;
+ }
+ }
+ error = soreserve(so, sndreserve, rcvreserve);
+ } while (error != 0 && pktscale > 2);
+ soclose(so);
+ if (error) {
+ td->td_ucred = origcred;
+ return (error);
+ }
+
+ client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog,
+ nrp->nr_vers, sndreserve, rcvreserve);
+ CLNT_CONTROL(client, CLSET_WAITCHAN, "newnfsreq");
+ if (nmp != NULL) {
+ if ((nmp->nm_flag & NFSMNT_INT))
+ CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
+ if ((nmp->nm_flag & NFSMNT_RESVPORT))
+ CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
+ if (NFSHASSOFT(nmp))
+ retries = nmp->nm_retry;
+ else
+ retries = INT_MAX;
+ } else {
+ /*
+ * Three cases:
+ * - Null RPC callback to client
+ * - Non-Null RPC callback to client, wait a little longer
+ * - upcalls to nfsuserd and gssd (clp == NULL)
+ */
+ if (callback_retry_mult == 0) {
+ retries = NFSV4_UPCALLRETRY;
+ CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
+ } else {
+ retries = NFSV4_CALLBACKRETRY * callback_retry_mult;
+ }
+ }
+ CLNT_CONTROL(client, CLSET_RETRIES, &retries);
+
+ mtx_lock(&nrp->nr_mtx);
+ if (nrp->nr_client != NULL) {
+ /*
+ * Someone else already connected.
+ */
+ CLNT_RELEASE(client);
+ } else {
+ nrp->nr_client = client;
+ }
+
+ /*
+ * Protocols that do not require connections may be optionally left
+ * unconnected for servers that reply from a port other than NFS_PORT.
+ */
+ if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) {
+ mtx_unlock(&nrp->nr_mtx);
+ CLNT_CONTROL(client, CLSET_CONNECT, &one);
+ } else {
+ mtx_unlock(&nrp->nr_mtx);
+ }
+
+ /* Restore current thread's credentials. */
+ td->td_ucred = origcred;
+ return (0);
+}
+
+/*
+ * NFS disconnect. Clean up and unlink.
+ */
+void
+newnfs_disconnect(struct nfssockreq *nrp)
+{
+ CLIENT *client;
+
+ mtx_lock(&nrp->nr_mtx);
+ if (nrp->nr_client != NULL) {
+ client = nrp->nr_client;
+ nrp->nr_client = NULL;
+ mtx_unlock(&nrp->nr_mtx);
+#ifdef KGSSAPI
+ rpc_gss_secpurge(client);
+#endif
+ CLNT_CLOSE(client);
+ CLNT_RELEASE(client);
+ } else {
+ mtx_unlock(&nrp->nr_mtx);
+ }
+}
+
+static AUTH *
+nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal,
+ char *srv_principal, gss_OID mech_oid, struct ucred *cred)
+{
+#ifdef KGSSAPI
+ rpc_gss_service_t svc;
+ AUTH *auth;
+ rpc_gss_options_req_t req_options;
+#endif
+
+ switch (secflavour) {
+#ifdef KGSSAPI
+ case RPCSEC_GSS_KRB5:
+ case RPCSEC_GSS_KRB5I:
+ case RPCSEC_GSS_KRB5P:
+ if (!mech_oid) {
+ if (!rpc_gss_mech_to_oid("kerberosv5", &mech_oid))
+ return (NULL);
+ }
+ if (secflavour == RPCSEC_GSS_KRB5)
+ svc = rpc_gss_svc_none;
+ else if (secflavour == RPCSEC_GSS_KRB5I)
+ svc = rpc_gss_svc_integrity;
+ else
+ svc = rpc_gss_svc_privacy;
+ req_options.req_flags = GSS_C_MUTUAL_FLAG;
+ req_options.time_req = 0;
+ req_options.my_cred = GSS_C_NO_CREDENTIAL;
+ req_options.input_channel_bindings = NULL;
+ req_options.enc_type = nfs_keytab_enctype;
+
+ auth = rpc_gss_secfind(nrp->nr_client, cred,
+ clnt_principal, srv_principal, mech_oid, svc,
+ &req_options);
+ return (auth);
+#endif
+ case AUTH_SYS:
+ default:
+ return (authunix_create(cred));
+
+ }
+}
+
+/*
+ * Callback from the RPC code to generate up/down notifications.
+ */
+
+struct nfs_feedback_arg {
+ struct nfsmount *nf_mount;
+ int nf_lastmsg; /* last tprintf */
+ int nf_tprintfmsg;
+ struct thread *nf_td;
+};
+
+static void
+nfs_feedback(int type, int proc, void *arg)
+{
+ struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg;
+ struct nfsmount *nmp = nf->nf_mount;
+ struct timeval now;
+
+ getmicrouptime(&now);
+
+ switch (type) {
+ case FEEDBACK_REXMIT2:
+ case FEEDBACK_RECONNECT:
+ if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) {
+ nfs_down(nmp, nf->nf_td,
+ "not responding", 0, NFSSTA_TIMEO);
+ nf->nf_tprintfmsg = TRUE;
+ nf->nf_lastmsg = now.tv_sec;
+ }
+ break;
+
+ case FEEDBACK_OK:
+ nfs_up(nf->nf_mount, nf->nf_td,
+ "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg);
+ break;
+ }
+}
+
+/*
+ * newnfs_request - goes something like this
+ * - does the rpc by calling the krpc layer
+ * - break down rpc header and return with nfs reply
+ * nb: always frees up nd_mreq mbuf list
+ */
+int
+newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
+ struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp,
+ struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
+ u_char *retsum, int toplevel, u_int64_t *xidp)
+{
+ u_int32_t *tl;
+ time_t waituntil;
+ int i, j;
+ int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS;
+ u_int16_t procnum;
+ u_int trylater_delay = 1;
+ struct nfs_feedback_arg nf;
+ struct timeval timo, now;
+ AUTH *auth;
+ struct rpc_callextra ext;
+ enum clnt_stat stat;
+ struct nfsreq *rep = NULL;
+ char *srv_principal = NULL;
+
+ if (xidp != NULL)
+ *xidp = 0;
+ /* Reject requests while attempting a forced unmount. */
+ if (nmp != NULL && (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)) {
+ m_freem(nd->nd_mreq);
+ return (ESTALE);
+ }
+
+ /*
+ * For a client side mount, nmp is != NULL and clp == NULL. For
+ * server calls (callbacks or upcalls), nmp == NULL.
+ */
+ if (clp != NULL) {
+ NFSLOCKSTATE();
+ if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) {
+ secflavour = RPCSEC_GSS_KRB5;
+ if (nd->nd_procnum != NFSPROC_NULL) {
+ if (clp->lc_flags & LCL_GSSINTEGRITY)
+ secflavour = RPCSEC_GSS_KRB5I;
+ else if (clp->lc_flags & LCL_GSSPRIVACY)
+ secflavour = RPCSEC_GSS_KRB5P;
+ }
+ }
+ NFSUNLOCKSTATE();
+ } else if (nmp != NULL && NFSHASKERB(nmp) &&
+ nd->nd_procnum != NFSPROC_NULL) {
+ if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0)
+ nd->nd_flag |= ND_USEGSSNAME;
+ if ((nd->nd_flag & ND_USEGSSNAME) && nmp->nm_krbnamelen > 0)
+ usegssname = 1;
+ if (NFSHASINTEGRITY(nmp))
+ secflavour = RPCSEC_GSS_KRB5I;
+ else if (NFSHASPRIVACY(nmp))
+ secflavour = RPCSEC_GSS_KRB5P;
+ else
+ secflavour = RPCSEC_GSS_KRB5;
+ srv_principal = NFSMNT_SRVKRBNAME(nmp);
+ }
+
+ if (nmp != NULL) {
+ bzero(&nf, sizeof(struct nfs_feedback_arg));
+ nf.nf_mount = nmp;
+ nf.nf_td = td;
+ getmicrouptime(&now);
+ nf.nf_lastmsg = now.tv_sec -
+ ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay));
+ }
+
+ /*
+ * XXX if not already connected call nfs_connect now. Longer
+ * term, change nfs_mount to call nfs_connect unconditionally
+ * and let clnt_reconnect_create handle reconnects.
+ */
+ if (nrp->nr_client == NULL)
+ newnfs_connect(nmp, nrp, cred, td, 0);
+
+ if (usegssname)
+ auth = nfs_getauth(nrp, secflavour, nmp->nm_krbname,
+ srv_principal, NULL, cred);
+ else
+ auth = nfs_getauth(nrp, secflavour, NULL,
+ srv_principal, NULL, cred);
+ if (auth == NULL) {
+ m_freem(nd->nd_mreq);
+ return (EACCES);
+ }
+ bzero(&ext, sizeof(ext));
+ ext.rc_auth = auth;
+ if (nmp != NULL) {
+ ext.rc_feedback = nfs_feedback;
+ ext.rc_feedback_arg = &nf;
+ }
+
+ procnum = nd->nd_procnum;
+ if ((nd->nd_flag & ND_NFSV4) &&
+ nd->nd_procnum != NFSV4PROC_CBNULL &&
+ nd->nd_procnum != NFSV4PROC_CBCOMPOUND)
+ procnum = NFSV4PROC_COMPOUND;
+
+ if (nmp != NULL) {
+ NFSINCRGLOBAL(newnfsstats.rpcrequests);
+ /*
+ * Now only used for the R_DONTRECOVER case, but until that is
+ * supported within the krpc code, I need to keep a queue of
+ * outstanding RPCs for nfsv4 client requests.
+ */
+ if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND)
+ MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq),
+ M_NFSDREQ, M_WAITOK);
+ }
+ trycnt = 0;
+tryagain:
+ if (nmp == NULL) {
+ timo.tv_usec = 0;
+ if (clp == NULL)
+ timo.tv_sec = NFSV4_UPCALLTIMEO;
+ else
+ timo.tv_sec = NFSV4_CALLBACKTIMEO;
+ } else {
+ if (nrp->nr_sotype != SOCK_DGRAM) {
+ timo.tv_usec = 0;
+ if ((nmp->nm_flag & NFSMNT_NFSV4))
+ timo.tv_sec = INT_MAX;
+ else
+ timo.tv_sec = NFS_TCPTIMEO;
+ } else {
+ timo.tv_sec = nmp->nm_timeo / NFS_HZ;
+ timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ;
+ }
+
+ if (rep != NULL) {
+ rep->r_flags = 0;
+ rep->r_nmp = nmp;
+ /*
+ * Chain request into list of outstanding requests.
+ */
+ NFSLOCKREQ();
+ TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain);
+ NFSUNLOCKREQ();
+ }
+ }
+
+ nd->nd_mrep = NULL;
+ stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, nd->nd_mreq,
+ &nd->nd_mrep, timo);
+
+ if (rep != NULL) {
+ /*
+ * RPC done, unlink the request.
+ */
+ NFSLOCKREQ();
+ TAILQ_REMOVE(&nfsd_reqq, rep, r_chain);
+ NFSUNLOCKREQ();
+ }
+
+ /*
+ * If there was a successful reply and a tprintf msg.
+ * tprintf a response.
+ */
+ if (stat == RPC_SUCCESS) {
+ error = 0;
+ } else if (stat == RPC_TIMEDOUT) {
+ error = ETIMEDOUT;
+ } else if (stat == RPC_VERSMISMATCH) {
+ error = EOPNOTSUPP;
+ } else if (stat == RPC_PROGVERSMISMATCH) {
+ error = EPROTONOSUPPORT;
+ } else {
+ error = EACCES;
+ }
+ if (error) {
+ m_freem(nd->nd_mreq);
+ AUTH_DESTROY(auth);
+ if (rep != NULL)
+ FREE((caddr_t)rep, M_NFSDREQ);
+ return (error);
+ }
+
+ KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n"));
+
+ nd->nd_md = nd->nd_mrep;
+ nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
+ nd->nd_repstat = 0;
+ if (nd->nd_procnum != NFSPROC_NULL) {
+ /*
+ * and now the actual NFS xdr.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl);
+ if (nd->nd_repstat != 0) {
+ if ((nd->nd_repstat == NFSERR_DELAY &&
+ (nd->nd_flag & ND_NFSV4) &&
+ nd->nd_procnum != NFSPROC_SETATTR &&
+ nd->nd_procnum != NFSPROC_READ &&
+ nd->nd_procnum != NFSPROC_WRITE &&
+ nd->nd_procnum != NFSPROC_OPEN &&
+ nd->nd_procnum != NFSPROC_CREATE &&
+ nd->nd_procnum != NFSPROC_OPENCONFIRM &&
+ nd->nd_procnum != NFSPROC_OPENDOWNGRADE &&
+ nd->nd_procnum != NFSPROC_CLOSE &&
+ nd->nd_procnum != NFSPROC_LOCK &&
+ nd->nd_procnum != NFSPROC_LOCKU) ||
+ (nd->nd_repstat == NFSERR_DELAY &&
+ (nd->nd_flag & ND_NFSV4) == 0) ||
+ nd->nd_repstat == NFSERR_RESOURCE) {
+ if (trylater_delay > NFS_TRYLATERDEL)
+ trylater_delay = NFS_TRYLATERDEL;
+ waituntil = NFSD_MONOSEC + trylater_delay;
+ while (NFSD_MONOSEC < waituntil)
+ (void) nfs_catnap(PZERO, "nfstry");
+ trylater_delay *= 2;
+ goto tryagain;
+ }
+
+ /*
+ * If the File Handle was stale, invalidate the
+ * lookup cache, just in case.
+ * (vp != NULL implies a client side call)
+ */
+ if (nd->nd_repstat == ESTALE && vp != NULL) {
+ cache_purge(vp);
+ if (ncl_call_invalcaches != NULL)
+ (*ncl_call_invalcaches)(vp);
+ }
+ }
+
+ /*
+ * Get rid of the tag, return count, and PUTFH result for V4.
+ */
+ if (nd->nd_flag & ND_NFSV4) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *tl);
+ error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
+ if (error)
+ goto nfsmout;
+ NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *++tl);
+
+ /*
+ * If the first op's status is non-zero, mark that
+ * there is no more data to process.
+ */
+ if (*++tl)
+ nd->nd_flag |= ND_NOMOREDATA;
+
+ /*
+ * If the first op is Putfh, throw its results away
+ * and toss the op# and status for the first op.
+ */
+ if (nmp != NULL && i == NFSV4OP_PUTFH && *tl == 0) {
+ NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *tl++);
+ j = fxdr_unsigned(int, *tl);
+ /*
+ * All Compounds that do an Op that must
+ * be in sequence consist of NFSV4OP_PUTFH
+ * followed by one of these. As such, we
+ * can determine if the seqid# should be
+ * incremented, here.
+ */
+ if ((i == NFSV4OP_OPEN ||
+ i == NFSV4OP_OPENCONFIRM ||
+ i == NFSV4OP_OPENDOWNGRADE ||
+ i == NFSV4OP_CLOSE ||
+ i == NFSV4OP_LOCK ||
+ i == NFSV4OP_LOCKU) &&
+ (j == 0 ||
+ (j != NFSERR_STALECLIENTID &&
+ j != NFSERR_STALESTATEID &&
+ j != NFSERR_BADSTATEID &&
+ j != NFSERR_BADSEQID &&
+ j != NFSERR_BADXDR &&
+ j != NFSERR_RESOURCE &&
+ j != NFSERR_NOFILEHANDLE)))
+ nd->nd_flag |= ND_INCRSEQID;
+ /*
+ * If the first op's status is non-zero, mark
+ * that there is no more data to process.
+ */
+ if (j)
+ nd->nd_flag |= ND_NOMOREDATA;
+ }
+
+ /*
+ * If R_DONTRECOVER is set, replace the stale error
+ * reply, so that recovery isn't initiated.
+ */
+ if ((nd->nd_repstat == NFSERR_STALECLIENTID ||
+ nd->nd_repstat == NFSERR_STALESTATEID) &&
+ rep != NULL && (rep->r_flags & R_DONTRECOVER))
+ nd->nd_repstat = NFSERR_STALEDONTRECOVER;
+ }
+
+ m_freem(nd->nd_mreq);
+ AUTH_DESTROY(auth);
+ if (rep != NULL)
+ FREE((caddr_t)rep, M_NFSDREQ);
+ return (0);
+ }
+ error = EPROTONOSUPPORT;
+nfsmout:
+ mbuf_freem(nd->nd_mrep);
+ mbuf_freem(nd->nd_mreq);
+ AUTH_DESTROY(auth);
+ if (rep != NULL)
+ FREE((caddr_t)rep, M_NFSDREQ);
+ return (error);
+}
+
+/*
+ * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
+ * wait for all requests to complete. This is used by forced unmounts
+ * to terminate any outstanding RPCs.
+ */
+int
+newnfs_nmcancelreqs(struct nfsmount *nmp)
+{
+
+ if (nmp->nm_sockreq.nr_client != NULL)
+ CLNT_CLOSE(nmp->nm_sockreq.nr_client);
+ return (0);
+}
+
+/*
+ * Any signal that can interrupt an NFS operation in an intr mount
+ * should be added to this set. SIGSTOP and SIGKILL cannot be masked.
+ */
+int newnfs_sig_set[] = {
+ SIGINT,
+ SIGTERM,
+ SIGHUP,
+ SIGKILL,
+ SIGSTOP,
+ SIGQUIT
+};
+
+/*
+ * Check to see if one of the signals in our subset is pending on
+ * the process (in an intr mount).
+ */
+static int
+nfs_sig_pending(sigset_t set)
+{
+ int i;
+
+ for (i = 0 ; i < sizeof(newnfs_sig_set)/sizeof(int) ; i++)
+ if (SIGISMEMBER(set, newnfs_sig_set[i]))
+ return (1);
+ return (0);
+}
+
+/*
+ * The set/restore sigmask functions are used to (temporarily) overwrite
+ * the process p_sigmask during an RPC call (for example). These are also
+ * used in other places in the NFS client that might tsleep().
+ */
+void
+newnfs_set_sigmask(struct thread *td, sigset_t *oldset)
+{
+ sigset_t newset;
+ int i;
+ struct proc *p;
+
+ SIGFILLSET(newset);
+ if (td == NULL)
+ td = curthread; /* XXX */
+ p = td->td_proc;
+ /* Remove the NFS set of signals from newset */
+ PROC_LOCK(p);
+ mtx_lock(&p->p_sigacts->ps_mtx);
+ for (i = 0 ; i < sizeof(newnfs_sig_set)/sizeof(int) ; i++) {
+ /*
+ * But make sure we leave the ones already masked
+ * by the process, ie. remove the signal from the
+ * temporary signalmask only if it wasn't already
+ * in p_sigmask.
+ */
+ if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) &&
+ !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i]))
+ SIGDELSET(newset, newnfs_sig_set[i]);
+ }
+ mtx_unlock(&p->p_sigacts->ps_mtx);
+ PROC_UNLOCK(p);
+ kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0);
+}
+
+void
+newnfs_restore_sigmask(struct thread *td, sigset_t *set)
+{
+ if (td == NULL)
+ td = curthread; /* XXX */
+ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0);
+}
+
+/*
+ * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the
+ * old one after msleep() returns.
+ */
+int
+newnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo)
+{
+ sigset_t oldset;
+ int error;
+ struct proc *p;
+
+ if ((priority & PCATCH) == 0)
+ return msleep(ident, mtx, priority, wmesg, timo);
+ if (td == NULL)
+ td = curthread; /* XXX */
+ newnfs_set_sigmask(td, &oldset);
+ error = msleep(ident, mtx, priority, wmesg, timo);
+ newnfs_restore_sigmask(td, &oldset);
+ p = td->td_proc;
+ return (error);
+}
+
+/*
+ * Test for a termination condition pending on the process.
+ * This is used for NFSMNT_INT mounts.
+ */
+int
+newnfs_sigintr(struct nfsmount *nmp, struct thread *td)
+{
+ struct proc *p;
+ sigset_t tmpset;
+
+ /* Terminate all requests while attempting a forced unmount. */
+ if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
+ return (EIO);
+ if (!(nmp->nm_flag & NFSMNT_INT))
+ return (0);
+ if (td == NULL)
+ return (0);
+ p = td->td_proc;
+ PROC_LOCK(p);
+ tmpset = p->p_siglist;
+ SIGSETOR(tmpset, td->td_siglist);
+ SIGSETNAND(tmpset, td->td_sigmask);
+ mtx_lock(&p->p_sigacts->ps_mtx);
+ SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
+ mtx_unlock(&p->p_sigacts->ps_mtx);
+ if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist))
+ && nfs_sig_pending(tmpset)) {
+ PROC_UNLOCK(p);
+ return (EINTR);
+ }
+ PROC_UNLOCK(p);
+ return (0);
+}
+
+static int
+nfs_msg(struct thread *td, const char *server, const char *msg, int error)
+{
+ struct proc *p;
+
+ p = td ? td->td_proc : NULL;
+ if (error) {
+ tprintf(p, LOG_INFO, "newnfs server %s: %s, error %d\n",
+ server, msg, error);
+ } else {
+ tprintf(p, LOG_INFO, "newnfs server %s: %s\n", server, msg);
+ }
+ return (0);
+}
+
+static void
+nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg,
+ int error, int flags)
+{
+ if (nmp == NULL)
+ return;
+ mtx_lock(&nmp->nm_mtx);
+ if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) {
+ nmp->nm_state |= NFSSTA_TIMEO;
+ mtx_unlock(&nmp->nm_mtx);
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESP, 0);
+ } else
+ mtx_unlock(&nmp->nm_mtx);
+ mtx_lock(&nmp->nm_mtx);
+ if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) {
+ nmp->nm_state |= NFSSTA_LOCKTIMEO;
+ mtx_unlock(&nmp->nm_mtx);
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESPLOCK, 0);
+ } else
+ mtx_unlock(&nmp->nm_mtx);
+ nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error);
+}
+
+static void
+nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg,
+ int flags, int tprintfmsg)
+{
+ if (nmp == NULL)
+ return;
+ if (tprintfmsg) {
+ nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0);
+ }
+
+ mtx_lock(&nmp->nm_mtx);
+ if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) {
+ nmp->nm_state &= ~NFSSTA_TIMEO;
+ mtx_unlock(&nmp->nm_mtx);
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESP, 1);
+ } else
+ mtx_unlock(&nmp->nm_mtx);
+
+ mtx_lock(&nmp->nm_mtx);
+ if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) {
+ nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
+ mtx_unlock(&nmp->nm_mtx);
+ vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid,
+ VQ_NOTRESPLOCK, 1);
+ } else
+ mtx_unlock(&nmp->nm_mtx);
+}
+
diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c
new file mode 100644
index 0000000..1c22657
--- /dev/null
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -0,0 +1,486 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Functions that need to be different for different versions of BSD
+ * kernel should be kept here, along with any global storage specific
+ * to this BSD variant.
+ */
+#include <fs/nfs/nfsport.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_param.h>
+#include <vm/vm_map.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <vm/uma.h>
+#include <vm/uma_int.h>
+
+extern int nfscl_ticks;
+extern int nfsrv_nfsuserd;
+extern struct nfssockreq nfsrv_nfsuserdsock;
+extern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *,
+ struct thread *);
+extern int nfsrv_useacl;
+struct mount nfsv4root_mnt;
+int newnfs_numnfsd = 0;
+struct nfsstats newnfsstats;
+int nfs_numnfscbd = 0;
+char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
+struct callout newnfsd_callout;
+void (*nfsd_call_servertimer)(void) = NULL;
+void (*ncl_call_invalcaches)(struct vnode *) = NULL;
+
+static int nfs_realign_test;
+static int nfs_realign_count;
+
+SYSCTL_NODE(_vfs, OID_AUTO, newnfs, CTLFLAG_RW, 0, "New NFS filesystem");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, "");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, "");
+SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs4acl_enable, CTLFLAG_RW, &nfsrv_useacl, 0, "");
+SYSCTL_STRING(_vfs_newnfs, OID_AUTO, callback_addr, CTLFLAG_RW,
+ nfsv4_callbackaddr, sizeof(nfsv4_callbackaddr), "");
+
+/*
+ * Defines for malloc
+ * (Here for FreeBSD, since they allocate storage.)
+ */
+MALLOC_DEFINE(M_NEWNFSRVCACHE, "NFSD srvcache", "NFSD Server Request Cache");
+MALLOC_DEFINE(M_NEWNFSDCLIENT, "NFSD V4client", "NFSD V4 Client Id");
+MALLOC_DEFINE(M_NEWNFSDSTATE, "NFSD V4state", "NFSD V4 State (Openowner, Open, Lockowner, Delegation");
+MALLOC_DEFINE(M_NEWNFSDLOCK, "NFSD V4lock", "NFSD V4 byte range lock");
+MALLOC_DEFINE(M_NEWNFSDLOCKFILE, "NFSD lckfile", "NFSD Open/Lock file");
+MALLOC_DEFINE(M_NEWNFSSTRING, "NFSD string", "NFSD V4 long string");
+MALLOC_DEFINE(M_NEWNFSUSERGROUP, "NFSD usrgroup", "NFSD V4 User/group map");
+MALLOC_DEFINE(M_NEWNFSDREQ, "NFS req", "NFS request header");
+MALLOC_DEFINE(M_NEWNFSFH, "NFS fh", "NFS file handle");
+MALLOC_DEFINE(M_NEWNFSCLOWNER, "NFSCL owner", "NFSCL Open Owner");
+MALLOC_DEFINE(M_NEWNFSCLOPEN, "NFSCL open", "NFSCL Open");
+MALLOC_DEFINE(M_NEWNFSCLDELEG, "NFSCL deleg", "NFSCL Delegation");
+MALLOC_DEFINE(M_NEWNFSCLCLIENT, "NFSCL client", "NFSCL Client");
+MALLOC_DEFINE(M_NEWNFSCLLOCKOWNER, "NFSCL lckown", "NFSCL Lock Owner");
+MALLOC_DEFINE(M_NEWNFSCLLOCK, "NFSCL lck", "NFSCL Lock");
+MALLOC_DEFINE(M_NEWNFSV4NODE, "NEWNFSnode", "New nfs vnode");
+MALLOC_DEFINE(M_NEWNFSDIRECTIO, "NEWdirectio", "New nfs Direct IO buffer");
+MALLOC_DEFINE(M_NEWNFSDIROFF, "Newnfscl_diroff", "New NFS directory offset data");
+
+/*
+ * Definition of mutex locks.
+ * newnfsd_mtx is used in nfsrvd_nfsd() to protect the nfs socket list
+ * and assorted other nfsd structures.
+ * Giant is used to protect the nfsd list and count, which is just
+ * updated when nfsd's start/stop and is grabbed for nfsrvd_dorpc()
+ * for the VFS ops.
+ */
+struct mtx newnfsd_mtx;
+struct mtx nfs_sockl_mutex;
+struct mtx nfs_state_mutex;
+struct mtx nfs_nameid_mutex;
+struct mtx nfs_req_mutex;
+struct mtx nfs_slock_mutex;
+
+/* local functions */
+static int nfssvc_call(struct thread *, struct nfssvc_args *, struct ucred *);
+
+#if defined(__i386__)
+/*
+ * These architectures don't need re-alignment, so just return.
+ */
+void
+newnfs_realign(struct mbuf **pm)
+{
+
+ return;
+}
+#else
+/*
+ * nfs_realign:
+ *
+ * Check for badly aligned mbuf data and realign by copying the unaligned
+ * portion of the data into a new mbuf chain and freeing the portions
+ * of the old chain that were replaced.
+ *
+ * We cannot simply realign the data within the existing mbuf chain
+ * because the underlying buffers may contain other rpc commands and
+ * we cannot afford to overwrite them.
+ *
+ * We would prefer to avoid this situation entirely. The situation does
+ * not occur with NFS/UDP and is supposed to only occassionally occur
+ * with TCP. Use vfs.nfs.realign_count and realign_test to check this.
+ */
+void
+newnfs_realign(struct mbuf **pm)
+{
+ struct mbuf *m;
+ struct mbuf *n = NULL;
+ int off = 0;
+
+ ++nfs_realign_test;
+ while ((m = *pm) != NULL) {
+ if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) {
+ MGET(n, M_WAIT, MT_DATA);
+ if (m->m_len >= MINCLSIZE) {
+ MCLGET(n, M_WAIT);
+ }
+ n->m_len = 0;
+ break;
+ }
+ pm = &m->m_next;
+ }
+
+ /*
+ * If n is non-NULL, loop on m copying data, then replace the
+ * portion of the chain that had to be realigned.
+ */
+ if (n != NULL) {
+ ++nfs_realign_count;
+ while (m) {
+ m_copyback(n, off, m->m_len, mtod(m, caddr_t));
+ off += m->m_len;
+ m = m->m_next;
+ }
+ m_freem(*pm);
+ *pm = n;
+ }
+}
+#endif /* newnfs_realign */
+
+#ifdef notdef
+static void
+nfsrv_object_create(struct vnode *vp, struct thread *td)
+{
+
+ if (vp == NULL || vp->v_type != VREG)
+ return;
+ (void) vfs_object_create(vp, td, td->td_ucred);
+}
+#endif
+
+/*
+ * Look up a file name. Basically just initialize stuff and call namei().
+ */
+int
+nfsrv_lookupfilename(struct nameidata *ndp, char *fname, NFSPROC_T *p)
+{
+ int error;
+
+ NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fname, p);
+ error = namei(ndp);
+ if (!error) {
+ NDFREE(ndp, NDF_ONLY_PNBUF);
+ }
+ return (error);
+}
+
+/*
+ * Copy NFS uid, gids to the cred structure.
+ */
+void
+newnfs_copycred(struct nfscred *nfscr, struct ucred *cr)
+{
+ int ngroups, i;
+
+ cr->cr_uid = nfscr->nfsc_uid;
+ ngroups = (nfscr->nfsc_ngroups < NGROUPS) ?
+ nfscr->nfsc_ngroups : NGROUPS;
+ for (i = 0; i < ngroups; i++)
+ cr->cr_groups[i] = nfscr->nfsc_groups[i];
+ cr->cr_ngroups = ngroups;
+}
+
+/*
+ * Map args from nfsmsleep() to msleep().
+ */
+int
+nfsmsleep(void *chan, void *mutex, int prio, const char *wmesg,
+ struct timespec *ts)
+{
+ u_int64_t nsecval;
+ int error, timeo;
+
+ if (ts) {
+ timeo = hz * ts->tv_sec;
+ nsecval = (u_int64_t)ts->tv_nsec;
+ nsecval = ((nsecval * ((u_int64_t)hz)) + 500000000) /
+ 1000000000;
+ timeo += (int)nsecval;
+ } else {
+ timeo = 0;
+ }
+ error = msleep(chan, (struct mtx *)mutex, prio, wmesg, timeo);
+ return (error);
+}
+
+/*
+ * Get the file system info for the server. For now, just assume FFS.
+ */
+void
+nfsvno_getfs(struct nfsfsinfo *sip, int isdgram)
+{
+ int pref;
+
+ /*
+ * XXX
+ * There should be file system VFS OP(s) to get this information.
+ * For now, assume ufs.
+ */
+ if (isdgram)
+ pref = NFS_MAXDGRAMDATA;
+ else
+ pref = NFS_MAXDATA;
+ sip->fs_rtmax = NFS_MAXDATA;
+ sip->fs_rtpref = pref;
+ sip->fs_rtmult = NFS_FABLKSIZE;
+ sip->fs_wtmax = NFS_MAXDATA;
+ sip->fs_wtpref = pref;
+ sip->fs_wtmult = NFS_FABLKSIZE;
+ sip->fs_dtpref = pref;
+ sip->fs_maxfilesize = 0xffffffffffffffffull;
+ sip->fs_timedelta.tv_sec = 0;
+ sip->fs_timedelta.tv_nsec = 1;
+ sip->fs_properties = (NFSV3FSINFO_LINK |
+ NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
+ NFSV3FSINFO_CANSETTIME);
+}
+
+/* Fake nfsrv_atroot. Just return 0 */
+int
+nfsrv_atroot(struct vnode *vp, long *retp)
+{
+
+ return (0);
+}
+
+/*
+ * Set the credentials to refer to root.
+ * If only the various BSDen could agree on whether cr_gid is a separate
+ * field or cr_groups[0]...
+ */
+void
+newnfs_setroot(struct ucred *cred)
+{
+
+ cred->cr_uid = 0;
+ cred->cr_groups[0] = 0;
+ cred->cr_ngroups = 1;
+}
+
+/*
+ * Get the client credential. Used for Renew and recovery.
+ */
+struct ucred *
+newnfs_getcred(void)
+{
+ struct ucred *cred;
+ struct thread *td = curthread;
+
+ cred = crdup(td->td_ucred);
+ newnfs_setroot(cred);
+ return (cred);
+}
+
+/*
+ * Nfs timer routine
+ * Call the nfsd's timer function once/sec.
+ */
+void
+newnfs_timer(void *arg)
+{
+ static time_t lasttime = 0;
+ /*
+ * Call the server timer, if set up.
+ * The argument indicates if it is the next second and therefore
+ * leases should be checked.
+ */
+ if (lasttime != NFSD_MONOSEC) {
+ lasttime = NFSD_MONOSEC;
+ if (nfsd_call_servertimer != NULL)
+ (*nfsd_call_servertimer)();
+ }
+ callout_reset(&newnfsd_callout, nfscl_ticks, newnfs_timer, NULL);
+}
+
+
+/*
+ * sleep for a short period of time.
+ * Since lbolt doesn't exist in FreeBSD-CURRENT, just use a timeout on
+ * an event that never gets a wakeup. Only return EINTR or 0.
+ */
+int
+nfs_catnap(int prio, const char *wmesg)
+{
+ static int non_event;
+ int ret;
+
+ ret = tsleep(&non_event, prio, wmesg, 1);
+ if (ret != EINTR)
+ ret = 0;
+ return (ret);
+}
+
+/*
+ * Get referral. For now, just fail.
+ */
+struct nfsreferral *
+nfsv4root_getreferral(struct vnode *vp, struct vnode *dvp, u_int32_t fileno)
+{
+
+ return (NULL);
+}
+
+static int
+nfssvc_nfscommon(struct thread *td, struct nfssvc_args *uap)
+{
+ int error;
+
+ error = nfssvc_call(td, uap, td->td_ucred);
+ return (error);
+}
+
+static int
+nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
+{
+ int error = EINVAL;
+ struct nfsd_idargs nid;
+
+ if (uap->flag & NFSSVC_IDNAME) {
+ error = copyin(uap->argp, (caddr_t)&nid, sizeof (nid));
+ if (error)
+ return (error);
+ error = nfssvc_idname(&nid);
+ return (error);
+ } else if (uap->flag & NFSSVC_GETSTATS) {
+ error = copyout(&newnfsstats,
+ CAST_USER_ADDR_T(uap->argp), sizeof (newnfsstats));
+ return (error);
+ } else if (uap->flag & NFSSVC_NFSUSERDPORT) {
+ u_short sockport;
+
+ error = copyin(uap->argp, (caddr_t)&sockport,
+ sizeof (u_short));
+ if (!error)
+ error = nfsrv_nfsuserdport(sockport, p);
+ } else if (uap->flag & NFSSVC_NFSUSERDDELPORT) {
+ nfsrv_nfsuserddelport();
+ error = 0;
+ }
+ return (error);
+}
+
+/*
+ * called by all three modevent routines, so that it gets things
+ * initialized soon enough.
+ */
+void
+newnfs_portinit(void)
+{
+ static int inited = 0;
+
+ if (inited)
+ return;
+ inited = 1;
+ /* Initialize SMP locks used by both client and server. */
+ mtx_init(&newnfsd_mtx, "newnfsd_mtx", NULL, MTX_DEF);
+ mtx_init(&nfs_state_mutex, "nfs_state_mutex", NULL, MTX_DEF);
+}
+
+extern int (*nfsd_call_nfscommon)(struct thread *, struct nfssvc_args *);
+
+/*
+ * Called once to initialize data structures...
+ */
+static int
+nfscommon_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
+ static int loaded = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ if (loaded)
+ return (0);
+ newnfs_portinit();
+ mtx_init(&nfs_nameid_mutex, "nfs_nameid_mutex", NULL, MTX_DEF);
+ mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF);
+ mtx_init(&nfs_slock_mutex, "nfs_slock_mutex", NULL, MTX_DEF);
+ mtx_init(&nfs_req_mutex, "nfs_req_mutex", NULL, MTX_DEF);
+ mtx_init(&nfsrv_nfsuserdsock.nr_mtx, "nfsuserd", NULL,
+ MTX_DEF);
+ callout_init(&newnfsd_callout, CALLOUT_MPSAFE);
+ newnfs_init();
+ nfsd_call_nfscommon = nfssvc_nfscommon;
+ loaded = 1;
+ break;
+
+ case MOD_UNLOAD:
+ if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != 0 ||
+ nfs_numnfscbd != 0) {
+ error = EBUSY;
+ break;
+ }
+
+ nfsd_call_nfscommon = NULL;
+ callout_drain(&newnfsd_callout);
+ /* and get rid of the mutexes */
+ mtx_destroy(&nfs_nameid_mutex);
+ mtx_destroy(&newnfsd_mtx);
+ mtx_destroy(&nfs_state_mutex);
+ mtx_destroy(&nfs_sockl_mutex);
+ mtx_destroy(&nfs_slock_mutex);
+ mtx_destroy(&nfs_req_mutex);
+ mtx_destroy(&nfsrv_nfsuserdsock.nr_mtx);
+ loaded = 0;
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return error;
+}
+static moduledata_t nfscommon_mod = {
+ "nfscommon",
+ nfscommon_modevent,
+ NULL,
+};
+DECLARE_MODULE(nfscommon, nfscommon_mod, SI_SUB_VFS, SI_ORDER_ANY);
+
+/* So that loader and kldload(2) can find us, wherever we are.. */
+MODULE_VERSION(nfscommon, 1);
+MODULE_DEPEND(nfscommon, nfssvc, 1, 1, 1);
+MODULE_DEPEND(nfscommon, krpc, 1, 1, 1);
+
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
new file mode 100644
index 0000000..bb19902
--- /dev/null
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -0,0 +1,3404 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * These functions support the macros and help fiddle mbuf chains for
+ * the nfs op functions. They do things like create the rpc header and
+ * copy data between mbuf chains and uio lists.
+ */
+#ifndef APPLEKEXT
+#include <fs/nfs/nfsport.h>
+
+/*
+ * Data items converted to xdr at startup, since they are constant
+ * This is kinda hokey, but may save a little time doing byte swaps
+ */
+u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
+
+/* And other global data */
+nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
+ NFFIFO, NFNON };
+enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
+enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
+struct timeval nfsboottime; /* Copy boottime once, so it never changes */
+int nfscl_ticks;
+int nfsrv_useacl = 1;
+struct nfssockreq nfsrv_nfsuserdsock;
+int nfsrv_nfsuserd = 0;
+struct nfsreqhead nfsd_reqq;
+uid_t nfsrv_defaultuid;
+gid_t nfsrv_defaultgid;
+int nfsrv_lease = NFSRV_LEASE;
+int ncl_mbuf_mlen = MLEN;
+NFSNAMEIDMUTEX;
+NFSSOCKMUTEX;
+
+/*
+ * This array of structures indicates, for V4:
+ * retfh - which of 3 types of calling args are used
+ * 0 - doesn't change cfh or use a sfh
+ * 1 - replaces cfh with a new one (unless it returns an error status)
+ * 2 - uses cfh and sfh
+ * needscfh - if the op wants a cfh and premtime
+ * 0 - doesn't use a cfh
+ * 1 - uses a cfh, but doesn't want pre-op attributes
+ * 2 - uses a cfh and wants pre-op attributes
+ * savereply - indicates a non-idempotent Op
+ * 0 - not non-idempotent
+ * 1 - non-idempotent
+ * Ops that are ordered via seqid# are handled separately from these
+ * non-idempotent Ops.
+ * Define it here, since it is used by both the client and server.
+ */
+struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
+ { 0, 0, 0, 0 }, /* undef */
+ { 0, 0, 0, 0 }, /* undef */
+ { 0, 0, 0, 0 }, /* undef */
+ { 0, 1, 0, 0 }, /* Access */
+ { 0, 1, 0, 0 }, /* Close */
+ { 0, 2, 0, 1 }, /* Commit */
+ { 1, 2, 1, 1 }, /* Create */
+ { 0, 0, 0, 0 }, /* Delegpurge */
+ { 0, 1, 0, 0 }, /* Delegreturn */
+ { 0, 1, 0, 0 }, /* Getattr */
+ { 0, 1, 0, 0 }, /* GetFH */
+ { 2, 1, 1, 1 }, /* Link */
+ { 0, 1, 0, 0 }, /* Lock */
+ { 0, 1, 0, 0 }, /* LockT */
+ { 0, 1, 0, 0 }, /* LockU */
+ { 1, 1, 0, 0 }, /* Lookup */
+ { 1, 1, 0, 0 }, /* Lookupp */
+ { 0, 1, 0, 0 }, /* NVerify */
+ { 1, 1, 0, 1 }, /* Open */
+ { 1, 1, 0, 0 }, /* OpenAttr */
+ { 0, 1, 0, 0 }, /* OpenConfirm */
+ { 0, 1, 0, 0 }, /* OpenDowngrade */
+ { 1, 0, 0, 0 }, /* PutFH */
+ { 1, 0, 0, 0 }, /* PutPubFH */
+ { 1, 0, 0, 0 }, /* PutRootFH */
+ { 0, 1, 0, 0 }, /* Read */
+ { 0, 1, 0, 0 }, /* Readdir */
+ { 0, 1, 0, 0 }, /* ReadLink */
+ { 0, 2, 1, 1 }, /* Remove */
+ { 2, 1, 1, 1 }, /* Rename */
+ { 0, 0, 0, 0 }, /* Renew */
+ { 0, 0, 0, 0 }, /* RestoreFH */
+ { 0, 1, 0, 0 }, /* SaveFH */
+ { 0, 1, 0, 0 }, /* SecInfo */
+ { 0, 2, 1, 1 }, /* Setattr */
+ { 0, 0, 0, 0 }, /* SetClientID */
+ { 0, 0, 0, 0 }, /* SetClientIDConfirm */
+ { 0, 1, 0, 0 }, /* Verify */
+ { 0, 2, 1, 1 }, /* Write */
+ { 0, 0, 0, 0 }, /* ReleaseLockOwner */
+};
+#endif /* !APPLEKEXT */
+
+static int ncl_mbuf_mhlen = MHLEN;
+static int nfsrv_usercnt = 0;
+static int nfsrv_dnsnamelen;
+static u_char *nfsrv_dnsname = NULL;
+static int nfsrv_usermax = 999999999;
+static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
+static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
+static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
+static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
+static struct nfsuserlruhead nfsuserlruhead;
+
+/*
+ * This static array indicates whether or not the RPC generates a large
+ * reply. This is used by nfs_reply() to decide whether or not an mbuf
+ * cluster should be allocated. (If a cluster is required by an RPC
+ * marked 0 in this array, the code will still work, just not quite as
+ * efficiently.)
+ */
+static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0 };
+
+/* local functions */
+static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
+static void nfsv4_wanted(struct nfsv4lock *lp);
+static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
+static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
+ NFSPROC_T *p);
+static void nfsrv_removeuser(struct nfsusrgrp *usrp);
+static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
+ int *, int *);
+static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
+
+
+#ifndef APPLE
+/*
+ * copies mbuf chain to the uio scatter/gather list
+ */
+int
+nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
+{
+ char *mbufcp, *uiocp;
+ int xfer, left, len;
+ mbuf_t mp;
+ long uiosiz, rem;
+ int error = 0;
+
+ mp = nd->nd_md;
+ mbufcp = nd->nd_dpos;
+ len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
+ rem = NFSM_RNDUP(siz) - siz;
+ while (siz > 0) {
+ if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
+ return (EBADRPC);
+ left = uiop->uio_iov->iov_len;
+ uiocp = uiop->uio_iov->iov_base;
+ if (left > siz)
+ left = siz;
+ uiosiz = left;
+ while (left > 0) {
+ while (len == 0) {
+ mp = mbuf_next(mp);
+ if (mp == NULL)
+ return (EBADRPC);
+ mbufcp = NFSMTOD(mp, caddr_t);
+ len = mbuf_len(mp);
+ }
+ xfer = (left > len) ? len : left;
+#ifdef notdef
+ /* Not Yet.. */
+ if (uiop->uio_iov->iov_op != NULL)
+ (*(uiop->uio_iov->iov_op))
+ (mbufcp, uiocp, xfer);
+ else
+#endif
+ if (uiop->uio_segflg == UIO_SYSSPACE)
+ NFSBCOPY(mbufcp, uiocp, xfer);
+ else
+ copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
+ left -= xfer;
+ len -= xfer;
+ mbufcp += xfer;
+ uiocp += xfer;
+ uiop->uio_offset += xfer;
+ uiop->uio_resid -= xfer;
+ }
+ if (uiop->uio_iov->iov_len <= siz) {
+ uiop->uio_iovcnt--;
+ uiop->uio_iov++;
+ } else {
+ uiop->uio_iov->iov_base = (void *)
+ ((char *)uiop->uio_iov->iov_base + uiosiz);
+ uiop->uio_iov->iov_len -= uiosiz;
+ }
+ siz -= uiosiz;
+ }
+ nd->nd_dpos = mbufcp;
+ nd->nd_md = mp;
+ if (rem > 0) {
+ if (len < rem)
+ error = nfsm_advance(nd, rem, len);
+ else
+ nd->nd_dpos += rem;
+ }
+ return (error);
+}
+#endif /* !APPLE */
+
+/*
+ * Help break down an mbuf chain by setting the first siz bytes contiguous
+ * pointed to by returned val.
+ * This is used by the macro NFSM_DISSECT for tough
+ * cases.
+ */
+APPLESTATIC void *
+nfsm_dissct(struct nfsrv_descript *nd, int siz)
+{
+ mbuf_t mp2;
+ int siz2, xfer;
+ caddr_t p;
+ int left;
+ caddr_t retp;
+
+ retp = NULL;
+ left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
+ while (left == 0) {
+ nd->nd_md = mbuf_next(nd->nd_md);
+ if (nd->nd_md == NULL)
+ return (retp);
+ left = mbuf_len(nd->nd_md);
+ nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
+ }
+ if (left >= siz) {
+ retp = nd->nd_dpos;
+ nd->nd_dpos += siz;
+ } else if (mbuf_next(nd->nd_md) == NULL) {
+ return (retp);
+ } else if (siz > ncl_mbuf_mhlen) {
+ panic("nfs S too big");
+ } else {
+ NFSMGET(mp2);
+ mbuf_setnext(mp2, mbuf_next(nd->nd_md));
+ mbuf_setnext(nd->nd_md, mp2);
+ mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
+ nd->nd_md = mp2;
+ retp = p = NFSMTOD(mp2, caddr_t);
+ NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
+ siz2 = siz - left;
+ p += left;
+ mp2 = mbuf_next(mp2);
+ /* Loop around copying up the siz2 bytes */
+ while (siz2 > 0) {
+ if (mp2 == NULL)
+ return (NULL);
+ xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
+ if (xfer > 0) {
+ NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
+ NFSM_DATAP(mp2, xfer);
+ mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
+ p += xfer;
+ siz2 -= xfer;
+ }
+ if (siz2 > 0)
+ mp2 = mbuf_next(mp2);
+ }
+ mbuf_setlen(nd->nd_md, siz);
+ nd->nd_md = mp2;
+ nd->nd_dpos = NFSMTOD(mp2, caddr_t);
+ }
+ return (retp);
+}
+
+/*
+ * Advance the position in the mbuf chain.
+ * If offs == 0, this is a no-op, but it is simpler to just return from
+ * here than check for offs > 0 for all calls to nfsm_advance.
+ * If left == -1, it should be calculated here.
+ */
+APPLESTATIC int
+nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
+{
+
+ if (offs == 0)
+ return (0);
+ /*
+ * A negative offs should be considered a serious problem.
+ */
+ if (offs < 0)
+ panic("nfsrv_advance");
+
+ /*
+ * If left == -1, calculate it here.
+ */
+ if (left == -1)
+ left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
+ nd->nd_dpos;
+
+ /*
+ * Loop around, advancing over the mbuf data.
+ */
+ while (offs > left) {
+ offs -= left;
+ nd->nd_md = mbuf_next(nd->nd_md);
+ if (nd->nd_md == NULL)
+ return (EBADRPC);
+ left = mbuf_len(nd->nd_md);
+ nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
+ }
+ nd->nd_dpos += offs;
+ return (0);
+}
+
+/*
+ * Copy a string into mbuf(s).
+ * Return the number of bytes output, including XDR overheads.
+ */
+APPLESTATIC int
+nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
+{
+ mbuf_t m2;
+ int xfer, left;
+ mbuf_t m1;
+ int rem, bytesize;
+ u_int32_t *tl;
+ char *cp2;
+
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(siz);
+ rem = NFSM_RNDUP(siz) - siz;
+ bytesize = NFSX_UNSIGNED + siz + rem;
+ m2 = nd->nd_mb;
+ cp2 = nd->nd_bpos;
+ left = M_TRAILINGSPACE(m2);
+
+ /*
+ * Loop around copying the string to mbuf(s).
+ */
+ while (siz > 0) {
+ if (left == 0) {
+ if (siz > ncl_mbuf_mlen)
+ NFSMCLGET(m1, M_WAIT);
+ else
+ NFSMGET(m1);
+ mbuf_setlen(m1, 0);
+ mbuf_setnext(m2, m1);
+ m2 = m1;
+ cp2 = NFSMTOD(m2, caddr_t);
+ left = M_TRAILINGSPACE(m2);
+ }
+ if (left >= siz)
+ xfer = siz;
+ else
+ xfer = left;
+ NFSBCOPY(cp, cp2, xfer);
+ cp += xfer;
+ mbuf_setlen(m2, mbuf_len(m2) + xfer);
+ siz -= xfer;
+ left -= xfer;
+ if (siz == 0 && rem) {
+ if (left < rem)
+ panic("nfsm_strtom");
+ NFSBZERO(cp2 + xfer, rem);
+ mbuf_setlen(m2, mbuf_len(m2) + rem);
+ }
+ }
+ nd->nd_mb = m2;
+ nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
+ return (bytesize);
+}
+
+/*
+ * Called once to initialize data structures...
+ */
+APPLESTATIC void
+newnfs_init(void)
+{
+ static int nfs_inited = 0;
+
+ if (nfs_inited)
+ return;
+ nfs_inited = 1;
+
+ newnfs_true = txdr_unsigned(TRUE);
+ newnfs_false = txdr_unsigned(FALSE);
+ newnfs_xdrneg1 = txdr_unsigned(-1);
+ nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
+ if (nfscl_ticks < 1)
+ nfscl_ticks = 1;
+ NFSSETBOOTTIME(nfsboottime);
+
+ /*
+ * Initialize reply list and start timer
+ */
+ TAILQ_INIT(&nfsd_reqq);
+ NFS_TIMERINIT;
+}
+
+/*
+ * Put a file handle in an mbuf list.
+ * If the size argument == 0, just use the default size.
+ * set_true == 1 if there should be an newnfs_true prepended on the file handle.
+ * Return the number of bytes output, including XDR overhead.
+ */
+APPLESTATIC int
+nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
+{
+ u_int32_t *tl;
+ u_int8_t *cp;
+ int fullsiz, rem, bytesize = 0;
+
+ if (size == 0)
+ size = NFSX_MYFH;
+ switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
+ case ND_NFSV2:
+ if (size > NFSX_V2FH)
+ panic("fh size > NFSX_V2FH for NFSv2");
+ NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
+ NFSBCOPY(fhp, cp, size);
+ if (size < NFSX_V2FH)
+ NFSBZERO(cp + size, NFSX_V2FH - size);
+ bytesize = NFSX_V2FH;
+ break;
+ case ND_NFSV3:
+ case ND_NFSV4:
+ fullsiz = NFSM_RNDUP(size);
+ rem = fullsiz - size;
+ if (set_true) {
+ bytesize = 2 * NFSX_UNSIGNED + fullsiz;
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_true;
+ } else {
+ bytesize = NFSX_UNSIGNED + fullsiz;
+ }
+ (void) nfsm_strtom(nd, fhp, size);
+ break;
+ };
+ return (bytesize);
+}
+
+/*
+ * This function compares two net addresses by family and returns TRUE
+ * if they are the same host.
+ * If there is any doubt, return FALSE.
+ * The AF_INET family is handled as a special case so that address mbufs
+ * don't need to be saved to store "struct in_addr", which is only 4 bytes.
+ */
+APPLESTATIC int
+nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
+{
+ struct sockaddr_in *inetaddr;
+
+ switch (family) {
+ case AF_INET:
+ inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
+ if (inetaddr->sin_family == AF_INET &&
+ inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
+ return (1);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *inetaddr6;
+
+ inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
+ /* XXX - should test sin6_scope_id ? */
+ if (inetaddr6->sin6_family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
+ &haddr->had_inet6))
+ return (1);
+ }
+ break;
+#endif
+ };
+ return (0);
+}
+
+/*
+ * Similar to the above, but takes to NFSSOCKADDR_T args.
+ */
+APPLESTATIC int
+nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
+{
+ struct sockaddr_in *addr1, *addr2;
+ struct sockaddr *inaddr;
+
+ inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
+ switch (inaddr->sa_family) {
+ case AF_INET:
+ addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
+ addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
+ if (addr2->sin_family == AF_INET &&
+ addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
+ return (1);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *inet6addr1, *inet6addr2;
+
+ inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
+ inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
+ /* XXX - should test sin6_scope_id ? */
+ if (inet6addr2->sin6_family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
+ &inet6addr2->sin6_addr))
+ return (1);
+ }
+ break;
+#endif
+ };
+ return (0);
+}
+
+
+/*
+ * Trim the stuff already dissected off the mbuf list.
+ */
+APPLESTATIC void
+newnfs_trimleading(nd)
+ struct nfsrv_descript *nd;
+{
+ mbuf_t m, n;
+ int offs;
+
+ /*
+ * First, free up leading mbufs.
+ */
+ if (nd->nd_mrep != nd->nd_md) {
+ m = nd->nd_mrep;
+ while (mbuf_next(m) != nd->nd_md) {
+ if (mbuf_next(m) == NULL)
+ panic("nfsm trim leading");
+ m = mbuf_next(m);
+ }
+ mbuf_setnext(m, NULL);
+ mbuf_freem(nd->nd_mrep);
+ }
+ m = nd->nd_md;
+
+ /*
+ * Now, adjust this mbuf, based on nd_dpos.
+ */
+ offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
+ if (offs == mbuf_len(m)) {
+ n = m;
+ m = mbuf_next(m);
+ if (m == NULL)
+ panic("nfsm trim leading2");
+ mbuf_setnext(n, NULL);
+ mbuf_freem(n);
+ } else if (offs > 0) {
+ mbuf_setlen(m, mbuf_len(m) - offs);
+ NFSM_DATAP(m, offs);
+ } else if (offs < 0)
+ panic("nfsm trimleading offs");
+ nd->nd_mrep = m;
+ nd->nd_md = m;
+ nd->nd_dpos = NFSMTOD(m, caddr_t);
+}
+
+/*
+ * Trim trailing data off the mbuf list being built.
+ */
+APPLESTATIC void
+newnfs_trimtrailing(nd, mb, bpos)
+ struct nfsrv_descript *nd;
+ mbuf_t mb;
+ caddr_t bpos;
+{
+
+ if (mbuf_next(mb)) {
+ mbuf_freem(mbuf_next(mb));
+ mbuf_setnext(mb, NULL);
+ }
+ mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
+ nd->nd_mb = mb;
+ nd->nd_bpos = bpos;
+}
+
+/*
+ * Dissect a file handle on the client.
+ */
+APPLESTATIC int
+nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
+{
+ u_int32_t *tl;
+ struct nfsfh *nfhp;
+ int error, len;
+
+ *nfhpp = NULL;
+ if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
+ len > NFSX_FHMAX)
+ return (EBADRPC);
+ } else
+ len = NFSX_V2FH;
+ MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
+ M_NFSFH, M_WAITOK);
+ error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
+ if (error) {
+ FREE((caddr_t)nfhp, M_NFSFH);
+ return (error);
+ }
+ nfhp->nfh_len = len;
+ *nfhpp = nfhp;
+nfsmout:
+ return (error);
+}
+
+/*
+ * Break down the nfsv4 acl.
+ * If the aclp == NULL or won't fit in an acl, just discard the acl info.
+ */
+APPLESTATIC int
+nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
+ int *aclsizep, __unused NFSPROC_T *p)
+{
+ u_int32_t *tl;
+ int i, aclsize;
+ int acecnt, error = 0, aceerr = 0, acesize;
+
+ *aclerrp = 0;
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (aclp)
+ aclp->acl_cnt = 0;
+#endif
+ /*
+ * Parse out the ace entries and expect them to conform to
+ * what can be supported by R/W/X bits.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ aclsize = NFSX_UNSIGNED;
+ acecnt = fxdr_unsigned(int, *tl);
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (acecnt > ACL_MAX_ENTRIES)
+ aceerr = 1;
+#endif
+ if (nfsrv_useacl == 0)
+ aceerr = 1;
+ for (i = 0; i < acecnt; i++) {
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (aclp && !aceerr)
+ error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
+ &aceerr, &acesize, p);
+ else
+#endif
+ error = nfsrv_skipace(nd, &acesize);
+ if (error)
+ return (error);
+ aclsize += acesize;
+ }
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (aclp && !aceerr)
+ aclp->acl_cnt = acecnt;
+#endif
+ if (aceerr)
+ *aclerrp = aceerr;
+ if (aclsizep)
+ *aclsizep = aclsize;
+nfsmout:
+ return (error);
+}
+
+/*
+ * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
+ */
+static int
+nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
+{
+ u_int32_t *tl;
+ int error, len = 0;
+
+ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
+ len = fxdr_unsigned(int, *(tl + 3));
+ error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
+nfsmout:
+ *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
+ return (error);
+}
+
+/*
+ * Get attribute bits from an mbuf list.
+ * Returns EBADRPC for a parsing error, 0 otherwise.
+ * If the clearinvalid flag is set, clear the bits not supported.
+ */
+APPLESTATIC int
+nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
+ int *retnotsupp)
+{
+ u_int32_t *tl;
+ int cnt, i, outcnt;
+ int error = 0;
+
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ cnt = fxdr_unsigned(int, *tl);
+ if (cnt < 0)
+ return (NFSERR_BADXDR);
+ if (cnt > NFSATTRBIT_MAXWORDS) {
+ outcnt = NFSATTRBIT_MAXWORDS;
+ if (retnotsupp)
+ *retnotsupp = NFSERR_ATTRNOTSUPP;
+ } else {
+ outcnt = cnt;
+ }
+ NFSZERO_ATTRBIT(attrbitp);
+ if (outcnt > 0) {
+ NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
+ for (i = 0; i < outcnt; i++)
+ attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
+ }
+ if (cnt > outcnt)
+ error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
+ if (cntp)
+ *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
+nfsmout:
+ return (error);
+}
+
+/*
+ * Get the attributes for V4.
+ * If the compare flag is true, test for any attribute changes,
+ * otherwise return the attribute values.
+ * These attributes cover fields in "struct vattr", "struct statfs",
+ * "struct nfsfsinfo", the file handle and the lease duration.
+ * The value of retcmpp is set to 1 if all attributes are the same,
+ * and 0 otherwise.
+ * Returns EBADRPC if it can't be parsed, 0 otherwise.
+ */
+APPLESTATIC int
+nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
+ struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
+ struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
+ struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
+ u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
+{
+ u_int32_t *tl;
+ int i = 0, j, k, l, m, bitpos, attrsum = 0;
+ int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
+ u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
+ nfsattrbit_t attrbits, retattrbits, checkattrbits;
+ struct nfsfh *tnfhp;
+ struct nfsreferral *refp;
+ u_quad_t tquad;
+ nfsquad_t tnfsquad;
+ struct timespec temptime;
+ uid_t uid;
+ gid_t gid;
+ long fid;
+ u_int32_t freenum = 0, tuint;
+ u_int64_t uquad = 0, thyp, thyp2;
+#ifdef QUOTA
+ struct dqblk dqb;
+ uid_t savuid;
+#endif
+
+ if (compare) {
+ retnotsup = 0;
+ error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
+ } else {
+ error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
+ }
+ if (error)
+ return (error);
+
+ if (compare) {
+ *retcmpp = retnotsup;
+ } else {
+ /*
+ * Just set default values to some of the important ones.
+ */
+ if (nap != NULL) {
+ nap->na_type = VREG;
+ nap->na_mode = 0;
+ nap->na_rdev = (NFSDEV_T)0;
+ nap->na_mtime.tv_sec = 0;
+ nap->na_mtime.tv_nsec = 0;
+ nap->na_gen = 0;
+ nap->na_flags = 0;
+ nap->na_blocksize = NFS_FABLKSIZE;
+ }
+ if (sbp != NULL) {
+ sbp->f_bsize = NFS_FABLKSIZE;
+ sbp->f_blocks = 0;
+ sbp->f_bfree = 0;
+ sbp->f_bavail = 0;
+ sbp->f_files = 0;
+ sbp->f_ffree = 0;
+ }
+ if (fsp != NULL) {
+ fsp->fs_rtmax = 8192;
+ fsp->fs_rtpref = 8192;
+ fsp->fs_maxname = NFS_MAXNAMLEN;
+ fsp->fs_wtmax = 8192;
+ fsp->fs_wtpref = 8192;
+ fsp->fs_wtmult = NFS_FABLKSIZE;
+ fsp->fs_dtpref = 8192;
+ fsp->fs_maxfilesize = 0xffffffffffffffffull;
+ fsp->fs_timedelta.tv_sec = 0;
+ fsp->fs_timedelta.tv_nsec = 1;
+ fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
+ NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
+ }
+ if (pc != NULL) {
+ pc->pc_linkmax = LINK_MAX;
+ pc->pc_namemax = NAME_MAX;
+ pc->pc_notrunc = 0;
+ pc->pc_chownrestricted = 0;
+ pc->pc_caseinsensitive = 0;
+ pc->pc_casepreserving = 1;
+ }
+ }
+
+ /*
+ * Loop around getting the attributes.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ attrsize = fxdr_unsigned(int, *tl);
+ for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
+ if (attrsum > attrsize) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ if (NFSISSET_ATTRBIT(&attrbits, bitpos))
+ switch (bitpos) {
+ case NFSATTRBIT_SUPPORTEDATTRS:
+ retnotsup = 0;
+ if (compare || nap == NULL)
+ error = nfsrv_getattrbits(nd, &retattrbits,
+ &cnt, &retnotsup);
+ else
+ error = nfsrv_getattrbits(nd, &nap->na_suppattr,
+ &cnt, &retnotsup);
+ if (error)
+ return (error);
+ if (compare && !(*retcmpp)) {
+ NFSSETSUPP_ATTRBIT(&checkattrbits);
+ if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
+ || retnotsup)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += cnt;
+ break;
+ case NFSATTRBIT_TYPE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nap->na_type != nfsv34tov_type(*tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_type = nfsv34tov_type(*tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_FHEXPIRETYPE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp)) {
+ if (fxdr_unsigned(int, *tl) !=
+ NFSV4FHTYPE_PERSISTENT)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CHANGE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nap->na_filerev != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_filerev = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SIZE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nap->na_size != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_size = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_LINKSUPPORT:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_properties & NFSV3_FSFLINK) {
+ if (*tl == newnfs_false)
+ *retcmpp = NFSERR_NOTSAME;
+ } else {
+ if (*tl == newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ }
+ } else if (fsp != NULL) {
+ if (*tl == newnfs_true)
+ fsp->fs_properties |= NFSV3_FSFLINK;
+ else
+ fsp->fs_properties &= ~NFSV3_FSFLINK;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_SYMLINKSUPPORT:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
+ if (*tl == newnfs_false)
+ *retcmpp = NFSERR_NOTSAME;
+ } else {
+ if (*tl == newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ }
+ } else if (fsp != NULL) {
+ if (*tl == newnfs_true)
+ fsp->fs_properties |= NFSV3_FSFSYMLINK;
+ else
+ fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_NAMEDATTR:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp)) {
+ if (*tl != newnfs_false)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_FSID:
+ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
+ thyp = fxdr_hyper(tl);
+ tl += 2;
+ thyp2 = fxdr_hyper(tl);
+ if (compare) {
+ if (*retcmpp == 0) {
+ if (thyp != (u_int64_t)
+ vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
+ thyp2 != (u_int64_t)
+ vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_filesid[0] = thyp;
+ nap->na_filesid[1] = thyp2;
+ }
+ attrsum += (4 * NFSX_UNSIGNED);
+ break;
+ case NFSATTRBIT_UNIQUEHANDLES:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp)) {
+ if (*tl != newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_LEASETIME:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
+ !(*retcmpp))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (leasep != NULL) {
+ *leasep = fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_RDATTRERROR:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp))
+ *retcmpp = NFSERR_INVAL;
+ } else if (rderrp != NULL) {
+ *rderrp = fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_ACL:
+ if (compare) {
+ if (!(*retcmpp)) {
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (nfsrv_useacl) {
+ NFSACL_T *naclp;
+
+ naclp = acl_alloc();
+ error = nfsrv_dissectacl(nd, naclp, &aceerr,
+ &cnt, p);
+ if (error) {
+ acl_free(naclp);
+ return (error);
+ }
+ if (aceerr || nfsrv_compareacl(aclp, naclp))
+ *retcmpp = NFSERR_NOTSAME;
+ acl_free(naclp);
+ } else
+#endif
+ {
+ error = nfsrv_dissectacl(nd, NULL, &aceerr,
+ &cnt, p);
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ }
+ }
+ } else {
+ if (vp != NULL && aclp != NULL)
+ error = nfsrv_dissectacl(nd, aclp, &aceerr,
+ &cnt, p);
+ else
+ error = nfsrv_dissectacl(nd, NULL, &aceerr,
+ &cnt, p);
+ if (error)
+ return (error);
+ }
+ attrsum += cnt;
+ break;
+ case NFSATTRBIT_ACLSUPPORT:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp)) {
+ if (nfsrv_useacl) {
+ if (fxdr_unsigned(u_int32_t, *tl) !=
+ NFSV4ACE_SUPTYPES)
+ *retcmpp = NFSERR_NOTSAME;
+ } else {
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ }
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_ARCHIVE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CANSETTIME:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
+ if (*tl == newnfs_false)
+ *retcmpp = NFSERR_NOTSAME;
+ } else {
+ if (*tl == newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ }
+ } else if (fsp != NULL) {
+ if (*tl == newnfs_true)
+ fsp->fs_properties |= NFSV3_FSFCANSETTIME;
+ else
+ fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CASEINSENSITIVE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (*tl != newnfs_false)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (pc != NULL) {
+ pc->pc_caseinsensitive =
+ fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CASEPRESERVING:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (*tl != newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (pc != NULL) {
+ pc->pc_casepreserving =
+ fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CHOWNRESTRICTED:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (*tl != newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (pc != NULL) {
+ pc->pc_chownrestricted =
+ fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_FILEHANDLE:
+ error = nfsm_getfh(nd, &tnfhp);
+ if (error)
+ return (error);
+ tfhsize = tnfhp->nfh_len;
+ if (compare) {
+ if (!(*retcmpp) &&
+ !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
+ fhp, fhsize))
+ *retcmpp = NFSERR_NOTSAME;
+ FREE((caddr_t)tnfhp, M_NFSFH);
+ } else if (nfhpp != NULL) {
+ *nfhpp = tnfhp;
+ } else {
+ FREE((caddr_t)tnfhp, M_NFSFH);
+ }
+ attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
+ break;
+ case NFSATTRBIT_FILEID:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ thyp = fxdr_hyper(tl);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if ((u_int64_t)nap->na_fileid != thyp)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ if (*tl++)
+ printf("NFSv4 fileid > 32bits\n");
+ nap->na_fileid = thyp;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FILESAVAIL:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp) &&
+ sfp->sf_afiles != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (sfp != NULL) {
+ sfp->sf_afiles = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FILESFREE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp) &&
+ sfp->sf_ffiles != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (sfp != NULL) {
+ sfp->sf_ffiles = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FILESTOTAL:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp) &&
+ sfp->sf_tfiles != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (sfp != NULL) {
+ sfp->sf_tfiles = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FSLOCATIONS:
+ error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
+ if (error)
+ return (error);
+ attrsum += l;
+ if (compare && !(*retcmpp)) {
+ refp = nfsv4root_getreferral(vp, NULL, 0);
+ if (refp != NULL) {
+ if (cp == NULL || cp2 == NULL ||
+ strcmp(cp, "/") ||
+ strcmp(cp2, refp->nfr_srvlist))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (m == 0) {
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ }
+ if (cp != NULL)
+ free(cp, M_NFSSTRING);
+ if (cp2 != NULL)
+ free(cp2, M_NFSSTRING);
+ break;
+ case NFSATTRBIT_HIDDEN:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_HOMOGENEOUS:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_properties &
+ NFSV3_FSFHOMOGENEOUS) {
+ if (*tl == newnfs_false)
+ *retcmpp = NFSERR_NOTSAME;
+ } else {
+ if (*tl == newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ }
+ } else if (fsp != NULL) {
+ if (*tl == newnfs_true)
+ fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
+ else
+ fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_MAXFILESIZE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ tnfsquad.qval = fxdr_hyper(tl);
+ if (compare) {
+ if (!(*retcmpp)) {
+ tquad = NFSRV_MAXFILESIZE;
+ if (tquad != tnfsquad.qval)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (fsp != NULL) {
+ fsp->fs_maxfilesize = tnfsquad.qval;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_MAXLINK:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fxdr_unsigned(int, *tl) != LINK_MAX)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (pc != NULL) {
+ pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_MAXNAME:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_maxname !=
+ fxdr_unsigned(u_int32_t, *tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else {
+ tuint = fxdr_unsigned(u_int32_t, *tl);
+ /*
+ * Some Linux NFSv4 servers report this
+ * as 0 or 4billion, so I'll set it to
+ * NFS_MAXNAMLEN. If a server actually creates
+ * a name longer than NFS_MAXNAMLEN, it will
+ * get an error back.
+ */
+ if (tuint == 0 || tuint > NFS_MAXNAMLEN)
+ tuint = NFS_MAXNAMLEN;
+ if (fsp != NULL)
+ fsp->fs_maxname = tuint;
+ if (pc != NULL)
+ pc->pc_namemax = tuint;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_MAXREAD:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
+ *(tl + 1)) || *tl != 0)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (fsp != NULL) {
+ fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
+ fsp->fs_rtpref = fsp->fs_rtmax;
+ fsp->fs_dtpref = fsp->fs_rtpref;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_MAXWRITE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
+ *(tl + 1)) || *tl != 0)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (fsp != NULL) {
+ fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
+ fsp->fs_wtpref = fsp->fs_wtmax;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_MIMETYPE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *tl);
+ attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
+ error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
+ if (error)
+ goto nfsmout;
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ break;
+ case NFSATTRBIT_MODE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nap->na_mode != nfstov_mode(*tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_mode = nfstov_mode(*tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_NOTRUNC:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (*tl != newnfs_true)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (pc != NULL) {
+ pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_NUMLINKS:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ tuint = fxdr_unsigned(u_int32_t, *tl);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if ((u_int32_t)nap->na_nlink != tuint)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_nlink = tuint;
+ }
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_OWNER:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ j = fxdr_unsigned(int, *tl);
+ if (j < 0)
+ return (NFSERR_BADXDR);
+ attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
+ if (j > NFSV4_SMALLSTR)
+ cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
+ else
+ cp = namestr;
+ error = nfsrv_mtostr(nd, cp, j);
+ if (error) {
+ if (j > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ return (error);
+ }
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nfsv4_strtouid(cp, j, &uid, p) ||
+ nap->na_uid != uid)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ if (nfsv4_strtouid(cp, j, &uid, p))
+ nap->na_uid = nfsrv_defaultuid;
+ else
+ nap->na_uid = uid;
+ }
+ if (j > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ break;
+ case NFSATTRBIT_OWNERGROUP:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ j = fxdr_unsigned(int, *tl);
+ if (j < 0)
+ return (NFSERR_BADXDR);
+ attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
+ if (j > NFSV4_SMALLSTR)
+ cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
+ else
+ cp = namestr;
+ error = nfsrv_mtostr(nd, cp, j);
+ if (error) {
+ if (j > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ return (error);
+ }
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nfsv4_strtogid(cp, j, &gid, p) ||
+ nap->na_gid != gid)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ if (nfsv4_strtogid(cp, j, &gid, p))
+ nap->na_gid = nfsrv_defaultgid;
+ else
+ nap->na_gid = gid;
+ }
+ if (j > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ break;
+ case NFSATTRBIT_QUOTAHARD:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (sbp != NULL) {
+ if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
+ freenum = sbp->f_bfree;
+ else
+ freenum = sbp->f_bavail;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
+ USRQUOTA), cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = min(dqb.dqb_bhardlimit, freenum);
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ uquad = (u_int64_t)freenum;
+ NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
+ }
+ if (compare && !(*retcmpp)) {
+ if (uquad != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_QUOTASOFT:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (sbp != NULL) {
+ if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
+ freenum = sbp->f_bfree;
+ else
+ freenum = sbp->f_bavail;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
+ USRQUOTA), cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = min(dqb.dqb_bsoftlimit, freenum);
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ uquad = (u_int64_t)freenum;
+ NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
+ }
+ if (compare && !(*retcmpp)) {
+ if (uquad != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_QUOTAUSED:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (sbp != NULL) {
+ freenum = 0;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
+ USRQUOTA), cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = dqb.dqb_curblocks;
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ uquad = (u_int64_t)freenum;
+ NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
+ }
+ if (compare && !(*retcmpp)) {
+ if (uquad != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_RAWDEV:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
+ j = fxdr_unsigned(int, *tl++);
+ k = fxdr_unsigned(int, *tl);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (nap->na_rdev != NFSMAKEDEV(j, k))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_rdev = NFSMAKEDEV(j, k);
+ }
+ attrsum += NFSX_V4SPECDATA;
+ break;
+ case NFSATTRBIT_SPACEAVAIL:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp) &&
+ sfp->sf_abytes != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (sfp != NULL) {
+ sfp->sf_abytes = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SPACEFREE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp) &&
+ sfp->sf_fbytes != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (sfp != NULL) {
+ sfp->sf_fbytes = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SPACETOTAL:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ if (compare) {
+ if (!(*retcmpp) &&
+ sfp->sf_tbytes != fxdr_hyper(tl))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (sfp != NULL) {
+ sfp->sf_tbytes = fxdr_hyper(tl);
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SPACEUSED:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ thyp = fxdr_hyper(tl);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if ((u_int64_t)nap->na_bytes != thyp)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_bytes = thyp;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SYSTEM:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ attrsum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_TIMEACCESS:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ fxdr_nfsv4time(tl, &temptime);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (!NFS_CMPTIME(temptime, nap->na_atime))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_atime = temptime;
+ }
+ attrsum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEACCESSSET:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ attrsum += NFSX_UNSIGNED;
+ i = fxdr_unsigned(int, *tl);
+ if (i == NFSV4SATTRTIME_TOCLIENT) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ attrsum += NFSX_V4TIME;
+ }
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_INVAL;
+ break;
+ case NFSATTRBIT_TIMEBACKUP:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ attrsum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMECREATE:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ attrsum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEDELTA:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ if (fsp != NULL) {
+ if (compare) {
+ if (!(*retcmpp)) {
+ if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
+ fxdr_unsigned(u_int32_t, *(tl + 1)) ||
+ (u_int32_t)fsp->fs_timedelta.tv_nsec !=
+ (fxdr_unsigned(u_int32_t, *(tl + 2)) %
+ 1000000000) ||
+ *tl != 0)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else {
+ fxdr_nfsv4time(tl, &fsp->fs_timedelta);
+ }
+ }
+ attrsum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEMETADATA:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ fxdr_nfsv4time(tl, &temptime);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (!NFS_CMPTIME(temptime, nap->na_ctime))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_ctime = temptime;
+ }
+ attrsum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEMODIFY:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ fxdr_nfsv4time(tl, &temptime);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (!NFS_CMPTIME(temptime, nap->na_mtime))
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ } else if (nap != NULL) {
+ nap->na_mtime = temptime;
+ }
+ attrsum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEMODIFYSET:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ attrsum += NFSX_UNSIGNED;
+ i = fxdr_unsigned(int, *tl);
+ if (i == NFSV4SATTRTIME_TOCLIENT) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
+ attrsum += NFSX_V4TIME;
+ }
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_INVAL;
+ break;
+ case NFSATTRBIT_MOUNTEDONFILEID:
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
+ thyp = fxdr_hyper(tl);
+ if (compare) {
+ if (!(*retcmpp)) {
+ if (*tl++) {
+ *retcmpp = NFSERR_NOTSAME;
+ } else {
+ if (!vp || !nfsrv_atroot(vp, &fid))
+ fid = nap->na_fileid;
+ if ((u_int64_t)fid != thyp)
+ *retcmpp = NFSERR_NOTSAME;
+ }
+ }
+ } else if (nap != NULL) {
+ if (*tl++)
+ printf("NFSv4 mounted on fileid > 32bits\n");
+ nap->na_mntonfileno = thyp;
+ }
+ attrsum += NFSX_HYPER;
+ break;
+ default:
+ printf("EEK! nfsv4_loadattr unknown attr=%d\n",
+ bitpos);
+ if (compare && !(*retcmpp))
+ *retcmpp = NFSERR_ATTRNOTSUPP;
+ /*
+ * and get out of the loop, since we can't parse
+ * the unknown attrbute data.
+ */
+ bitpos = NFSATTRBIT_MAX;
+ break;
+ };
+ }
+
+ /*
+ * some clients pad the attrlist, so we need to skip over the
+ * padding.
+ */
+ if (attrsum > attrsize) {
+ error = NFSERR_BADXDR;
+ } else {
+ attrsize = NFSM_RNDUP(attrsize);
+ if (attrsum < attrsize)
+ error = nfsm_advance(nd, attrsize - attrsum, -1);
+ }
+nfsmout:
+ return (error);
+}
+
+/*
+ * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
+ * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
+ * The first argument is a pointer to an nfsv4lock structure.
+ * The second argument is 1 iff a blocking lock is wanted.
+ * If this argument is 0, the call waits until no thread either wants nor
+ * holds an exclusive lock.
+ * It returns 1 if the lock was acquired, 0 otherwise.
+ * If several processes call this function concurrently wanting the exclusive
+ * lock, one will get the lock and the rest will return without getting the
+ * lock. (If the caller must have the lock, it simply calls this function in a
+ * loop until the function returns 1 to indicate the lock was acquired.)
+ * Any usecnt must be decremented by calling nfsv4_relref() before
+ * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
+ * be called in a loop.
+ * The last argument is set to indicate if the call slept, iff not NULL.
+ */
+APPLESTATIC int
+nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
+ void *mutex)
+{
+
+ if (isleptp)
+ *isleptp = 0;
+ /*
+ * If a lock is wanted, loop around until the lock is acquired by
+ * someone and then released. If I want the lock, try to acquire it.
+ * For a lock to be issued, no lock must be in force and the usecnt
+ * must be zero.
+ */
+ if (iwantlock) {
+ if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
+ lp->nfslock_usecnt == 0) {
+ lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
+ lp->nfslock_lock |= NFSV4LOCK_LOCK;
+ return (1);
+ }
+ lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
+ }
+ while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
+ lp->nfslock_lock |= NFSV4LOCK_WANTED;
+ if (isleptp)
+ *isleptp = 1;
+ (void) nfsmsleep(&lp->nfslock_lock, mutex,
+ PZERO - 1, "nfsv4lck", NULL);
+ if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
+ lp->nfslock_usecnt == 0) {
+ lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
+ lp->nfslock_lock |= NFSV4LOCK_LOCK;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Release the lock acquired by nfsv4_lock().
+ * The second argument is set to 1 to indicate the nfslock_usecnt should be
+ * incremented, as well.
+ */
+APPLESTATIC void
+nfsv4_unlock(struct nfsv4lock *lp, int incref)
+{
+
+ lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
+ if (incref)
+ lp->nfslock_usecnt++;
+ nfsv4_wanted(lp);
+}
+
+/*
+ * Release a reference cnt.
+ */
+APPLESTATIC void
+nfsv4_relref(struct nfsv4lock *lp)
+{
+
+ if (lp->nfslock_usecnt <= 0)
+ panic("nfsv4root ref cnt");
+ lp->nfslock_usecnt--;
+ if (lp->nfslock_usecnt == 0)
+ nfsv4_wanted(lp);
+}
+
+/*
+ * Get a reference cnt.
+ * This function will wait for any exclusive lock to be released, but will
+ * not wait for threads that want the exclusive lock. If priority needs
+ * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
+ * with the 2nd argument == 0 should be done before calling nfsv4_getref().
+ */
+APPLESTATIC void
+nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
+{
+
+ if (isleptp)
+ *isleptp = 0;
+
+ /*
+ * Wait for a lock held.
+ */
+ while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
+ lp->nfslock_lock |= NFSV4LOCK_WANTED;
+ if (isleptp)
+ *isleptp = 1;
+ (void) nfsmsleep(&lp->nfslock_lock, mutex,
+ PZERO - 1, "nfsv4lck", NULL);
+ }
+
+ lp->nfslock_usecnt++;
+}
+
+/*
+ * Wake up anyone sleeping, waiting for this lock.
+ */
+static void
+nfsv4_wanted(struct nfsv4lock *lp)
+{
+
+ if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
+ lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
+ wakeup((caddr_t)&lp->nfslock_lock);
+ }
+}
+
+/*
+ * Copy a string from an mbuf list into a character array.
+ * Return EBADRPC if there is an mbuf error,
+ * 0 otherwise.
+ */
+APPLESTATIC int
+nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
+{
+ char *cp;
+ int xfer, len;
+ mbuf_t mp;
+ int rem, error = 0;
+
+ mp = nd->nd_md;
+ cp = nd->nd_dpos;
+ len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
+ rem = NFSM_RNDUP(siz) - siz;
+ while (siz > 0) {
+ if (len > siz)
+ xfer = siz;
+ else
+ xfer = len;
+ NFSBCOPY(cp, str, xfer);
+ str += xfer;
+ siz -= xfer;
+ if (siz > 0) {
+ mp = mbuf_next(mp);
+ if (mp == NULL)
+ return (EBADRPC);
+ cp = NFSMTOD(mp, caddr_t);
+ len = mbuf_len(mp);
+ } else {
+ cp += xfer;
+ len -= xfer;
+ }
+ }
+ *str = '\0';
+ nd->nd_dpos = cp;
+ nd->nd_md = mp;
+ if (rem > 0) {
+ if (len < rem)
+ error = nfsm_advance(nd, rem, len);
+ else
+ nd->nd_dpos += rem;
+ }
+ return (error);
+}
+
+/*
+ * Fill in the attributes as marked by the bitmap (V4).
+ */
+APPLESTATIC int
+nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp,
+ struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
+ struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr)
+{
+ int bitpos, retnum = 0;
+ u_int32_t *tl;
+ int siz, prefixnum, error;
+ u_char *cp, namestr[NFSV4_SMALLSTR];
+ nfsattrbit_t attrbits, retbits;
+ nfsattrbit_t *retbitp = &retbits;
+ u_int32_t freenum, *retnump;
+ u_int64_t uquad;
+ long fid;
+ struct statfs fs;
+ struct nfsfsinfo fsinf;
+ struct timespec temptime;
+ struct timeval curtime;
+ NFSACL_T *aclp, *naclp = NULL;
+#ifdef QUOTA
+ struct dqblk dqb;
+ uid_t savuid;
+#endif
+
+ /*
+ * First, set the bits that can be filled and get fsinfo.
+ */
+ NFSSET_ATTRBIT(retbitp, attrbitp);
+ /* If p and cred are NULL, it is a client side call */
+ if (p == NULL && cred == NULL) {
+ NFSCLRNOTSETABLE_ATTRBIT(retbitp);
+ aclp = saclp;
+ } else {
+ NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
+#ifdef NFS4_ACL_EXTATTR_NAME
+ naclp = acl_alloc();
+#endif
+ aclp = naclp;
+ }
+ nfsvno_getfs(&fsinf, isdgram);
+#ifndef APPLE
+ /*
+ * Get the VFS_STATFS(), since some attributes need them.
+ */
+ if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
+ error = VFS_STATFS(vnode_mount(vp), &fs, p);
+ if (error != 0) {
+ if (reterr) {
+ nd->nd_repstat = NFSERR_ACCES;
+ return (0);
+ }
+ NFSCLRSTATFS_ATTRBIT(retbitp);
+ }
+ }
+#endif
+
+ /*
+ * And the NFSv4 ACL...
+ */
+ if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT)
+#ifdef NFS4_ACL_EXTATTR_NAME
+ && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
+ !NFSHASNFS4ACL(vnode_mount(vp))))
+#endif
+ ) {
+ NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
+ }
+ if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
+ !NFSHASNFS4ACL(vnode_mount(vp)))) {
+#endif
+ NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
+#ifdef NFS4_ACL_EXTATTR_NAME
+ } else if (naclp != NULL) {
+ NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ error = VOP_ACCESS(vp, VREAD_ACL, cred, p);
+ if (error == 0)
+ error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp,
+ cred, p);
+ NFSVOPUNLOCK(vp, 0, p);
+ if (error != 0) {
+ if (reterr) {
+ nd->nd_repstat = NFSERR_ACCES;
+ return (0);
+ }
+ NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
+ }
+ }
+#endif
+ }
+ /*
+ * Put out the attribute bitmap for the ones being filled in
+ * and get the field for the number of attributes returned.
+ */
+ prefixnum = nfsrv_putattrbit(nd, retbitp);
+ NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
+ prefixnum += NFSX_UNSIGNED;
+
+ /*
+ * Now, loop around filling in the attributes for each bit set.
+ */
+ for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
+ if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
+ switch (bitpos) {
+ case NFSATTRBIT_SUPPORTEDATTRS:
+ NFSSETSUPP_ATTRBIT(&attrbits);
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
+ && !NFSHASNFS4ACL(vnode_mount(vp))))
+#endif
+ {
+ NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
+ NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
+ }
+ retnum += nfsrv_putattrbit(nd, &attrbits);
+ break;
+ case NFSATTRBIT_TYPE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = vtonfsv34_type(vap->va_type);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_FHEXPIRETYPE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CHANGE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ txdr_hyper(vap->va_filerev, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SIZE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ txdr_hyper(vap->va_size, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_LINKSUPPORT:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (fsinf.fs_properties & NFSV3FSINFO_LINK)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_SYMLINKSUPPORT:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_NAMEDATTR:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_FSID:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
+ *tl++ = 0;
+ *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
+ *tl++ = 0;
+ *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]);
+ retnum += NFSX_V4FSID;
+ break;
+ case NFSATTRBIT_UNIQUEHANDLES:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_true;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_LEASETIME:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(nfsrv_lease);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_RDATTRERROR:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(rderror);
+ retnum += NFSX_UNSIGNED;
+ break;
+ /*
+ * Recommended Attributes. (Only the supported ones.)
+ */
+#ifdef NFS4_ACL_EXTATTR_NAME
+ case NFSATTRBIT_ACL:
+ retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
+ break;
+ case NFSATTRBIT_ACLSUPPORT:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
+ retnum += NFSX_UNSIGNED;
+ break;
+#endif
+ case NFSATTRBIT_CANSETTIME:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CASEINSENSITIVE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CASEPRESERVING:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_true;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_CHOWNRESTRICTED:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_true;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_FILEHANDLE:
+ retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
+ break;
+ case NFSATTRBIT_FILEID:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ *tl = txdr_unsigned(vap->va_fileid);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FILESAVAIL:
+ /*
+ * Check quota and use min(quota, f_ffree).
+ */
+ freenum = fs.f_ffree;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
+ cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
+ freenum);
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ *tl = txdr_unsigned(freenum);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FILESFREE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ *tl = txdr_unsigned(fs.f_ffree);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FILESTOTAL:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ *tl = txdr_unsigned(fs.f_files);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_FSLOCATIONS:
+ NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
+ *tl++ = 0;
+ *tl = 0;
+ retnum += 2 * NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_HOMOGENEOUS:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_MAXFILESIZE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ uquad = NFSRV_MAXFILESIZE;
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_MAXLINK:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(LINK_MAX);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_MAXNAME:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFS_MAXNAMLEN);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_MAXREAD:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ *tl = txdr_unsigned(fsinf.fs_rtmax);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_MAXWRITE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ *tl = txdr_unsigned(fsinf.fs_wtmax);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_MODE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = vtonfsv34_mode(vap->va_mode);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_NOTRUNC:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = newnfs_true;
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_NUMLINKS:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(vap->va_nlink);
+ retnum += NFSX_UNSIGNED;
+ break;
+ case NFSATTRBIT_OWNER:
+ cp = namestr;
+ nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
+ retnum += nfsm_strtom(nd, cp, siz);
+ if (cp != namestr)
+ free(cp, M_NFSSTRING);
+ break;
+ case NFSATTRBIT_OWNERGROUP:
+ cp = namestr;
+ nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
+ retnum += nfsm_strtom(nd, cp, siz);
+ if (cp != namestr)
+ free(cp, M_NFSSTRING);
+ break;
+ case NFSATTRBIT_QUOTAHARD:
+ if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
+ freenum = fs.f_bfree;
+ else
+ freenum = fs.f_bavail;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
+ cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = min(dqb.dqb_bhardlimit, freenum);
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ uquad = (u_int64_t)freenum;
+ NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_QUOTASOFT:
+ if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
+ freenum = fs.f_bfree;
+ else
+ freenum = fs.f_bavail;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
+ cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = min(dqb.dqb_bsoftlimit, freenum);
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ uquad = (u_int64_t)freenum;
+ NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_QUOTAUSED:
+ freenum = 0;
+#ifdef QUOTA
+ /*
+ * ufs_quotactl() insists that the uid argument
+ * equal p_ruid for non-root quota access, so
+ * we'll just make sure that's the case.
+ */
+ savuid = p->p_cred->p_ruid;
+ p->p_cred->p_ruid = cred->cr_uid;
+ if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
+ cred->cr_uid, (caddr_t)&dqb, p))
+ freenum = dqb.dqb_curblocks;
+ p->p_cred->p_ruid = savuid;
+#endif /* QUOTA */
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ uquad = (u_int64_t)freenum;
+ NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_RAWDEV:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
+ *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
+ *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
+ retnum += NFSX_V4SPECDATA;
+ break;
+ case NFSATTRBIT_SPACEAVAIL:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
+ uquad = (u_int64_t)fs.f_bfree;
+ else
+ uquad = (u_int64_t)fs.f_bavail;
+ uquad *= fs.f_bsize;
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SPACEFREE:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ uquad = (u_int64_t)fs.f_bfree;
+ uquad *= fs.f_bsize;
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SPACETOTAL:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ uquad = (u_int64_t)fs.f_blocks;
+ uquad *= fs.f_bsize;
+ txdr_hyper(uquad, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_SPACEUSED:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ txdr_hyper(vap->va_bytes, tl);
+ retnum += NFSX_HYPER;
+ break;
+ case NFSATTRBIT_TIMEACCESS:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
+ txdr_nfsv4time(&vap->va_atime, tl);
+ retnum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEACCESSSET:
+ NFSGETTIME(&curtime);
+ if (vap->va_atime.tv_sec != curtime.tv_sec) {
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
+ *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
+ txdr_nfsv4time(&vap->va_atime, tl);
+ retnum += NFSX_V4SETTIME;
+ } else {
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
+ retnum += NFSX_UNSIGNED;
+ }
+ break;
+ case NFSATTRBIT_TIMEDELTA:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
+ temptime.tv_sec = 0;
+ temptime.tv_nsec = 1000000000 / hz;
+ txdr_nfsv4time(&temptime, tl);
+ retnum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEMETADATA:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
+ txdr_nfsv4time(&vap->va_ctime, tl);
+ retnum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEMODIFY:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
+ txdr_nfsv4time(&vap->va_mtime, tl);
+ retnum += NFSX_V4TIME;
+ break;
+ case NFSATTRBIT_TIMEMODIFYSET:
+ NFSGETTIME(&curtime);
+ if (vap->va_mtime.tv_sec != curtime.tv_sec) {
+ NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
+ *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
+ txdr_nfsv4time(&vap->va_mtime, tl);
+ retnum += NFSX_V4SETTIME;
+ } else {
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
+ retnum += NFSX_UNSIGNED;
+ }
+ break;
+ case NFSATTRBIT_MOUNTEDONFILEID:
+ NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+ *tl++ = 0;
+ if (nfsrv_atroot(vp, &fid))
+ *tl = txdr_unsigned(fid);
+ else
+ *tl = txdr_unsigned(vap->va_fileid);
+ retnum += NFSX_HYPER;
+ break;
+ default:
+ printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
+ };
+ }
+ }
+#ifdef NFS4_ACL_EXTATTR_NAME
+ if (naclp != NULL)
+ acl_free(naclp);
+#endif
+ *retnump = txdr_unsigned(retnum);
+ return (retnum + prefixnum);
+}
+
+/*
+ * Put the attribute bits onto an mbuf list.
+ * Return the number of bytes of output generated.
+ */
+APPLESTATIC int
+nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
+{
+ u_int32_t *tl;
+ int cnt, i, bytesize;
+
+ for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
+ if (attrbitp->bits[cnt - 1])
+ break;
+ bytesize = (cnt + 1) * NFSX_UNSIGNED;
+ NFSM_BUILD(tl, u_int32_t *, bytesize);
+ *tl++ = txdr_unsigned(cnt);
+ for (i = 0; i < cnt; i++)
+ *tl++ = txdr_unsigned(attrbitp->bits[i]);
+ return (bytesize);
+}
+
+/*
+ * Convert a uid to a string.
+ * If the lookup fails, just output the digits.
+ * uid - the user id
+ * cpp - points to a buffer of size NFSV4_SMALLSTR
+ * (malloc a larger one, as required)
+ * retlenp - pointer to length to be returned
+ */
+APPLESTATIC void
+nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
+{
+ int i;
+ struct nfsusrgrp *usrp;
+ u_char *cp = *cpp;
+ uid_t tmp;
+ int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
+
+ cnt = 0;
+tryagain:
+ NFSLOCKNAMEID();
+ if (nfsrv_dnsname) {
+ /*
+ * Always map nfsrv_defaultuid to "nobody".
+ */
+ if (uid == nfsrv_defaultuid) {
+ i = nfsrv_dnsnamelen + 7;
+ if (i > len) {
+ NFSUNLOCKNAMEID();
+ if (len > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ cp = malloc(i, M_NFSSTRING, M_WAITOK);
+ *cpp = cp;
+ len = i;
+ goto tryagain;
+ }
+ *retlenp = i;
+ NFSBCOPY("nobody@", cp, 7);
+ cp += 7;
+ NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+ NFSUNLOCKNAMEID();
+ return;
+ }
+ hasampersand = 0;
+ LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
+ if (usrp->lug_uid == uid) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ /*
+ * If the name doesn't already have an '@'
+ * in it, append @domainname to it.
+ */
+ for (i = 0; i < usrp->lug_namelen; i++) {
+ if (usrp->lug_name[i] == '@') {
+ hasampersand = 1;
+ break;
+ }
+ }
+ if (hasampersand)
+ i = usrp->lug_namelen;
+ else
+ i = usrp->lug_namelen +
+ nfsrv_dnsnamelen + 1;
+ if (i > len) {
+ NFSUNLOCKNAMEID();
+ if (len > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ cp = malloc(i, M_NFSSTRING, M_WAITOK);
+ *cpp = cp;
+ len = i;
+ goto tryagain;
+ }
+ *retlenp = i;
+ NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
+ if (!hasampersand) {
+ cp += usrp->lug_namelen;
+ *cp++ = '@';
+ NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+ }
+ TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
+ TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
+ NFSUNLOCKNAMEID();
+ return;
+ }
+ }
+ NFSUNLOCKNAMEID();
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
+ NULL, p);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
+ } else {
+ NFSUNLOCKNAMEID();
+ }
+
+ /*
+ * No match, just return a string of digits.
+ */
+ tmp = uid;
+ i = 0;
+ while (tmp || i == 0) {
+ tmp /= 10;
+ i++;
+ }
+ len = (i > len) ? len : i;
+ *retlenp = len;
+ cp += (len - 1);
+ tmp = uid;
+ for (i = 0; i < len; i++) {
+ *cp-- = '0' + (tmp % 10);
+ tmp /= 10;
+ }
+ return;
+}
+
+/*
+ * Convert a string to a uid.
+ * If no conversion is possible return NFSERR_BADOWNER, otherwise
+ * return 0.
+ */
+APPLESTATIC int
+nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
+{
+ int i;
+ u_char *cp;
+ struct nfsusrgrp *usrp;
+ int cnt, ret;
+
+ if (len == 0)
+ return (NFSERR_BADOWNER);
+ /*
+ * Look for an '@'.
+ */
+ cp = str;
+ for (i = 0; i < len; i++)
+ if (*cp++ == '@')
+ break;
+
+ cnt = 0;
+tryagain:
+ NFSLOCKNAMEID();
+ /*
+ * If an '@' is found and the domain name matches, search for the name
+ * with dns stripped off.
+ * Mixed case alpahbetics will match for the domain name, but all
+ * upper case will not.
+ */
+ if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
+ (len - 1 - i) == nfsrv_dnsnamelen &&
+ !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
+ len -= (nfsrv_dnsnamelen + 1);
+ *(cp - 1) = '\0';
+ }
+
+ /*
+ * Check for the special case of "nobody".
+ */
+ if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
+ *uidp = nfsrv_defaultuid;
+ NFSUNLOCKNAMEID();
+ return (0);
+ }
+
+ LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
+ if (usrp->lug_namelen == len &&
+ !NFSBCMP(usrp->lug_name, str, len)) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ *uidp = usrp->lug_uid;
+ TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
+ TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
+ NFSUNLOCKNAMEID();
+ return (0);
+ }
+ }
+ NFSUNLOCKNAMEID();
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
+ str, p);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
+ return (NFSERR_BADOWNER);
+}
+
+/*
+ * Convert a gid to a string.
+ * gid - the group id
+ * cpp - points to a buffer of size NFSV4_SMALLSTR
+ * (malloc a larger one, as required)
+ * retlenp - pointer to length to be returned
+ */
+APPLESTATIC void
+nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
+{
+ int i;
+ struct nfsusrgrp *usrp;
+ u_char *cp = *cpp;
+ gid_t tmp;
+ int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
+
+ cnt = 0;
+tryagain:
+ NFSLOCKNAMEID();
+ if (nfsrv_dnsname) {
+ /*
+ * Always map nfsrv_defaultgid to "nogroup".
+ */
+ if (gid == nfsrv_defaultgid) {
+ i = nfsrv_dnsnamelen + 8;
+ if (i > len) {
+ NFSUNLOCKNAMEID();
+ if (len > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ cp = malloc(i, M_NFSSTRING, M_WAITOK);
+ *cpp = cp;
+ len = i;
+ goto tryagain;
+ }
+ *retlenp = i;
+ NFSBCOPY("nogroup@", cp, 8);
+ cp += 8;
+ NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+ NFSUNLOCKNAMEID();
+ return;
+ }
+ hasampersand = 0;
+ LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
+ if (usrp->lug_gid == gid) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ /*
+ * If the name doesn't already have an '@'
+ * in it, append @domainname to it.
+ */
+ for (i = 0; i < usrp->lug_namelen; i++) {
+ if (usrp->lug_name[i] == '@') {
+ hasampersand = 1;
+ break;
+ }
+ }
+ if (hasampersand)
+ i = usrp->lug_namelen;
+ else
+ i = usrp->lug_namelen +
+ nfsrv_dnsnamelen + 1;
+ if (i > len) {
+ NFSUNLOCKNAMEID();
+ if (len > NFSV4_SMALLSTR)
+ free(cp, M_NFSSTRING);
+ cp = malloc(i, M_NFSSTRING, M_WAITOK);
+ *cpp = cp;
+ len = i;
+ goto tryagain;
+ }
+ *retlenp = i;
+ NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
+ if (!hasampersand) {
+ cp += usrp->lug_namelen;
+ *cp++ = '@';
+ NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+ }
+ TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
+ TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
+ NFSUNLOCKNAMEID();
+ return;
+ }
+ }
+ NFSUNLOCKNAMEID();
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
+ NULL, p);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
+ } else {
+ NFSUNLOCKNAMEID();
+ }
+
+ /*
+ * No match, just return a string of digits.
+ */
+ tmp = gid;
+ i = 0;
+ while (tmp || i == 0) {
+ tmp /= 10;
+ i++;
+ }
+ len = (i > len) ? len : i;
+ *retlenp = len;
+ cp += (len - 1);
+ tmp = gid;
+ for (i = 0; i < len; i++) {
+ *cp-- = '0' + (tmp % 10);
+ tmp /= 10;
+ }
+ return;
+}
+
+/*
+ * Convert a string to a gid.
+ */
+APPLESTATIC int
+nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
+{
+ int i;
+ u_char *cp;
+ struct nfsusrgrp *usrp;
+ int cnt, ret;
+
+ if (len == 0)
+ return (NFSERR_BADOWNER);
+ /*
+ * Look for an '@'.
+ */
+ cp = str;
+ for (i = 0; i < len; i++)
+ if (*cp++ == '@')
+ break;
+
+ cnt = 0;
+tryagain:
+ NFSLOCKNAMEID();
+ /*
+ * If an '@' is found and the dns name matches, search for the name
+ * with the dns stripped off.
+ */
+ if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
+ (len - 1 - i) == nfsrv_dnsnamelen &&
+ !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
+ len -= (nfsrv_dnsnamelen + 1);
+ *(cp - 1) = '\0';
+ }
+
+ /*
+ * Check for the special case of "nogroup".
+ */
+ if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
+ *gidp = nfsrv_defaultgid;
+ NFSUNLOCKNAMEID();
+ return (0);
+ }
+
+ LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
+ if (usrp->lug_namelen == len &&
+ !NFSBCMP(usrp->lug_name, str, len)) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ break;
+ *gidp = usrp->lug_gid;
+ TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
+ TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
+ NFSUNLOCKNAMEID();
+ return (0);
+ }
+ }
+ NFSUNLOCKNAMEID();
+ cnt++;
+ ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
+ str, p);
+ if (ret == 0 && cnt < 2)
+ goto tryagain;
+ return (NFSERR_BADOWNER);
+}
+
+/*
+ * Cmp len chars, allowing mixed case in the first argument to match lower
+ * case in the second, but not if the first argument is all upper case.
+ * Return 0 for a match, 1 otherwise.
+ */
+static int
+nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
+{
+ int i;
+ u_char tmp;
+ int fndlower = 0;
+
+ for (i = 0; i < len; i++) {
+ if (*cp >= 'A' && *cp <= 'Z') {
+ tmp = *cp++ + ('a' - 'A');
+ } else {
+ tmp = *cp++;
+ if (tmp >= 'a' && tmp <= 'z')
+ fndlower = 1;
+ }
+ if (tmp != *cp2++)
+ return (1);
+ }
+ if (fndlower)
+ return (0);
+ else
+ return (1);
+}
+
+/*
+ * Set the port for the nfsuserd.
+ */
+APPLESTATIC int
+nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
+{
+ struct nfssockreq *rp;
+ struct sockaddr_in *ad;
+ int error;
+
+ NFSLOCKNAMEID();
+ if (nfsrv_nfsuserd) {
+ NFSUNLOCKNAMEID();
+ return (EPERM);
+ }
+ nfsrv_nfsuserd = 1;
+ NFSUNLOCKNAMEID();
+ /*
+ * Set up the socket record and connect.
+ */
+ rp = &nfsrv_nfsuserdsock;
+ rp->nr_client = NULL;
+ rp->nr_sotype = SOCK_DGRAM;
+ rp->nr_soproto = IPPROTO_UDP;
+ rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
+ rp->nr_cred = NULL;
+ NFSSOCKADDRALLOC(rp->nr_nam);
+ NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
+ ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
+ ad->sin_family = AF_INET;
+ ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
+ ad->sin_port = port;
+ rp->nr_prog = RPCPROG_NFSUSERD;
+ rp->nr_vers = RPCNFSUSERD_VERS;
+ error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
+ if (error) {
+ NFSSOCKADDRFREE(rp->nr_nam);
+ nfsrv_nfsuserd = 0;
+ }
+ return (error);
+}
+
+/*
+ * Delete the nfsuserd port.
+ */
+APPLESTATIC void
+nfsrv_nfsuserddelport(void)
+{
+
+ NFSLOCKNAMEID();
+ if (nfsrv_nfsuserd == 0) {
+ NFSUNLOCKNAMEID();
+ return;
+ }
+ nfsrv_nfsuserd = 0;
+ NFSUNLOCKNAMEID();
+ newnfs_disconnect(&nfsrv_nfsuserdsock);
+ NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
+}
+
+/*
+ * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
+ * name<-->id cache.
+ * Returns 0 upon success, non-zero otherwise.
+ */
+static int
+nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
+{
+ u_int32_t *tl;
+ struct nfsrv_descript *nd;
+ int len;
+ struct nfsrv_descript nfsd;
+ struct ucred *cred;
+ int error;
+
+ NFSLOCKNAMEID();
+ if (nfsrv_nfsuserd == 0) {
+ NFSUNLOCKNAMEID();
+ return (EPERM);
+ }
+ NFSUNLOCKNAMEID();
+ nd = &nfsd;
+ cred = newnfs_getcred();
+ nd->nd_flag = ND_GSSINITREPLY;
+ nfsrvd_rephead(nd);
+
+ nd->nd_procnum = procnum;
+ if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
+ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (procnum == RPCNFSUSERD_GETUID)
+ *tl = txdr_unsigned(uid);
+ else
+ *tl = txdr_unsigned(gid);
+ } else {
+ len = strlen(name);
+ (void) nfsm_strtom(nd, name, len);
+ }
+ error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
+ cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
+ NFSFREECRED(cred);
+ if (!error) {
+ mbuf_freem(nd->nd_mrep);
+ error = nd->nd_repstat;
+ }
+ return (error);
+}
+
+/*
+ * This function is called from the nfssvc(2) system call, to update the
+ * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
+ */
+APPLESTATIC int
+nfssvc_idname(struct nfsd_idargs *nidp)
+{
+ struct nfsusrgrp *nusrp, *usrp, *newusrp;
+ struct nfsuserhashhead *hp;
+ int i;
+ int error = 0;
+ u_char *cp;
+
+ if (nidp->nid_flag & NFSID_INITIALIZE) {
+ cp = (u_char *)malloc(nidp->nid_namelen + 1,
+ M_NFSSTRING, M_WAITOK);
+ error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
+ nidp->nid_namelen);
+ NFSLOCKNAMEID();
+ if (nfsrv_dnsname) {
+ /*
+ * Free up all the old stuff and reinitialize hash lists.
+ */
+ TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
+ nfsrv_removeuser(usrp);
+ }
+ free(nfsrv_dnsname, M_NFSSTRING);
+ nfsrv_dnsname = NULL;
+ }
+ TAILQ_INIT(&nfsuserlruhead);
+ for (i = 0; i < NFSUSERHASHSIZE; i++)
+ LIST_INIT(&nfsuserhash[i]);
+ for (i = 0; i < NFSGROUPHASHSIZE; i++)
+ LIST_INIT(&nfsgrouphash[i]);
+ for (i = 0; i < NFSUSERHASHSIZE; i++)
+ LIST_INIT(&nfsusernamehash[i]);
+ for (i = 0; i < NFSGROUPHASHSIZE; i++)
+ LIST_INIT(&nfsgroupnamehash[i]);
+
+ /*
+ * Put name in "DNS" string.
+ */
+ if (!error) {
+ nfsrv_dnsname = cp;
+ nfsrv_dnsnamelen = nidp->nid_namelen;
+ nfsrv_defaultuid = nidp->nid_uid;
+ nfsrv_defaultgid = nidp->nid_gid;
+ nfsrv_usercnt = 0;
+ nfsrv_usermax = nidp->nid_usermax;
+ }
+ NFSUNLOCKNAMEID();
+ if (error)
+ free(cp, M_NFSSTRING);
+ return (error);
+ }
+
+ /*
+ * malloc the new one now, so any potential sleep occurs before
+ * manipulation of the lists.
+ */
+ MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
+ nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
+ error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
+ nidp->nid_namelen);
+ if (error) {
+ free((caddr_t)newusrp, M_NFSUSERGROUP);
+ return (error);
+ }
+ newusrp->lug_namelen = nidp->nid_namelen;
+
+ NFSLOCKNAMEID();
+ /*
+ * Delete old entries, as required.
+ */
+ if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
+ hp = NFSUSERHASH(nidp->nid_uid);
+ LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
+ if (usrp->lug_uid == nidp->nid_uid)
+ nfsrv_removeuser(usrp);
+ }
+ }
+ if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
+ hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
+ LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
+ if (usrp->lug_namelen == newusrp->lug_namelen &&
+ !NFSBCMP(usrp->lug_name, newusrp->lug_name,
+ usrp->lug_namelen))
+ nfsrv_removeuser(usrp);
+ }
+ }
+ if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
+ hp = NFSGROUPHASH(nidp->nid_gid);
+ LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
+ if (usrp->lug_gid == nidp->nid_gid)
+ nfsrv_removeuser(usrp);
+ }
+ }
+ if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
+ hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
+ LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
+ if (usrp->lug_namelen == newusrp->lug_namelen &&
+ !NFSBCMP(usrp->lug_name, newusrp->lug_name,
+ usrp->lug_namelen))
+ nfsrv_removeuser(usrp);
+ }
+ }
+ TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
+ if (usrp->lug_expiry < NFSD_MONOSEC)
+ nfsrv_removeuser(usrp);
+ }
+ while (nfsrv_usercnt >= nfsrv_usermax) {
+ usrp = TAILQ_FIRST(&nfsuserlruhead);
+ nfsrv_removeuser(usrp);
+ }
+
+ /*
+ * Now, we can add the new one.
+ */
+ if (nidp->nid_usertimeout)
+ newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
+ else
+ newusrp->lug_expiry = NFSD_MONOSEC + 5;
+ if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
+ newusrp->lug_uid = nidp->nid_uid;
+ LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
+ lug_numhash);
+ LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
+ newusrp->lug_namelen), newusrp, lug_namehash);
+ TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
+ nfsrv_usercnt++;
+ } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
+ newusrp->lug_gid = nidp->nid_gid;
+ LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
+ lug_numhash);
+ LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
+ newusrp->lug_namelen), newusrp, lug_namehash);
+ TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
+ nfsrv_usercnt++;
+ } else
+ FREE((caddr_t)newusrp, M_NFSUSERGROUP);
+ NFSUNLOCKNAMEID();
+ return (error);
+}
+
+/*
+ * Remove a user/group name element.
+ */
+static void
+nfsrv_removeuser(struct nfsusrgrp *usrp)
+{
+
+ NFSNAMEIDREQUIRED();
+ LIST_REMOVE(usrp, lug_numhash);
+ LIST_REMOVE(usrp, lug_namehash);
+ TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
+ nfsrv_usercnt--;
+ FREE((caddr_t)usrp, M_NFSUSERGROUP);
+}
+
+/*
+ * This function scans a byte string and checks for UTF-8 compliance.
+ * It returns 0 if it conforms and NFSERR_INVAL if not.
+ */
+APPLESTATIC int
+nfsrv_checkutf8(u_int8_t *cp, int len)
+{
+ u_int32_t val = 0x0;
+ int cnt = 0, gotd = 0, shift = 0;
+ u_int8_t byte;
+ static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
+
+ /*
+ * Here are what the variables are used for:
+ * val - the calculated value of a multibyte char, used to check
+ * that it was coded with the correct range
+ * cnt - the number of 10xxxxxx bytes to follow
+ * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
+ * shift - lower order bits of range (ie. "val >> shift" should
+ * not be 0, in other words, dividing by the lower bound
+ * of the range should get a non-zero value)
+ * byte - used to calculate cnt
+ */
+ while (len > 0) {
+ if (cnt > 0) {
+ /* This handles the 10xxxxxx bytes */
+ if ((*cp & 0xc0) != 0x80 ||
+ (gotd && (*cp & 0x20)))
+ return (NFSERR_INVAL);
+ gotd = 0;
+ val <<= 6;
+ val |= (*cp & 0x3f);
+ cnt--;
+ if (cnt == 0 && (val >> shift) == 0x0)
+ return (NFSERR_INVAL);
+ } else if (*cp & 0x80) {
+ /* first byte of multi byte char */
+ byte = *cp;
+ while ((byte & 0x40) && cnt < 6) {
+ cnt++;
+ byte <<= 1;
+ }
+ if (cnt == 0 || cnt == 6)
+ return (NFSERR_INVAL);
+ val = (*cp & (0x3f >> cnt));
+ shift = utf8_shift[cnt - 1];
+ if (cnt == 2 && val == 0xd)
+ /* Check for the 0xd800-0xdfff case */
+ gotd = 1;
+ }
+ cp++;
+ len--;
+ }
+ if (cnt > 0)
+ return (NFSERR_INVAL);
+ return (0);
+}
+
+/*
+ * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
+ * strings, one with the root path in it and the other with the list of
+ * locations. The list is in the same format as is found in nfr_refs.
+ * It is a "," separated list of entries, where each of them is of the
+ * form <server>:<rootpath>. For example
+ * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
+ * The nilp argument is set to 1 for the special case of a null fs_root
+ * and an empty server list.
+ * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
+ * number of xdr bytes parsed in sump.
+ */
+static int
+nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
+ int *sump, int *nilp)
+{
+ u_int32_t *tl;
+ u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
+ int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
+ struct list {
+ SLIST_ENTRY(list) next;
+ int len;
+ u_char host[1];
+ } *lsp, *nlsp;
+ SLIST_HEAD(, list) head;
+
+ *fsrootp = NULL;
+ *srvp = NULL;
+ *nilp = 0;
+
+ /*
+ * Get the fs_root path and check for the special case of null path
+ * and 0 length server list.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ len = fxdr_unsigned(int, *tl);
+ if (len < 0 || len > 10240)
+ return (NFSERR_BADXDR);
+ if (len == 0) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ if (*tl != 0)
+ return (NFSERR_BADXDR);
+ *nilp = 1;
+ *sump = 2 * NFSX_UNSIGNED;
+ return (0);
+ }
+ cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
+ error = nfsrv_mtostr(nd, cp, len);
+ if (!error) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ cnt = fxdr_unsigned(int, *tl);
+ if (cnt <= 0)
+ error = NFSERR_BADXDR;
+ }
+ if (error) {
+ free(cp, M_NFSSTRING);
+ return (error);
+ }
+
+ /*
+ * Now, loop through the location list and make up the srvlist.
+ */
+ xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
+ cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
+ slen = 1024;
+ siz = 0;
+ for (i = 0; i < cnt; i++) {
+ SLIST_INIT(&head);
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ nsrv = fxdr_unsigned(int, *tl);
+ if (nsrv <= 0) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (NFSERR_BADXDR);
+ }
+
+ /*
+ * Handle the first server by putting it in the srvstr.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ len = fxdr_unsigned(int, *tl);
+ if (len <= 0 || len > 1024) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (NFSERR_BADXDR);
+ }
+ nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
+ if (cp3 != cp2) {
+ *cp3++ = ',';
+ siz++;
+ }
+ error = nfsrv_mtostr(nd, cp3, len);
+ if (error) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (error);
+ }
+ cp3 += len;
+ *cp3++ = ':';
+ siz += (len + 1);
+ xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
+ for (j = 1; j < nsrv; j++) {
+ /*
+ * Yuck, put them in an slist and process them later.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ len = fxdr_unsigned(int, *tl);
+ if (len <= 0 || len > 1024) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (NFSERR_BADXDR);
+ }
+ lsp = (struct list *)malloc(sizeof (struct list)
+ + len, M_TEMP, M_WAITOK);
+ error = nfsrv_mtostr(nd, lsp->host, len);
+ if (error) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (error);
+ }
+ xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
+ lsp->len = len;
+ SLIST_INSERT_HEAD(&head, lsp, next);
+ }
+
+ /*
+ * Finally, we can get the path.
+ */
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ len = fxdr_unsigned(int, *tl);
+ if (len <= 0 || len > 1024) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (NFSERR_BADXDR);
+ }
+ nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
+ error = nfsrv_mtostr(nd, cp3, len);
+ if (error) {
+ free(cp, M_NFSSTRING);
+ free(cp2, M_NFSSTRING);
+ return (error);
+ }
+ xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
+ str = cp3;
+ stringlen = len;
+ cp3 += len;
+ siz += len;
+ SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
+ nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
+ &cp2, &cp3, &slen);
+ *cp3++ = ',';
+ NFSBCOPY(lsp->host, cp3, lsp->len);
+ cp3 += lsp->len;
+ *cp3++ = ':';
+ NFSBCOPY(str, cp3, stringlen);
+ cp3 += stringlen;
+ *cp3 = '\0';
+ siz += (lsp->len + stringlen + 2);
+ free((caddr_t)lsp, M_TEMP);
+ }
+ }
+ *fsrootp = cp;
+ *srvp = cp2;
+ *sump = xdrsum;
+ return (0);
+nfsmout:
+ if (cp != NULL)
+ free(cp, M_NFSSTRING);
+ if (cp2 != NULL)
+ free(cp2, M_NFSSTRING);
+ return (error);
+}
+
+/*
+ * Make the malloc'd space large enough. This is a pain, but the xdr
+ * doesn't set an upper bound on the side, so...
+ */
+static void
+nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
+{
+ u_char *cp;
+ int i;
+
+ if (siz <= *slenp)
+ return;
+ cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
+ NFSBCOPY(*cpp, cp, *slenp);
+ free(*cpp, M_NFSSTRING);
+ i = *cpp2 - *cpp;
+ *cpp = cp;
+ *cpp2 = cp + i;
+ *slenp = siz + 1024;
+}
+
+/*
+ * Initialize the reply header data structures.
+ */
+APPLESTATIC void
+nfsrvd_rephead(struct nfsrv_descript *nd)
+{
+ mbuf_t mreq;
+
+ /*
+ * If this is a big reply, use a cluster.
+ */
+ if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
+ nfs_bigreply[nd->nd_procnum]) {
+ NFSMCLGET(mreq, M_WAIT);
+ nd->nd_mreq = mreq;
+ nd->nd_mb = mreq;
+ } else {
+ NFSMGET(mreq);
+ nd->nd_mreq = mreq;
+ nd->nd_mb = mreq;
+ }
+ nd->nd_bpos = NFSMTOD(mreq, caddr_t);
+ mbuf_setlen(mreq, 0);
+
+ if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
+ NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
+}
+
+/*
+ * Lock a socket against others.
+ * Currently used to serialize connect/disconnect attempts.
+ */
+int
+newnfs_sndlock(int *flagp)
+{
+ struct timespec ts;
+
+ NFSLOCKSOCK();
+ while (*flagp & NFSR_SNDLOCK) {
+ *flagp |= NFSR_WANTSND;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
+ PZERO - 1, "nfsndlck", &ts);
+ }
+ *flagp |= NFSR_SNDLOCK;
+ NFSUNLOCKSOCK();
+ return (0);
+}
+
+/*
+ * Unlock the stream socket for others.
+ */
+void
+newnfs_sndunlock(int *flagp)
+{
+
+ NFSLOCKSOCK();
+ if ((*flagp & NFSR_SNDLOCK) == 0)
+ panic("nfs sndunlock");
+ *flagp &= ~NFSR_SNDLOCK;
+ if (*flagp & NFSR_WANTSND) {
+ *flagp &= ~NFSR_WANTSND;
+ wakeup((caddr_t)flagp);
+ }
+ NFSUNLOCKSOCK();
+}
+
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
new file mode 100644
index 0000000..64b1e90
--- /dev/null
+++ b/sys/fs/nfs/nfs_var.h
@@ -0,0 +1,604 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * XXX needs <nfs/rpcv2.h> and <nfs/nfs.h> because of typedefs
+ */
+
+struct uio;
+struct ucred;
+struct nfscred;
+NFSPROC_T;
+struct buf;
+struct nfs_diskless;
+struct sockaddr_in;
+struct nfs_dlmount;
+struct file;
+struct nfsmount;
+struct socket;
+struct nfsreq;
+struct nfssockreq;
+struct vattr;
+struct nameidata;
+struct nfsnode;
+struct nfsfh;
+struct sillyrename;
+struct componentname;
+struct nfsd_srvargs;
+struct nfsrv_descript;
+struct nfs_fattr;
+union nethostaddr;
+struct nfsstate;
+struct nfslock;
+struct nfsclient;
+struct nfslockconflict;
+struct nfsd_idargs;
+struct nfsd_clid;
+struct nfsusrgrp;
+struct nfsclowner;
+struct nfsclopen;
+struct nfsclopenhead;
+struct nfsclclient;
+struct nfscllockowner;
+struct nfscllock;
+struct nfscldeleg;
+struct nfsv4lock;
+struct nfsvattr;
+struct nfs_vattr;
+struct NFSSVCARGS;
+#ifdef __FreeBSD__
+NFS_ACCESS_ARGS;
+NFS_OPEN_ARGS;
+NFS_GETATTR_ARGS;
+NFS_LOOKUP_ARGS;
+NFS_READDIR_ARGS;
+#endif
+
+/* nfsd_srvstate.c */
+int nfsrv_setclient(struct nfsrv_descript *, struct nfsclient **,
+ nfsquad_t *, nfsquad_t *, NFSPROC_T *);
+int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, nfsquad_t,
+ struct nfsrv_descript *, NFSPROC_T *);
+int nfsrv_adminrevoke(struct nfsd_clid *, NFSPROC_T *);
+void nfsrv_dumpclients(struct nfsd_dumpclients *, int);
+void nfsrv_dumplocks(vnode_t, struct nfsd_dumplocks *, int, NFSPROC_T *);
+int nfsrv_lockctrl(vnode_t, struct nfsstate **,
+ struct nfslock **, struct nfslockconflict *, nfsquad_t, nfsv4stateid_t *,
+ struct nfsexstuff *, struct nfsrv_descript *, NFSPROC_T *);
+int nfsrv_openctrl(struct nfsrv_descript *, vnode_t,
+ struct nfsstate **, nfsquad_t, nfsv4stateid_t *, nfsv4stateid_t *,
+ u_int32_t *, struct nfsexstuff *, NFSPROC_T *, u_quad_t);
+int nfsrv_opencheck(nfsquad_t, nfsv4stateid_t *, struct nfsstate *,
+ vnode_t, struct nfsrv_descript *, NFSPROC_T *, int);
+int nfsrv_openupdate(vnode_t, struct nfsstate *, nfsquad_t,
+ nfsv4stateid_t *, struct nfsrv_descript *, NFSPROC_T *);
+int nfsrv_delegupdate(nfsquad_t, nfsv4stateid_t *, vnode_t, int,
+ struct ucred *, NFSPROC_T *);
+int nfsrv_releaselckown(struct nfsstate *, nfsquad_t, NFSPROC_T *);
+void nfsrv_zapclient(struct nfsclient *, NFSPROC_T *);
+int nfssvc_idname(struct nfsd_idargs *);
+void nfsrv_servertimer(void);
+int nfsrv_getclientipaddr(struct nfsrv_descript *, struct nfsclient *);
+void nfsrv_setupstable(NFSPROC_T *);
+void nfsrv_updatestable(NFSPROC_T *);
+void nfsrv_writestable(u_char *, int, int, NFSPROC_T *);
+void nfsrv_throwawayopens(NFSPROC_T *);
+int nfsrv_checkremove(vnode_t, int, NFSPROC_T *);
+void nfsd_recalldelegation(vnode_t, NFSPROC_T *);
+void nfsd_disabledelegation(vnode_t, NFSPROC_T *);
+int nfsrv_checksetattr(vnode_t, struct nfsrv_descript *,
+ nfsv4stateid_t *, struct nfsvattr *, nfsattrbit_t *, struct nfsexstuff *,
+ NFSPROC_T *);
+int nfsrv_checkgetattr(struct nfsrv_descript *, vnode_t,
+ struct nfsvattr *, nfsattrbit_t *, struct ucred *, NFSPROC_T *);
+int nfsrv_nfsuserdport(u_short, NFSPROC_T *);
+void nfsrv_nfsuserddelport(void);
+
+/* nfsd_serv.c */
+int nfsrvd_access(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_getattr(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_setattr(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_lookup(struct nfsrv_descript *, int,
+ vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsrvd_readlink(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_read(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_write(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_create(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_mknod(struct nfsrv_descript *, int,
+ vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsrvd_remove(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_rename(struct nfsrv_descript *, int,
+ vnode_t, vnode_t, NFSPROC_T *, struct nfsexstuff *,
+ struct nfsexstuff *);
+int nfsrvd_link(struct nfsrv_descript *, int,
+ vnode_t, vnode_t, NFSPROC_T *, struct nfsexstuff *,
+ struct nfsexstuff *);
+int nfsrvd_symlink(struct nfsrv_descript *, int,
+ vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsrvd_mkdir(struct nfsrv_descript *, int,
+ vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsrvd_readdir(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_readdirplus(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_commit(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_statfs(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_fsinfo(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_close(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_delegpurge(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_delegreturn(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_getfh(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_lock(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_lockt(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_locku(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_openconfirm(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_opendowngrade(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_renew(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_secinfo(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_setclientid(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_setclientidcfrm(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_verify(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_open(struct nfsrv_descript *, int,
+ vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsrvd_openattr(struct nfsrv_descript *, int,
+ vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsrvd_releaselckown(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_pathconf(struct nfsrv_descript *, int,
+ vnode_t, NFSPROC_T *, struct nfsexstuff *);
+
+/* newnfs_socket.c */
+int newnfs_request(struct nfsrv_descript *, struct nfsmount *,
+ struct nfsclient *, struct nfssockreq *, vnode_t, NFSPROC_T *,
+ struct ucred *, u_int32_t, u_int32_t, u_char *, int, u_int64_t *);
+int newnfs_connect(struct nfsmount *, struct nfssockreq *,
+ struct ucred *, NFSPROC_T *, int);
+void newnfs_disconnect(struct nfssockreq *);
+void newnfs_timer(void *);
+int newnfs_sigintr(struct nfsmount *, NFSPROC_T *);
+int newnfs_sndlock(int *);
+void newnfs_sndunlock(int *);
+
+/* nfsd_srvsocket.c */
+void nfsrvd_rephead(struct nfsrv_descript *);
+void nfsrvd_dorpc(struct nfsrv_descript *, int, NFSPROC_T *);
+
+/* nfs_srvcache.c */
+void nfsrvd_initcache(void);
+int nfsrvd_getcache(struct nfsrv_descript *, struct socket *);
+struct nfsrvcache *nfsrvd_updatecache(struct nfsrv_descript *,
+ struct socket *);
+void nfsrvd_sentcache(struct nfsrvcache *, struct socket *, int);
+void nfsrvd_cleancache(void);
+void nfsrvd_refcache(struct nfsrvcache *);
+void nfsrvd_derefcache(struct nfsrvcache *);
+void nfsrvd_delcache(struct nfsrvcache *);
+
+/* newnfs_subs.c */
+void newnfs_init(void);
+int nfsaddr_match(int, union nethostaddr *, NFSSOCKADDR_T);
+int nfsaddr2_match(NFSSOCKADDR_T, NFSSOCKADDR_T);
+int nfsm_strtom(struct nfsrv_descript *, const char *, int);
+int nfsm_mbufuio(struct nfsrv_descript *, struct uio *, int);
+int nfsm_fhtom(struct nfsrv_descript *, u_int8_t *, int, int);
+int nfsm_advance(struct nfsrv_descript *, int, int);
+void *nfsm_dissct(struct nfsrv_descript *, int);
+void newnfs_trimleading(struct nfsrv_descript *);
+void newnfs_trimtrailing(struct nfsrv_descript *, mbuf_t,
+ caddr_t);
+void newnfs_copycred(struct nfscred *, struct ucred *);
+void newnfs_copyincred(struct ucred *, struct nfscred *);
+int nfsrv_dissectacl(struct nfsrv_descript *, NFSACL_T *, int *,
+ int *, NFSPROC_T *);
+int nfsrv_getattrbits(struct nfsrv_descript *, nfsattrbit_t *, int *,
+ int *);
+int nfsv4_loadattr(struct nfsrv_descript *, vnode_t,
+ struct nfsvattr *, struct nfsfh **, fhandle_t *, int,
+ struct nfsv3_pathconf *, struct statfs *, struct nfsstatfs *,
+ struct nfsfsinfo *, NFSACL_T *,
+ int, int *, u_int32_t *, u_int32_t *, NFSPROC_T *, struct ucred *);
+int nfsv4_lock(struct nfsv4lock *, int, int *, void *);
+void nfsv4_unlock(struct nfsv4lock *, int);
+void nfsv4_relref(struct nfsv4lock *);
+void nfsv4_getref(struct nfsv4lock *, int *, void *);
+int nfsrv_mtostr(struct nfsrv_descript *, char *, int);
+int nfsrv_checkutf8(u_int8_t *, int);
+
+/* nfscl_subs.c */
+void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
+void nfscl_reqstart(struct nfsrv_descript *, int, struct nfsmount *,
+ u_int8_t *, int, u_int32_t **);
+nfsuint64 *nfscl_getcookie(struct nfsnode *, off_t off, int);
+void nfscl_fillsattr(struct nfsrv_descript *, struct vattr *,
+ vnode_t, int, u_int32_t);
+u_int8_t *nfscl_getmyip(struct nfsmount *, int *);
+int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **);
+int nfscl_mtofh(struct nfsrv_descript *, struct nfsfh **,
+ struct nfsvattr *, int *);
+int nfscl_postop_attr(struct nfsrv_descript *, struct nfsvattr *, int *,
+ void *);
+int nfscl_wcc_data(struct nfsrv_descript *, vnode_t,
+ struct nfsvattr *, int *, int *, void *);
+int nfsm_loadattr(struct nfsrv_descript *, struct nfsvattr *);
+int nfscl_request(struct nfsrv_descript *, vnode_t,
+ NFSPROC_T *, struct ucred *, void *);
+void nfsm_stateidtom(struct nfsrv_descript *, nfsv4stateid_t *, int);
+
+/* nfsd_srvsubs.c */
+void nfsd_fhtovp(struct nfsrv_descript *, struct nfsrvfh *,
+ vnode_t *, struct nfsexstuff *,
+ mount_t *, int, NFSPROC_T *);
+int nfsd_excred(struct nfsrv_descript *, struct nfsexstuff *, struct ucred *);
+int nfsrv_mtofh(struct nfsrv_descript *, struct nfsrvfh *);
+int nfsrv_putattrbit(struct nfsrv_descript *, nfsattrbit_t *);
+void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int,
+ struct nfsvattr *);
+int nfsv4_fillattr(struct nfsrv_descript *, vnode_t, NFSACL_T *,
+ struct vattr *, fhandle_t *, int, nfsattrbit_t *,
+ struct ucred *, NFSPROC_T *, int, int);
+void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *);
+void nfsrv_adj(mbuf_t, int, int);
+void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *);
+int nfsd_errmap(struct nfsrv_descript *);
+void nfsv4_uidtostr(uid_t, u_char **, int *, NFSPROC_T *);
+int nfsv4_strtouid(u_char *, int, uid_t *, NFSPROC_T *);
+void nfsv4_gidtostr(gid_t, u_char **, int *, NFSPROC_T *);
+int nfsv4_strtogid(u_char *, int, gid_t *, NFSPROC_T *);
+int nfsrv_checkuidgid(struct nfsrv_descript *, struct nfsvattr *);
+void nfsrv_fixattr(struct nfsrv_descript *, vnode_t,
+ struct nfsvattr *, NFSACL_T *, NFSPROC_T *, nfsattrbit_t *,
+ struct nfsexstuff *);
+int nfsrv_errmoved(int);
+int nfsrv_putreferralattr(struct nfsrv_descript *, nfsattrbit_t *,
+ struct nfsreferral *, int, int *);
+int nfsrv_parsename(struct nfsrv_descript *, char *, u_long *,
+ NFSPATHLEN_T *);
+
+/* nfs_srvsyscalls.c */
+void nfsd_init(void);
+
+/* nfs_vfsops.c */
+
+/* newnfs_port.c */
+int nfsrv_checksockseqnum(struct socket *, tcp_seq);
+int nfsrv_getsockseqnum(struct socket *, tcp_seq *);
+int nfsrv_getsocksndseq(struct socket *, tcp_seq *, tcp_seq *);
+int nfsrv_lookupfilename(struct nameidata *, char *, NFSPROC_T *);
+void nfsrv_object_create(vnode_t, NFSPROC_T *);
+int nfsrv_mallocmget_limit(void);
+int nfsvno_v4rootexport(struct nfsrv_descript *);
+void newnfs_portinit(void);
+struct ucred *newnfs_getcred(void);
+void newnfs_setroot(struct ucred *);
+int nfs_catnap(int, const char *);
+struct nfsreferral *nfsv4root_getreferral(vnode_t, vnode_t, u_int32_t);
+int nfsrv_atroot(vnode_t, long *);
+
+/* newnfs_acl.c */
+int nfsrv_dissectace(struct nfsrv_descript *, struct acl_entry *,
+ int *, int *, NFSPROC_T *);
+#ifdef NFS4_ACL_EXTATTR_NAME
+int nfsrv_buildacl(struct nfsrv_descript *, NFSACL_T *, enum vtype,
+ NFSPROC_T *);
+int nfsrv_aclaccess(vnode_t, accmode_t, u_int32_t, struct ucred *,
+ NFSPROC_T *);
+int nfsrv_setacl(vnode_t, NFSACL_T *, struct ucred *,
+ NFSPROC_T *);
+int nfsrv_compareacl(NFSACL_T *, NFSACL_T *);
+#endif
+
+/* nfscl_rpcops.c */
+int nfsrpc_null(vnode_t, struct ucred *, NFSPROC_T *);
+int nfsrpc_access(vnode_t, int, struct ucred *, NFSPROC_T *,
+ struct nfsvattr *, int *);
+int nfsrpc_accessrpc(vnode_t, u_int32_t, struct ucred *,
+ NFSPROC_T *, struct nfsvattr *, int *, u_int32_t *, void *);
+int nfsrpc_open(vnode_t, int, struct ucred *, NFSPROC_T *);
+int nfsrpc_openrpc(struct nfsmount *, vnode_t, u_int8_t *, int, u_int8_t *, int,
+ u_int32_t, struct nfsclopen *, u_int8_t *, int, struct nfscldeleg **, int,
+ u_int32_t, struct ucred *, NFSPROC_T *, int, int);
+int nfsrpc_opendowngrade(vnode_t, u_int32_t, struct nfsclopen *,
+ struct ucred *, NFSPROC_T *);
+int nfsrpc_close(vnode_t, struct ucred *, NFSPROC_T *);
+int nfsrpc_closerpc(struct nfsrv_descript *, struct nfsmount *,
+ struct nfsclopen *, struct ucred *, NFSPROC_T *, int);
+int nfsrpc_openconfirm(vnode_t, u_int8_t *, int, struct nfsclopen *,
+ struct ucred *, NFSPROC_T *);
+int nfsrpc_setclient(struct nfsmount *, struct nfsclclient *,
+ struct ucred *, NFSPROC_T *);
+int nfsrpc_getattr(vnode_t, struct ucred *, NFSPROC_T *,
+ struct nfsvattr *, void *);
+int nfsrpc_getattrnovp(struct nfsmount *, u_int8_t *, int, int,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, u_int64_t *);
+int nfsrpc_setattr(vnode_t, struct vattr *, NFSACL_T *, struct ucred *,
+ NFSPROC_T *, struct nfsvattr *, int *, void *);
+int nfsrpc_lookup(vnode_t, char *, int, struct ucred *, NFSPROC_T *,
+ struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *,
+ void *);
+int nfsrpc_readlink(vnode_t, struct uio *, struct ucred *,
+ NFSPROC_T *, struct nfsvattr *, int *, void *);
+int nfsrpc_read(vnode_t, struct uio *, struct ucred *, NFSPROC_T *,
+ struct nfsvattr *, int *, void *);
+int nfsrpc_write(vnode_t, struct uio *, int *, u_char *,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
+int nfsrpc_mknod(vnode_t, char *, int, struct vattr *, u_int32_t,
+ enum vtype, struct ucred *, NFSPROC_T *, struct nfsvattr *,
+ struct nfsvattr *, struct nfsfh **, int *, int *, void *);
+int nfsrpc_create(vnode_t, char *, int, struct vattr *, nfsquad_t,
+ int, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
+ struct nfsfh **, int *, int *, void *);
+int nfsrpc_remove(vnode_t, char *, int, vnode_t, struct ucred *, NFSPROC_T *,
+ struct nfsvattr *, int *, void *);
+int nfsrpc_rename(vnode_t, vnode_t, char *, int, vnode_t, vnode_t, char *, int,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
+ int *, int *, void *, void *);
+int nfsrpc_link(vnode_t, vnode_t, char *, int,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
+ int *, int *, void *);
+int nfsrpc_symlink(vnode_t, char *, int, char *, struct vattr *,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
+ struct nfsfh **, int *, int *, void *);
+int nfsrpc_mkdir(vnode_t, char *, int, struct vattr *,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
+ struct nfsfh **, int *, int *, void *);
+int nfsrpc_rmdir(vnode_t, char *, int, struct ucred *, NFSPROC_T *,
+ struct nfsvattr *, int *, void *);
+int nfsrpc_readdir(vnode_t, struct uio *, nfsuint64 *, struct ucred *,
+ NFSPROC_T *, struct nfsvattr *, int *, int *, void *);
+int nfsrpc_readdirplus(vnode_t, struct uio *, nfsuint64 *,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, int *, void *);
+int nfsrpc_commit(vnode_t, u_quad_t, int, struct ucred *,
+ NFSPROC_T *, u_char *, struct nfsvattr *, int *, void *);
+int nfsrpc_advlock(vnode_t, off_t, int, struct flock *, int,
+ struct ucred *, NFSPROC_T *);
+int nfsrpc_lockt(struct nfsrv_descript *, vnode_t,
+ struct nfsclclient *, u_int64_t, u_int64_t, struct flock *,
+ struct ucred *, NFSPROC_T *);
+int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t,
+ u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t,
+ u_int64_t, short, struct ucred *, NFSPROC_T *, int);
+int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
+int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *,
+ NFSPROC_T *, struct nfsvattr *, int *, void *);
+int nfsrpc_pathconf(vnode_t, struct nfsv3_pathconf *,
+ struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
+int nfsrpc_renew(struct nfsclclient *, struct ucred *,
+ NFSPROC_T *);
+int nfsrpc_rellockown(struct nfsmount *, struct nfscllockowner *,
+ struct ucred *, NFSPROC_T *);
+int nfsrpc_getdirpath(struct nfsmount *, u_char *, struct ucred *,
+ NFSPROC_T *);
+int nfsrpc_delegreturn(struct nfscldeleg *, struct ucred *,
+ struct nfsmount *, NFSPROC_T *, int);
+int nfsrpc_getacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *);
+int nfsrpc_setacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *);
+
+/* nfscl_state.c */
+int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int,
+ struct ucred *, NFSPROC_T *, struct nfsclowner **, struct nfsclopen **,
+ int *, int *, int);
+int nfscl_getstateid(vnode_t, u_int8_t *, int, u_int32_t, struct ucred *,
+ NFSPROC_T *, nfsv4stateid_t *, void **);
+void nfscl_ownerrelease(struct nfsclowner *, int, int, int);
+void nfscl_openrelease(struct nfsclopen *, int, int);
+int nfscl_getcl(vnode_t, struct ucred *, NFSPROC_T *,
+ struct nfsclclient **);
+struct nfsclclient *nfscl_findcl(struct nfsmount *);
+void nfscl_clientrelease(struct nfsclclient *);
+void nfscl_freelock(struct nfscllock *, int);
+int nfscl_getbytelock(vnode_t, u_int64_t, u_int64_t, short,
+ struct ucred *, NFSPROC_T *, struct nfsclclient *, int, u_int8_t *,
+ u_int8_t *, struct nfscllockowner **, int *, int *);
+int nfscl_relbytelock(vnode_t, u_int64_t, u_int64_t,
+ struct ucred *, NFSPROC_T *, int, struct nfsclclient *,
+ struct nfscllockowner **, int *);
+int nfscl_checkwritelocked(vnode_t, struct flock *,
+ struct ucred *, NFSPROC_T *);
+void nfscl_lockrelease(struct nfscllockowner *, int, int);
+void nfscl_fillclid(u_int64_t, char *, u_int8_t *, u_int16_t);
+void nfscl_filllockowner(NFSPROC_T *, u_int8_t *);
+void nfscl_freeopen(struct nfsclopen *, int);
+void nfscl_umount(struct nfsmount *, NFSPROC_T *);
+void nfscl_renewthread(struct nfsclclient *, NFSPROC_T *);
+void nfscl_initiate_recovery(struct nfsclclient *);
+int nfscl_hasexpired(struct nfsclclient *, u_int32_t, NFSPROC_T *);
+void nfscl_dumpstate(struct nfsmount *, int, int, int, int);
+void nfscl_dupopen(vnode_t, int);
+int nfscl_getclose(vnode_t, struct ucred *, NFSPROC_T *,
+ struct nfsclclient **, struct nfsclopenhead *);
+int nfscl_deleg(mount_t, struct nfsclclient *, u_int8_t *, int,
+ struct ucred *, NFSPROC_T *, struct nfscldeleg **);
+void nfscl_lockinit(struct nfsv4lock *);
+void nfscl_lockexcl(struct nfsv4lock *, void *);
+void nfscl_lockunlock(struct nfsv4lock *);
+void nfscl_lockderef(struct nfsv4lock *);
+void nfscl_docb(struct nfsrv_descript *, NFSPROC_T *);
+void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *);
+int nfscl_lockt(vnode_t, struct nfsclclient *, u_int64_t,
+ u_int64_t, struct flock *, NFSPROC_T *);
+int nfscl_mustflush(vnode_t);
+int nfscl_nodeleg(vnode_t, int);
+int nfscl_removedeleg(vnode_t, NFSPROC_T *, nfsv4stateid_t *);
+int nfscl_getref(struct nfsmount *);
+void nfscl_relref(struct nfsmount *);
+int nfscl_renamedeleg(vnode_t, nfsv4stateid_t *, int *, vnode_t,
+ nfsv4stateid_t *, int *, NFSPROC_T *);
+void nfscl_reclaimnode(vnode_t);
+void nfscl_newnode(vnode_t);
+void nfscl_delegmodtime(vnode_t);
+void nfscl_deleggetmodtime(vnode_t, struct timespec *);
+int nfscl_tryclose(struct nfsclopen *, struct ucred *,
+ struct nfsmount *, NFSPROC_T *);
+void nfscl_cleanup(NFSPROC_T *);
+
+/* nfscl_port.c */
+int nfscl_nget(mount_t, vnode_t, struct nfsfh *,
+ struct componentname *, NFSPROC_T *, struct nfsnode **, void *);
+NFSPROC_T *nfscl_getparent(NFSPROC_T *);
+void nfscl_start_renewthread(struct nfsclclient *);
+void nfscl_loadsbinfo(struct nfsmount *, struct nfsstatfs *, void *);
+void nfscl_loadfsinfo (struct nfsmount *, struct nfsfsinfo *);
+void nfscl_delegreturn(struct nfscldeleg *, int, struct nfsmount *,
+ struct ucred *, NFSPROC_T *);
+void nfsrvd_cbinit(int);
+int nfscl_checksattr(struct vattr *, struct nfsvattr *);
+int nfscl_ngetreopen(mount_t, u_int8_t *, int, NFSPROC_T *,
+ struct nfsnode **);
+int nfscl_procdoesntexist(u_int8_t *);
+int nfscl_maperr(NFSPROC_T *, int, uid_t, gid_t);
+
+/* nfsclient/ncl_subs.c */
+void nfscl_init(void);
+
+/* nfsclient/ncl_bio.c */
+int ncl_flush(vnode_t, int, struct ucred *, NFSPROC_T *, int);
+
+/* nfsclient/ncl_node.c */
+void ncl_invalcaches(vnode_t);
+
+/* nfsd/nfsd_port.c */
+int nfsvno_getattr(vnode_t, struct nfsvattr *, struct ucred *,
+ NFSPROC_T *);
+int nfsvno_setattr(vnode_t, struct nfsvattr *, struct ucred *,
+ NFSPROC_T *, struct nfsexstuff *);
+int nfsvno_getfh(vnode_t, fhandle_t *, NFSPROC_T *);
+int nfsvno_accchk(vnode_t, u_int32_t, struct ucred *,
+ struct nfsexstuff *, NFSPROC_T *, int, int);
+int nfsvno_namei(struct nfsrv_descript *, struct nameidata *,
+ vnode_t, int, struct nfsexstuff *, NFSPROC_T *, vnode_t *);
+void nfsvno_setpathbuf(struct nameidata *, char **, u_long **);
+void nfsvno_relpathbuf(struct nameidata *);
+int nfsvno_readlink(vnode_t, struct ucred *, NFSPROC_T *, mbuf_t *,
+ mbuf_t *, int *);
+int nfsvno_read(vnode_t, off_t, int, struct ucred *, NFSPROC_T *,
+ mbuf_t *, mbuf_t *);
+int nfsvno_write(vnode_t, off_t, int, int, int, mbuf_t,
+ char *, struct ucred *, NFSPROC_T *);
+int nfsvno_createsub(struct nfsrv_descript *, struct nameidata *,
+ vnode_t *, struct nfsvattr *, int *, u_char *, NFSDEV_T, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsvno_mknod(struct nameidata *, struct nfsvattr *, struct ucred *,
+ NFSPROC_T *);
+int nfsvno_mkdir(struct nameidata *,
+ struct nfsvattr *, uid_t, struct ucred *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsvno_symlink(struct nameidata *, struct nfsvattr *, char *, int, int,
+ uid_t, struct ucred *, NFSPROC_T *, struct nfsexstuff *);
+int nfsvno_getsymlink(struct nfsrv_descript *, struct nfsvattr *,
+ NFSPROC_T *, char **, int *);
+int nfsvno_removesub(struct nameidata *, int, struct ucred *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsvno_rmdirsub(struct nameidata *, int, struct ucred *, NFSPROC_T *,
+ struct nfsexstuff *);
+int nfsvno_rename(struct nameidata *, struct nameidata *, u_int32_t,
+ u_int32_t, struct ucred *, NFSPROC_T *);
+int nfsvno_link(struct nameidata *, vnode_t, struct ucred *,
+ NFSPROC_T *, struct nfsexstuff *);
+int nfsvno_fsync(vnode_t, u_int64_t, int, struct ucred *, NFSPROC_T *);
+int nfsvno_statfs(vnode_t, struct statfs *, struct ucred *, NFSPROC_T *);
+void nfsvno_getfs(struct nfsfsinfo *, int);
+void nfsvno_open(struct nfsrv_descript *, struct nameidata *, nfsquad_t,
+ nfsv4stateid_t *, struct nfsstate *, int *, struct nfsvattr *, u_char *,
+ int, NFSACL_T *, nfsattrbit_t *, struct ucred *, NFSPROC_T *,
+ struct nfsexstuff *, vnode_t *);
+void nfsvno_updfilerev(vnode_t, struct nfsvattr *, struct ucred *,
+ NFSPROC_T *);
+int nfsvno_fillattr(struct nfsrv_descript *, vnode_t,
+ struct nfsvattr *, fhandle_t *, int, nfsattrbit_t *,
+ struct ucred *, NFSPROC_T *, int, int);
+int nfsrv_sattr(struct nfsrv_descript *, struct nfsvattr *, nfsattrbit_t *,
+ NFSACL_T *, NFSPROC_T *);
+int nfsv4_sattr(struct nfsrv_descript *, struct nfsvattr *, nfsattrbit_t *,
+ NFSACL_T *, NFSPROC_T *);
+int nfsvno_checkexp(mount_t, NFSSOCKADDR_T, struct nfsexstuff *,
+ struct ucred **);
+int nfsvno_fhtovp(mount_t, fhandle_t *, NFSSOCKADDR_T,
+ vnode_t *, struct nfsexstuff *, struct ucred **);
+int nfsvno_pathconf(vnode_t, int, register_t *, struct ucred *,
+ NFSPROC_T *);
+vnode_t nfsvno_getvp(fhandle_t *);
+int nfsvno_localconflict(vnode_t, int, u_int64_t, u_int64_t,
+ struct nfslockconflict *, NFSPROC_T *);
+int nfsvno_advlock(vnode_t, int, u_int64_t, u_int64_t, NFSPROC_T *);
+void nfsvno_unlockvfs(mount_t);
+int nfsvno_lockvfs(mount_t);
+int nfsrv_v4rootexport(void *, struct ucred *, NFSPROC_T *);
+
+/* newnfs_krpc.c */
+int newnfs_nmcancelreqs(struct nfsmount *);
+void newnfs_set_sigmask(struct thread *, sigset_t *);
+void newnfs_restore_sigmask(struct thread *, sigset_t *);
+int newnfs_msleep(struct thread *, void *, struct mtx *, int, char *, int);
+
+/* nfsd_srvkrpc.c */
+int nfsrvd_addsock(struct file *);
+int nfsrvd_nfsd(NFSPROC_T *, struct nfsd_nfsd_args *);
+void nfsrvd_init(int);
+
+/* nfscl_srvkrpc.c */
+int nfscbd_addsock(struct file *);
+int nfscbd_nfsd(NFSPROC_T *, struct nfsd_nfscbd_args *);
+
diff --git a/sys/fs/nfs/nfscl.h b/sys/fs/nfs/nfscl.h
new file mode 100644
index 0000000..1c459ad
--- /dev/null
+++ b/sys/fs/nfs/nfscl.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSCL_H
+#define _NFS_NFSCL_H
+
+/*
+ * Extra stuff for a NFSv4 nfsnode.
+ * MALLOC'd to the correct length for the name and file handle.
+ * n4_data has the file handle, followed by the file name.
+ * The macro NFS4NODENAME() returns a pointer to the start of the
+ * name.
+ */
+struct nfsv4node {
+ u_int16_t n4_fhlen;
+ u_int16_t n4_namelen;
+ u_int8_t n4_data[1];
+};
+
+#define NFS4NODENAME(n) (&((n)->n4_data[(n)->n4_fhlen]))
+
+/*
+ * Just a macro to convert the nfscl_reqstart arguments.
+ */
+#define NFSCL_REQSTART(n, p, v) \
+ nfscl_reqstart((n), (p), VFSTONFS((v)->v_mount), \
+ VTONFS(v)->n_fhp->nfh_fh, VTONFS(v)->n_fhp->nfh_len, NULL)
+
+/*
+ * These two macros convert between a lease duration and renew interval.
+ * For now, just make the renew interval 1/2 the lease duration.
+ * (They should be inverse operators.)
+ */
+#define NFSCL_RENEW(l) (((l) < 2) ? 1 : ((l) / 2))
+#define NFSCL_LEASE(r) ((r) * 2)
+
+/*
+ * These flag bits are used for the argument to nfscl_fillsattr() to
+ * indicate special handling of the attributes.
+ */
+#define NFSSATTR_FULL 0x1
+#define NFSSATTR_SIZE0 0x2
+#define NFSSATTR_SIZENEG1 0x4
+#define NFSSATTR_SIZERDEV 0x8
+
+#endif /* _NFS_NFSCL_H */
diff --git a/sys/fs/nfs/nfsclstate.h b/sys/fs/nfs/nfsclstate.h
new file mode 100644
index 0000000..10747af
--- /dev/null
+++ b/sys/fs/nfs/nfsclstate.h
@@ -0,0 +1,175 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSCLSTATE_H_
+#define _NFS_NFSCLSTATE_H_
+
+/*
+ * Definitions for NFS V4 client state handling.
+ */
+LIST_HEAD(nfsclopenhead, nfsclopen);
+LIST_HEAD(nfscllockownerhead, nfscllockowner);
+LIST_HEAD(nfscllockhead, nfscllock);
+LIST_HEAD(nfsclhead, nfsclclient);
+LIST_HEAD(nfsclownerhead, nfsclowner);
+TAILQ_HEAD(nfscldeleghead, nfscldeleg);
+LIST_HEAD(nfscldeleghash, nfscldeleg);
+#define NFSCLDELEGHASHSIZE 256
+#define NFSCLDELEGHASH(c, f, l) \
+ (&((c)->nfsc_deleghash[ncl_hash((f), (l)) % NFSCLDELEGHASHSIZE]))
+
+struct nfsclclient {
+ LIST_ENTRY(nfsclclient) nfsc_list;
+ struct nfsclownerhead nfsc_owner;
+ struct nfscldeleghead nfsc_deleg;
+ struct nfscldeleghash nfsc_deleghash[NFSCLDELEGHASHSIZE];
+ struct nfscllockownerhead nfsc_defunctlockowner;
+ struct nfsv4lock nfsc_lock;
+ struct proc *nfsc_renewthread;
+ struct nfsmount *nfsc_nmp;
+ nfsquad_t nfsc_clientid;
+ time_t nfsc_expire;
+ u_int32_t nfsc_clientidrev;
+ u_int32_t nfsc_renew;
+ u_int32_t nfsc_cbident;
+ u_int16_t nfsc_flags;
+ u_int16_t nfsc_idlen;
+ u_int8_t nfsc_id[1]; /* Malloc'd to correct length */
+};
+
+/*
+ * Bits for nfsc_flags.
+ */
+#define NFSCLFLAGS_INITED 0x0001
+#define NFSCLFLAGS_HASCLIENTID 0x0002
+#define NFSCLFLAGS_RECOVER 0x0004
+#define NFSCLFLAGS_UMOUNT 0x0008
+#define NFSCLFLAGS_HASTHREAD 0x0010
+#define NFSCLFLAGS_AFINET6 0x0020
+#define NFSCLFLAGS_EXPIREIT 0x0040
+#define NFSCLFLAGS_FIRSTDELEG 0x0080
+#define NFSCLFLAGS_GOTDELEG 0x0100
+
+struct nfsclowner {
+ LIST_ENTRY(nfsclowner) nfsow_list;
+ struct nfsclopenhead nfsow_open;
+ struct nfsclclient *nfsow_clp;
+ u_int32_t nfsow_seqid;
+ u_int32_t nfsow_defunct;
+ struct nfsv4lock nfsow_rwlock;
+ u_int8_t nfsow_owner[NFSV4CL_LOCKNAMELEN];
+};
+
+/*
+ * MALLOC'd to the correct length to accommodate the file handle.
+ */
+struct nfscldeleg {
+ TAILQ_ENTRY(nfscldeleg) nfsdl_list;
+ LIST_ENTRY(nfscldeleg) nfsdl_hash;
+ struct nfsclownerhead nfsdl_owner; /* locally issued state */
+ struct nfscllockownerhead nfsdl_lock;
+ nfsv4stateid_t nfsdl_stateid;
+ struct acl_entry nfsdl_ace; /* Delegation ace */
+ struct nfsclclient *nfsdl_clp;
+ struct nfsv4lock nfsdl_rwlock; /* for active I/O ops */
+ struct nfscred nfsdl_cred; /* Cred. used for Open */
+ time_t nfsdl_timestamp; /* used for stale cleanup */
+ u_int64_t nfsdl_sizelimit; /* Limit for file growth */
+ u_int64_t nfsdl_size; /* saved copy of file size */
+ u_int64_t nfsdl_change; /* and change attribute */
+ struct timespec nfsdl_modtime; /* local modify time */
+ u_int16_t nfsdl_fhlen;
+ u_int8_t nfsdl_flags;
+ u_int8_t nfsdl_fh[1]; /* must be last */
+};
+
+/*
+ * nfsdl_flags bits.
+ */
+#define NFSCLDL_READ 0x01
+#define NFSCLDL_WRITE 0x02
+#define NFSCLDL_RECALL 0x04
+#define NFSCLDL_NEEDRECLAIM 0x08
+#define NFSCLDL_ZAPPED 0x10
+#define NFSCLDL_MODTIMESET 0x20
+
+/*
+ * MALLOC'd to the correct length to accommodate the file handle.
+ */
+struct nfsclopen {
+ LIST_ENTRY(nfsclopen) nfso_list;
+ struct nfscllockownerhead nfso_lock;
+ nfsv4stateid_t nfso_stateid;
+ struct nfsclowner *nfso_own;
+ struct nfscred nfso_cred; /* Cred. used for Open */
+ u_int32_t nfso_mode;
+ u_int32_t nfso_opencnt;
+ u_int16_t nfso_fhlen;
+ u_int8_t nfso_posixlock; /* 1 for POSIX type locking */
+ u_int8_t nfso_fh[1]; /* must be last */
+};
+
+/*
+ * Return values for nfscl_open(). NFSCLOPEN_OK must == 0.
+ */
+#define NFSCLOPEN_OK 0
+#define NFSCLOPEN_DOOPEN 1
+#define NFSCLOPEN_DOOPENDOWNGRADE 2
+
+struct nfscllockowner {
+ LIST_ENTRY(nfscllockowner) nfsl_list;
+ struct nfscllockhead nfsl_lock;
+ struct nfsclopen *nfsl_open;
+ NFSPROC_T *nfsl_inprog;
+ nfsv4stateid_t nfsl_stateid;
+ u_int32_t nfsl_seqid;
+ u_int32_t nfsl_defunct;
+ struct nfsv4lock nfsl_rwlock;
+ u_int8_t nfsl_owner[NFSV4CL_LOCKNAMELEN];
+ u_int8_t nfsl_openowner[NFSV4CL_LOCKNAMELEN];
+};
+
+/*
+ * Byte range entry for the above lock owner.
+ */
+struct nfscllock {
+ LIST_ENTRY(nfscllock) nfslo_list;
+ u_int64_t nfslo_first;
+ u_int64_t nfslo_end;
+ short nfslo_type;
+};
+
+/*
+ * Macro for incrementing the seqid#.
+ */
+#define NFSCL_INCRSEQID(s, n) do { \
+ if (((n)->nd_flag & ND_INCRSEQID)) \
+ (s)++; \
+ } while (0)
+
+#endif /* _NFS_NFSCLSTATE_H_ */
diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h
new file mode 100644
index 0000000..f8ee445
--- /dev/null
+++ b/sys/fs/nfs/nfsdport.h
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * These macros handle nfsvattr fields. They look a bit silly here, but
+ * are quite different for the Darwin port.
+ */
+#define NFSVNO_ATTRINIT(n) (VATTR_NULL(&((n)->na_vattr)))
+#define NFSVNO_SETATTRVAL(n, f, v) ((n)->na_##f = (v))
+#define NFSVNO_SETACTIVE(n, f)
+#define NFSVNO_UNSET(n, f) ((n)->na_##f = VNOVAL)
+#define NFSVNO_NOTSETMODE(n) ((n)->na_mode == ((mode_t)VNOVAL))
+#define NFSVNO_ISSETMODE(n) ((n)->na_mode != ((mode_t)VNOVAL))
+#define NFSVNO_NOTSETUID(n) ((n)->na_uid == ((uid_t)VNOVAL))
+#define NFSVNO_ISSETUID(n) ((n)->na_uid != ((uid_t)VNOVAL))
+#define NFSVNO_NOTSETGID(n) ((n)->na_gid == ((gid_t)VNOVAL))
+#define NFSVNO_ISSETGID(n) ((n)->na_gid != ((gid_t)VNOVAL))
+#define NFSVNO_NOTSETSIZE(n) ((n)->na_size == VNOVAL)
+#define NFSVNO_ISSETSIZE(n) ((n)->na_size != VNOVAL)
+#define NFSVNO_NOTSETATIME(n) ((n)->na_atime.tv_sec == VNOVAL)
+#define NFSVNO_ISSETATIME(n) ((n)->na_atime.tv_sec != VNOVAL)
+#define NFSVNO_NOTSETMTIME(n) ((n)->na_mtime.tv_sec == VNOVAL)
+#define NFSVNO_ISSETMTIME(n) ((n)->na_mtime.tv_sec != VNOVAL)
+
+/*
+ * This structure acts as a "catch-all" for information that
+ * needs to be returned by nfsd_fhtovp().
+ */
+struct nfsexstuff {
+ int nes_vfslocked; /* required for all ports */
+ int nes_exflag;
+};
+
+#define NFSVNO_EXINIT(e) ((e)->nes_exflag = 0)
+#define NFSVNO_EXPORTED(e) ((e)->nes_exflag & MNT_EXPORTED)
+#define NFSVNO_EXRDONLY(e) ((e)->nes_exflag & MNT_EXRDONLY)
+#define NFSVNO_EXPORTANON(e) ((e)->nes_exflag & MNT_EXPORTANON)
+#define NFSVNO_EXSTRICTACCESS(e) ((e)->nes_exflag & MNT_EXSTRICTACCESS)
+#define NFSVNO_EXGSSONLY(e) ((e)->nes_exflag & MNT_EXGSSONLY)
+#define NFSVNO_EXV4ONLY(e) ((e)->nes_exflag & MNT_EXV4ONLY)
+
+#define NFSVNO_SETEXRDONLY(e) ((e)->nes_exflag = (MNT_EXPORTED|MNT_EXRDONLY))
+#define NFSVNO_SETEXGSSONLY(e) ((e)->nes_exflag |= MNT_EXGSSONLY)
+
+#define NFSVNO_CMPFH(f1, f2) \
+ ((f1)->fh_fsid.val[0] == (f2)->fh_fsid.val[0] && \
+ (f1)->fh_fsid.val[1] == (f2)->fh_fsid.val[1] && \
+ !bcmp((f1)->fh_fid.fid_data, (f2)->fh_fid.fid_data, \
+ (f1)->fh_fid.fid_len))
+
+#define NFSLOCKHASH(f) \
+ (&nfslockhash[(*((u_int32_t *)((f)->fh_fid.fid_data))) % NFSLOCKHASHSIZE])
+
+#define NFSFPVNODE(f) ((struct vnode *)((f)->f_data))
+#define NFSFPCRED(f) ((f)->f_cred)
+#define NFSFPFLAG(f) ((f)->f_flag)
+
+int fp_getfvp(NFSPROC_T *, int, struct file **, struct vnode **);
+
+#define NFSNAMEICNDSET(n, c, o, f) do { \
+ (n)->cn_cred = (c); \
+ (n)->cn_nameiop = (o); \
+ (n)->cn_flags = (f); \
+ } while (0)
+
+/*
+ * A little bit of Darwin vfs kpi.
+ */
+#define vnode_mount(v) ((v)->v_mount)
+#define vfs_statfs(m) (&((m)->mnt_stat))
+
+#define NFSPATHLEN_T size_t
+
+/*
+ * These are set to the minimum and maximum size of a server file
+ * handle.
+ */
+#define NFSRV_MINFH (sizeof (fhandle_t))
+#define NFSRV_MAXFH (sizeof (fhandle_t))
+
diff --git a/sys/fs/nfs/nfskpiport.h b/sys/fs/nfs/nfskpiport.h
new file mode 100644
index 0000000..1e1fb9c
--- /dev/null
+++ b/sys/fs/nfs/nfskpiport.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSKPIPORT_H_
+#define _NFSKPIPORT_NFS_H_
+/*
+ * These definitions are needed since the generic code is now using Darwin8
+ * KPI stuff. (I know, seems a bit silly, but I want the code to build on
+ * Darwin8 and hopefully subsequent releases from Apple.)
+ */
+typedef struct mount * mount_t;
+#define vfs_statfs(m) (&((m)->mnt_stat))
+#define vfs_flags(m) ((m)->mnt_flag)
+
+typedef struct vnode * vnode_t;
+#define vnode_mount(v) ((v)->v_mount)
+#define vnode_vtype(v) ((v)->v_type)
+
+typedef struct mbuf * mbuf_t;
+#define mbuf_freem(m) m_freem(m)
+#define mbuf_data(m) mtod((m), void *)
+#define mbuf_len(m) ((m)->m_len)
+#define mbuf_next(m) ((m)->m_next)
+#define mbuf_setlen(m, l) ((m)->m_len = (l))
+#define mbuf_setnext(m, p) ((m)->m_next = (p))
+#define mbuf_pkthdr_len(m) ((m)->m_pkthdr.len)
+#define mbuf_pkthdr_setlen(m, l) ((m)->m_pkthdr.len = (l))
+#define mbuf_pkthdr_setrcvif(m, p) ((m)->m_pkthdr.rcvif = (p))
+
+/*
+ * This stuff is needed by Darwin for handling the uio structure.
+ */
+#define CAST_USER_ADDR_T(a) (a)
+#define CAST_DOWN(c, a) ((c) (a))
+#define uio_uio_resid(p) ((p)->uio_resid)
+#define uio_uio_resid_add(p, v) ((p)->uio_resid += (v))
+#define uio_uio_resid_set(p, v) ((p)->uio_resid = (v))
+#define uio_iov_base(p) ((p)->uio_iov->iov_base)
+#define uio_iov_base_add(p, v) do { \
+ char *pp; \
+ pp = (char *)(p)->uio_iov->iov_base; \
+ pp += (v); \
+ (p)->uio_iov->iov_base = (void *)pp; \
+ } while (0)
+#define uio_iov_len(p) ((p)->uio_iov->iov_len)
+#define uio_iov_len_add(p, v) ((p)->uio_iov->iov_len += (v))
+
+#endif /* _NFSKPIPORT_NFS_H */
diff --git a/sys/fs/nfs/nfsm_subs.h b/sys/fs/nfs/nfsm_subs.h
new file mode 100644
index 0000000..a2777a0
--- /dev/null
+++ b/sys/fs/nfs/nfsm_subs.h
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSM_SUBS_H_
+#define _NFS_NFSM_SUBS_H_
+
+
+/*
+ * These macros do strange and peculiar things to mbuf chains for
+ * the assistance of the nfs code. To attempt to use them for any
+ * other purpose will be dangerous. (they make weird assumptions)
+ */
+
+#ifndef APPLE
+/*
+ * First define what the actual subs. return
+ */
+#define M_HASCL(m) ((m)->m_flags & M_EXT)
+#define NFSMINOFF(m) \
+ if (M_HASCL(m)) \
+ (m)->m_data = (m)->m_ext.ext_buf; \
+ else if ((m)->m_flags & M_PKTHDR) \
+ (m)->m_data = (m)->m_pktdat; \
+ else \
+ (m)->m_data = (m)->m_dat
+#define NFSMSIZ(m) ((M_HASCL(m))?MCLBYTES: \
+ (((m)->m_flags & M_PKTHDR)?MHLEN:MLEN))
+#define NFSM_DATAP(m, s) (m)->m_data += (s)
+
+/*
+ * Now for the macros that do the simple stuff and call the functions
+ * for the hard stuff.
+ * They use fields in struct nfsrv_descript to handle the mbuf queues.
+ * Replace most of the macro with an inline function, to minimize
+ * the machine code. The inline functions in lower case can be called
+ * directly, bypassing the macro.
+ */
+static __inline void *
+nfsm_build(struct nfsrv_descript *nd, int siz)
+{
+ void *retp;
+ struct mbuf *mb2;
+
+ if (siz > M_TRAILINGSPACE(nd->nd_mb)) {
+ NFSMCLGET(mb2, M_DONTWAIT);
+ if (siz > MLEN)
+ panic("build > MLEN");
+ mbuf_setlen(mb2, 0);
+ nd->nd_bpos = NFSMTOD(mb2, caddr_t);
+ nd->nd_mb->m_next = mb2;
+ nd->nd_mb = mb2;
+ }
+ retp = (void *)(nd->nd_bpos);
+ nd->nd_mb->m_len += siz;
+ nd->nd_bpos += siz;
+ return (retp);
+}
+
+#define NFSM_BUILD(a, c, s) ((a) = (c)nfsm_build(nd, (s)))
+
+static __inline void *
+nfsm_dissect(struct nfsrv_descript *nd, int siz)
+{
+ int tt1;
+ void *retp;
+
+ tt1 = NFSMTOD(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
+ if (tt1 >= siz) {
+ retp = (void *)nd->nd_dpos;
+ nd->nd_dpos += siz;
+ } else {
+ retp = nfsm_dissct(nd, siz);
+ }
+ return (retp);
+}
+
+#define NFSM_DISSECT(a, c, s) \
+ do { \
+ (a) = (c)nfsm_dissect(nd, (s)); \
+ if ((a) == NULL) { \
+ error = EBADRPC; \
+ goto nfsmout; \
+ } \
+ } while (0)
+#endif /* !APPLE */
+
+#define NFSM_STRSIZ(s, m) \
+ do { \
+ tl = (u_int32_t *)nfsm_dissect(nd, NFSX_UNSIGNED); \
+ if (!tl || ((s) = fxdr_unsigned(int32_t, *tl)) > (m)) { \
+ error = EBADRPC; \
+ goto nfsmout; \
+ } \
+ } while (0)
+
+#define NFSM_RNDUP(a) (((a)+3)&(~0x3))
+
+#endif /* _NFS_NFSM_SUBS_H_ */
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
new file mode 100644
index 0000000..e4b3d0a
--- /dev/null
+++ b/sys/fs/nfs/nfsport.h
@@ -0,0 +1,751 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSPORT_H_
+#define _NFSPORT_NFS_H_
+
+/*
+ * In general, I'm not fond of #includes in .h files, but this seems
+ * to be the cleanest way to handle #include files for the ports.
+ */
+#ifdef _KERNEL
+#include <sys/unistd.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/dirent.h>
+#include <sys/domain.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/lockf.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/reboot.h>
+#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/stat.h>
+#include <sys/syslog.h>
+#include <sys/sysproto.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/acl.h>
+#include <sys/module.h>
+#include <sys/sysent.h>
+#include <sys/syscall.h>
+#include <sys/priv.h>
+#include <sys/kthread.h>
+#include <sys/syscallsubr.h>
+#include <fs/fifofs/fifo.h>
+#include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/vinet.h>
+#include <machine/in_cksum.h>
+#include <crypto/des/des.h>
+#include <sys/md5.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcclnt.h>
+#include <rpc/rpcsec_gss.h>
+
+/*
+ * For Darwin, these functions should be "static" when built in a kext.
+ * (This is always defined as nil otherwise.)
+ */
+#define APPLESTATIC
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/ufsmount.h>
+#include <vm/uma.h>
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <nfs/nfssvc.h>
+#include "opt_nfs.h"
+#include "opt_ufs.h"
+
+/*
+ * These types must be defined before the nfs includes.
+ */
+#define NFSSOCKADDR_T struct sockaddr *
+#define NFSPROC_T struct thread
+#define NFSDEV_T dev_t
+#define NFSSVCARGS nfssvc_args
+#ifdef NFS4_ACL_EXTATTR_NAME
+#define NFSACL_T struct acl
+#else
+#define NFSACL_T void
+#endif
+
+/*
+ * These should be defined as the types used for the corresponding VOP's
+ * argument type.
+ */
+#define NFS_ACCESS_ARGS struct vop_access_args
+#define NFS_OPEN_ARGS struct vop_open_args
+#define NFS_GETATTR_ARGS struct vop_getattr_args
+#define NFS_LOOKUP_ARGS struct vop_lookup_args
+#define NFS_READDIR_ARGS struct vop_readdir_args
+
+/*
+ * Allocate mbufs. Must succeed and never set the mbuf ptr to NULL.
+ */
+#define NFSMGET(m) do { \
+ MGET((m), M_TRYWAIT, MT_DATA); \
+ while ((m) == NULL ) { \
+ (void) nfs_catnap(PZERO, "nfsmget"); \
+ MGET((m), M_TRYWAIT, MT_DATA); \
+ } \
+ } while (0)
+#define NFSMGETHDR(m) do { \
+ MGETHDR((m), M_TRYWAIT, MT_DATA); \
+ while ((m) == NULL ) { \
+ (void) nfs_catnap(PZERO, "nfsmget"); \
+ MGETHDR((m), M_TRYWAIT, MT_DATA); \
+ } \
+ } while (0)
+#define NFSMCLGET(m, w) do { \
+ MGET((m), M_TRYWAIT, MT_DATA); \
+ while ((m) == NULL ) { \
+ (void) nfs_catnap(PZERO, "nfsmget"); \
+ MGET((m), M_TRYWAIT, MT_DATA); \
+ } \
+ MCLGET((m), (w)); \
+ } while (0)
+#define NFSMCLGETHDR(m, w) do { \
+ MGETHDR((m), M_TRYWAIT, MT_DATA); \
+ while ((m) == NULL ) { \
+ (void) nfs_catnap(PZERO, "nfsmget"); \
+ MGETHDR((m), M_TRYWAIT, MT_DATA); \
+ } \
+ } while (0)
+#define NFSMTOD mtod
+
+/*
+ * Client side constant for size of a lockowner name.
+ */
+#define NFSV4CL_LOCKNAMELEN 12
+
+/*
+ * Type for a mutex lock.
+ */
+#define NFSMUTEX_T struct mtx
+
+#include <fs/nfs/nfskpiport.h>
+#include <fs/nfs/nfsdport.h>
+#include <fs/nfs/rpcv2.h>
+#include <fs/nfs/nfsproto.h>
+#include <fs/nfs/nfs.h>
+#include <fs/nfs/nfs_var.h>
+#include <fs/nfs/nfsm_subs.h>
+#include <fs/nfs/nfsrvcache.h>
+#include <fs/nfs/nfsrvstate.h>
+#include <fs/nfs/xdr_subs.h>
+#include <fs/nfs/nfscl.h>
+#include <fs/nfs/nfsclstate.h>
+#include <fs/nfsclient/nfsargs.h>
+#include <fs/nfsclient/nfsmount.h>
+
+/*
+ * Just to keep nfs_var.h happy.
+ */
+struct nfs_vattr {
+ int junk;
+};
+
+struct nfsvattr {
+ struct vattr na_vattr;
+ nfsattrbit_t na_suppattr;
+ u_int32_t na_mntonfileno;
+ u_int64_t na_filesid[2];
+};
+
+#define na_type na_vattr.va_type
+#define na_mode na_vattr.va_mode
+#define na_nlink na_vattr.va_nlink
+#define na_uid na_vattr.va_uid
+#define na_gid na_vattr.va_gid
+#define na_fsid na_vattr.va_fsid
+#define na_fileid na_vattr.va_fileid
+#define na_size na_vattr.va_size
+#define na_blocksize na_vattr.va_blocksize
+#define na_atime na_vattr.va_atime
+#define na_mtime na_vattr.va_mtime
+#define na_ctime na_vattr.va_ctime
+#define na_gen na_vattr.va_gen
+#define na_flags na_vattr.va_flags
+#define na_rdev na_vattr.va_rdev
+#define na_bytes na_vattr.va_bytes
+#define na_filerev na_vattr.va_filerev
+#define na_vaflags na_vattr.va_vaflags
+
+#include <fs/nfsclient/nfsnode.h>
+
+/*
+ * This is the header structure used for the lists, etc. (It has the
+ * above record in it.
+ */
+struct nfsrv_stablefirst {
+ LIST_HEAD(, nfsrv_stable) nsf_head; /* Head of nfsrv_stable list */
+ time_t nsf_eograce; /* Time grace period ends */
+ time_t *nsf_bootvals; /* Previous boottime values */
+ struct file *nsf_fp; /* File table pointer */
+ u_char nsf_flags; /* NFSNSF_ flags */
+ struct nfsf_rec nsf_rec; /* and above first record */
+};
+#define nsf_lease nsf_rec.lease
+#define nsf_numboots nsf_rec.numboots
+
+/* NFSNSF_xxx flags */
+#define NFSNSF_UPDATEDONE 0x01
+#define NFSNSF_GRACEOVER 0x02
+#define NFSNSF_NEEDLOCK 0x04
+#define NFSNSF_EXPIREDCLIENT 0x08
+#define NFSNSF_NOOPENS 0x10
+#define NFSNSF_OK 0x20
+
+/*
+ * Maximum number of boot times allowed in record. Although there is
+ * really no need for a fixed upper bound, this serves as a sanity check
+ * for a corrupted file.
+ */
+#define NFSNSF_MAXNUMBOOTS 10000
+
+/*
+ * This structure defines the other records in the file. The
+ * nst_client array is actually the size of the client string name.
+ */
+struct nfst_rec {
+ u_int16_t len;
+ u_char flag;
+ u_char client[1];
+};
+/* and the values for flag */
+#define NFSNST_NEWSTATE 0x1
+#define NFSNST_REVOKE 0x2
+#define NFSNST_GOTSTATE 0x4
+
+/*
+ * This structure is linked onto nfsrv_stablefirst for the duration of
+ * reclaim.
+ */
+struct nfsrv_stable {
+ LIST_ENTRY(nfsrv_stable) nst_list;
+ struct nfsclient *nst_clp;
+ struct nfst_rec nst_rec;
+};
+#define nst_timestamp nst_rec.timestamp
+#define nst_len nst_rec.len
+#define nst_flag nst_rec.flag
+#define nst_client nst_rec.client
+
+/*
+ * At some point the server will run out of kernel storage for
+ * state structures. For FreeBSD5.2, this results in a panic
+ * kmem_map is full. It happens at well over 1000000 opens plus
+ * locks on a PIII-800 with 256Mbytes, so that is where I've set
+ * the limit. If your server panics due to too many opens/locks,
+ * decrease the size of NFSRV_V4STATELIMIT. If you find the server
+ * returning NFS4ERR_RESOURCE a lot and have lots of memory, try
+ * increasing it.
+ */
+#define NFSRV_V4STATELIMIT 500000 /* Max # of Opens + Locks */
+
+/*
+ * The type required differs with BSDen (just the second arg).
+ */
+void nfsrvd_rcv(struct socket *, void *, int);
+
+/*
+ * Macros for handling socket addresses. (Hopefully this makes the code
+ * more portable, since I've noticed some 'BSD don't have sockaddrs in
+ * mbufs any more.)
+ */
+#define NFSSOCKADDR(a, t) ((t)(a))
+#define NFSSOCKADDRALLOC(a) \
+ do { \
+ MALLOC((a), struct sockaddr *, sizeof (struct sockaddr), \
+ M_SONAME, M_WAITOK); \
+ NFSBZERO((a), sizeof (struct sockaddr)); \
+ } while (0)
+#define NFSSOCKADDRSIZE(a, s) ((a)->sa_len = (s))
+#define NFSSOCKADDRFREE(a) \
+ do { \
+ if (a) \
+ FREE((caddr_t)(a), M_SONAME); \
+ } while (0)
+
+/*
+ * These should be defined as a process or thread structure, as required
+ * for signal handling, etc.
+ */
+#define NFSNEWCRED(c) (crdup(c))
+#define NFSPROCCRED(p) ((p)->td_ucred)
+#define NFSFREECRED(c) (crfree(c))
+#define NFSUIOPROC(u, p) ((u)->uio_td = NULL)
+#define NFSPROCP(p) ((p)->td_proc)
+
+/*
+ * Define these so that cn_hash and its length is ignored.
+ */
+#define NFSCNHASHZERO(c)
+#define NFSCNHASH(c, v)
+#define NCHNAMLEN 9999999
+
+/*
+ * Define these to use the time of day clock.
+ */
+#define NFSGETTIME(t) (getmicrotime(t))
+#define NFSGETNANOTIME(t) (getnanotime(t))
+
+/*
+ * These macros are defined to initialize and set the timer routine.
+ */
+#define NFS_TIMERINIT \
+ newnfs_timer(NULL)
+
+/*
+ * Handle SMP stuff:
+ */
+#define NFSSTATESPINLOCK extern struct mtx nfs_state_mutex
+#define NFSLOCKSTATE() mtx_lock(&nfs_state_mutex)
+#define NFSUNLOCKSTATE() mtx_unlock(&nfs_state_mutex)
+#define NFSREQSPINLOCK extern struct mtx nfs_req_mutex
+#define NFSLOCKREQ() mtx_lock(&nfs_req_mutex)
+#define NFSUNLOCKREQ() mtx_unlock(&nfs_req_mutex)
+#define NFSCACHEMUTEX extern struct mtx nfs_cache_mutex
+#define NFSCACHEMUTEXPTR (&nfs_cache_mutex)
+#define NFSLOCKCACHE() mtx_lock(&nfs_cache_mutex)
+#define NFSUNLOCKCACHE() mtx_unlock(&nfs_cache_mutex)
+#define NFSCACHELOCKREQUIRED() mtx_assert(&nfs_cache_mutex, MA_OWNED)
+#define NFSSOCKMUTEX extern struct mtx nfs_slock_mutex
+#define NFSSOCKMUTEXPTR (&nfs_slock_mutex)
+#define NFSLOCKSOCK() mtx_lock(&nfs_slock_mutex)
+#define NFSUNLOCKSOCK() mtx_unlock(&nfs_slock_mutex)
+#define NFSNAMEIDMUTEX extern struct mtx nfs_nameid_mutex
+#define NFSLOCKNAMEID() mtx_lock(&nfs_nameid_mutex)
+#define NFSUNLOCKNAMEID() mtx_unlock(&nfs_nameid_mutex)
+#define NFSNAMEIDREQUIRED() mtx_assert(&nfs_nameid_mutex, MA_OWNED)
+#define NFSCLSTATEMUTEX extern struct mtx nfs_clstate_mutex
+#define NFSCLSTATEMUTEXPTR (&nfs_clstate_mutex)
+#define NFSLOCKCLSTATE() mtx_lock(&nfs_clstate_mutex)
+#define NFSUNLOCKCLSTATE() mtx_unlock(&nfs_clstate_mutex)
+#define NFSDLOCKMUTEX extern struct mtx newnfsd_mtx
+#define NFSDLOCKMUTEXPTR (&newnfsd_mtx)
+#define NFSD_LOCK() mtx_lock(&newnfsd_mtx)
+#define NFSD_UNLOCK() mtx_unlock(&newnfsd_mtx)
+#define NFSD_LOCK_ASSERT() mtx_assert(&newnfsd_mtx, MA_OWNED)
+#define NFSD_UNLOCK_ASSERT() mtx_assert(&newnfsd_mtx, MA_NOTOWNED)
+#define NFSV4ROOTLOCKMUTEX extern struct mtx nfs_v4root_mutex
+#define NFSV4ROOTLOCKMUTEXPTR (&nfs_v4root_mutex)
+#define NFSLOCKV4ROOTMUTEX() mtx_lock(&nfs_v4root_mutex)
+#define NFSUNLOCKV4ROOTMUTEX() mtx_unlock(&nfs_v4root_mutex)
+#define NFSLOCKNODE(n) mtx_lock(&((n)->n_mtx))
+#define NFSUNLOCKNODE(n) mtx_unlock(&((n)->n_mtx))
+#define NFSLOCKMNT(m) mtx_lock(&((m)->nm_mtx))
+#define NFSUNLOCKMNT(m) mtx_unlock(&((m)->nm_mtx))
+#define NFSLOCKREQUEST(r) mtx_lock(&((r)->r_mtx))
+#define NFSUNLOCKREQUEST(r) mtx_unlock(&((r)->r_mtx))
+#define NFSPROCLISTLOCK() sx_slock(&allproc_lock)
+#define NFSPROCLISTUNLOCK() sx_sunlock(&allproc_lock)
+#define NFSLOCKSOCKREQ(r) mtx_lock(&((r)->nr_mtx))
+#define NFSUNLOCKSOCKREQ(r) mtx_unlock(&((r)->nr_mtx))
+
+/*
+ * Use these macros to initialize/free a mutex.
+ */
+#define NFSINITSOCKMUTEX(m) mtx_init((m), "nfssock", NULL, MTX_DEF)
+#define NFSFREEMUTEX(m) mtx_destroy((m))
+
+int nfsmsleep(void *, void *, int, const char *, struct timespec *);
+
+/*
+ * And weird vm stuff in the nfs server.
+ */
+#define PDIRUNLOCK 0x0
+#define MAX_COMMIT_COUNT (1024 * 1024)
+
+/*
+ * These macros are called at the start and end of operations that
+ * might modify the underlying file system.
+ */
+#define NFS_STARTWRITE(v, m) vn_start_write((v), (m), V_WAIT)
+#define NFS_ENDWRITE(m) vn_finished_write(m)
+
+/*
+ * Define these to handle the type of va_rdev.
+ */
+#define NFSMAKEDEV(m, n) makedev((m), (n))
+#define NFSMAJOR(d) major(d)
+#define NFSMINOR(d) minor(d)
+
+/*
+ * Define this to be the macro that returns the minimum size required
+ * for a directory entry.
+ */
+#define DIRENT_SIZE(dp) GENERIC_DIRSIZ(dp)
+
+/*
+ * The vnode tag for nfsv4root.
+ */
+#define VT_NFSV4ROOT "nfsv4root"
+
+/*
+ * XXX - not in any system .h file, just vfs_export.c
+ * Network address lookup element
+ */
+struct netcred {
+ struct radix_node netc_rnodes[2];
+ int netc_exflags;
+ struct ucred netc_anon;
+};
+
+/*
+ * Define whatever it takes to do a vn_rdwr().
+ */
+#define NFSD_RDWR(r, v, b, l, o, s, i, c, a, p) \
+ vn_rdwr((r), (v), (b), (l), (o), (s), (i), (c), NULL, (int *)(a), (p))
+
+/*
+ * Macros for handling memory for different BSDen.
+ * NFSBCOPY(src, dst, len) - copies len bytes, non-overlapping
+ * NFSOVBCOPY(src, dst, len) - ditto, but data areas might overlap
+ * NFSBCMP(cp1, cp2, len) - compare len bytes, return 0 if same
+ * NFSBZERO(cp, len) - set len bytes to 0x0
+ */
+#define NFSBCOPY(s, d, l) bcopy((s), (d), (l))
+#define NFSOVBCOPY(s, d, l) ovbcopy((s), (d), (l))
+#define NFSBCMP(s, d, l) bcmp((s), (d), (l))
+#define NFSBZERO(s, l) bzero((s), (l))
+
+/*
+ * Some queue.h files don't have these dfined in them.
+ */
+#define LIST_END(head) NULL
+#define SLIST_END(head) NULL
+#define TAILQ_END(head) NULL
+
+/*
+ * This must be defined to be a global variable the increments once
+ * per second, but never stops or goes backwards, even when a "date"
+ * command changes the tod clock. It is used for delta times for
+ * leases, etc.
+ */
+#define NFSD_MONOSEC time_uptime
+
+/*
+ * Declare the malloc types.
+ */
+MALLOC_DECLARE(M_NEWNFSRVCACHE);
+MALLOC_DECLARE(M_NEWNFSDCLIENT);
+MALLOC_DECLARE(M_NEWNFSDSTATE);
+MALLOC_DECLARE(M_NEWNFSDLOCK);
+MALLOC_DECLARE(M_NEWNFSDLOCKFILE);
+MALLOC_DECLARE(M_NEWNFSSTRING);
+MALLOC_DECLARE(M_NEWNFSUSERGROUP);
+MALLOC_DECLARE(M_NEWNFSDREQ);
+MALLOC_DECLARE(M_NEWNFSFH);
+MALLOC_DECLARE(M_NEWNFSCLOWNER);
+MALLOC_DECLARE(M_NEWNFSCLOPEN);
+MALLOC_DECLARE(M_NEWNFSCLDELEG);
+MALLOC_DECLARE(M_NEWNFSCLCLIENT);
+MALLOC_DECLARE(M_NEWNFSCLLOCKOWNER);
+MALLOC_DECLARE(M_NEWNFSCLLOCK);
+MALLOC_DECLARE(M_NEWNFSDIROFF);
+MALLOC_DECLARE(M_NEWNFSV4NODE);
+MALLOC_DECLARE(M_NEWNFSDIRECTIO);
+MALLOC_DECLARE(M_NEWNFSMNT);
+#define M_NFSRVCACHE M_NEWNFSRVCACHE
+#define M_NFSDCLIENT M_NEWNFSDCLIENT
+#define M_NFSDSTATE M_NEWNFSDSTATE
+#define M_NFSDLOCK M_NEWNFSDLOCK
+#define M_NFSDLOCKFILE M_NEWNFSDLOCKFILE
+#define M_NFSSTRING M_NEWNFSSTRING
+#define M_NFSUSERGROUP M_NEWNFSUSERGROUP
+#define M_NFSDREQ M_NEWNFSDREQ
+#define M_NFSFH M_NEWNFSFH
+#define M_NFSCLOWNER M_NEWNFSCLOWNER
+#define M_NFSCLOPEN M_NEWNFSCLOPEN
+#define M_NFSCLDELEG M_NEWNFSCLDELEG
+#define M_NFSCLCLIENT M_NEWNFSCLCLIENT
+#define M_NFSCLLOCKOWNER M_NEWNFSCLLOCKOWNER
+#define M_NFSCLLOCK M_NEWNFSCLLOCK
+#define M_NFSDIROFF M_NEWNFSDIROFF
+#define M_NFSV4NODE M_NEWNFSV4NODE
+#define M_NFSDIRECTIO M_NEWNFSDIRECTIO
+
+#define NFSINT_SIGMASK(set) \
+ (SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \
+ SIGISMEMBER(set, SIGHUP) || SIGISMEMBER(set, SIGKILL) || \
+ SIGISMEMBER(set, SIGQUIT))
+
+/*
+ * Convert a quota block count to byte count.
+ */
+#define NFSQUOTABLKTOBYTE(q, b) (q) *= (b)
+
+/*
+ * Define this as the largest file size supported. (It should probably
+ * be available via a VFS_xxx Op, but it isn't.
+ */
+#define NFSRV_MAXFILESIZE ((u_int64_t)0x800000000000)
+
+/*
+ * Set this macro to index() or strchr(), whichever is supported.
+ */
+#define STRCHR(s, c) index((s), (c))
+
+/*
+ * Set the n_time in the client write rpc, as required.
+ */
+#define NFSWRITERPC_SETTIME(w, n, v4) \
+ do { \
+ if (w) { \
+ (n)->n_mtime = (n)->n_vattr.na_vattr.va_mtime; \
+ if (v4) \
+ (n)->n_change = (n)->n_vattr.na_vattr.va_filerev; \
+ } \
+ } while (0)
+
+/*
+ * Fake value, just to make the client work.
+ */
+#define NFS_LATTR_NOSHRINK 1
+
+/*
+ * Prototypes for functions where the arguments vary for different ports.
+ */
+int nfscl_loadattrcache(struct vnode **, struct nfsvattr *, void *, void *,
+ int, int);
+void newnfs_realign(struct mbuf **);
+
+/*
+ * If the port runs on an SMP box that can enforce Atomic ops with low
+ * overheads, define these as atomic increments/decrements. If not,
+ * don't worry about it, since these are used for stats that can be
+ * "out by one" without disastrous consequences.
+ */
+#define NFSINCRGLOBAL(a) ((a)++)
+
+/*
+ * Assorted funky stuff to make things work under Darwin8.
+ */
+/*
+ * These macros checks for a field in vattr being set.
+ */
+#define NFSATTRISSET(t, v, a) ((v)->a != (t)VNOVAL)
+#define NFSATTRISSETTIME(v, a) ((v)->a.tv_sec != VNOVAL)
+
+/*
+ * Manipulate mount flags.
+ */
+#define NFSSTA_HASWRITEVERF 0x00040000 /* Has write verifier */
+#define NFSSTA_GOTFSINFO 0x00100000 /* Got the fsinfo */
+#define NFSSTA_TIMEO 0x10000000 /* Experiencing a timeout */
+#define NFSSTA_LOCKTIMEO 0x20000000 /* Experiencing a lockd timeout */
+#define NFSSTA_HASSETFSID 0x40000000 /* Has set the fsid */
+
+#define NFSHASNFSV3(n) ((n)->nm_flag & NFSMNT_NFSV3)
+#define NFSHASNFSV4(n) ((n)->nm_flag & NFSMNT_NFSV4)
+#define NFSHASNFSV3OR4(n) ((n)->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4))
+#define NFSHASGOTFSINFO(n) ((n)->nm_state & NFSSTA_GOTFSINFO)
+#define NFSHASHASSETFSID(n) ((n)->nm_state & NFSSTA_HASSETFSID)
+#define NFSHASSTRICT3530(n) ((n)->nm_flag & NFSMNT_STRICT3530)
+#define NFSHASWRITEVERF(n) ((n)->nm_state & NFSSTA_HASWRITEVERF)
+#define NFSHASINT(n) ((n)->nm_flag & NFSMNT_INT)
+#define NFSHASSOFT(n) ((n)->nm_flag & NFSMNT_SOFT)
+#define NFSHASINTORSOFT(n) ((n)->nm_flag & (NFSMNT_INT | NFSMNT_SOFT))
+#define NFSHASDUMBTIMR(n) ((n)->nm_flag & NFSMNT_DUMBTIMR)
+#define NFSHASNOCONN(n) ((n)->nm_flag & NFSMNT_MNTD)
+#define NFSHASKERB(n) ((n)->nm_flag & NFSMNT_KERB)
+#define NFSHASALLGSSNAME(n) ((n)->nm_flag & NFSMNT_ALLGSSNAME)
+#define NFSHASINTEGRITY(n) ((n)->nm_flag & NFSMNT_INTEGRITY)
+#define NFSHASPRIVACY(n) ((n)->nm_flag & NFSMNT_PRIVACY)
+#define NFSSETWRITEVERF(n) ((n)->nm_state |= NFSSTA_HASWRITEVERF)
+#define NFSSETHASSETFSID(n) ((n)->nm_state |= NFSSTA_HASSETFSID)
+#ifdef NFS4_ACL_EXTATTR_NAME
+#define NFSHASNFS4ACL(m) ((m)->mnt_flag & MNT_NFS4ACLS)
+#else
+#define NFSHASNFS4ACL(m) 0
+#endif
+
+/*
+ * Gets the stats field out of the mount structure.
+ */
+#define vfs_statfs(m) (&((m)->mnt_stat))
+
+/*
+ * Set boottime.
+ */
+#define NFSSETBOOTTIME(b) ((b) = boottime)
+
+/*
+ * The size of directory blocks in the buffer cache.
+ * MUST BE in the range of PAGE_SIZE <= NFS_DIRBLKSIZ <= MAXBSIZE!!
+ */
+#define NFS_DIRBLKSIZ (16 * DIRBLKSIZ) /* Must be a multiple of DIRBLKSIZ */
+
+/*
+ * Define these macros to access mnt_flag fields.
+ */
+#define NFSMNT_RDONLY(m) ((m)->mnt_flag & MNT_RDONLY)
+#endif /* _KERNEL */
+
+/*
+ * Define a structure similar to ufs_args for use in exporting the V4 root.
+ */
+struct nfsex_args {
+ char *fspec;
+ struct export_args export;
+};
+
+/*
+ * Define these here, so they don't have to be in mount.h, for now.
+ */
+#define MNT_EXGSSKRB5 MNT_EXKERB
+
+/*
+ * These export flags should be defined, but there are no bits left.
+ * Maybe a separate mnt_exflag field could be added or the mnt_flag
+ * field increased to 64 bits?
+ */
+#ifndef MNT_EXSTRICTACCESS
+#define MNT_EXSTRICTACCESS 0x0
+#endif
+#ifndef MNT_EXV4ONLY
+#define MNT_EXV4ONLY 0x0
+#endif
+
+#ifdef _KERNEL
+/*
+ * Define this to invalidate the attribute cache for the nfs node.
+ */
+#define NFSINVALATTRCACHE(n) ((n)->n_attrstamp = 0)
+
+/* Used for FreeBSD only */
+void nfsd_mntinit(void);
+
+/*
+ * Define these for vnode lock/unlock ops.
+ */
+#define NFSVOPLOCK(v, f, p) vn_lock((v), (f))
+#define NFSVOPUNLOCK(v, f, p) VOP_UNLOCK((v), (f))
+#define NFSVOPISLOCKED(v, p) VOP_ISLOCKED((v))
+
+/*
+ * Define ncl_hash().
+ */
+#define ncl_hash(f, l) (fnv_32_buf((f), (l), FNV1_32_INIT))
+
+int newnfs_iosize(struct nfsmount *);
+
+#ifdef NFS_DEBUG
+
+extern int nfs_debug;
+#define NFS_DEBUG_ASYNCIO 1 /* asynchronous i/o */
+#define NFS_DEBUG_WG 2 /* server write gathering */
+#define NFS_DEBUG_RC 4 /* server request caching */
+
+#define NFS_DPF(cat, args) \
+ do { \
+ if (nfs_debug & NFS_DEBUG_##cat) printf args; \
+ } while (0)
+
+#else
+
+#define NFS_DPF(cat, args)
+
+#endif
+
+int newnfs_vncmpf(struct vnode *, void *);
+
+#ifndef NFS_MINDIRATTRTIMO
+#define NFS_MINDIRATTRTIMO 3 /* VDIR attrib cache timeout in sec */
+#endif
+#ifndef NFS_MAXDIRATTRTIMO
+#define NFS_MAXDIRATTRTIMO 60
+#endif
+
+/*
+ * Nfs outstanding request list element
+ */
+struct nfsreq {
+ TAILQ_ENTRY(nfsreq) r_chain;
+ u_int32_t r_flags; /* flags on request, see below */
+ struct nfsmount *r_nmp; /* Client mnt ptr */
+ struct mtx r_mtx; /* Mutex lock for this structure */
+};
+
+#ifndef NFS_MAXBSIZE
+#define NFS_MAXBSIZE MAXBSIZE
+#endif
+
+/*
+ * This macro checks to see if issuing of delegations is allowed for this
+ * vnode.
+ */
+#ifdef VV_DISABLEDELEG
+#define NFSVNO_DELEGOK(v) \
+ ((v) == NULL || ((v)->v_vflag & VV_DISABLEDELEG) == 0)
+#else
+#define NFSVNO_DELEGOK(v) (1)
+#endif
+
+#endif /* _KERNEL */
+
+#endif /* _NFSPORT_NFS_H */
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
new file mode 100644
index 0000000..a092790
--- /dev/null
+++ b/sys/fs/nfs/nfsproto.h
@@ -0,0 +1,1129 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSPROTO_H_
+#define _NFS_NFSPROTO_H_
+
+/*
+ * nfs definitions as per the Version 2, 3 and 4 specs
+ */
+
+/*
+ * Constants as defined in the NFS Version 2, 3 and 4 specs.
+ * "NFS: Network File System Protocol Specification" RFC1094
+ * and in the "NFS: Network File System Version 3 Protocol
+ * Specification"
+ */
+
+#define NFS_PORT 2049
+#define NFS_PROG 100003
+#define NFS_CALLBCKPROG 0x40000000 /* V4 only */
+#define NFS_VER2 2
+#define NFS_VER3 3
+#define NFS_VER4 4
+#define NFS_V2MAXDATA 8192
+#define NFS_MAXDGRAMDATA 16384
+#define NFS_MAXDATA NFS_MAXBSIZE
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_MAXPKTHDR 404
+#define NFS_MAXPACKET (NFS_MAXDATA + 2048)
+#define NFS_MINPACKET 20
+#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */
+#define NFSV4_MINORVERSION 0 /* V4 Minor version */
+#define NFSV4_CBVERS 1 /* V4 CB Version */
+#define NFSV4_SMALLSTR 50 /* Strings small enough for stack */
+
+/* Stat numbers for rpc returns (version 2, 3 and 4) */
+#define NFSERR_OK 0
+#define NFSERR_PERM 1
+#define NFSERR_NOENT 2
+#define NFSERR_IO 5
+#define NFSERR_NXIO 6
+#define NFSERR_ACCES 13
+#define NFSERR_EXIST 17
+#define NFSERR_XDEV 18 /* Version 3, 4 only */
+#define NFSERR_NODEV 19
+#define NFSERR_NOTDIR 20
+#define NFSERR_ISDIR 21
+#define NFSERR_INVAL 22 /* Version 3, 4 only */
+#define NFSERR_FBIG 27
+#define NFSERR_NOSPC 28
+#define NFSERR_ROFS 30
+#define NFSERR_MLINK 31 /* Version 3, 4 only */
+#define NFSERR_NAMETOL 63
+#define NFSERR_NOTEMPTY 66
+#define NFSERR_DQUOT 69
+#define NFSERR_STALE 70
+#define NFSERR_REMOTE 71 /* Version 3 only */
+#define NFSERR_WFLUSH 99 /* Version 2 only */
+#define NFSERR_BADHANDLE 10001 /* These are Version 3, 4 only */
+#define NFSERR_NOT_SYNC 10002 /* Version 3 Only */
+#define NFSERR_BAD_COOKIE 10003
+#define NFSERR_NOTSUPP 10004
+#define NFSERR_TOOSMALL 10005
+#define NFSERR_SERVERFAULT 10006
+#define NFSERR_BADTYPE 10007
+#define NFSERR_DELAY 10008 /* Called NFSERR_JUKEBOX for V3 */
+#define NFSERR_SAME 10009 /* These are Version 4 only */
+#define NFSERR_DENIED 10010
+#define NFSERR_EXPIRED 10011
+#define NFSERR_LOCKED 10012
+#define NFSERR_GRACE 10013
+#define NFSERR_FHEXPIRED 10014
+#define NFSERR_SHAREDENIED 10015
+#define NFSERR_WRONGSEC 10016
+#define NFSERR_CLIDINUSE 10017
+#define NFSERR_RESOURCE 10018
+#define NFSERR_MOVED 10019
+#define NFSERR_NOFILEHANDLE 10020
+#define NFSERR_MINORVERMISMATCH 10021
+#define NFSERR_STALECLIENTID 10022
+#define NFSERR_STALESTATEID 10023
+#define NFSERR_OLDSTATEID 10024
+#define NFSERR_BADSTATEID 10025
+#define NFSERR_BADSEQID 10026
+#define NFSERR_NOTSAME 10027
+#define NFSERR_LOCKRANGE 10028
+#define NFSERR_SYMLINK 10029
+#define NFSERR_RESTOREFH 10030
+#define NFSERR_LEASEMOVED 10031
+#define NFSERR_ATTRNOTSUPP 10032
+#define NFSERR_NOGRACE 10033
+#define NFSERR_RECLAIMBAD 10034
+#define NFSERR_RECLAIMCONFLICT 10035
+#define NFSERR_BADXDR 10036
+#define NFSERR_LOCKSHELD 10037
+#define NFSERR_OPENMODE 10038
+#define NFSERR_BADOWNER 10039
+#define NFSERR_BADCHAR 10040
+#define NFSERR_BADNAME 10041
+#define NFSERR_BADRANGE 10042
+#define NFSERR_LOCKNOTSUPP 10043
+#define NFSERR_OPILLEGAL 10044
+#define NFSERR_DEADLOCK 10045
+#define NFSERR_FILEOPEN 10046
+#define NFSERR_ADMINREVOKED 10047
+#define NFSERR_CBPATHDOWN 10048
+
+#define NFSERR_STALEWRITEVERF 30001 /* Fake return for nfs_commit() */
+#define NFSERR_DONTREPLY 30003 /* Don't process request */
+#define NFSERR_RETVOID 30004 /* Return void, not error */
+#define NFSERR_REPLYFROMCACHE 30005 /* Reply from recent request cache */
+#define NFSERR_STALEDONTRECOVER 30006 /* Don't initiate recovery */
+
+#define NFSERR_RPCERR 0x40000000 /* Mark an RPC layer error */
+#define NFSERR_AUTHERR 0x80000000 /* Mark an authentication error */
+
+#define NFSERR_RPCMISMATCH (NFSERR_RPCERR | RPC_MISMATCH)
+#define NFSERR_PROGUNAVAIL (NFSERR_RPCERR | RPC_PROGUNAVAIL)
+#define NFSERR_PROGMISMATCH (NFSERR_RPCERR | RPC_PROGMISMATCH)
+#define NFSERR_PROGNOTV4 (NFSERR_RPCERR | 0xffff)
+#define NFSERR_PROCUNAVAIL (NFSERR_RPCERR | RPC_PROCUNAVAIL)
+#define NFSERR_GARBAGE (NFSERR_RPCERR | RPC_GARBAGE)
+
+/* Sizes in bytes of various nfs rpc components */
+#define NFSX_UNSIGNED 4
+#define NFSX_HYPER (2 * NFSX_UNSIGNED)
+
+/* specific to NFS Version 2 */
+#define NFSX_V2FH 32
+#define NFSX_V2FATTR 68
+#define NFSX_V2SATTR 32
+#define NFSX_V2COOKIE 4
+#define NFSX_V2STATFS 20
+
+/* specific to NFS Version 3 */
+#define NFSX_V3FHMAX 64 /* max. allowed by protocol */
+#define NFSX_V3FATTR 84
+#define NFSX_V3SATTR 60 /* max. all fields filled in */
+#define NFSX_V3SRVSATTR (sizeof (struct nfsv3_sattr))
+#define NFSX_V3POSTOPATTR (NFSX_V3FATTR + NFSX_UNSIGNED)
+#define NFSX_V3WCCDATA (NFSX_V3POSTOPATTR + 8 * NFSX_UNSIGNED)
+#define NFSX_V3STATFS 52
+#define NFSX_V3FSINFO 48
+#define NFSX_V3PATHCONF 24
+
+/* specific to NFS Version 4 */
+#define NFSX_V4FHMAX 128
+#define NFSX_V4FSID (2 * NFSX_HYPER)
+#define NFSX_V4SPECDATA (2 * NFSX_UNSIGNED)
+#define NFSX_V4TIME (NFSX_HYPER + NFSX_UNSIGNED)
+#define NFSX_V4SETTIME (NFSX_UNSIGNED + NFSX_V4TIME)
+
+/* sizes common to multiple NFS versions */
+#define NFSX_FHMAX (NFSX_V4FHMAX)
+#define NFSX_MYFH (sizeof (fhandle_t)) /* size this server uses */
+#define NFSX_VERF 8
+#define NFSX_STATEIDOTHER 12
+#define NFSX_STATEID (NFSX_UNSIGNED + NFSX_STATEIDOTHER)
+#define NFSX_GSSH 12
+
+/* variants for multiple versions */
+#define NFSX_STATFS(v3) ((v3) ? NFSX_V3STATFS : NFSX_V2STATFS)
+
+/* nfs rpc procedure numbers (before version mapping) */
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_LOOKUP 3
+#define NFSPROC_ACCESS 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITE 7
+#define NFSPROC_CREATE 8
+#define NFSPROC_MKDIR 9
+#define NFSPROC_SYMLINK 10
+#define NFSPROC_MKNOD 11
+#define NFSPROC_REMOVE 12
+#define NFSPROC_RMDIR 13
+#define NFSPROC_RENAME 14
+#define NFSPROC_LINK 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_READDIRPLUS 17
+#define NFSPROC_FSSTAT 18
+#define NFSPROC_FSINFO 19
+#define NFSPROC_PATHCONF 20
+#define NFSPROC_COMMIT 21
+
+/*
+ * These cover all the procedures for V2 and 3. The higher numbers are
+ * used to reference other V4 ops.
+ * NFS_V3NPROCS is one greater than the last V3 op and NFS_NPROCS is
+ * one greater than the last number.
+ */
+#define NFS_V3NPROCS 22
+
+#define NFSPROC_LOOKUPP 22
+#define NFSPROC_SETCLIENTID 23
+#define NFSPROC_SETCLIENTIDCFRM 24
+#define NFSPROC_LOCK 25
+#define NFSPROC_LOCKU 26
+#define NFSPROC_OPEN 27
+#define NFSPROC_CLOSE 28
+#define NFSPROC_OPENCONFIRM 29
+#define NFSPROC_LOCKT 30
+#define NFSPROC_OPENDOWNGRADE 31
+#define NFSPROC_RENEW 32
+#define NFSPROC_PUTROOTFH 33
+#define NFSPROC_RELEASELCKOWN 34
+#define NFSPROC_DELEGRETURN 35
+#define NFSPROC_RETDELEGREMOVE 36
+#define NFSPROC_RETDELEGRENAME1 37
+#define NFSPROC_RETDELEGRENAME2 38
+#define NFSPROC_GETACL 39
+#define NFSPROC_SETACL 40
+
+#define NFS_NPROCS 41
+
+/*
+ * NFSPROC_NOOP is a fake op# that can't be the same as any V2/3/4 Procedure
+ * or Operation#. Since the NFS V4 Op #s go higher, use NFSV4OP_NOPS, which
+ * is one greater than the highest Op#.
+ */
+#define NFSPROC_NOOP NFSV4OP_NOPS
+
+/* Actual Version 2 procedure numbers */
+#define NFSV2PROC_NULL 0
+#define NFSV2PROC_GETATTR 1
+#define NFSV2PROC_SETATTR 2
+#define NFSV2PROC_NOOP 3
+#define NFSV2PROC_ROOT NFSV2PROC_NOOP /* Obsolete */
+#define NFSV2PROC_LOOKUP 4
+#define NFSV2PROC_READLINK 5
+#define NFSV2PROC_READ 6
+#define NFSV2PROC_WRITECACHE NFSV2PROC_NOOP /* Obsolete */
+#define NFSV2PROC_WRITE 8
+#define NFSV2PROC_CREATE 9
+#define NFSV2PROC_REMOVE 10
+#define NFSV2PROC_RENAME 11
+#define NFSV2PROC_LINK 12
+#define NFSV2PROC_SYMLINK 13
+#define NFSV2PROC_MKDIR 14
+#define NFSV2PROC_RMDIR 15
+#define NFSV2PROC_READDIR 16
+#define NFSV2PROC_STATFS 17
+
+/*
+ * V4 Procedure and suboperation numbers
+ */
+#define NFSV4PROC_COMPOUND 1
+#define NFSV4PROC_CBNULL 0
+#define NFSV4PROC_CBCOMPOUND 1
+
+#define NFSV4OP_ACCESS 3
+#define NFSV4OP_CLOSE 4
+#define NFSV4OP_COMMIT 5
+#define NFSV4OP_CREATE 6
+#define NFSV4OP_DELEGPURGE 7
+#define NFSV4OP_DELEGRETURN 8
+#define NFSV4OP_GETATTR 9
+#define NFSV4OP_GETFH 10
+#define NFSV4OP_LINK 11
+#define NFSV4OP_LOCK 12
+#define NFSV4OP_LOCKT 13
+#define NFSV4OP_LOCKU 14
+#define NFSV4OP_LOOKUP 15
+#define NFSV4OP_LOOKUPP 16
+#define NFSV4OP_NVERIFY 17
+#define NFSV4OP_OPEN 18
+#define NFSV4OP_OPENATTR 19
+#define NFSV4OP_OPENCONFIRM 20
+#define NFSV4OP_OPENDOWNGRADE 21
+#define NFSV4OP_PUTFH 22
+#define NFSV4OP_PUTPUBFH 23
+#define NFSV4OP_PUTROOTFH 24
+#define NFSV4OP_READ 25
+#define NFSV4OP_READDIR 26
+#define NFSV4OP_READLINK 27
+#define NFSV4OP_REMOVE 28
+#define NFSV4OP_RENAME 29
+#define NFSV4OP_RENEW 30
+#define NFSV4OP_RESTOREFH 31
+#define NFSV4OP_SAVEFH 32
+#define NFSV4OP_SECINFO 33
+#define NFSV4OP_SETATTR 34
+#define NFSV4OP_SETCLIENTID 35
+#define NFSV4OP_SETCLIENTIDCFRM 36
+#define NFSV4OP_VERIFY 37
+#define NFSV4OP_WRITE 38
+#define NFSV4OP_RELEASELCKOWN 39
+
+/*
+ * and the Callback OPs
+ */
+#define NFSV4OP_CBGETATTR 3
+#define NFSV4OP_CBRECALL 4
+
+/*
+ * NFSV4OP_NOPS is one greater than the largest V4 Op#. (Used for sizing
+ * arrays, etc.)
+ */
+#define NFSV4OP_NOPS 40
+#define NFSV4OP_CBNOPS 5
+
+/*
+ * Fake NFSV4OP_xxx used for nfsstat. Start at NFSV4OP_NOPS.
+ */
+#define NFSV4OP_SYMLINK (NFSV4OP_NOPS)
+#define NFSV4OP_MKDIR (NFSV4OP_NOPS + 1)
+#define NFSV4OP_RMDIR (NFSV4OP_NOPS + 2)
+#define NFSV4OP_READDIRPLUS (NFSV4OP_NOPS + 3)
+#define NFSV4OP_MKNOD (NFSV4OP_NOPS + 4)
+#define NFSV4OP_FSSTAT (NFSV4OP_NOPS + 5)
+#define NFSV4OP_FSINFO (NFSV4OP_NOPS + 6)
+#define NFSV4OP_PATHCONF (NFSV4OP_NOPS + 7)
+#define NFSV4OP_V3CREATE (NFSV4OP_NOPS + 8)
+
+#define NFSV4OP_FAKENOPS 9
+
+/*
+ * Constants used by the Version 3 and 4 protocols for various RPCs
+ */
+#define NFSV3SATTRTIME_DONTCHANGE 0
+#define NFSV3SATTRTIME_TOSERVER 1
+#define NFSV3SATTRTIME_TOCLIENT 2
+
+#define NFSV4SATTRTIME_TOSERVER 0
+#define NFSV4SATTRTIME_TOCLIENT 1
+
+#define NFSV4LOCKT_READ 1
+#define NFSV4LOCKT_WRITE 2
+#define NFSV4LOCKT_READW 3
+#define NFSV4LOCKT_WRITEW 4
+#define NFSV4LOCKT_RELEASE 5
+
+#define NFSV4OPEN_NOCREATE 0
+#define NFSV4OPEN_CREATE 1
+#define NFSV4OPEN_CLAIMNULL 0
+#define NFSV4OPEN_CLAIMPREVIOUS 1
+#define NFSV4OPEN_CLAIMDELEGATECUR 2
+#define NFSV4OPEN_CLAIMDELEGATEPREV 3
+#define NFSV4OPEN_DELEGATENONE 0
+#define NFSV4OPEN_DELEGATEREAD 1
+#define NFSV4OPEN_DELEGATEWRITE 2
+#define NFSV4OPEN_LIMITSIZE 1
+#define NFSV4OPEN_LIMITBLOCKS 2
+
+/*
+ * Nfs V4 ACE stuff
+ */
+#define NFSV4ACE_ALLOWEDTYPE 0x00000000
+#define NFSV4ACE_DENIEDTYPE 0x00000001
+#define NFSV4ACE_AUDITTYPE 0x00000002
+#define NFSV4ACE_ALARMTYPE 0x00000003
+
+#define NFSV4ACE_SUPALLOWED 0x00000001
+#define NFSV4ACE_SUPDENIED 0x00000002
+#define NFSV4ACE_SUPAUDIT 0x00000004
+#define NFSV4ACE_SUPALARM 0x00000008
+
+#define NFSV4ACE_SUPTYPES (NFSV4ACE_SUPALLOWED | NFSV4ACE_SUPDENIED)
+
+#define NFSV4ACE_FILEINHERIT 0x00000001
+#define NFSV4ACE_DIRECTORYINHERIT 0x00000002
+#define NFSV4ACE_NOPROPAGATEINHERIT 0x00000004
+#define NFSV4ACE_INHERITONLY 0x00000008
+#define NFSV4ACE_SUCCESSFULACCESS 0x00000010
+#define NFSV4ACE_FAILEDACCESS 0x00000020
+#define NFSV4ACE_IDENTIFIERGROUP 0x00000040
+
+#define NFSV4ACE_READDATA 0x00000001
+#define NFSV4ACE_LISTDIRECTORY 0x00000001
+#define NFSV4ACE_WRITEDATA 0x00000002
+#define NFSV4ACE_ADDFILE 0x00000002
+#define NFSV4ACE_APPENDDATA 0x00000004
+#define NFSV4ACE_ADDSUBDIRECTORY 0x00000004
+#define NFSV4ACE_READNAMEDATTR 0x00000008
+#define NFSV4ACE_WRITENAMEDATTR 0x00000010
+#define NFSV4ACE_EXECUTE 0x00000020
+#define NFSV4ACE_SEARCH 0x00000020
+#define NFSV4ACE_DELETECHILD 0x00000040
+#define NFSV4ACE_READATTRIBUTES 0x00000080
+#define NFSV4ACE_WRITEATTRIBUTES 0x00000100
+#define NFSV4ACE_DELETE 0x00010000
+#define NFSV4ACE_READACL 0x00020000
+#define NFSV4ACE_WRITEACL 0x00040000
+#define NFSV4ACE_WRITEOWNER 0x00080000
+#define NFSV4ACE_SYNCHRONIZE 0x00100000
+
+/*
+ * Here are the mappings between mode bits and acl mask bits for
+ * directories and other files.
+ * (Named attributes have not been included, since named attributes are
+ * not yet supported.)
+ * The mailing list seems to indicate that NFSV4ACE_EXECUTE refers to
+ * searching a directory, although I can't find a statement of that in
+ * the RFC.
+ */
+#define NFSV4ACE_ALLFILESMASK (NFSV4ACE_READATTRIBUTES | NFSV4ACE_READACL)
+#define NFSV4ACE_OWNERMASK (NFSV4ACE_WRITEATTRIBUTES | NFSV4ACE_WRITEACL)
+#define NFSV4ACE_DIRREADMASK NFSV4ACE_LISTDIRECTORY
+#define NFSV4ACE_DIREXECUTEMASK NFSV4ACE_EXECUTE
+#define NFSV4ACE_DIRWRITEMASK (NFSV4ACE_ADDFILE | \
+ NFSV4ACE_ADDSUBDIRECTORY | NFSV4ACE_DELETECHILD)
+#define NFSV4ACE_READMASK NFSV4ACE_READDATA
+#define NFSV4ACE_WRITEMASK (NFSV4ACE_WRITEDATA | NFSV4ACE_APPENDDATA)
+#define NFSV4ACE_EXECUTEMASK NFSV4ACE_EXECUTE
+#define NFSV4ACE_ALLFILEBITS (NFSV4ACE_READMASK | NFSV4ACE_WRITEMASK | \
+ NFSV4ACE_EXECUTEMASK | NFSV4ACE_SYNCHRONIZE)
+#define NFSV4ACE_ALLDIRBITS (NFSV4ACE_DIRREADMASK | \
+ NFSV4ACE_DIRWRITEMASK | NFSV4ACE_DIREXECUTEMASK)
+#define NFSV4ACE_AUDITMASK 0x0
+
+/*
+ * These GENERIC masks are not used and are no longer believed to be useful.
+ */
+#define NFSV4ACE_GENERICREAD 0x00120081
+#define NFSV4ACE_GENERICWRITE 0x00160106
+#define NFSV4ACE_GENERICEXECUTE 0x001200a0
+
+#define NFSSTATEID_PUTALLZERO 0
+#define NFSSTATEID_PUTALLONE 1
+#define NFSSTATEID_PUTSTATEID 2
+
+/*
+ * Bits for share access and deny.
+ */
+#define NFSV4OPEN_ACCESSREAD 0x00000001
+#define NFSV4OPEN_ACCESSWRITE 0x00000002
+#define NFSV4OPEN_ACCESSBOTH 0x00000003
+
+#define NFSV4OPEN_DENYNONE 0x00000000
+#define NFSV4OPEN_DENYREAD 0x00000001
+#define NFSV4OPEN_DENYWRITE 0x00000002
+#define NFSV4OPEN_DENYBOTH 0x00000003
+
+/*
+ * Open result flags
+ * (The first two are in the spec. The rest are used internally.)
+ */
+#define NFSV4OPEN_RESULTCONFIRM 0x00000002
+#define NFSV4OPEN_LOCKTYPEPOSIX 0x00000004
+#define NFSV4OPEN_RFLAGS \
+ (NFSV4OPEN_RESULTCONFIRM | NFSV4OPEN_LOCKTYPEPOSIX)
+#define NFSV4OPEN_RECALL 0x00010000
+#define NFSV4OPEN_READDELEGATE 0x00020000
+#define NFSV4OPEN_WRITEDELEGATE 0x00040000
+
+/*
+ * NFS V4 File Handle types
+ */
+#define NFSV4FHTYPE_PERSISTENT 0x0
+#define NFSV4FHTYPE_NOEXPIREWITHOPEN 0x1
+#define NFSV4FHTYPE_VOLATILEANY 0x2
+#define NFSV4FHTYPE_VOLATILEMIGRATE 0x4
+#define NFSV4FHTYPE_VOLATILERENAME 0x8
+
+/*
+ * Maximum size of V4 opaque strings.
+ */
+#define NFSV4_OPAQUELIMIT 1024
+
+/*
+ * These are the same for V3 and V4.
+ */
+#define NFSACCESS_READ 0x01
+#define NFSACCESS_LOOKUP 0x02
+#define NFSACCESS_MODIFY 0x04
+#define NFSACCESS_EXTEND 0x08
+#define NFSACCESS_DELETE 0x10
+#define NFSACCESS_EXECUTE 0x20
+
+#define NFSWRITE_UNSTABLE 0
+#define NFSWRITE_DATASYNC 1
+#define NFSWRITE_FILESYNC 2
+
+#define NFSCREATE_UNCHECKED 0
+#define NFSCREATE_GUARDED 1
+#define NFSCREATE_EXCLUSIVE 2
+
+#define NFSV3FSINFO_LINK 0x01
+#define NFSV3FSINFO_SYMLINK 0x02
+#define NFSV3FSINFO_HOMOGENEOUS 0x08
+#define NFSV3FSINFO_CANSETTIME 0x10
+
+/* Conversion macros */
+#define vtonfsv2_mode(t,m) \
+ txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \
+ MAKEIMODE((t), (m)))
+#define vtonfsv34_mode(m) txdr_unsigned((m) & 07777)
+#define nfstov_mode(a) (fxdr_unsigned(u_int16_t, (a))&07777)
+#define vtonfsv2_type(a) (((u_int32_t)(a)) >= 9 ? txdr_unsigned(NFNON) : \
+ txdr_unsigned(newnfsv2_type[((u_int32_t)(a))]))
+#define vtonfsv34_type(a) (((u_int32_t)(a)) >= 9 ? txdr_unsigned(NFNON) : \
+ txdr_unsigned(nfsv34_type[((u_int32_t)(a))]))
+#define nfsv2tov_type(a) newnv2tov_type[fxdr_unsigned(u_int32_t,(a))&0x7]
+#define nfsv34tov_type(a) nv34tov_type[fxdr_unsigned(u_int32_t,(a))&0x7]
+#define vtonfs_dtype(a) (((u_int32_t)(a)) >= 9 ? IFTODT(VTTOIF(VNON)) : \
+ IFTODT(VTTOIF(a)))
+
+/* File types */
+typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5,
+ NFSOCK=6, NFFIFO=7, NFATTRDIR=8, NFNAMEDATTR=9 } nfstype;
+
+/* Structs for common parts of the rpc's */
+
+struct nfsv2_time {
+ u_int32_t nfsv2_sec;
+ u_int32_t nfsv2_usec;
+};
+typedef struct nfsv2_time nfstime2;
+
+struct nfsv3_time {
+ u_int32_t nfsv3_sec;
+ u_int32_t nfsv3_nsec;
+};
+typedef struct nfsv3_time nfstime3;
+
+struct nfsv4_time {
+ u_int32_t nfsv4_highsec;
+ u_int32_t nfsv4_sec;
+ u_int32_t nfsv4_nsec;
+};
+typedef struct nfsv4_time nfstime4;
+
+/*
+ * Quads are defined as arrays of 2 longs to ensure dense packing for the
+ * protocol and to facilitate xdr conversion.
+ */
+struct nfs_uquad {
+ u_int32_t nfsuquad[2];
+};
+typedef struct nfs_uquad nfsuint64;
+
+/*
+ * Used to convert between two u_longs and a u_quad_t.
+ */
+union nfs_quadconvert {
+ u_int32_t lval[2];
+ u_quad_t qval;
+};
+typedef union nfs_quadconvert nfsquad_t;
+
+/*
+ * NFS Version 3 special file number.
+ */
+struct nfsv3_spec {
+ u_int32_t specdata1;
+ u_int32_t specdata2;
+};
+typedef struct nfsv3_spec nfsv3spec;
+
+/*
+ * File attributes and setable attributes. These structures cover both
+ * NFS version 2 and the version 3 protocol. Note that the union is only
+ * used so that one pointer can refer to both variants. These structures
+ * go out on the wire and must be densely packed, so no quad data types
+ * are used. (all fields are longs or u_longs or structures of same)
+ * NB: You can't do sizeof(struct nfs_fattr), you must use the
+ * NFSX_FATTR(v3) macro.
+ */
+struct nfs_fattr {
+ u_int32_t fa_type;
+ u_int32_t fa_mode;
+ u_int32_t fa_nlink;
+ u_int32_t fa_uid;
+ u_int32_t fa_gid;
+ union {
+ struct {
+ u_int32_t nfsv2fa_size;
+ u_int32_t nfsv2fa_blocksize;
+ u_int32_t nfsv2fa_rdev;
+ u_int32_t nfsv2fa_blocks;
+ u_int32_t nfsv2fa_fsid;
+ u_int32_t nfsv2fa_fileid;
+ nfstime2 nfsv2fa_atime;
+ nfstime2 nfsv2fa_mtime;
+ nfstime2 nfsv2fa_ctime;
+ } fa_nfsv2;
+ struct {
+ nfsuint64 nfsv3fa_size;
+ nfsuint64 nfsv3fa_used;
+ nfsv3spec nfsv3fa_rdev;
+ nfsuint64 nfsv3fa_fsid;
+ nfsuint64 nfsv3fa_fileid;
+ nfstime3 nfsv3fa_atime;
+ nfstime3 nfsv3fa_mtime;
+ nfstime3 nfsv3fa_ctime;
+ } fa_nfsv3;
+ } fa_un;
+};
+
+/* and some ugly defines for accessing union components */
+#define fa2_size fa_un.fa_nfsv2.nfsv2fa_size
+#define fa2_blocksize fa_un.fa_nfsv2.nfsv2fa_blocksize
+#define fa2_rdev fa_un.fa_nfsv2.nfsv2fa_rdev
+#define fa2_blocks fa_un.fa_nfsv2.nfsv2fa_blocks
+#define fa2_fsid fa_un.fa_nfsv2.nfsv2fa_fsid
+#define fa2_fileid fa_un.fa_nfsv2.nfsv2fa_fileid
+#define fa2_atime fa_un.fa_nfsv2.nfsv2fa_atime
+#define fa2_mtime fa_un.fa_nfsv2.nfsv2fa_mtime
+#define fa2_ctime fa_un.fa_nfsv2.nfsv2fa_ctime
+#define fa3_size fa_un.fa_nfsv3.nfsv3fa_size
+#define fa3_used fa_un.fa_nfsv3.nfsv3fa_used
+#define fa3_rdev fa_un.fa_nfsv3.nfsv3fa_rdev
+#define fa3_fsid fa_un.fa_nfsv3.nfsv3fa_fsid
+#define fa3_fileid fa_un.fa_nfsv3.nfsv3fa_fileid
+#define fa3_atime fa_un.fa_nfsv3.nfsv3fa_atime
+#define fa3_mtime fa_un.fa_nfsv3.nfsv3fa_mtime
+#define fa3_ctime fa_un.fa_nfsv3.nfsv3fa_ctime
+
+struct nfsv2_sattr {
+ u_int32_t sa_mode;
+ u_int32_t sa_uid;
+ u_int32_t sa_gid;
+ u_int32_t sa_size;
+ nfstime2 sa_atime;
+ nfstime2 sa_mtime;
+};
+
+/*
+ * NFS Version 3 sattr structure for the new node creation case.
+ */
+struct nfsv3_sattr {
+ u_int32_t sa_modetrue;
+ u_int32_t sa_mode;
+ u_int32_t sa_uidfalse;
+ u_int32_t sa_gidfalse;
+ u_int32_t sa_sizefalse;
+ u_int32_t sa_atimetype;
+ nfstime3 sa_atime;
+ u_int32_t sa_mtimetype;
+ nfstime3 sa_mtime;
+};
+
+/*
+ * The attribute bits used for V4.
+ * NFSATTRBIT_xxx defines the attribute# (and its bit position)
+ * NFSATTRBM_xxx is a 32bit mask with the correct bit set within the
+ * appropriate 32bit word.
+ * NFSATTRBIT_MAX is one greater than the largest NFSATTRBIT_xxx
+ */
+#define NFSATTRBIT_SUPPORTEDATTRS 0
+#define NFSATTRBIT_TYPE 1
+#define NFSATTRBIT_FHEXPIRETYPE 2
+#define NFSATTRBIT_CHANGE 3
+#define NFSATTRBIT_SIZE 4
+#define NFSATTRBIT_LINKSUPPORT 5
+#define NFSATTRBIT_SYMLINKSUPPORT 6
+#define NFSATTRBIT_NAMEDATTR 7
+#define NFSATTRBIT_FSID 8
+#define NFSATTRBIT_UNIQUEHANDLES 9
+#define NFSATTRBIT_LEASETIME 10
+#define NFSATTRBIT_RDATTRERROR 11
+#define NFSATTRBIT_ACL 12
+#define NFSATTRBIT_ACLSUPPORT 13
+#define NFSATTRBIT_ARCHIVE 14
+#define NFSATTRBIT_CANSETTIME 15
+#define NFSATTRBIT_CASEINSENSITIVE 16
+#define NFSATTRBIT_CASEPRESERVING 17
+#define NFSATTRBIT_CHOWNRESTRICTED 18
+#define NFSATTRBIT_FILEHANDLE 19
+#define NFSATTRBIT_FILEID 20
+#define NFSATTRBIT_FILESAVAIL 21
+#define NFSATTRBIT_FILESFREE 22
+#define NFSATTRBIT_FILESTOTAL 23
+#define NFSATTRBIT_FSLOCATIONS 24
+#define NFSATTRBIT_HIDDEN 25
+#define NFSATTRBIT_HOMOGENEOUS 26
+#define NFSATTRBIT_MAXFILESIZE 27
+#define NFSATTRBIT_MAXLINK 28
+#define NFSATTRBIT_MAXNAME 29
+#define NFSATTRBIT_MAXREAD 30
+#define NFSATTRBIT_MAXWRITE 31
+#define NFSATTRBIT_MIMETYPE 32
+#define NFSATTRBIT_MODE 33
+#define NFSATTRBIT_NOTRUNC 34
+#define NFSATTRBIT_NUMLINKS 35
+#define NFSATTRBIT_OWNER 36
+#define NFSATTRBIT_OWNERGROUP 37
+#define NFSATTRBIT_QUOTAHARD 38
+#define NFSATTRBIT_QUOTASOFT 39
+#define NFSATTRBIT_QUOTAUSED 40
+#define NFSATTRBIT_RAWDEV 41
+#define NFSATTRBIT_SPACEAVAIL 42
+#define NFSATTRBIT_SPACEFREE 43
+#define NFSATTRBIT_SPACETOTAL 44
+#define NFSATTRBIT_SPACEUSED 45
+#define NFSATTRBIT_SYSTEM 46
+#define NFSATTRBIT_TIMEACCESS 47
+#define NFSATTRBIT_TIMEACCESSSET 48
+#define NFSATTRBIT_TIMEBACKUP 49
+#define NFSATTRBIT_TIMECREATE 50
+#define NFSATTRBIT_TIMEDELTA 51
+#define NFSATTRBIT_TIMEMETADATA 52
+#define NFSATTRBIT_TIMEMODIFY 53
+#define NFSATTRBIT_TIMEMODIFYSET 54
+#define NFSATTRBIT_MOUNTEDONFILEID 55
+
+#define NFSATTRBM_SUPPORTEDATTRS 0x00000001
+#define NFSATTRBM_TYPE 0x00000002
+#define NFSATTRBM_FHEXPIRETYPE 0x00000004
+#define NFSATTRBM_CHANGE 0x00000008
+#define NFSATTRBM_SIZE 0x00000010
+#define NFSATTRBM_LINKSUPPORT 0x00000020
+#define NFSATTRBM_SYMLINKSUPPORT 0x00000040
+#define NFSATTRBM_NAMEDATTR 0x00000080
+#define NFSATTRBM_FSID 0x00000100
+#define NFSATTRBM_UNIQUEHANDLES 0x00000200
+#define NFSATTRBM_LEASETIME 0x00000400
+#define NFSATTRBM_RDATTRERROR 0x00000800
+#define NFSATTRBM_ACL 0x00001000
+#define NFSATTRBM_ACLSUPPORT 0x00002000
+#define NFSATTRBM_ARCHIVE 0x00004000
+#define NFSATTRBM_CANSETTIME 0x00008000
+#define NFSATTRBM_CASEINSENSITIVE 0x00010000
+#define NFSATTRBM_CASEPRESERVING 0x00020000
+#define NFSATTRBM_CHOWNRESTRICTED 0x00040000
+#define NFSATTRBM_FILEHANDLE 0x00080000
+#define NFSATTRBM_FILEID 0x00100000
+#define NFSATTRBM_FILESAVAIL 0x00200000
+#define NFSATTRBM_FILESFREE 0x00400000
+#define NFSATTRBM_FILESTOTAL 0x00800000
+#define NFSATTRBM_FSLOCATIONS 0x01000000
+#define NFSATTRBM_HIDDEN 0x02000000
+#define NFSATTRBM_HOMOGENEOUS 0x04000000
+#define NFSATTRBM_MAXFILESIZE 0x08000000
+#define NFSATTRBM_MAXLINK 0x10000000
+#define NFSATTRBM_MAXNAME 0x20000000
+#define NFSATTRBM_MAXREAD 0x40000000
+#define NFSATTRBM_MAXWRITE 0x80000000
+#define NFSATTRBM_MIMETYPE 0x00000001
+#define NFSATTRBM_MODE 0x00000002
+#define NFSATTRBM_NOTRUNC 0x00000004
+#define NFSATTRBM_NUMLINKS 0x00000008
+#define NFSATTRBM_OWNER 0x00000010
+#define NFSATTRBM_OWNERGROUP 0x00000020
+#define NFSATTRBM_QUOTAHARD 0x00000040
+#define NFSATTRBM_QUOTASOFT 0x00000080
+#define NFSATTRBM_QUOTAUSED 0x00000100
+#define NFSATTRBM_RAWDEV 0x00000200
+#define NFSATTRBM_SPACEAVAIL 0x00000400
+#define NFSATTRBM_SPACEFREE 0x00000800
+#define NFSATTRBM_SPACETOTAL 0x00001000
+#define NFSATTRBM_SPACEUSED 0x00002000
+#define NFSATTRBM_SYSTEM 0x00004000
+#define NFSATTRBM_TIMEACCESS 0x00008000
+#define NFSATTRBM_TIMEACCESSSET 0x00010000
+#define NFSATTRBM_TIMEBACKUP 0x00020000
+#define NFSATTRBM_TIMECREATE 0x00040000
+#define NFSATTRBM_TIMEDELTA 0x00080000
+#define NFSATTRBM_TIMEMETADATA 0x00100000
+#define NFSATTRBM_TIMEMODIFY 0x00200000
+#define NFSATTRBM_TIMEMODIFYSET 0x00400000
+#define NFSATTRBM_MOUNTEDONFILEID 0x00800000
+
+#define NFSATTRBIT_MAX 56
+
+/*
+ * Sets of attributes that are supported, by words in the bitmap.
+ */
+/*
+ * NFSATTRBIT_SUPPORTED - SUPP0 - bits 0<->31
+ * SUPP1 - bits 32<->63
+ */
+#define NFSATTRBIT_SUPP0 \
+ (NFSATTRBM_SUPPORTEDATTRS | \
+ NFSATTRBM_TYPE | \
+ NFSATTRBM_FHEXPIRETYPE | \
+ NFSATTRBM_CHANGE | \
+ NFSATTRBM_SIZE | \
+ NFSATTRBM_LINKSUPPORT | \
+ NFSATTRBM_SYMLINKSUPPORT | \
+ NFSATTRBM_NAMEDATTR | \
+ NFSATTRBM_FSID | \
+ NFSATTRBM_UNIQUEHANDLES | \
+ NFSATTRBM_LEASETIME | \
+ NFSATTRBM_RDATTRERROR | \
+ NFSATTRBM_ACL | \
+ NFSATTRBM_ACLSUPPORT | \
+ NFSATTRBM_CANSETTIME | \
+ NFSATTRBM_CASEINSENSITIVE | \
+ NFSATTRBM_CASEPRESERVING | \
+ NFSATTRBM_CHOWNRESTRICTED | \
+ NFSATTRBM_FILEHANDLE | \
+ NFSATTRBM_FILEID | \
+ NFSATTRBM_FILESAVAIL | \
+ NFSATTRBM_FILESFREE | \
+ NFSATTRBM_FILESTOTAL | \
+ NFSATTRBM_FSLOCATIONS | \
+ NFSATTRBM_HOMOGENEOUS | \
+ NFSATTRBM_MAXFILESIZE | \
+ NFSATTRBM_MAXLINK | \
+ NFSATTRBM_MAXNAME | \
+ NFSATTRBM_MAXREAD | \
+ NFSATTRBM_MAXWRITE)
+
+/*
+ * NFSATTRBIT_S1 - subset of SUPP1 - OR of the following bits:
+ */
+#define NFSATTRBIT_S1 \
+ (NFSATTRBM_MODE | \
+ NFSATTRBM_NOTRUNC | \
+ NFSATTRBM_NUMLINKS | \
+ NFSATTRBM_OWNER | \
+ NFSATTRBM_OWNERGROUP | \
+ NFSATTRBM_RAWDEV | \
+ NFSATTRBM_SPACEAVAIL | \
+ NFSATTRBM_SPACEFREE | \
+ NFSATTRBM_SPACETOTAL | \
+ NFSATTRBM_SPACEUSED | \
+ NFSATTRBM_TIMEACCESS | \
+ NFSATTRBM_TIMEDELTA | \
+ NFSATTRBM_TIMEMETADATA | \
+ NFSATTRBM_TIMEMODIFY | \
+ NFSATTRBM_MOUNTEDONFILEID)
+
+#ifdef QUOTA
+/*
+ * If QUOTA OR in NFSATTRBIT_QUOTAHARD, NFSATTRBIT_QUOTASOFT and
+ * NFSATTRBIT_QUOTAUSED.
+ */
+#define NFSATTRBIT_SUPP1 (NFSATTRBIT_S1 | \
+ NFSATTRBM_QUOTAHARD | \
+ NFSATTRBM_QUOTASOFT | \
+ NFSATTRBM_QUOTAUSED)
+#else
+#define NFSATTRBIT_SUPP1 NFSATTRBIT_S1
+#endif
+
+/*
+ * NFSATTRBIT_SUPPSETONLY is the OR of NFSATTRBIT_TIMEACCESSSET and
+ * NFSATTRBIT_TIMEMODIFYSET.
+ */
+#define NFSATTRBIT_SUPPSETONLY (NFSATTRBM_TIMEACCESSSET | \
+ NFSATTRBM_TIMEMODIFYSET)
+
+/*
+ * NFSATTRBIT_SETABLE - SETABLE0 - bits 0<->31
+ * SETABLE1 - bits 32<->63
+ */
+#define NFSATTRBIT_SETABLE0 \
+ (NFSATTRBM_SIZE | \
+ NFSATTRBM_ACL)
+#define NFSATTRBIT_SETABLE1 \
+ (NFSATTRBM_MODE | \
+ NFSATTRBM_OWNER | \
+ NFSATTRBM_OWNERGROUP | \
+ NFSATTRBM_TIMEACCESSSET | \
+ NFSATTRBM_TIMEMODIFYSET)
+
+/*
+ * Set of attributes that the getattr vnode op needs.
+ * OR of the following bits.
+ * NFSATTRBIT_GETATTR0 - bits 0<->31
+ */
+#define NFSATTRBIT_GETATTR0 \
+ (NFSATTRBM_SUPPORTEDATTRS | \
+ NFSATTRBM_TYPE | \
+ NFSATTRBM_CHANGE | \
+ NFSATTRBM_SIZE | \
+ NFSATTRBM_FSID | \
+ NFSATTRBM_FILEID | \
+ NFSATTRBM_MAXREAD)
+
+/*
+ * NFSATTRBIT_GETATTR1 - bits 32<->63
+ */
+#define NFSATTRBIT_GETATTR1 \
+ (NFSATTRBM_MODE | \
+ NFSATTRBM_NUMLINKS | \
+ NFSATTRBM_OWNER | \
+ NFSATTRBM_OWNERGROUP | \
+ NFSATTRBM_RAWDEV | \
+ NFSATTRBM_SPACEUSED | \
+ NFSATTRBM_TIMEACCESS | \
+ NFSATTRBM_TIMEMETADATA | \
+ NFSATTRBM_TIMEMODIFY)
+
+/*
+ * Subset of the above that the Write RPC gets.
+ * OR of the following bits.
+ * NFSATTRBIT_WRITEGETATTR0 - bits 0<->31
+ */
+#define NFSATTRBIT_WRITEGETATTR0 \
+ (NFSATTRBM_CHANGE | \
+ NFSATTRBM_SIZE | \
+ NFSATTRBM_FSID)
+
+/*
+ * NFSATTRBIT_WRITEGETATTR1 - bits 32<->63
+ */
+#define NFSATTRBIT_WRITEGETATTR1 \
+ (NFSATTRBM_TIMEMETADATA | \
+ NFSATTRBM_TIMEMODIFY)
+
+/*
+ * Set of attributes that the wccattr operation op needs.
+ * OR of the following bits.
+ * NFSATTRBIT_WCCATTR0 - bits 0<->31
+ */
+#define NFSATTRBIT_WCCATTR0 0
+
+/*
+ * NFSATTRBIT_WCCATTR1 - bits 32<->63
+ */
+#define NFSATTRBIT_WCCATTR1 \
+ (NFSATTRBM_TIMEMODIFY)
+
+/*
+ * NFSATTRBIT_CBGETATTR0 - bits 0<->31
+ */
+#define NFSATTRBIT_CBGETATTR0 (NFSATTRBM_CHANGE | NFSATTRBM_SIZE)
+
+/*
+ * NFSATTRBIT_CBGETATTR1 - bits 32<->63
+ */
+#define NFSATTRBIT_CBGETATTR1 0x0
+
+/*
+ * Sets of attributes that require a VFS_STATFS() call to get the
+ * values of.
+ * NFSATTRBIT_STATFS0 - bits 0<->31
+ */
+#define NFSATTRBIT_STATFS0 \
+ (NFSATTRBM_LINKSUPPORT | \
+ NFSATTRBM_SYMLINKSUPPORT | \
+ NFSATTRBM_CANSETTIME | \
+ NFSATTRBM_FILESAVAIL | \
+ NFSATTRBM_FILESFREE | \
+ NFSATTRBM_FILESTOTAL | \
+ NFSATTRBM_HOMOGENEOUS | \
+ NFSATTRBM_MAXFILESIZE | \
+ NFSATTRBM_MAXNAME | \
+ NFSATTRBM_MAXREAD | \
+ NFSATTRBM_MAXWRITE)
+
+/*
+ * NFSATTRBIT_STATFS1 - bits 32<->63
+ */
+#define NFSATTRBIT_STATFS1 \
+ (NFSATTRBM_QUOTAHARD | \
+ NFSATTRBM_QUOTASOFT | \
+ NFSATTRBM_QUOTAUSED | \
+ NFSATTRBM_SPACEAVAIL | \
+ NFSATTRBM_SPACEFREE | \
+ NFSATTRBM_SPACETOTAL | \
+ NFSATTRBM_SPACEUSED | \
+ NFSATTRBM_TIMEDELTA)
+
+/*
+ * These are the bits that are needed by the nfs_statfs() call.
+ * (The regular getattr bits are or'd in so the vnode gets the correct
+ * type, etc.)
+ * NFSGETATTRBIT_STATFS0 - bits 0<->31
+ */
+#define NFSGETATTRBIT_STATFS0 (NFSATTRBIT_GETATTR0 | \
+ NFSATTRBM_LINKSUPPORT | \
+ NFSATTRBM_SYMLINKSUPPORT | \
+ NFSATTRBM_CANSETTIME | \
+ NFSATTRBM_FILESFREE | \
+ NFSATTRBM_FILESTOTAL | \
+ NFSATTRBM_HOMOGENEOUS | \
+ NFSATTRBM_MAXFILESIZE | \
+ NFSATTRBM_MAXNAME | \
+ NFSATTRBM_MAXREAD | \
+ NFSATTRBM_MAXWRITE)
+
+/*
+ * NFSGETATTRBIT_STATFS1 - bits 32<->63
+ */
+#define NFSGETATTRBIT_STATFS1 (NFSATTRBIT_GETATTR1 | \
+ NFSATTRBM_SPACEAVAIL | \
+ NFSATTRBM_SPACEFREE | \
+ NFSATTRBM_SPACETOTAL | \
+ NFSATTRBM_TIMEDELTA)
+
+/*
+ * Set of attributes for the equivalent of an nfsv3 pathconf rpc.
+ * NFSGETATTRBIT_PATHCONF0 - bits 0<->31
+ */
+#define NFSGETATTRBIT_PATHCONF0 (NFSATTRBIT_GETATTR0 | \
+ NFSATTRBM_CASEINSENSITIVE | \
+ NFSATTRBM_CASEPRESERVING | \
+ NFSATTRBM_CHOWNRESTRICTED | \
+ NFSATTRBM_MAXLINK | \
+ NFSATTRBM_MAXNAME)
+
+/*
+ * NFSGETATTRBIT_PATHCONF1 - bits 32<->63
+ */
+#define NFSGETATTRBIT_PATHCONF1 (NFSATTRBIT_GETATTR1 | \
+ NFSATTRBM_NOTRUNC)
+
+/*
+ * Sets of attributes required by readdir and readdirplus.
+ * NFSATTRBIT_READDIRPLUS0 (NFSATTRBIT_GETATTR0 | NFSATTRBIT_FILEHANDLE |
+ * NFSATTRBIT_RDATTRERROR)
+ */
+#define NFSATTRBIT_READDIRPLUS0 (NFSATTRBIT_GETATTR0 | NFSATTRBM_FILEHANDLE | \
+ NFSATTRBM_RDATTRERROR)
+#define NFSATTRBIT_READDIRPLUS1 NFSATTRBIT_GETATTR1
+
+/*
+ * Set of attributes supported by Referral vnodes.
+ */
+#define NFSATTRBIT_REFERRAL0 (NFSATTRBM_TYPE | NFSATTRBM_FSID | \
+ NFSATTRBM_RDATTRERROR | NFSATTRBM_FSLOCATIONS)
+#define NFSATTRBIT_REFERRAL1 NFSATTRBM_MOUNTEDONFILEID
+
+/*
+ * Structure for data handled by the statfs rpc. Since some fields are
+ * u_int64_t, this cannot be used for copying data on/off the wire, due
+ * to alignment concerns.
+ */
+struct nfsstatfs {
+ union {
+ struct {
+ u_int32_t nfsv2sf_tsize;
+ u_int32_t nfsv2sf_bsize;
+ u_int32_t nfsv2sf_blocks;
+ u_int32_t nfsv2sf_bfree;
+ u_int32_t nfsv2sf_bavail;
+ } sf_nfsv2;
+ struct {
+ u_int64_t nfsv3sf_tbytes;
+ u_int64_t nfsv3sf_fbytes;
+ u_int64_t nfsv3sf_abytes;
+ u_int64_t nfsv3sf_tfiles;
+ u_int64_t nfsv3sf_ffiles;
+ u_int64_t nfsv3sf_afiles;
+ u_int32_t nfsv3sf_invarsec;
+ } sf_nfsv3;
+ } sf_un;
+};
+
+#define sf_tsize sf_un.sf_nfsv2.nfsv2sf_tsize
+#define sf_bsize sf_un.sf_nfsv2.nfsv2sf_bsize
+#define sf_blocks sf_un.sf_nfsv2.nfsv2sf_blocks
+#define sf_bfree sf_un.sf_nfsv2.nfsv2sf_bfree
+#define sf_bavail sf_un.sf_nfsv2.nfsv2sf_bavail
+#define sf_tbytes sf_un.sf_nfsv3.nfsv3sf_tbytes
+#define sf_fbytes sf_un.sf_nfsv3.nfsv3sf_fbytes
+#define sf_abytes sf_un.sf_nfsv3.nfsv3sf_abytes
+#define sf_tfiles sf_un.sf_nfsv3.nfsv3sf_tfiles
+#define sf_ffiles sf_un.sf_nfsv3.nfsv3sf_ffiles
+#define sf_afiles sf_un.sf_nfsv3.nfsv3sf_afiles
+#define sf_invarsec sf_un.sf_nfsv3.nfsv3sf_invarsec
+
+/*
+ * Now defined using u_int64_t for the 64 bit field(s).
+ * (Cannot be used to move data on/off the wire, due to alignment concerns.)
+ */
+struct nfsfsinfo {
+ u_int32_t fs_rtmax;
+ u_int32_t fs_rtpref;
+ u_int32_t fs_rtmult;
+ u_int32_t fs_wtmax;
+ u_int32_t fs_wtpref;
+ u_int32_t fs_wtmult;
+ u_int32_t fs_dtpref;
+ u_int64_t fs_maxfilesize;
+ struct timespec fs_timedelta;
+ u_int32_t fs_properties;
+};
+
+/*
+ * Bits for fs_properties
+ */
+#define NFSV3_FSFLINK 0x1
+#define NFSV3_FSFSYMLINK 0x2
+#define NFSV3_FSFHOMOGENEOUS 0x4
+#define NFSV3_FSFCANSETTIME 0x8
+
+/*
+ * Yikes, overload fs_rtmult as fs_maxname for V4.
+ */
+#define fs_maxname fs_rtmult
+
+struct nfsv3_pathconf {
+ u_int32_t pc_linkmax;
+ u_int32_t pc_namemax;
+ u_int32_t pc_notrunc;
+ u_int32_t pc_chownrestricted;
+ u_int32_t pc_caseinsensitive;
+ u_int32_t pc_casepreserving;
+};
+
+/*
+ * NFS V4 data structures.
+ */
+struct nfsv4stateid {
+ u_int32_t seqid;
+ u_int32_t other[NFSX_STATEIDOTHER / NFSX_UNSIGNED];
+};
+typedef struct nfsv4stateid nfsv4stateid_t;
+
+#endif /* _NFS_NFSPROTO_H_ */
diff --git a/sys/fs/nfs/nfsrvcache.h b/sys/fs/nfs/nfsrvcache.h
new file mode 100644
index 0000000..30f757a
--- /dev/null
+++ b/sys/fs/nfs/nfsrvcache.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSRVCACHE_H_
+#define _NFS_NFSRVCACHE_H_
+
+/*
+ * Definitions for the server recent request cache
+ */
+#define NFSRVCACHE_MAX_SIZE 2048
+#define NFSRVCACHE_MIN_SIZE 64
+
+#define NFSRVCACHE_HASHSIZE 20
+
+struct nfsrvcache {
+ LIST_ENTRY(nfsrvcache) rc_hash; /* Hash chain */
+ TAILQ_ENTRY(nfsrvcache) rc_lru; /* UDP lru chain */
+ u_int32_t rc_xid; /* rpc id number */
+ time_t rc_timestamp; /* Time done */
+ union {
+ mbuf_t repmb; /* Reply mbuf list OR */
+ int repstat; /* Reply status */
+ } rc_un;
+ union {
+ struct {
+ union nethostaddr haddr; /* Host address */
+ } udp;
+ struct {
+ u_int64_t sockref;
+ u_int32_t len;
+ u_int32_t tcpseq;
+ int16_t refcnt;
+ u_int16_t cksum;
+ time_t cachetime;
+ } ot;
+ } rc_un2;
+ u_int16_t rc_proc; /* rpc proc number */
+ u_int16_t rc_flag; /* Flag bits */
+};
+
+#define rc_reply rc_un.repmb
+#define rc_status rc_un.repstat
+#define rc_inet rc_un2.udp.haddr.had_inet.s_addr
+#define rc_inet6 rc_un2.udp.haddr.had_inet6
+#define rc_haddr rc_un2.udp.haddr
+#define rc_sockref rc_un2.ot.sockref
+#define rc_tcpseq rc_un2.ot.tcpseq
+#define rc_refcnt rc_un2.ot.refcnt
+#define rc_reqlen rc_un2.ot.len
+#define rc_cksum rc_un2.ot.cksum
+#define rc_cachetime rc_un2.ot.cachetime
+
+/* Return values */
+#define RC_DROPIT 0
+#define RC_REPLY 1
+#define RC_DOIT 2
+
+/* Flag bits */
+#define RC_LOCKED 0x0001
+#define RC_WANTED 0x0002
+#define RC_REPSTATUS 0x0004
+#define RC_REPMBUF 0x0008
+#define RC_UDP 0x0010
+#define RC_INETIPV6 0x0020
+#define RC_INPROG 0x0040
+#define RC_TCPSEQ 0x0080
+#define RC_NFSV2 0x0100
+#define RC_NFSV3 0x0200
+#define RC_NFSV4 0x0400
+#define RC_NFSVERS (RC_NFSV2 | RC_NFSV3 | RC_NFSV4)
+#define RC_REFCNT 0x0800
+#define RC_SAMETCPCONN 0x1000
+
+LIST_HEAD(nfsrvhashhead, nfsrvcache);
+
+#endif /* _NFS_NFSRVCACHE_H_ */
diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h
new file mode 100644
index 0000000..629b18c
--- /dev/null
+++ b/sys/fs/nfs/nfsrvstate.h
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSRVSTATE_H_
+#define _NFS_NFSRVSTATE_H_
+
+/*
+ * Definitions for NFS V4 server state handling.
+ */
+
+/*
+ * List heads for nfsclient, nfsstate and nfslockfile.
+ * (Some systems seem to like to dynamically size these things, but I
+ * don't see any point in doing so for these ones.)
+ */
+LIST_HEAD(nfsclienthashhead, nfsclient);
+LIST_HEAD(nfsstatehead, nfsstate);
+LIST_HEAD(nfslockhead, nfslock);
+LIST_HEAD(nfslockhashhead, nfslockfile);
+
+/*
+ * List head for nfsusrgrp.
+ */
+LIST_HEAD(nfsuserhashhead, nfsusrgrp);
+TAILQ_HEAD(nfsuserlruhead, nfsusrgrp);
+
+#define NFSCLIENTHASH(id) \
+ (&nfsclienthash[(id).lval[1] % NFSCLIENTHASHSIZE])
+#define NFSSTATEHASH(clp, id) \
+ (&((clp)->lc_stateid[(id).other[2] % NFSSTATEHASHSIZE]))
+#define NFSUSERHASH(id) \
+ (&nfsuserhash[(id) % NFSUSERHASHSIZE])
+#define NFSUSERNAMEHASH(p, l) \
+ (&nfsusernamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \
+ % NFSUSERHASHSIZE])
+#define NFSGROUPHASH(id) \
+ (&nfsgrouphash[(id) % NFSGROUPHASHSIZE])
+#define NFSGROUPNAMEHASH(p, l) \
+ (&nfsgroupnamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \
+ % NFSGROUPHASHSIZE])
+
+/*
+ * Client server structure for V4. It is doubly linked into two lists.
+ * The first is a hash table based on the clientid and the second is a
+ * list of all clients maintained in LRU order.
+ * The actual size malloc'd is large enough to accomodate the id string.
+ */
+struct nfsclient {
+ LIST_ENTRY(nfsclient) lc_hash; /* Clientid hash list */
+ struct nfsstatehead lc_stateid[NFSSTATEHASHSIZE]; /* stateid hash */
+ struct nfsstatehead lc_open; /* Open owner list */
+ struct nfsstatehead lc_deleg; /* Delegations */
+ struct nfsstatehead lc_olddeleg; /* and old delegations */
+ time_t lc_expiry; /* Expiry time (sec) */
+ time_t lc_delegtime; /* Old deleg expiry (sec) */
+ nfsquad_t lc_clientid; /* 64 bit clientid */
+ nfsquad_t lc_confirm; /* 64 bit confirm value */
+ u_int32_t lc_program; /* RPC Program # */
+ u_int32_t lc_callback; /* Callback id */
+ u_int32_t lc_stateindex; /* Current state index# */
+ u_int32_t lc_statemaxindex; /* Max state index# */
+ u_int32_t lc_cbref; /* Cnt of callbacks */
+ uid_t lc_uid; /* User credential */
+ gid_t lc_gid;
+ u_int16_t lc_namelen;
+ u_char *lc_name;
+ struct nfssockreq lc_req; /* Callback info */
+ u_short lc_idlen; /* Length of id string */
+ u_int32_t lc_flags; /* LCL_ flag bits */
+ u_char lc_verf[NFSX_VERF]; /* client verifier */
+ u_char lc_id[1]; /* Malloc'd correct size */
+};
+
+#define CLOPS_CONFIRM 0x0001
+#define CLOPS_RENEW 0x0002
+#define CLOPS_RENEWOP 0x0004
+
+/*
+ * Nfs state structure. I couldn't resist overloading this one, since
+ * it makes cleanup, etc. simpler. These structures are used in four ways:
+ * - open_owner structures chained off of nfsclient
+ * - open file structures chained off an open_owner structure
+ * - lock_owner structures chained off an open file structure
+ * - delegated file structures chained off of nfsclient and nfslockfile
+ * - the ls_list field is used for the chain it is in
+ * - the ls_head structure is used to chain off the sibling structure
+ * (it is a union between an nfsstate and nfslock structure head)
+ * If it is a lockowner stateid, nfslock structures hang off it.
+ * For the open file and lockowner cases, it is in the hash table in
+ * nfsclient for stateid.
+ */
+struct nfsstate {
+ LIST_ENTRY(nfsstate) ls_hash; /* Hash list entry */
+ LIST_ENTRY(nfsstate) ls_list; /* List of opens/delegs */
+ LIST_ENTRY(nfsstate) ls_file; /* Opens/Delegs for a file */
+ union {
+ struct nfsstatehead open; /* Opens list */
+ struct nfslockhead lock; /* Locks list */
+ } ls_head;
+ nfsv4stateid_t ls_stateid; /* The state id */
+ u_int32_t ls_seq; /* seq id */
+ uid_t ls_uid; /* uid of locker */
+ u_int32_t ls_flags; /* Type of lock, etc. */
+ union {
+ struct nfsstate *openowner; /* Open only */
+ u_int32_t opentolockseq; /* Lock call only */
+ u_int32_t noopens; /* Openowner only */
+ struct {
+ u_quad_t filerev; /* Delegations only */
+ time_t expiry;
+ time_t limit;
+ u_int64_t compref;
+ } deleg;
+ } ls_un;
+ struct nfslockfile *ls_lfp; /* Back pointer */
+ struct nfsrvcache *ls_op; /* Op cache reference */
+ struct nfsclient *ls_clp; /* Back pointer */
+ u_short ls_ownerlen; /* Length of ls_owner */
+ u_char ls_owner[1]; /* malloc'd the correct size */
+};
+#define ls_lock ls_head.lock
+#define ls_open ls_head.open
+#define ls_opentolockseq ls_un.opentolockseq
+#define ls_openowner ls_un.openowner
+#define ls_openstp ls_un.openowner
+#define ls_noopens ls_un.noopens
+#define ls_filerev ls_un.deleg.filerev
+#define ls_delegtime ls_un.deleg.expiry
+#define ls_delegtimelimit ls_un.deleg.limit
+#define ls_compref ls_un.deleg.compref
+
+/*
+ * Nfs lock structure.
+ * This structure is chained off of the nfsstate (the lockowner) and
+ * nfslockfile (the file) structures, for the file and owner it
+ * refers to. It holds flags and a byte range.
+ * It also has back pointers to the associated lock_owner and lockfile.
+ */
+struct nfslock {
+ LIST_ENTRY(nfslock) lo_lckowner;
+ LIST_ENTRY(nfslock) lo_lckfile;
+ struct nfsstate *lo_stp;
+ struct nfslockfile *lo_lfp;
+ u_int64_t lo_first;
+ u_int64_t lo_end;
+ u_int32_t lo_flags;
+};
+
+/*
+ * Structure used to return a conflicting lock. (Must be large
+ * enough for the largest lock owner we can have.)
+ */
+struct nfslockconflict {
+ nfsquad_t cl_clientid;
+ u_int64_t cl_first;
+ u_int64_t cl_end;
+ u_int32_t cl_flags;
+ u_short cl_ownerlen;
+ u_char cl_owner[NFSV4_OPAQUELIMIT];
+};
+
+/*
+ * This structure refers to a file for which lock(s) and/or open(s) exist.
+ * Searched via hash table on file handle or found via the back pointer from an
+ * open or lock owner.
+ */
+struct nfslockfile {
+ LIST_HEAD(, nfsstate) lf_open; /* Open list */
+ LIST_HEAD(, nfsstate) lf_deleg; /* Delegation list */
+ LIST_HEAD(, nfslock) lf_lock; /* Lock list */
+ LIST_ENTRY(nfslockfile) lf_hash; /* Hash list entry */
+ fhandle_t lf_fh; /* The file handle */
+};
+
+/*
+ * This structure is malloc'd an chained off hash lists for user/group
+ * names.
+ */
+struct nfsusrgrp {
+ TAILQ_ENTRY(nfsusrgrp) lug_lru; /* LRU list */
+ LIST_ENTRY(nfsusrgrp) lug_numhash; /* Hash by id# */
+ LIST_ENTRY(nfsusrgrp) lug_namehash; /* and by name */
+ time_t lug_expiry; /* Expiry time in sec */
+ union {
+ uid_t un_uid; /* id# */
+ gid_t un_gid;
+ } lug_un;
+ int lug_namelen; /* Name length */
+ u_char lug_name[1]; /* malloc'd correct length */
+};
+#define lug_uid lug_un.un_uid
+#define lug_gid lug_un.un_gid
+
+/*
+ * These structures are used for the stable storage restart stuff.
+ */
+/*
+ * Record at beginning of file.
+ */
+struct nfsf_rec {
+ u_int32_t lease; /* Lease duration */
+ u_int32_t numboots; /* Number of boottimes */
+};
+
+#if defined(_KERNEL) || defined(KERNEL)
+void nfsrv_cleanclient(struct nfsclient *, NFSPROC_T *);
+void nfsrv_freedeleglist(struct nfsstatehead *);
+#endif
+
+#endif /* _NFS_NFSRVSTATE_H_ */
diff --git a/sys/fs/nfs/nfsv4_errstr.h b/sys/fs/nfs/nfsv4_errstr.h
new file mode 100644
index 0000000..4f6460d
--- /dev/null
+++ b/sys/fs/nfs/nfsv4_errstr.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2009 Rick Macklem, University of Guelph
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_NFSV4ERRSTR_H_
+#define _NFS_NFSV4ERRSTR_H_
+
+/*
+ * Defines static storage in the C file, but I can't be bothered creating
+ * a library of one function for this, since it is only currently used by
+ * mount_newnfs.c.
+ */
+static const char *nfsv4_errstr[48] = {
+ "Illegal filehandle",
+ "Undefined NFSv4 err",
+ "READDIR cookie is stale",
+ "operation not supported",
+ "response limit exceeded",
+ "undefined server error",
+ "type invalid for CREATE",
+ "file busy - retry",
+ "nverify says attrs same",
+ "lock unavailable",
+ "lock lease expired",
+ "I/O failed due to lock",
+ "in grace period",
+ "filehandle expired",
+ "share reserve denied",
+ "wrong security flavor",
+ "clientid in use",
+ "resource exhaustion",
+ "filesystem relocated",
+ "current FH is not set",
+ "minor vers not supp",
+ "server has rebooted",
+ "server has rebooted",
+ "state is out of sync",
+ "incorrect stateid",
+ "request is out of seq",
+ "verify - attrs not same",
+ "lock range not supported",
+ "should be file/directory",
+ "no saved filehandle",
+ "some filesystem moved",
+ "recommended attr not sup",
+ "reclaim outside of grace",
+ "reclaim error at server",
+ "conflict on reclaim",
+ "XDR decode failed",
+ "file locks held at CLOSE",
+ "conflict in OPEN and I/O",
+ "owner translation bad",
+ "utf-8 char not supported",
+ "name not supported",
+ "lock range not supported",
+ "no atomic up/downgrade",
+ "undefined operation",
+ "file locking deadlock",
+ "open file blocks op",
+ "lockowner state revoked",
+ "callback path down"
+};
+
+/*
+ * Return the error string for the NFS4ERR_xxx. The pointers returned are
+ * static and must not be free'd.
+ */
+static const char *
+nfsv4_geterrstr(int errval)
+{
+
+ if (errval < NFSERR_BADHANDLE || errval > NFSERR_CBPATHDOWN)
+ return (NULL);
+ return (nfsv4_errstr[errval - NFSERR_BADHANDLE]);
+}
+
+#endif /* _NFS_NFSV4ERRSTR_H_ */
diff --git a/sys/fs/nfs/rpcv2.h b/sys/fs/nfs/rpcv2.h
new file mode 100644
index 0000000..d2174ac
--- /dev/null
+++ b/sys/fs/nfs/rpcv2.h
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_RPCV2_H_
+#define _NFS_RPCV2_H_
+
+/*
+ * Definitions for Sun RPC Version 2, from
+ * "RPC: Remote Procedure Call Protocol Specification" RFC1057
+ */
+
+/* Version # */
+#define RPC_VER2 2
+
+/* Authentication flavours */
+#define RPCAUTH_NULL 0
+#define RPCAUTH_UNIX 1
+#define RPCAUTH_SHORT 2
+#define RPCAUTH_KERB4 4
+#define RPCAUTH_GSS 6
+#define RPCAUTH_GSSKRB5 390003
+#define RPCAUTH_GSSKRB5INTEGRITY 390004
+#define RPCAUTH_GSSKRB5PRIVACY 390005
+
+#define RPCAUTH_MAXSIZ 400
+#define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */
+
+/*
+ * RPCAUTH_UNIX defs.
+ */
+#define RPCAUTHUNIX_MINSIZ (5 * NFSX_UNSIGNED)
+#define RPCAUTH_UNIXGIDS 16
+
+/*
+ * RPCAUTH_GSS defs.
+ */
+#define RPCAUTHGSS_VERS1 1
+
+#define RPCAUTHGSS_DATA 0
+#define RPCAUTHGSS_INIT 1
+#define RPCAUTHGSS_CONTINIT 2
+#define RPCAUTHGSS_DESTROY 3
+
+#define RPCAUTHGSS_SVCNONE 1
+#define RPCAUTHGSS_SVCINTEGRITY 2
+#define RPCAUTHGSS_SVCPRIVACY 3
+
+#define RPCAUTHGSS_MAXSEQ 0x80000000
+
+#define RPCAUTHGSS_WINDOW 64 /* # of bits in u_int64_t */
+#define RPCAUTHGSS_SEQWINDOW (RPCAUTHGSS_WINDOW + 1)
+
+#define RPCAUTHGSS_MIC 1
+#define RPCAUTHGSS_WRAP 2
+
+/*
+ * Qop values for the types of security services.
+ */
+#define GSS_KERBV_QOP 0
+
+/*
+ * Sizes of GSS stuff.
+ */
+#define RPCGSS_KEYSIZ 8
+
+#define GSSX_AUTHHEAD (5 * NFSX_UNSIGNED)
+#define GSSX_MYHANDLE (sizeof (long) + sizeof (u_int64_t))
+#define GSSX_RPCHEADER (13 * NFSX_UNSIGNED + GSSX_MYHANDLE)
+#define GSSX_MINWRAP (2 * NFSX_UNSIGNED)
+#define GSSX_KERBVTOKEN 24
+#define GSSX_LOCALHANDLE (sizeof (void *))
+
+/*
+ * Stuff for the gssd.
+ */
+#define RPCPROG_GSSD 0x20101010
+#define RPCGSSD_VERS 1
+#define RPCGSSD_INIT 1
+#define RPCGSSD_CONTINIT 2
+#define RPCGSSD_CONTINITDESTROY 3
+#define RPCGSSD_CLINIT 4
+#define RPCGSSD_CLINITUID 5
+#define RPCGSSD_CLCONT 6
+#define RPCGSSD_CLCONTUID 7
+#define RPCGSSD_CLINITNAME 8
+#define RPCGSSD_CLCONTNAME 9
+
+/*
+ * Stuff for the nfsuserd
+ */
+#define RPCPROG_NFSUSERD 0x21010101
+#define RPCNFSUSERD_VERS 1
+#define RPCNFSUSERD_GETUID 1
+#define RPCNFSUSERD_GETGID 2
+#define RPCNFSUSERD_GETUSER 3
+#define RPCNFSUSERD_GETGROUP 4
+
+/*
+ * Some major status codes.
+ */
+#if !defined(_GSSAPI_H_) && !defined(GSSAPI_H_) && !defined(_GSSAPI_GSSAPI_H_) && !defined(_RPCSEC_GSS_H)
+#define GSS_S_COMPLETE 0x00000000
+#define GSS_S_CONTINUE_NEEDED 0x00000001
+#define GSS_S_DUPLICATE_TOKEN 0x00000002
+#define GSS_S_OLD_TOKEN 0x00000004
+#define GSS_S_UNSEQ_TOKEN 0x00000008
+#define GSS_S_GAP_TOKEN 0x00000010
+#define GSS_S_BAD_MECH 0x00010000
+#define GSS_S_BAD_NAME 0x00020000
+#define GSS_S_BAD_NAMETYPE 0x00030000
+#define GSS_S_BAD_BINDINGS 0x00040000
+#define GSS_S_BAD_STATUS 0x00050000
+#define GSS_S_BAD_MIC 0x00060000
+#define GSS_S_BAD_SIG 0x00060000
+#define GSS_S_NO_CRED 0x00070000
+#define GSS_S_NO_CONTEXT 0x00080000
+#define GSS_S_DEFECTIVE_TOKEN 0x00090000
+#define GSS_S_DEFECTIVE_CREDENTIAL 0x000a0000
+#define GSS_S_CREDENTIALS_EXPIRED 0x000b0000
+#define GSS_S_CONTEXT_EXPIRED 0x000c0000
+#define GSS_S_FAILURE 0x000d0000
+#define GSS_S_BAD_QOP 0x000e0000
+#define GSS_S_UNAUTHORIZED 0x000f0000
+#define GSS_S_UNAVAILABLE 0x00100000
+#define GSS_S_DUPLICATE_ELEMENT 0x00110000
+#define GSS_S_NAME_NOT_MN 0x00120000
+#define GSS_S_CALL_INACCESSIBLE_READ 0x01000000
+#define GSS_S_CALL_INACCESSIBLE_WRITE 0x02000000
+#define GSS_S_CALL_BAD_STRUCTURE 0x03000000
+#endif /* _GSSAPI_H_ */
+
+/* Rpc Constants */
+#define RPC_CALL 0
+#define RPC_REPLY 1
+#define RPC_MSGACCEPTED 0
+#define RPC_MSGDENIED 1
+#define RPC_PROGUNAVAIL 1
+#define RPC_PROGMISMATCH 2
+#define RPC_PROCUNAVAIL 3
+#define RPC_GARBAGE 4 /* I like this one */
+#define RPC_MISMATCH 0
+#define RPC_AUTHERR 1
+
+/* Authentication failures */
+#define AUTH_BADCRED 1
+#define AUTH_REJECTCRED 2
+#define AUTH_BADVERF 3
+#define AUTH_REJECTVERF 4
+#define AUTH_TOOWEAK 5 /* Give em wheaties */
+#define AUTH_PROBCRED 13
+#define AUTH_CTXCRED 14
+
+/* Sizes of rpc header parts */
+#define RPC_SIZ 24
+#define RPC_REPLYSIZ 28
+
+/* RPC Prog definitions */
+#define RPCPROG_MNT 100005
+#define RPCMNT_VER1 1
+#define RPCMNT_VER3 3
+#define RPCMNT_MOUNT 1
+#define RPCMNT_DUMP 2
+#define RPCMNT_UMOUNT 3
+#define RPCMNT_UMNTALL 4
+#define RPCMNT_EXPORT 5
+#define RPCMNT_NAMELEN 255
+#define RPCMNT_PATHLEN 1024
+#define RPCPROG_NFS 100003
+
+/* Structs for common parts of the rpc's */
+struct rpcv2_time {
+ u_int32_t rpc_sec;
+ u_int32_t rpc_usec;
+};
+
+#endif /* _NFS_RPCV2_H_ */
diff --git a/sys/fs/nfs/xdr_subs.h b/sys/fs/nfs/xdr_subs.h
new file mode 100644
index 0000000..a3e69f9
--- /dev/null
+++ b/sys/fs/nfs/xdr_subs.h
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFS_XDR_SUBS_H_
+#define _NFS_XDR_SUBS_H_
+
+/*
+ * Macros used for conversion to/from xdr representation by nfs...
+ * These use the MACHINE DEPENDENT routines ntohl, htonl
+ * As defined by "XDR: External Data Representation Standard" RFC1014
+ *
+ * To simplify the implementation, we use ntohl/htonl even on big-endian
+ * machines, and count on them being `#define'd away. Some of these
+ * might be slightly more efficient as quad_t copies on a big-endian,
+ * but we cannot count on their alignment anyway.
+ */
+
+#define fxdr_unsigned(t, v) ((t)ntohl((int32_t)(v)))
+#define txdr_unsigned(v) (htonl((int32_t)(v)))
+
+#define fxdr_nfsv2time(f, t) do { \
+ (t)->tv_sec = ntohl(((struct nfsv2_time *)(f))->nfsv2_sec); \
+ if (((struct nfsv2_time *)(f))->nfsv2_usec != 0xffffffff) \
+ (t)->tv_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfsv2_usec); \
+ else \
+ (t)->tv_nsec = 0; \
+ } while (0)
+
+#define txdr_nfsv2time(f, t) do { \
+ ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->tv_sec); \
+ if ((f)->tv_nsec != -1) \
+ ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->tv_nsec / 1000); \
+ else \
+ ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \
+ } while (0)
+
+#define fxdr_nfsv3time(f, t) do { \
+ (t)->tv_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \
+ (t)->tv_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \
+ } while (0)
+
+#define txdr_nfsv3time(f, t) do { \
+ ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->tv_sec); \
+ ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->tv_nsec); \
+ } while (0)
+
+#define fxdr_nfsv4time(f, t) do { \
+ (t)->tv_sec = ntohl(((struct nfsv4_time *)(f))->nfsv4_sec); \
+ (t)->tv_nsec = (ntohl(((struct nfsv4_time *)(f))->nfsv4_nsec) % \
+ 1000000000); \
+ } while (0)
+
+#define txdr_nfsv4time(f, t) do { \
+ ((struct nfsv4_time *)(t))->nfsv4_highsec = 0; \
+ ((struct nfsv4_time *)(t))->nfsv4_sec = htonl((f)->tv_sec); \
+ ((struct nfsv4_time *)(t))->nfsv4_nsec = htonl((f)->tv_nsec); \
+ } while (0)
+
+#define fxdr_hyper(f) \
+ ((((u_quad_t)ntohl(((u_int32_t *)(f))[0])) << 32) | \
+ (u_quad_t)(ntohl(((u_int32_t *)(f))[1])))
+
+#define txdr_hyper(f, t) do { \
+ ((u_int32_t *)(t))[0] = htonl((u_int32_t)((f) >> 32)); \
+ ((u_int32_t *)(t))[1] = htonl((u_int32_t)((f) & 0xffffffff)); \
+ } while (0)
+
+#endif /* _NFS_XDR_SUBS_H_ */
OpenPOWER on IntegriCloud