xref: /onnv-gate/usr/src/uts/common/fs/nfs/nfs_server.c (revision 12553:e64e5d843075)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51610Sthurlow  * Common Development and Distribution License (the "License").
61610Sthurlow  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12553SKaren.Rochford@Sun.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
270Sstevel@tonic-gate  *	All rights reserved.
280Sstevel@tonic-gate  *	Use is subject to license terms.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/cred.h>
350Sstevel@tonic-gate #include <sys/proc.h>
360Sstevel@tonic-gate #include <sys/user.h>
370Sstevel@tonic-gate #include <sys/buf.h>
380Sstevel@tonic-gate #include <sys/vfs.h>
390Sstevel@tonic-gate #include <sys/vnode.h>
400Sstevel@tonic-gate #include <sys/pathname.h>
410Sstevel@tonic-gate #include <sys/uio.h>
420Sstevel@tonic-gate #include <sys/file.h>
430Sstevel@tonic-gate #include <sys/stat.h>
440Sstevel@tonic-gate #include <sys/errno.h>
450Sstevel@tonic-gate #include <sys/socket.h>
460Sstevel@tonic-gate #include <sys/sysmacros.h>
470Sstevel@tonic-gate #include <sys/siginfo.h>
480Sstevel@tonic-gate #include <sys/tiuser.h>
490Sstevel@tonic-gate #include <sys/statvfs.h>
500Sstevel@tonic-gate #include <sys/stream.h>
510Sstevel@tonic-gate #include <sys/strsubr.h>
520Sstevel@tonic-gate #include <sys/stropts.h>
530Sstevel@tonic-gate #include <sys/timod.h>
540Sstevel@tonic-gate #include <sys/t_kuser.h>
550Sstevel@tonic-gate #include <sys/kmem.h>
560Sstevel@tonic-gate #include <sys/kstat.h>
570Sstevel@tonic-gate #include <sys/dirent.h>
580Sstevel@tonic-gate #include <sys/cmn_err.h>
590Sstevel@tonic-gate #include <sys/debug.h>
600Sstevel@tonic-gate #include <sys/unistd.h>
610Sstevel@tonic-gate #include <sys/vtrace.h>
620Sstevel@tonic-gate #include <sys/mode.h>
630Sstevel@tonic-gate #include <sys/acl.h>
640Sstevel@tonic-gate #include <sys/sdt.h>
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #include <rpc/types.h>
670Sstevel@tonic-gate #include <rpc/auth.h>
680Sstevel@tonic-gate #include <rpc/auth_unix.h>
690Sstevel@tonic-gate #include <rpc/auth_des.h>
700Sstevel@tonic-gate #include <rpc/svc.h>
710Sstevel@tonic-gate #include <rpc/xdr.h>
728695SRajkumar.Sivaprakasam@Sun.COM #include <rpc/rpc_rdma.h>
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #include <nfs/nfs.h>
750Sstevel@tonic-gate #include <nfs/export.h>
760Sstevel@tonic-gate #include <nfs/nfssys.h>
770Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
780Sstevel@tonic-gate #include <nfs/nfs_acl.h>
790Sstevel@tonic-gate #include <nfs/nfs_log.h>
807961SNatalie.Li@Sun.COM #include <nfs/nfs_cmd.h>
810Sstevel@tonic-gate #include <nfs/lm.h>
8274Srg137905 #include <nfs/nfs_dispatch.h>
8374Srg137905 #include <nfs/nfs4_drc.h>
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #include <sys/modctl.h>
860Sstevel@tonic-gate #include <sys/cladm.h>
870Sstevel@tonic-gate #include <sys/clconf.h>
880Sstevel@tonic-gate 
899871SJarrett.Lu@Sun.COM #include <sys/tsol/label.h>
909871SJarrett.Lu@Sun.COM 
910Sstevel@tonic-gate #define	MAXHOST 32
920Sstevel@tonic-gate const char *kinet_ntop6(uchar_t *, char *, size_t);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * Module linkage information.
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate static struct modlmisc modlmisc = {
990Sstevel@tonic-gate 	&mod_miscops, "NFS server module"
1000Sstevel@tonic-gate };
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static struct modlinkage modlinkage = {
1030Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
1040Sstevel@tonic-gate };
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate char _depends_on[] = "misc/klmmod";
1070Sstevel@tonic-gate 
10811539SChunli.Zhang@Sun.COM kmem_cache_t *nfs_xuio_cache;
10911539SChunli.Zhang@Sun.COM int nfs_loaned_buffers = 0;
11011539SChunli.Zhang@Sun.COM 
1110Sstevel@tonic-gate int
_init(void)1120Sstevel@tonic-gate _init(void)
1130Sstevel@tonic-gate {
1140Sstevel@tonic-gate 	int status;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if ((status = nfs_srvinit()) != 0) {
1170Sstevel@tonic-gate 		cmn_err(CE_WARN, "_init: nfs_srvinit failed");
1180Sstevel@tonic-gate 		return (status);
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	status = mod_install((struct modlinkage *)&modlinkage);
1220Sstevel@tonic-gate 	if (status != 0) {
1230Sstevel@tonic-gate 		/*
1240Sstevel@tonic-gate 		 * Could not load module, cleanup previous
1250Sstevel@tonic-gate 		 * initialization work.
1260Sstevel@tonic-gate 		 */
1270Sstevel@tonic-gate 		nfs_srvfini();
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1302035Scalum 	/*
1312035Scalum 	 * Initialise some placeholders for nfssys() calls. These have
1322035Scalum 	 * to be declared by the nfs module, since that handles nfssys()
1332035Scalum 	 * calls - also used by NFS clients - but are provided by this
1342035Scalum 	 * nfssrv module. These also then serve as confirmation to the
1352035Scalum 	 * relevant code in nfs that nfssrv has been loaded, as they're
1362035Scalum 	 * initially NULL.
1372035Scalum 	 */
1380Sstevel@tonic-gate 	nfs_srv_quiesce_func = nfs_srv_quiesce_all;
1392035Scalum 	nfs_srv_dss_func = rfs4_dss_setpaths;
1402035Scalum 
1412035Scalum 	/* setup DSS paths here; must be done before initial server startup */
1422035Scalum 	rfs4_dss_paths = rfs4_dss_oldpaths = NULL;
1430Sstevel@tonic-gate 
14411539SChunli.Zhang@Sun.COM 	/* initialize the copy reduction caches */
14511539SChunli.Zhang@Sun.COM 
14611539SChunli.Zhang@Sun.COM 	nfs_xuio_cache = kmem_cache_create("nfs_xuio_cache",
14711539SChunli.Zhang@Sun.COM 	    sizeof (nfs_xuio_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
14811539SChunli.Zhang@Sun.COM 
1490Sstevel@tonic-gate 	return (status);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate int
_fini()1530Sstevel@tonic-gate _fini()
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	return (EBUSY);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1590Sstevel@tonic-gate _info(struct modinfo *modinfop)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate  * PUBLICFH_CHECK() checks if the dispatch routine supports
1660Sstevel@tonic-gate  * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the
1670Sstevel@tonic-gate  * incoming request is using the public filehandle. The check duplicates
1680Sstevel@tonic-gate  * the exportmatch() call done in checkexport(), and we should consider
1690Sstevel@tonic-gate  * modifying those routines to avoid the duplication. For now, we optimize
1700Sstevel@tonic-gate  * by calling exportmatch() only after checking that the dispatch routine
1710Sstevel@tonic-gate  * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported
1720Sstevel@tonic-gate  * public (i.e., not the placeholder).
1730Sstevel@tonic-gate  */
1741610Sthurlow #define	PUBLICFH_CHECK(disp, exi, fsid, xfid) \
1750Sstevel@tonic-gate 		((disp->dis_flags & RPC_PUBLICFH_OK) && \
1760Sstevel@tonic-gate 		((exi->exi_export.ex_flags & EX_PUBLIC) || \
1770Sstevel@tonic-gate 		(exi == exi_public && exportmatch(exi_root, \
1781610Sthurlow 		fsid, xfid))))
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate static void	nfs_srv_shutdown_all(int);
1810Sstevel@tonic-gate static void	rfs4_server_start(int);
1820Sstevel@tonic-gate static void	nullfree(void);
1830Sstevel@tonic-gate static void	rfs_dispatch(struct svc_req *, SVCXPRT *);
1840Sstevel@tonic-gate static void	acl_dispatch(struct svc_req *, SVCXPRT *);
1850Sstevel@tonic-gate static void	common_dispatch(struct svc_req *, SVCXPRT *,
1860Sstevel@tonic-gate 		rpcvers_t, rpcvers_t, char *,
1870Sstevel@tonic-gate 		struct rpc_disptable *);
1882035Scalum static void	hanfsv4_failover(void);
1890Sstevel@tonic-gate static	int	checkauth(struct exportinfo *, struct svc_req *, cred_t *, int,
1900Sstevel@tonic-gate 			bool_t);
1910Sstevel@tonic-gate static char	*client_name(struct svc_req *req);
1920Sstevel@tonic-gate static char	*client_addr(struct svc_req *req, char *buf);
1930Sstevel@tonic-gate extern	int	sec_svc_getcred(struct svc_req *, cred_t *cr, char **, int *);
1940Sstevel@tonic-gate extern	bool_t	sec_svc_inrootlist(int, caddr_t, int, caddr_t *);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate #define	NFSLOG_COPY_NETBUF(exi, xprt, nb)	{		\
1970Sstevel@tonic-gate 	(nb)->maxlen = (xprt)->xp_rtaddr.maxlen;		\
1980Sstevel@tonic-gate 	(nb)->len = (xprt)->xp_rtaddr.len;			\
1990Sstevel@tonic-gate 	(nb)->buf = kmem_alloc((nb)->len, KM_SLEEP);		\
2000Sstevel@tonic-gate 	bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len);	\
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * Public Filehandle common nfs routines
2050Sstevel@tonic-gate  */
2060Sstevel@tonic-gate static int	MCLpath(char **);
2070Sstevel@tonic-gate static void	URLparse(char *);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate  * NFS callout table.
2110Sstevel@tonic-gate  * This table is used by svc_getreq() to dispatch a request with
2120Sstevel@tonic-gate  * a given prog/vers pair to an appropriate service provider
2130Sstevel@tonic-gate  * dispatch routine.
2140Sstevel@tonic-gate  *
2150Sstevel@tonic-gate  * NOTE: ordering is relied upon below when resetting the version min/max
2160Sstevel@tonic-gate  * for NFS_PROGRAM.  Careful, if this is ever changed.
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate static SVC_CALLOUT __nfs_sc_clts[] = {
2190Sstevel@tonic-gate 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
2200Sstevel@tonic-gate 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
2210Sstevel@tonic-gate };
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate static SVC_CALLOUT_TABLE nfs_sct_clts = {
2240Sstevel@tonic-gate 	sizeof (__nfs_sc_clts) / sizeof (__nfs_sc_clts[0]), FALSE,
2250Sstevel@tonic-gate 	__nfs_sc_clts
2260Sstevel@tonic-gate };
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate static SVC_CALLOUT __nfs_sc_cots[] = {
2290Sstevel@tonic-gate 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
2300Sstevel@tonic-gate 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
2310Sstevel@tonic-gate };
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate static SVC_CALLOUT_TABLE nfs_sct_cots = {
2340Sstevel@tonic-gate 	sizeof (__nfs_sc_cots) / sizeof (__nfs_sc_cots[0]), FALSE, __nfs_sc_cots
2350Sstevel@tonic-gate };
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate static SVC_CALLOUT __nfs_sc_rdma[] = {
2380Sstevel@tonic-gate 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
2390Sstevel@tonic-gate 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
2400Sstevel@tonic-gate };
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate static SVC_CALLOUT_TABLE nfs_sct_rdma = {
2430Sstevel@tonic-gate 	sizeof (__nfs_sc_rdma) / sizeof (__nfs_sc_rdma[0]), FALSE, __nfs_sc_rdma
2440Sstevel@tonic-gate };
2450Sstevel@tonic-gate rpcvers_t nfs_versmin = NFS_VERSMIN_DEFAULT;
2460Sstevel@tonic-gate rpcvers_t nfs_versmax = NFS_VERSMAX_DEFAULT;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * Used to track the state of the server so that initialization
2500Sstevel@tonic-gate  * can be done properly.
2510Sstevel@tonic-gate  */
2520Sstevel@tonic-gate typedef enum {
2530Sstevel@tonic-gate 	NFS_SERVER_STOPPED,	/* server state destroyed */
2540Sstevel@tonic-gate 	NFS_SERVER_STOPPING,	/* server state being destroyed */
2550Sstevel@tonic-gate 	NFS_SERVER_RUNNING,
2560Sstevel@tonic-gate 	NFS_SERVER_QUIESCED,	/* server state preserved */
2570Sstevel@tonic-gate 	NFS_SERVER_OFFLINE	/* server pool offline */
2580Sstevel@tonic-gate } nfs_server_running_t;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate static nfs_server_running_t nfs_server_upordown;
2610Sstevel@tonic-gate static kmutex_t nfs_server_upordown_lock;
2620Sstevel@tonic-gate static	kcondvar_t nfs_server_upordown_cv;
2630Sstevel@tonic-gate 
2642035Scalum /*
2652035Scalum  * DSS: distributed stable storage
2662035Scalum  * lists of all DSS paths: current, and before last warmstart
2672035Scalum  */
2682035Scalum nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
2692035Scalum 
27074Srg137905 int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *);
2714635Smaheshvs bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *);
27274Srg137905 
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate  * RDMA wait variables.
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate static kcondvar_t rdma_wait_cv;
2770Sstevel@tonic-gate static kmutex_t rdma_wait_mutex;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate /*
2800Sstevel@tonic-gate  * Will be called at the point the server pool is being unregistered
2810Sstevel@tonic-gate  * from the pool list. From that point onwards, the pool is waiting
2820Sstevel@tonic-gate  * to be drained and as such the server state is stale and pertains
2830Sstevel@tonic-gate  * to the old instantiation of the NFS server pool.
2840Sstevel@tonic-gate  */
2850Sstevel@tonic-gate void
nfs_srv_offline(void)2860Sstevel@tonic-gate nfs_srv_offline(void)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	mutex_enter(&nfs_server_upordown_lock);
2890Sstevel@tonic-gate 	if (nfs_server_upordown == NFS_SERVER_RUNNING) {
2900Sstevel@tonic-gate 		nfs_server_upordown = NFS_SERVER_OFFLINE;
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 	mutex_exit(&nfs_server_upordown_lock);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate  * Will be called at the point the server pool is being destroyed so
2970Sstevel@tonic-gate  * all transports have been closed and no service threads are in
2980Sstevel@tonic-gate  * existence.
2990Sstevel@tonic-gate  *
3000Sstevel@tonic-gate  * If we quiesce the server, we're shutting it down without destroying the
3010Sstevel@tonic-gate  * server state. This allows it to warm start subsequently.
3020Sstevel@tonic-gate  */
3030Sstevel@tonic-gate void
nfs_srv_stop_all(void)3040Sstevel@tonic-gate nfs_srv_stop_all(void)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate 	int quiesce = 0;
3070Sstevel@tonic-gate 	nfs_srv_shutdown_all(quiesce);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate  * This alternative shutdown routine can be requested via nfssys()
3120Sstevel@tonic-gate  */
3130Sstevel@tonic-gate void
nfs_srv_quiesce_all(void)3140Sstevel@tonic-gate nfs_srv_quiesce_all(void)
3150Sstevel@tonic-gate {
3160Sstevel@tonic-gate 	int quiesce = 1;
3170Sstevel@tonic-gate 	nfs_srv_shutdown_all(quiesce);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate static void
nfs_srv_shutdown_all(int quiesce)3210Sstevel@tonic-gate nfs_srv_shutdown_all(int quiesce) {
3220Sstevel@tonic-gate 	mutex_enter(&nfs_server_upordown_lock);
3230Sstevel@tonic-gate 	if (quiesce) {
3240Sstevel@tonic-gate 		if (nfs_server_upordown == NFS_SERVER_RUNNING ||
3250Sstevel@tonic-gate 			nfs_server_upordown == NFS_SERVER_OFFLINE) {
3260Sstevel@tonic-gate 			nfs_server_upordown = NFS_SERVER_QUIESCED;
3270Sstevel@tonic-gate 			cv_signal(&nfs_server_upordown_cv);
3282035Scalum 
3292035Scalum 			/* reset DSS state, for subsequent warm restart */
3302035Scalum 			rfs4_dss_numnewpaths = 0;
3312035Scalum 			rfs4_dss_newpaths = NULL;
3322035Scalum 
3330Sstevel@tonic-gate 			cmn_err(CE_NOTE, "nfs_server: server is now quiesced; "
3340Sstevel@tonic-gate 			    "NFSv4 state has been preserved");
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 	} else {
3370Sstevel@tonic-gate 		if (nfs_server_upordown == NFS_SERVER_OFFLINE) {
3380Sstevel@tonic-gate 			nfs_server_upordown = NFS_SERVER_STOPPING;
3390Sstevel@tonic-gate 			mutex_exit(&nfs_server_upordown_lock);
3400Sstevel@tonic-gate 			rfs4_state_fini();
34174Srg137905 			rfs4_fini_drc(nfs4_drc);
3420Sstevel@tonic-gate 			mutex_enter(&nfs_server_upordown_lock);
3430Sstevel@tonic-gate 			nfs_server_upordown = NFS_SERVER_STOPPED;
3440Sstevel@tonic-gate 			cv_signal(&nfs_server_upordown_cv);
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	mutex_exit(&nfs_server_upordown_lock);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate static int
nfs_srv_set_sc_versions(struct file * fp,SVC_CALLOUT_TABLE ** sctpp,rpcvers_t versmin,rpcvers_t versmax)3510Sstevel@tonic-gate nfs_srv_set_sc_versions(struct file *fp, SVC_CALLOUT_TABLE **sctpp,
3520Sstevel@tonic-gate 			rpcvers_t versmin, rpcvers_t versmax)
3530Sstevel@tonic-gate {
3540Sstevel@tonic-gate 	struct strioctl strioc;
3550Sstevel@tonic-gate 	struct T_info_ack tinfo;
3560Sstevel@tonic-gate 	int		error, retval;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/*
3590Sstevel@tonic-gate 	 * Find out what type of transport this is.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	strioc.ic_cmd = TI_GETINFO;
3620Sstevel@tonic-gate 	strioc.ic_timout = -1;
3630Sstevel@tonic-gate 	strioc.ic_len = sizeof (tinfo);
3640Sstevel@tonic-gate 	strioc.ic_dp = (char *)&tinfo;
3650Sstevel@tonic-gate 	tinfo.PRIM_type = T_INFO_REQ;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
3680Sstevel@tonic-gate 	    CRED(), &retval);
3690Sstevel@tonic-gate 	if (error || retval)
3700Sstevel@tonic-gate 		return (error);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	/*
3730Sstevel@tonic-gate 	 * Based on our query of the transport type...
3740Sstevel@tonic-gate 	 *
3750Sstevel@tonic-gate 	 * Reset the min/max versions based on the caller's request
3760Sstevel@tonic-gate 	 * NOTE: This assumes that NFS_PROGRAM is first in the array!!
3770Sstevel@tonic-gate 	 * And the second entry is the NFS_ACL_PROGRAM.
3780Sstevel@tonic-gate 	 */
3790Sstevel@tonic-gate 	switch (tinfo.SERV_type) {
3800Sstevel@tonic-gate 	case T_CLTS:
3810Sstevel@tonic-gate 		if (versmax == NFS_V4)
3820Sstevel@tonic-gate 			return (EINVAL);
3830Sstevel@tonic-gate 		__nfs_sc_clts[0].sc_versmin = versmin;
3840Sstevel@tonic-gate 		__nfs_sc_clts[0].sc_versmax = versmax;
3850Sstevel@tonic-gate 		__nfs_sc_clts[1].sc_versmin = versmin;
3860Sstevel@tonic-gate 		__nfs_sc_clts[1].sc_versmax = versmax;
3870Sstevel@tonic-gate 		*sctpp = &nfs_sct_clts;
3880Sstevel@tonic-gate 		break;
3890Sstevel@tonic-gate 	case T_COTS:
3900Sstevel@tonic-gate 	case T_COTS_ORD:
3910Sstevel@tonic-gate 		__nfs_sc_cots[0].sc_versmin = versmin;
3920Sstevel@tonic-gate 		__nfs_sc_cots[0].sc_versmax = versmax;
3930Sstevel@tonic-gate 		/* For the NFS_ACL program, check the max version */
3940Sstevel@tonic-gate 		if (versmax > NFS_ACL_VERSMAX)
3950Sstevel@tonic-gate 			versmax = NFS_ACL_VERSMAX;
3960Sstevel@tonic-gate 		__nfs_sc_cots[1].sc_versmin = versmin;
3970Sstevel@tonic-gate 		__nfs_sc_cots[1].sc_versmax = versmax;
3980Sstevel@tonic-gate 		*sctpp = &nfs_sct_cots;
3990Sstevel@tonic-gate 		break;
4000Sstevel@tonic-gate 	default:
4010Sstevel@tonic-gate 		error = EINVAL;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	return (error);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate /*
4080Sstevel@tonic-gate  * NFS Server system call.
4090Sstevel@tonic-gate  * Does all of the work of running a NFS server.
4100Sstevel@tonic-gate  * uap->fd is the fd of an open transport provider
4110Sstevel@tonic-gate  */
4120Sstevel@tonic-gate int
nfs_svc(struct nfs_svc_args * arg,model_t model)4130Sstevel@tonic-gate nfs_svc(struct nfs_svc_args *arg, model_t model)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	file_t *fp;
4160Sstevel@tonic-gate 	SVCMASTERXPRT *xprt;
4170Sstevel@tonic-gate 	int error;
4180Sstevel@tonic-gate 	int readsize;
4190Sstevel@tonic-gate 	char buf[KNC_STRSIZE];
4200Sstevel@tonic-gate 	size_t len;
4210Sstevel@tonic-gate 	STRUCT_HANDLE(nfs_svc_args, uap);
4220Sstevel@tonic-gate 	struct netbuf addrmask;
4230Sstevel@tonic-gate 	SVC_CALLOUT_TABLE *sctp = NULL;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate #ifdef lint
4260Sstevel@tonic-gate 	model = model;		/* STRUCT macros don't always refer to it */
4270Sstevel@tonic-gate #endif
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	STRUCT_SET_HANDLE(uap, model, arg);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/* Check privileges in nfssys() */
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if ((fp = getf(STRUCT_FGET(uap, fd))) == NULL)
4340Sstevel@tonic-gate 		return (EBADF);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * Set read buffer size to rsize
4380Sstevel@tonic-gate 	 * and add room for RPC headers.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	readsize = nfs3tsize() + (RPC_MAXDATASIZE - NFS_MAXDATA);
4410Sstevel@tonic-gate 	if (readsize < RPC_MAXDATASIZE)
4420Sstevel@tonic-gate 		readsize = RPC_MAXDATASIZE;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	error = copyinstr((const char *)STRUCT_FGETP(uap, netid), buf,
4450Sstevel@tonic-gate 	    KNC_STRSIZE, &len);
4460Sstevel@tonic-gate 	if (error) {
4470Sstevel@tonic-gate 		releasef(STRUCT_FGET(uap, fd));
4480Sstevel@tonic-gate 		return (error);
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	addrmask.len = STRUCT_FGET(uap, addrmask.len);
4520Sstevel@tonic-gate 	addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen);
4530Sstevel@tonic-gate 	addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP);
4540Sstevel@tonic-gate 	error = copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf,
4550Sstevel@tonic-gate 	    addrmask.len);
4560Sstevel@tonic-gate 	if (error) {
4570Sstevel@tonic-gate 		releasef(STRUCT_FGET(uap, fd));
4580Sstevel@tonic-gate 		kmem_free(addrmask.buf, addrmask.maxlen);
4590Sstevel@tonic-gate 		return (error);
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	nfs_versmin = STRUCT_FGET(uap, versmin);
4630Sstevel@tonic-gate 	nfs_versmax = STRUCT_FGET(uap, versmax);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/* Double check the vers min/max ranges */
4660Sstevel@tonic-gate 	if ((nfs_versmin > nfs_versmax) ||
4677961SNatalie.Li@Sun.COM 	    (nfs_versmin < NFS_VERSMIN) ||
4687961SNatalie.Li@Sun.COM 	    (nfs_versmax > NFS_VERSMAX)) {
4690Sstevel@tonic-gate 		nfs_versmin = NFS_VERSMIN_DEFAULT;
4700Sstevel@tonic-gate 		nfs_versmax = NFS_VERSMAX_DEFAULT;
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if (error =
4740Sstevel@tonic-gate 	    nfs_srv_set_sc_versions(fp, &sctp, nfs_versmin, nfs_versmax)) {
4750Sstevel@tonic-gate 		releasef(STRUCT_FGET(uap, fd));
4760Sstevel@tonic-gate 		kmem_free(addrmask.buf, addrmask.maxlen);
4770Sstevel@tonic-gate 		return (error);
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	/* Initialize nfsv4 server */
4810Sstevel@tonic-gate 	if (nfs_versmax == (rpcvers_t)NFS_V4)
4820Sstevel@tonic-gate 		rfs4_server_start(STRUCT_FGET(uap, delegation));
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/* Create a transport handle. */
4850Sstevel@tonic-gate 	error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt,
4867961SNatalie.Li@Sun.COM 	    sctp, NULL, NFS_SVCPOOL_ID, TRUE);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	if (error)
4890Sstevel@tonic-gate 		kmem_free(addrmask.buf, addrmask.maxlen);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	releasef(STRUCT_FGET(uap, fd));
4920Sstevel@tonic-gate 
4932035Scalum 	/* HA-NFSv4: save the cluster nodeid */
4940Sstevel@tonic-gate 	if (cluster_bootflags & CLUSTER_BOOTED)
4950Sstevel@tonic-gate 		lm_global_nlmid = clconf_get_nodeid();
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	return (error);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate static void
rfs4_server_start(int nfs4_srv_delegation)5010Sstevel@tonic-gate rfs4_server_start(int nfs4_srv_delegation)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	/*
5040Sstevel@tonic-gate 	 * Determine if the server has previously been "started" and
5050Sstevel@tonic-gate 	 * if not, do the per instance initialization
5060Sstevel@tonic-gate 	 */
5070Sstevel@tonic-gate 	mutex_enter(&nfs_server_upordown_lock);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (nfs_server_upordown != NFS_SERVER_RUNNING) {
5100Sstevel@tonic-gate 		/* Do we need to stop and wait on the previous server? */
5110Sstevel@tonic-gate 		while (nfs_server_upordown == NFS_SERVER_STOPPING ||
5127961SNatalie.Li@Sun.COM 		    nfs_server_upordown == NFS_SERVER_OFFLINE)
5130Sstevel@tonic-gate 			cv_wait(&nfs_server_upordown_cv,
5140Sstevel@tonic-gate 			    &nfs_server_upordown_lock);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		if (nfs_server_upordown != NFS_SERVER_RUNNING) {
5170Sstevel@tonic-gate 			(void) svc_pool_control(NFS_SVCPOOL_ID,
5180Sstevel@tonic-gate 			    SVCPSET_UNREGISTER_PROC, (void *)&nfs_srv_offline);
5190Sstevel@tonic-gate 			(void) svc_pool_control(NFS_SVCPOOL_ID,
5200Sstevel@tonic-gate 			    SVCPSET_SHUTDOWN_PROC, (void *)&nfs_srv_stop_all);
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 			/* is this an nfsd warm start? */
5230Sstevel@tonic-gate 			if (nfs_server_upordown == NFS_SERVER_QUIESCED) {
5240Sstevel@tonic-gate 				cmn_err(CE_NOTE, "nfs_server: "
5250Sstevel@tonic-gate 				    "server was previously quiesced; "
5260Sstevel@tonic-gate 				    "existing NFSv4 state will be re-used");
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 				/*
5292035Scalum 				 * HA-NFSv4: this is also the signal
5302035Scalum 				 * that a Resource Group failover has
5312035Scalum 				 * occurred.
5320Sstevel@tonic-gate 				 */
5332390Scalum 				if (cluster_bootflags & CLUSTER_BOOTED)
5342035Scalum 					hanfsv4_failover();
5350Sstevel@tonic-gate 			} else {
5362035Scalum 				/* cold start */
5370Sstevel@tonic-gate 				rfs4_state_init();
53874Srg137905 				nfs4_drc = rfs4_init_drc(nfs4_drc_max,
5397961SNatalie.Li@Sun.COM 				    nfs4_drc_hash);
5400Sstevel@tonic-gate 			}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 			/*
5430Sstevel@tonic-gate 			 * Check to see if delegation is to be
5440Sstevel@tonic-gate 			 * enabled at the server
5450Sstevel@tonic-gate 			 */
5460Sstevel@tonic-gate 			if (nfs4_srv_delegation != FALSE)
5470Sstevel@tonic-gate 				rfs4_set_deleg_policy(SRV_NORMAL_DELEGATE);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 			nfs_server_upordown = NFS_SERVER_RUNNING;
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 		cv_signal(&nfs_server_upordown_cv);
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 	mutex_exit(&nfs_server_upordown_lock);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate /*
5570Sstevel@tonic-gate  * If RDMA device available,
5580Sstevel@tonic-gate  * start RDMA listener.
5590Sstevel@tonic-gate  */
5600Sstevel@tonic-gate int
rdma_start(struct rdma_svc_args * rsa)5610Sstevel@tonic-gate rdma_start(struct rdma_svc_args *rsa)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	int error;
5640Sstevel@tonic-gate 	rdma_xprt_group_t started_rdma_xprts;
5658695SRajkumar.Sivaprakasam@Sun.COM 	rdma_stat stat;
5668695SRajkumar.Sivaprakasam@Sun.COM 	int svc_state = 0;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	/* Double check the vers min/max ranges */
5690Sstevel@tonic-gate 	if ((rsa->nfs_versmin > rsa->nfs_versmax) ||
5707961SNatalie.Li@Sun.COM 	    (rsa->nfs_versmin < NFS_VERSMIN) ||
5717961SNatalie.Li@Sun.COM 	    (rsa->nfs_versmax > NFS_VERSMAX)) {
5720Sstevel@tonic-gate 		rsa->nfs_versmin = NFS_VERSMIN_DEFAULT;
5730Sstevel@tonic-gate 		rsa->nfs_versmax = NFS_VERSMAX_DEFAULT;
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 	nfs_versmin = rsa->nfs_versmin;
5760Sstevel@tonic-gate 	nfs_versmax = rsa->nfs_versmax;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/* Set the versions in the callout table */
5790Sstevel@tonic-gate 	__nfs_sc_rdma[0].sc_versmin = rsa->nfs_versmin;
5800Sstevel@tonic-gate 	__nfs_sc_rdma[0].sc_versmax = rsa->nfs_versmax;
5810Sstevel@tonic-gate 	/* For the NFS_ACL program, check the max version */
5820Sstevel@tonic-gate 	__nfs_sc_rdma[1].sc_versmin = rsa->nfs_versmin;
5830Sstevel@tonic-gate 	if (rsa->nfs_versmax > NFS_ACL_VERSMAX)
5840Sstevel@tonic-gate 		__nfs_sc_rdma[1].sc_versmax = NFS_ACL_VERSMAX;
5850Sstevel@tonic-gate 	else
5860Sstevel@tonic-gate 		__nfs_sc_rdma[1].sc_versmax = rsa->nfs_versmax;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	/* Initialize nfsv4 server */
5890Sstevel@tonic-gate 	if (rsa->nfs_versmax == (rpcvers_t)NFS_V4)
5900Sstevel@tonic-gate 		rfs4_server_start(rsa->delegation);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	started_rdma_xprts.rtg_count = 0;
5930Sstevel@tonic-gate 	started_rdma_xprts.rtg_listhead = NULL;
5940Sstevel@tonic-gate 	started_rdma_xprts.rtg_poolid = rsa->poolid;
5958695SRajkumar.Sivaprakasam@Sun.COM 
5968695SRajkumar.Sivaprakasam@Sun.COM restart:
5970Sstevel@tonic-gate 	error = svc_rdma_kcreate(rsa->netid, &nfs_sct_rdma, rsa->poolid,
5980Sstevel@tonic-gate 	    &started_rdma_xprts);
5990Sstevel@tonic-gate 
6008695SRajkumar.Sivaprakasam@Sun.COM 	svc_state = !error;
6018695SRajkumar.Sivaprakasam@Sun.COM 
6028695SRajkumar.Sivaprakasam@Sun.COM 	while (!error) {
6038695SRajkumar.Sivaprakasam@Sun.COM 
6048695SRajkumar.Sivaprakasam@Sun.COM 		/*
6058695SRajkumar.Sivaprakasam@Sun.COM 		 * wait till either interrupted by a signal on
6068695SRajkumar.Sivaprakasam@Sun.COM 		 * nfs service stop/restart or signalled by a
6078695SRajkumar.Sivaprakasam@Sun.COM 		 * rdma plugin attach/detatch.
6088695SRajkumar.Sivaprakasam@Sun.COM 		 */
6098695SRajkumar.Sivaprakasam@Sun.COM 
6108695SRajkumar.Sivaprakasam@Sun.COM 		stat = rdma_kwait();
6118695SRajkumar.Sivaprakasam@Sun.COM 
6128695SRajkumar.Sivaprakasam@Sun.COM 		/*
6138695SRajkumar.Sivaprakasam@Sun.COM 		 * stop services if running -- either on a HCA detach event
6148695SRajkumar.Sivaprakasam@Sun.COM 		 * or if the nfs service is stopped/restarted.
6158695SRajkumar.Sivaprakasam@Sun.COM 		 */
6168695SRajkumar.Sivaprakasam@Sun.COM 
6178695SRajkumar.Sivaprakasam@Sun.COM 		if ((stat == RDMA_HCA_DETACH || stat == RDMA_INTR) &&
6188695SRajkumar.Sivaprakasam@Sun.COM 		    svc_state) {
6198695SRajkumar.Sivaprakasam@Sun.COM 			rdma_stop(&started_rdma_xprts);
6208695SRajkumar.Sivaprakasam@Sun.COM 			svc_state = 0;
6210Sstevel@tonic-gate 		}
6228695SRajkumar.Sivaprakasam@Sun.COM 
6238695SRajkumar.Sivaprakasam@Sun.COM 		/*
6248695SRajkumar.Sivaprakasam@Sun.COM 		 * nfs service stop/restart, break out of the
6258695SRajkumar.Sivaprakasam@Sun.COM 		 * wait loop and return;
6268695SRajkumar.Sivaprakasam@Sun.COM 		 */
6278695SRajkumar.Sivaprakasam@Sun.COM 		if (stat == RDMA_INTR)
6288695SRajkumar.Sivaprakasam@Sun.COM 			return (0);
6298695SRajkumar.Sivaprakasam@Sun.COM 
6308695SRajkumar.Sivaprakasam@Sun.COM 		/*
6318695SRajkumar.Sivaprakasam@Sun.COM 		 * restart stopped services on a HCA attach event
6328695SRajkumar.Sivaprakasam@Sun.COM 		 * (if not already running)
6338695SRajkumar.Sivaprakasam@Sun.COM 		 */
6348695SRajkumar.Sivaprakasam@Sun.COM 
6358695SRajkumar.Sivaprakasam@Sun.COM 		if ((stat == RDMA_HCA_ATTACH) && (svc_state == 0))
6368695SRajkumar.Sivaprakasam@Sun.COM 			goto restart;
6378695SRajkumar.Sivaprakasam@Sun.COM 
6388695SRajkumar.Sivaprakasam@Sun.COM 		/*
6398695SRajkumar.Sivaprakasam@Sun.COM 		 * loop until a nfs service stop/restart
6408695SRajkumar.Sivaprakasam@Sun.COM 		 */
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	return (error);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate /* ARGSUSED */
64774Srg137905 void
rpc_null(caddr_t * argp,caddr_t * resp)6480Sstevel@tonic-gate rpc_null(caddr_t *argp, caddr_t *resp)
6490Sstevel@tonic-gate {
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate /* ARGSUSED */
6535982Sahl void
rpc_null_v3(caddr_t * argp,caddr_t * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)6545982Sahl rpc_null_v3(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
6555982Sahl     struct svc_req *req, cred_t *cr)
6565982Sahl {
6575982Sahl 	DTRACE_NFSV3_3(op__null__start, struct svc_req *, req,
6585982Sahl 	    cred_t *, cr, vnode_t *, NULL);
6595982Sahl 	DTRACE_NFSV3_3(op__null__done, struct svc_req *, req,
6605982Sahl 	    cred_t *, cr, vnode_t *, NULL);
6615982Sahl }
6625982Sahl 
6635982Sahl /* ARGSUSED */
6640Sstevel@tonic-gate static void
rfs_error(caddr_t * argp,caddr_t * resp)6650Sstevel@tonic-gate rfs_error(caddr_t *argp, caddr_t *resp)
6660Sstevel@tonic-gate {
6670Sstevel@tonic-gate 	/* return (EOPNOTSUPP); */
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate static void
nullfree(void)6710Sstevel@tonic-gate nullfree(void)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate static char *rfscallnames_v2[] = {
6760Sstevel@tonic-gate 	"RFS2_NULL",
6770Sstevel@tonic-gate 	"RFS2_GETATTR",
6780Sstevel@tonic-gate 	"RFS2_SETATTR",
6790Sstevel@tonic-gate 	"RFS2_ROOT",
6800Sstevel@tonic-gate 	"RFS2_LOOKUP",
6810Sstevel@tonic-gate 	"RFS2_READLINK",
6820Sstevel@tonic-gate 	"RFS2_READ",
6830Sstevel@tonic-gate 	"RFS2_WRITECACHE",
6840Sstevel@tonic-gate 	"RFS2_WRITE",
6850Sstevel@tonic-gate 	"RFS2_CREATE",
6860Sstevel@tonic-gate 	"RFS2_REMOVE",
6870Sstevel@tonic-gate 	"RFS2_RENAME",
6880Sstevel@tonic-gate 	"RFS2_LINK",
6890Sstevel@tonic-gate 	"RFS2_SYMLINK",
6900Sstevel@tonic-gate 	"RFS2_MKDIR",
6910Sstevel@tonic-gate 	"RFS2_RMDIR",
6920Sstevel@tonic-gate 	"RFS2_READDIR",
6930Sstevel@tonic-gate 	"RFS2_STATFS"
6940Sstevel@tonic-gate };
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate static struct rpcdisp rfsdisptab_v2[] = {
6970Sstevel@tonic-gate 	/*
6980Sstevel@tonic-gate 	 * NFS VERSION 2
6990Sstevel@tonic-gate 	 */
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	/* RFS_NULL = 0 */
7020Sstevel@tonic-gate 	{rpc_null,
7030Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7040Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7050Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
70674Srg137905 	    0},
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
7090Sstevel@tonic-gate 	{rfs_getattr,
7100Sstevel@tonic-gate 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
7110Sstevel@tonic-gate 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
7120Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
71374Srg137905 	    rfs_getattr_getfh},
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
7160Sstevel@tonic-gate 	{rfs_setattr,
7170Sstevel@tonic-gate 	    xdr_saargs, NULL_xdrproc_t, sizeof (struct nfssaargs),
7180Sstevel@tonic-gate 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
7190Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
72074Srg137905 	    rfs_setattr_getfh},
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
7230Sstevel@tonic-gate 	{rfs_error,
7240Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7250Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7260Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
72774Srg137905 	    0},
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
7300Sstevel@tonic-gate 	{rfs_lookup,
7310Sstevel@tonic-gate 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
7320Sstevel@tonic-gate 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
7330Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP|RPC_PUBLICFH_OK,
73474Srg137905 	    rfs_lookup_getfh},
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
7370Sstevel@tonic-gate 	{rfs_readlink,
7380Sstevel@tonic-gate 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
7390Sstevel@tonic-gate 	    xdr_rdlnres, NULL_xdrproc_t, sizeof (struct nfsrdlnres),
7400Sstevel@tonic-gate 	    rfs_rlfree, RPC_IDEMPOTENT,
74174Srg137905 	    rfs_readlink_getfh},
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	/* RFS_READ = 6 */
7440Sstevel@tonic-gate 	{rfs_read,
7450Sstevel@tonic-gate 	    xdr_readargs, NULL_xdrproc_t, sizeof (struct nfsreadargs),
7460Sstevel@tonic-gate 	    xdr_rdresult, NULL_xdrproc_t, sizeof (struct nfsrdresult),
7470Sstevel@tonic-gate 	    rfs_rdfree, RPC_IDEMPOTENT,
74874Srg137905 	    rfs_read_getfh},
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
7510Sstevel@tonic-gate 	{rfs_error,
7520Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7530Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7540Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
75574Srg137905 	    0},
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
7580Sstevel@tonic-gate 	{rfs_write,
7590Sstevel@tonic-gate 	    xdr_writeargs, NULL_xdrproc_t, sizeof (struct nfswriteargs),
7600Sstevel@tonic-gate 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
7610Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
76274Srg137905 	    rfs_write_getfh},
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
7650Sstevel@tonic-gate 	{rfs_create,
7660Sstevel@tonic-gate 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
7670Sstevel@tonic-gate 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
7680Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
76974Srg137905 	    rfs_create_getfh},
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
7720Sstevel@tonic-gate 	{rfs_remove,
7730Sstevel@tonic-gate 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
7740Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
7750Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
7760Sstevel@tonic-gate #else
7770Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
7780Sstevel@tonic-gate #endif
7790Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
78074Srg137905 	    rfs_remove_getfh},
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
7830Sstevel@tonic-gate 	{rfs_rename,
7840Sstevel@tonic-gate 	    xdr_rnmargs, NULL_xdrproc_t, sizeof (struct nfsrnmargs),
7850Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
7860Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
7870Sstevel@tonic-gate #else
7880Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
7890Sstevel@tonic-gate #endif
7900Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
79174Srg137905 	    rfs_rename_getfh},
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	/* RFS_LINK = 12 */
7940Sstevel@tonic-gate 	{rfs_link,
7950Sstevel@tonic-gate 	    xdr_linkargs, NULL_xdrproc_t, sizeof (struct nfslinkargs),
7960Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
7970Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
7980Sstevel@tonic-gate #else
7990Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
8000Sstevel@tonic-gate #endif
8010Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
80274Srg137905 	    rfs_link_getfh},
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
8050Sstevel@tonic-gate 	{rfs_symlink,
8060Sstevel@tonic-gate 	    xdr_slargs, NULL_xdrproc_t, sizeof (struct nfsslargs),
8070Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
8080Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
8090Sstevel@tonic-gate #else
8100Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
8110Sstevel@tonic-gate #endif
8120Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
81374Srg137905 	    rfs_symlink_getfh},
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
8160Sstevel@tonic-gate 	{rfs_mkdir,
8170Sstevel@tonic-gate 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
8180Sstevel@tonic-gate 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
8190Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
82074Srg137905 	    rfs_mkdir_getfh},
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
8230Sstevel@tonic-gate 	{rfs_rmdir,
8240Sstevel@tonic-gate 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
8250Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
8260Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
8270Sstevel@tonic-gate #else
8280Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
8290Sstevel@tonic-gate #endif
8300Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
83174Srg137905 	    rfs_rmdir_getfh},
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
8340Sstevel@tonic-gate 	{rfs_readdir,
8350Sstevel@tonic-gate 	    xdr_rddirargs, NULL_xdrproc_t, sizeof (struct nfsrddirargs),
8360Sstevel@tonic-gate 	    xdr_putrddirres, NULL_xdrproc_t, sizeof (struct nfsrddirres),
8370Sstevel@tonic-gate 	    rfs_rddirfree, RPC_IDEMPOTENT,
83874Srg137905 	    rfs_readdir_getfh},
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
8410Sstevel@tonic-gate 	{rfs_statfs,
8420Sstevel@tonic-gate 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
8430Sstevel@tonic-gate 	    xdr_statfs, xdr_faststatfs, sizeof (struct nfsstatfs),
8440Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
84574Srg137905 	    rfs_statfs_getfh},
8460Sstevel@tonic-gate };
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate static char *rfscallnames_v3[] = {
8490Sstevel@tonic-gate 	"RFS3_NULL",
8500Sstevel@tonic-gate 	"RFS3_GETATTR",
8510Sstevel@tonic-gate 	"RFS3_SETATTR",
8520Sstevel@tonic-gate 	"RFS3_LOOKUP",
8530Sstevel@tonic-gate 	"RFS3_ACCESS",
8540Sstevel@tonic-gate 	"RFS3_READLINK",
8550Sstevel@tonic-gate 	"RFS3_READ",
8560Sstevel@tonic-gate 	"RFS3_WRITE",
8570Sstevel@tonic-gate 	"RFS3_CREATE",
8580Sstevel@tonic-gate 	"RFS3_MKDIR",
8590Sstevel@tonic-gate 	"RFS3_SYMLINK",
8600Sstevel@tonic-gate 	"RFS3_MKNOD",
8610Sstevel@tonic-gate 	"RFS3_REMOVE",
8620Sstevel@tonic-gate 	"RFS3_RMDIR",
8630Sstevel@tonic-gate 	"RFS3_RENAME",
8640Sstevel@tonic-gate 	"RFS3_LINK",
8650Sstevel@tonic-gate 	"RFS3_READDIR",
8660Sstevel@tonic-gate 	"RFS3_READDIRPLUS",
8670Sstevel@tonic-gate 	"RFS3_FSSTAT",
8680Sstevel@tonic-gate 	"RFS3_FSINFO",
8690Sstevel@tonic-gate 	"RFS3_PATHCONF",
8700Sstevel@tonic-gate 	"RFS3_COMMIT"
8710Sstevel@tonic-gate };
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate static struct rpcdisp rfsdisptab_v3[] = {
8740Sstevel@tonic-gate 	/*
8750Sstevel@tonic-gate 	 * NFS VERSION 3
8760Sstevel@tonic-gate 	 */
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/* RFS_NULL = 0 */
8795982Sahl 	{rpc_null_v3,
8800Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
8810Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
8820Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
88374Srg137905 	    0},
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/* RFS3_GETATTR = 1 */
8860Sstevel@tonic-gate 	{rfs3_getattr,
8871610Sthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (GETATTR3args),
8880Sstevel@tonic-gate 	    xdr_GETATTR3res, NULL_xdrproc_t, sizeof (GETATTR3res),
8890Sstevel@tonic-gate 	    nullfree, (RPC_IDEMPOTENT | RPC_ALLOWANON),
89074Srg137905 	    rfs3_getattr_getfh},
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	/* RFS3_SETATTR = 2 */
8930Sstevel@tonic-gate 	{rfs3_setattr,
8940Sstevel@tonic-gate 	    xdr_SETATTR3args, NULL_xdrproc_t, sizeof (SETATTR3args),
8950Sstevel@tonic-gate 	    xdr_SETATTR3res, NULL_xdrproc_t, sizeof (SETATTR3res),
8960Sstevel@tonic-gate 	    nullfree, 0,
89774Srg137905 	    rfs3_setattr_getfh},
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	/* RFS3_LOOKUP = 3 */
9000Sstevel@tonic-gate 	{rfs3_lookup,
9010Sstevel@tonic-gate 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (LOOKUP3args),
9020Sstevel@tonic-gate 	    xdr_LOOKUP3res, NULL_xdrproc_t, sizeof (LOOKUP3res),
9030Sstevel@tonic-gate 	    nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
90474Srg137905 	    rfs3_lookup_getfh},
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	/* RFS3_ACCESS = 4 */
9070Sstevel@tonic-gate 	{rfs3_access,
9080Sstevel@tonic-gate 	    xdr_ACCESS3args, NULL_xdrproc_t, sizeof (ACCESS3args),
9090Sstevel@tonic-gate 	    xdr_ACCESS3res, NULL_xdrproc_t, sizeof (ACCESS3res),
9100Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
91174Srg137905 	    rfs3_access_getfh},
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/* RFS3_READLINK = 5 */
9140Sstevel@tonic-gate 	{rfs3_readlink,
9151610Sthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (READLINK3args),
9160Sstevel@tonic-gate 	    xdr_READLINK3res, NULL_xdrproc_t, sizeof (READLINK3res),
9170Sstevel@tonic-gate 	    rfs3_readlink_free, RPC_IDEMPOTENT,
91874Srg137905 	    rfs3_readlink_getfh},
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	/* RFS3_READ = 6 */
9210Sstevel@tonic-gate 	{rfs3_read,
9220Sstevel@tonic-gate 	    xdr_READ3args, NULL_xdrproc_t, sizeof (READ3args),
9230Sstevel@tonic-gate 	    xdr_READ3res, NULL_xdrproc_t, sizeof (READ3res),
9240Sstevel@tonic-gate 	    rfs3_read_free, RPC_IDEMPOTENT,
92574Srg137905 	    rfs3_read_getfh},
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/* RFS3_WRITE = 7 */
9280Sstevel@tonic-gate 	{rfs3_write,
9290Sstevel@tonic-gate 	    xdr_WRITE3args, NULL_xdrproc_t, sizeof (WRITE3args),
9300Sstevel@tonic-gate 	    xdr_WRITE3res, NULL_xdrproc_t, sizeof (WRITE3res),
9310Sstevel@tonic-gate 	    nullfree, 0,
93274Srg137905 	    rfs3_write_getfh},
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	/* RFS3_CREATE = 8 */
9350Sstevel@tonic-gate 	{rfs3_create,
9360Sstevel@tonic-gate 	    xdr_CREATE3args, NULL_xdrproc_t, sizeof (CREATE3args),
9370Sstevel@tonic-gate 	    xdr_CREATE3res, NULL_xdrproc_t, sizeof (CREATE3res),
9380Sstevel@tonic-gate 	    nullfree, 0,
93974Srg137905 	    rfs3_create_getfh},
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/* RFS3_MKDIR = 9 */
9420Sstevel@tonic-gate 	{rfs3_mkdir,
9430Sstevel@tonic-gate 	    xdr_MKDIR3args, NULL_xdrproc_t, sizeof (MKDIR3args),
9440Sstevel@tonic-gate 	    xdr_MKDIR3res, NULL_xdrproc_t, sizeof (MKDIR3res),
9450Sstevel@tonic-gate 	    nullfree, 0,
94674Srg137905 	    rfs3_mkdir_getfh},
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/* RFS3_SYMLINK = 10 */
9490Sstevel@tonic-gate 	{rfs3_symlink,
9500Sstevel@tonic-gate 	    xdr_SYMLINK3args, NULL_xdrproc_t, sizeof (SYMLINK3args),
9510Sstevel@tonic-gate 	    xdr_SYMLINK3res, NULL_xdrproc_t, sizeof (SYMLINK3res),
9520Sstevel@tonic-gate 	    nullfree, 0,
95374Srg137905 	    rfs3_symlink_getfh},
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	/* RFS3_MKNOD = 11 */
9560Sstevel@tonic-gate 	{rfs3_mknod,
9570Sstevel@tonic-gate 	    xdr_MKNOD3args, NULL_xdrproc_t, sizeof (MKNOD3args),
9580Sstevel@tonic-gate 	    xdr_MKNOD3res, NULL_xdrproc_t, sizeof (MKNOD3res),
9590Sstevel@tonic-gate 	    nullfree, 0,
96074Srg137905 	    rfs3_mknod_getfh},
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	/* RFS3_REMOVE = 12 */
9630Sstevel@tonic-gate 	{rfs3_remove,
9640Sstevel@tonic-gate 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (REMOVE3args),
9650Sstevel@tonic-gate 	    xdr_REMOVE3res, NULL_xdrproc_t, sizeof (REMOVE3res),
9660Sstevel@tonic-gate 	    nullfree, 0,
96774Srg137905 	    rfs3_remove_getfh},
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	/* RFS3_RMDIR = 13 */
9700Sstevel@tonic-gate 	{rfs3_rmdir,
9710Sstevel@tonic-gate 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (RMDIR3args),
9720Sstevel@tonic-gate 	    xdr_RMDIR3res, NULL_xdrproc_t, sizeof (RMDIR3res),
9730Sstevel@tonic-gate 	    nullfree, 0,
97474Srg137905 	    rfs3_rmdir_getfh},
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	/* RFS3_RENAME = 14 */
9770Sstevel@tonic-gate 	{rfs3_rename,
9780Sstevel@tonic-gate 	    xdr_RENAME3args, NULL_xdrproc_t, sizeof (RENAME3args),
9790Sstevel@tonic-gate 	    xdr_RENAME3res, NULL_xdrproc_t, sizeof (RENAME3res),
9800Sstevel@tonic-gate 	    nullfree, 0,
98174Srg137905 	    rfs3_rename_getfh},
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	/* RFS3_LINK = 15 */
9840Sstevel@tonic-gate 	{rfs3_link,
9850Sstevel@tonic-gate 	    xdr_LINK3args, NULL_xdrproc_t, sizeof (LINK3args),
9860Sstevel@tonic-gate 	    xdr_LINK3res, NULL_xdrproc_t, sizeof (LINK3res),
9870Sstevel@tonic-gate 	    nullfree, 0,
98874Srg137905 	    rfs3_link_getfh},
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	/* RFS3_READDIR = 16 */
9910Sstevel@tonic-gate 	{rfs3_readdir,
9920Sstevel@tonic-gate 	    xdr_READDIR3args, NULL_xdrproc_t, sizeof (READDIR3args),
9930Sstevel@tonic-gate 	    xdr_READDIR3res, NULL_xdrproc_t, sizeof (READDIR3res),
9940Sstevel@tonic-gate 	    rfs3_readdir_free, RPC_IDEMPOTENT,
99574Srg137905 	    rfs3_readdir_getfh},
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	/* RFS3_READDIRPLUS = 17 */
9980Sstevel@tonic-gate 	{rfs3_readdirplus,
9990Sstevel@tonic-gate 	    xdr_READDIRPLUS3args, NULL_xdrproc_t, sizeof (READDIRPLUS3args),
10000Sstevel@tonic-gate 	    xdr_READDIRPLUS3res, NULL_xdrproc_t, sizeof (READDIRPLUS3res),
10010Sstevel@tonic-gate 	    rfs3_readdirplus_free, RPC_AVOIDWORK,
100274Srg137905 	    rfs3_readdirplus_getfh},
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/* RFS3_FSSTAT = 18 */
10050Sstevel@tonic-gate 	{rfs3_fsstat,
10061610Sthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSSTAT3args),
10070Sstevel@tonic-gate 	    xdr_FSSTAT3res, NULL_xdrproc_t, sizeof (FSSTAT3res),
10080Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
100974Srg137905 	    rfs3_fsstat_getfh},
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	/* RFS3_FSINFO = 19 */
10120Sstevel@tonic-gate 	{rfs3_fsinfo,
10131610Sthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSINFO3args),
10140Sstevel@tonic-gate 	    xdr_FSINFO3res, NULL_xdrproc_t, sizeof (FSINFO3res),
10150Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON,
101674Srg137905 	    rfs3_fsinfo_getfh},
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	/* RFS3_PATHCONF = 20 */
10190Sstevel@tonic-gate 	{rfs3_pathconf,
10201610Sthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (PATHCONF3args),
10210Sstevel@tonic-gate 	    xdr_PATHCONF3res, NULL_xdrproc_t, sizeof (PATHCONF3res),
10220Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
102374Srg137905 	    rfs3_pathconf_getfh},
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	/* RFS3_COMMIT = 21 */
10260Sstevel@tonic-gate 	{rfs3_commit,
10270Sstevel@tonic-gate 	    xdr_COMMIT3args, NULL_xdrproc_t, sizeof (COMMIT3args),
10280Sstevel@tonic-gate 	    xdr_COMMIT3res, NULL_xdrproc_t, sizeof (COMMIT3res),
10290Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
103074Srg137905 	    rfs3_commit_getfh},
10310Sstevel@tonic-gate };
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate static char *rfscallnames_v4[] = {
10340Sstevel@tonic-gate 	"RFS4_NULL",
10350Sstevel@tonic-gate 	"RFS4_COMPOUND",
10360Sstevel@tonic-gate 	"RFS4_NULL",
10370Sstevel@tonic-gate 	"RFS4_NULL",
10380Sstevel@tonic-gate 	"RFS4_NULL",
10390Sstevel@tonic-gate 	"RFS4_NULL",
10400Sstevel@tonic-gate 	"RFS4_NULL",
10410Sstevel@tonic-gate 	"RFS4_NULL",
10420Sstevel@tonic-gate 	"RFS4_CREATE"
10430Sstevel@tonic-gate };
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate static struct rpcdisp rfsdisptab_v4[] = {
10460Sstevel@tonic-gate 	/*
10470Sstevel@tonic-gate 	 * NFS VERSION 4
10480Sstevel@tonic-gate 	 */
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	/* RFS_NULL = 0 */
10510Sstevel@tonic-gate 	{rpc_null,
10520Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
10530Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
105474Srg137905 	    nullfree, RPC_IDEMPOTENT, 0},
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	/* RFS4_compound = 1 */
10570Sstevel@tonic-gate 	{rfs4_compound,
1058806Sek110237 	    xdr_COMPOUND4args_srv, NULL_xdrproc_t, sizeof (COMPOUND4args),
1059806Sek110237 	    xdr_COMPOUND4res_srv, NULL_xdrproc_t, sizeof (COMPOUND4res),
106074Srg137905 	    rfs4_compound_free, 0, 0},
10610Sstevel@tonic-gate };
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate union rfs_args {
10640Sstevel@tonic-gate 	/*
10650Sstevel@tonic-gate 	 * NFS VERSION 2
10660Sstevel@tonic-gate 	 */
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	/* RFS_NULL = 0 */
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
10710Sstevel@tonic-gate 	fhandle_t nfs2_getattr_args;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
10740Sstevel@tonic-gate 	struct nfssaargs nfs2_setattr_args;
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
10790Sstevel@tonic-gate 	struct nfsdiropargs nfs2_lookup_args;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
10820Sstevel@tonic-gate 	fhandle_t nfs2_readlink_args;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	/* RFS_READ = 6 */
10850Sstevel@tonic-gate 	struct nfsreadargs nfs2_read_args;
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
10900Sstevel@tonic-gate 	struct nfswriteargs nfs2_write_args;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
10930Sstevel@tonic-gate 	struct nfscreatargs nfs2_create_args;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
10960Sstevel@tonic-gate 	struct nfsdiropargs nfs2_remove_args;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
10990Sstevel@tonic-gate 	struct nfsrnmargs nfs2_rename_args;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	/* RFS_LINK = 12 */
11020Sstevel@tonic-gate 	struct nfslinkargs nfs2_link_args;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
11050Sstevel@tonic-gate 	struct nfsslargs nfs2_symlink_args;
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
11080Sstevel@tonic-gate 	struct nfscreatargs nfs2_mkdir_args;
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
11110Sstevel@tonic-gate 	struct nfsdiropargs nfs2_rmdir_args;
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
11140Sstevel@tonic-gate 	struct nfsrddirargs nfs2_readdir_args;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
11170Sstevel@tonic-gate 	fhandle_t nfs2_statfs_args;
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/*
11200Sstevel@tonic-gate 	 * NFS VERSION 3
11210Sstevel@tonic-gate 	 */
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	/* RFS_NULL = 0 */
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	/* RFS3_GETATTR = 1 */
11260Sstevel@tonic-gate 	GETATTR3args nfs3_getattr_args;
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	/* RFS3_SETATTR = 2 */
11290Sstevel@tonic-gate 	SETATTR3args nfs3_setattr_args;
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	/* RFS3_LOOKUP = 3 */
11320Sstevel@tonic-gate 	LOOKUP3args nfs3_lookup_args;
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	/* RFS3_ACCESS = 4 */
11350Sstevel@tonic-gate 	ACCESS3args nfs3_access_args;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	/* RFS3_READLINK = 5 */
11380Sstevel@tonic-gate 	READLINK3args nfs3_readlink_args;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	/* RFS3_READ = 6 */
11410Sstevel@tonic-gate 	READ3args nfs3_read_args;
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	/* RFS3_WRITE = 7 */
11440Sstevel@tonic-gate 	WRITE3args nfs3_write_args;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	/* RFS3_CREATE = 8 */
11470Sstevel@tonic-gate 	CREATE3args nfs3_create_args;
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	/* RFS3_MKDIR = 9 */
11500Sstevel@tonic-gate 	MKDIR3args nfs3_mkdir_args;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	/* RFS3_SYMLINK = 10 */
11530Sstevel@tonic-gate 	SYMLINK3args nfs3_symlink_args;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/* RFS3_MKNOD = 11 */
11560Sstevel@tonic-gate 	MKNOD3args nfs3_mknod_args;
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	/* RFS3_REMOVE = 12 */
11590Sstevel@tonic-gate 	REMOVE3args nfs3_remove_args;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	/* RFS3_RMDIR = 13 */
11620Sstevel@tonic-gate 	RMDIR3args nfs3_rmdir_args;
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	/* RFS3_RENAME = 14 */
11650Sstevel@tonic-gate 	RENAME3args nfs3_rename_args;
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	/* RFS3_LINK = 15 */
11680Sstevel@tonic-gate 	LINK3args nfs3_link_args;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	/* RFS3_READDIR = 16 */
11710Sstevel@tonic-gate 	READDIR3args nfs3_readdir_args;
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	/* RFS3_READDIRPLUS = 17 */
11740Sstevel@tonic-gate 	READDIRPLUS3args nfs3_readdirplus_args;
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/* RFS3_FSSTAT = 18 */
11770Sstevel@tonic-gate 	FSSTAT3args nfs3_fsstat_args;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	/* RFS3_FSINFO = 19 */
11800Sstevel@tonic-gate 	FSINFO3args nfs3_fsinfo_args;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	/* RFS3_PATHCONF = 20 */
11830Sstevel@tonic-gate 	PATHCONF3args nfs3_pathconf_args;
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	/* RFS3_COMMIT = 21 */
11860Sstevel@tonic-gate 	COMMIT3args nfs3_commit_args;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	/*
11890Sstevel@tonic-gate 	 * NFS VERSION 4
11900Sstevel@tonic-gate 	 */
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/* RFS_NULL = 0 */
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	/* COMPUND = 1 */
11950Sstevel@tonic-gate 	COMPOUND4args nfs4_compound_args;
11960Sstevel@tonic-gate };
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate union rfs_res {
11990Sstevel@tonic-gate 	/*
12000Sstevel@tonic-gate 	 * NFS VERSION 2
12010Sstevel@tonic-gate 	 */
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	/* RFS_NULL = 0 */
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
12060Sstevel@tonic-gate 	struct nfsattrstat nfs2_getattr_res;
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
12090Sstevel@tonic-gate 	struct nfsattrstat nfs2_setattr_res;
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
12140Sstevel@tonic-gate 	struct nfsdiropres nfs2_lookup_res;
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
12170Sstevel@tonic-gate 	struct nfsrdlnres nfs2_readlink_res;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/* RFS_READ = 6 */
12200Sstevel@tonic-gate 	struct nfsrdresult nfs2_read_res;
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
12250Sstevel@tonic-gate 	struct nfsattrstat nfs2_write_res;
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
12280Sstevel@tonic-gate 	struct nfsdiropres nfs2_create_res;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
12310Sstevel@tonic-gate 	enum nfsstat nfs2_remove_res;
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
12340Sstevel@tonic-gate 	enum nfsstat nfs2_rename_res;
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	/* RFS_LINK = 12 */
12370Sstevel@tonic-gate 	enum nfsstat nfs2_link_res;
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
12400Sstevel@tonic-gate 	enum nfsstat nfs2_symlink_res;
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
12430Sstevel@tonic-gate 	struct nfsdiropres nfs2_mkdir_res;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
12460Sstevel@tonic-gate 	enum nfsstat nfs2_rmdir_res;
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
12490Sstevel@tonic-gate 	struct nfsrddirres nfs2_readdir_res;
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
12520Sstevel@tonic-gate 	struct nfsstatfs nfs2_statfs_res;
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	/*
12550Sstevel@tonic-gate 	 * NFS VERSION 3
12560Sstevel@tonic-gate 	 */
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	/* RFS_NULL = 0 */
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	/* RFS3_GETATTR = 1 */
12610Sstevel@tonic-gate 	GETATTR3res nfs3_getattr_res;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	/* RFS3_SETATTR = 2 */
12640Sstevel@tonic-gate 	SETATTR3res nfs3_setattr_res;
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	/* RFS3_LOOKUP = 3 */
12670Sstevel@tonic-gate 	LOOKUP3res nfs3_lookup_res;
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	/* RFS3_ACCESS = 4 */
12700Sstevel@tonic-gate 	ACCESS3res nfs3_access_res;
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	/* RFS3_READLINK = 5 */
12730Sstevel@tonic-gate 	READLINK3res nfs3_readlink_res;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	/* RFS3_READ = 6 */
12760Sstevel@tonic-gate 	READ3res nfs3_read_res;
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	/* RFS3_WRITE = 7 */
12790Sstevel@tonic-gate 	WRITE3res nfs3_write_res;
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	/* RFS3_CREATE = 8 */
12820Sstevel@tonic-gate 	CREATE3res nfs3_create_res;
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	/* RFS3_MKDIR = 9 */
12850Sstevel@tonic-gate 	MKDIR3res nfs3_mkdir_res;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	/* RFS3_SYMLINK = 10 */
12880Sstevel@tonic-gate 	SYMLINK3res nfs3_symlink_res;
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	/* RFS3_MKNOD = 11 */
12910Sstevel@tonic-gate 	MKNOD3res nfs3_mknod_res;
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	/* RFS3_REMOVE = 12 */
12940Sstevel@tonic-gate 	REMOVE3res nfs3_remove_res;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	/* RFS3_RMDIR = 13 */
12970Sstevel@tonic-gate 	RMDIR3res nfs3_rmdir_res;
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	/* RFS3_RENAME = 14 */
13000Sstevel@tonic-gate 	RENAME3res nfs3_rename_res;
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	/* RFS3_LINK = 15 */
13030Sstevel@tonic-gate 	LINK3res nfs3_link_res;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	/* RFS3_READDIR = 16 */
13060Sstevel@tonic-gate 	READDIR3res nfs3_readdir_res;
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	/* RFS3_READDIRPLUS = 17 */
13090Sstevel@tonic-gate 	READDIRPLUS3res nfs3_readdirplus_res;
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	/* RFS3_FSSTAT = 18 */
13120Sstevel@tonic-gate 	FSSTAT3res nfs3_fsstat_res;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	/* RFS3_FSINFO = 19 */
13150Sstevel@tonic-gate 	FSINFO3res nfs3_fsinfo_res;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	/* RFS3_PATHCONF = 20 */
13180Sstevel@tonic-gate 	PATHCONF3res nfs3_pathconf_res;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	/* RFS3_COMMIT = 21 */
13210Sstevel@tonic-gate 	COMMIT3res nfs3_commit_res;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	/*
13240Sstevel@tonic-gate 	 * NFS VERSION 4
13250Sstevel@tonic-gate 	 */
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	/* RFS_NULL = 0 */
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	/* RFS4_COMPOUND = 1 */
13300Sstevel@tonic-gate 	COMPOUND4res nfs4_compound_res;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate };
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate static struct rpc_disptable rfs_disptable[] = {
13350Sstevel@tonic-gate 	{sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]),
13360Sstevel@tonic-gate 	    rfscallnames_v2,
13370Sstevel@tonic-gate 	    &rfsproccnt_v2_ptr, rfsdisptab_v2},
13380Sstevel@tonic-gate 	{sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]),
13390Sstevel@tonic-gate 	    rfscallnames_v3,
13400Sstevel@tonic-gate 	    &rfsproccnt_v3_ptr, rfsdisptab_v3},
13410Sstevel@tonic-gate 	{sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]),
13420Sstevel@tonic-gate 	    rfscallnames_v4,
13430Sstevel@tonic-gate 	    &rfsproccnt_v4_ptr, rfsdisptab_v4},
13440Sstevel@tonic-gate };
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate /*
13470Sstevel@tonic-gate  * If nfs_portmon is set, then clients are required to use privileged
13480Sstevel@tonic-gate  * ports (ports < IPPORT_RESERVED) in order to get NFS services.
13490Sstevel@tonic-gate  *
13500Sstevel@tonic-gate  * N.B.: this attempt to carry forward the already ill-conceived notion
13510Sstevel@tonic-gate  * of privileged ports for TCP/UDP is really quite ineffectual.  Not only
13520Sstevel@tonic-gate  * is it transport-dependent, it's laughably easy to spoof.  If you're
13530Sstevel@tonic-gate  * really interested in security, you must start with secure RPC instead.
13540Sstevel@tonic-gate  */
13550Sstevel@tonic-gate static int nfs_portmon = 0;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate #ifdef DEBUG
13580Sstevel@tonic-gate static int cred_hits = 0;
13590Sstevel@tonic-gate static int cred_misses = 0;
13600Sstevel@tonic-gate #endif
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate #ifdef DEBUG
13640Sstevel@tonic-gate /*
13650Sstevel@tonic-gate  * Debug code to allow disabling of rfs_dispatch() use of
13660Sstevel@tonic-gate  * fastxdrargs() and fastxdrres() calls for testing purposes.
13670Sstevel@tonic-gate  */
13680Sstevel@tonic-gate static int rfs_no_fast_xdrargs = 0;
13690Sstevel@tonic-gate static int rfs_no_fast_xdrres = 0;
13700Sstevel@tonic-gate #endif
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate union acl_args {
13730Sstevel@tonic-gate 	/*
13740Sstevel@tonic-gate 	 * ACL VERSION 2
13750Sstevel@tonic-gate 	 */
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	/* ACL2_NULL = 0 */
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/* ACL2_GETACL = 1 */
13800Sstevel@tonic-gate 	GETACL2args acl2_getacl_args;
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	/* ACL2_SETACL = 2 */
13830Sstevel@tonic-gate 	SETACL2args acl2_setacl_args;
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	/* ACL2_GETATTR = 3 */
13860Sstevel@tonic-gate 	GETATTR2args acl2_getattr_args;
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	/* ACL2_ACCESS = 4 */
13890Sstevel@tonic-gate 	ACCESS2args acl2_access_args;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	/* ACL2_GETXATTRDIR = 5 */
13920Sstevel@tonic-gate 	GETXATTRDIR2args acl2_getxattrdir_args;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 	/*
13950Sstevel@tonic-gate 	 * ACL VERSION 3
13960Sstevel@tonic-gate 	 */
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	/* ACL3_NULL = 0 */
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	/* ACL3_GETACL = 1 */
14010Sstevel@tonic-gate 	GETACL3args acl3_getacl_args;
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	/* ACL3_SETACL = 2 */
14040Sstevel@tonic-gate 	SETACL3args acl3_setacl;
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	/* ACL3_GETXATTRDIR = 3 */
14070Sstevel@tonic-gate 	GETXATTRDIR3args acl3_getxattrdir_args;
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate };
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate union acl_res {
14120Sstevel@tonic-gate 	/*
14130Sstevel@tonic-gate 	 * ACL VERSION 2
14140Sstevel@tonic-gate 	 */
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	/* ACL2_NULL = 0 */
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	/* ACL2_GETACL = 1 */
14190Sstevel@tonic-gate 	GETACL2res acl2_getacl_res;
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 	/* ACL2_SETACL = 2 */
14220Sstevel@tonic-gate 	SETACL2res acl2_setacl_res;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	/* ACL2_GETATTR = 3 */
14250Sstevel@tonic-gate 	GETATTR2res acl2_getattr_res;
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 	/* ACL2_ACCESS = 4 */
14280Sstevel@tonic-gate 	ACCESS2res acl2_access_res;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	/* ACL2_GETXATTRDIR = 5 */
14310Sstevel@tonic-gate 	GETXATTRDIR2args acl2_getxattrdir_res;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	/*
14340Sstevel@tonic-gate 	 * ACL VERSION 3
14350Sstevel@tonic-gate 	 */
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	/* ACL3_NULL = 0 */
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	/* ACL3_GETACL = 1 */
14400Sstevel@tonic-gate 	GETACL3res acl3_getacl_res;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	/* ACL3_SETACL = 2 */
14430Sstevel@tonic-gate 	SETACL3res acl3_setacl_res;
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	/* ACL3_GETXATTRDIR = 3 */
14460Sstevel@tonic-gate 	GETXATTRDIR3res acl3_getxattrdir_res;
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate };
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate static bool_t
auth_tooweak(struct svc_req * req,char * res)14510Sstevel@tonic-gate auth_tooweak(struct svc_req *req, char *res)
14520Sstevel@tonic-gate {
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	if (req->rq_vers == NFS_VERSION && req->rq_proc == RFS_LOOKUP) {
14550Sstevel@tonic-gate 		struct nfsdiropres *dr = (struct nfsdiropres *)res;
14560Sstevel@tonic-gate 		if (dr->dr_status == WNFSERR_CLNT_FLAVOR)
14570Sstevel@tonic-gate 			return (TRUE);
14580Sstevel@tonic-gate 	} else if (req->rq_vers == NFS_V3 && req->rq_proc == NFSPROC3_LOOKUP) {
14590Sstevel@tonic-gate 		LOOKUP3res *resp = (LOOKUP3res *)res;
14600Sstevel@tonic-gate 		if (resp->status == WNFSERR_CLNT_FLAVOR)
14610Sstevel@tonic-gate 			return (TRUE);
14620Sstevel@tonic-gate 	}
14630Sstevel@tonic-gate 	return (FALSE);
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate 
146674Srg137905 
14670Sstevel@tonic-gate static void
common_dispatch(struct svc_req * req,SVCXPRT * xprt,rpcvers_t min_vers,rpcvers_t max_vers,char * pgmname,struct rpc_disptable * disptable)14680Sstevel@tonic-gate common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
14690Sstevel@tonic-gate 		rpcvers_t max_vers, char *pgmname,
14700Sstevel@tonic-gate 		struct rpc_disptable *disptable)
14710Sstevel@tonic-gate {
14720Sstevel@tonic-gate 	int which;
14730Sstevel@tonic-gate 	rpcvers_t vers;
14740Sstevel@tonic-gate 	char *args;
14750Sstevel@tonic-gate 	union {
14760Sstevel@tonic-gate 			union rfs_args ra;
14770Sstevel@tonic-gate 			union acl_args aa;
14780Sstevel@tonic-gate 		} args_buf;
14790Sstevel@tonic-gate 	char *res;
14800Sstevel@tonic-gate 	union {
14810Sstevel@tonic-gate 			union rfs_res rr;
14820Sstevel@tonic-gate 			union acl_res ar;
14830Sstevel@tonic-gate 		} res_buf;
14840Sstevel@tonic-gate 	struct rpcdisp *disp = NULL;
14850Sstevel@tonic-gate 	int dis_flags = 0;
14860Sstevel@tonic-gate 	cred_t *cr;
14870Sstevel@tonic-gate 	int error = 0;
14880Sstevel@tonic-gate 	int anon_ok;
14890Sstevel@tonic-gate 	struct exportinfo *exi = NULL;
14900Sstevel@tonic-gate 	unsigned int nfslog_rec_id;
14910Sstevel@tonic-gate 	int dupstat;
14920Sstevel@tonic-gate 	struct dupreq *dr;
14930Sstevel@tonic-gate 	int authres;
14940Sstevel@tonic-gate 	bool_t publicfh_ok = FALSE;
14950Sstevel@tonic-gate 	enum_t auth_flavor;
14960Sstevel@tonic-gate 	bool_t dupcached = FALSE;
14970Sstevel@tonic-gate 	struct netbuf	nb;
14980Sstevel@tonic-gate 	bool_t logging_enabled = FALSE;
14990Sstevel@tonic-gate 	struct exportinfo *nfslog_exi = NULL;
15001232Srobinson 	char **procnames;
15011232Srobinson 	char cbuf[INET6_ADDRSTRLEN];	/* to hold both IPv4 and IPv6 addr */
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	vers = req->rq_vers;
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	if (vers < min_vers || vers > max_vers) {
15060Sstevel@tonic-gate 		svcerr_progvers(req->rq_xprt, min_vers, max_vers);
15070Sstevel@tonic-gate 		error++;
15080Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers);
15090Sstevel@tonic-gate 		goto done;
15100Sstevel@tonic-gate 	}
15110Sstevel@tonic-gate 	vers -= min_vers;
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	which = req->rq_proc;
15140Sstevel@tonic-gate 	if (which < 0 || which >= disptable[(int)vers].dis_nprocs) {
15150Sstevel@tonic-gate 		svcerr_noproc(req->rq_xprt);
15160Sstevel@tonic-gate 		error++;
15170Sstevel@tonic-gate 		goto done;
15180Sstevel@tonic-gate 	}
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	(*(disptable[(int)vers].dis_proccntp))[which].value.ui64++;
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	disp = &disptable[(int)vers].dis_table[which];
15231232Srobinson 	procnames = disptable[(int)vers].dis_procnames;
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	auth_flavor = req->rq_cred.oa_flavor;
15261232Srobinson 
15270Sstevel@tonic-gate 	/*
15280Sstevel@tonic-gate 	 * Deserialize into the args struct.
15290Sstevel@tonic-gate 	 */
15300Sstevel@tonic-gate 	args = (char *)&args_buf;
153174Srg137905 
15320Sstevel@tonic-gate #ifdef DEBUG
15330Sstevel@tonic-gate 	if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) ||
15340Sstevel@tonic-gate 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
15351610Sthurlow 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
15360Sstevel@tonic-gate #else
15370Sstevel@tonic-gate 	if ((auth_flavor == RPCSEC_GSS) ||
15380Sstevel@tonic-gate 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
15391610Sthurlow 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
15400Sstevel@tonic-gate #endif
15411610Sthurlow 	{
15420Sstevel@tonic-gate 		bzero(args, disp->dis_argsz);
15430Sstevel@tonic-gate 		if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) {
15444635Smaheshvs 			error++;
15454635Smaheshvs 			/*
15464635Smaheshvs 			 * Check if we are outside our capabilities.
15474635Smaheshvs 			 */
15484635Smaheshvs 			if (rfs4_minorvers_mismatch(req, xprt, (void *)args))
15494635Smaheshvs 				goto done;
15504635Smaheshvs 
15510Sstevel@tonic-gate 			svcerr_decode(xprt);
15521232Srobinson 			cmn_err(CE_NOTE,
15531232Srobinson 			    "Failed to decode arguments for %s version %u "
15541232Srobinson 			    "procedure %s client %s%s",
15551232Srobinson 			    pgmname, vers + min_vers, procnames[which],
15561232Srobinson 			    client_name(req), client_addr(req, cbuf));
15570Sstevel@tonic-gate 			goto done;
15580Sstevel@tonic-gate 		}
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	/*
156274Srg137905 	 * If Version 4 use that specific dispatch function.
15630Sstevel@tonic-gate 	 */
156474Srg137905 	if (req->rq_vers == 4) {
156574Srg137905 		error += rfs4_dispatch(disp, req, xprt, args);
156674Srg137905 		goto done;
156774Srg137905 	}
156874Srg137905 
156974Srg137905 	dis_flags = disp->dis_flags;
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	/*
15720Sstevel@tonic-gate 	 * Find export information and check authentication,
15730Sstevel@tonic-gate 	 * setting the credential if everything is ok.
15740Sstevel@tonic-gate 	 */
15750Sstevel@tonic-gate 	if (disp->dis_getfh != NULL) {
15761610Sthurlow 		void *fh;
15771610Sthurlow 		fsid_t *fsid;
15781610Sthurlow 		fid_t *fid, *xfid;
15791610Sthurlow 		fhandle_t *fh2;
15801610Sthurlow 		nfs_fh3 *fh3;
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 		fh = (*disp->dis_getfh)(args);
15831610Sthurlow 		switch (req->rq_vers) {
15841610Sthurlow 		case NFS_VERSION:
15851610Sthurlow 			fh2 = (fhandle_t *)fh;
15861610Sthurlow 			fsid = &fh2->fh_fsid;
15871610Sthurlow 			fid = (fid_t *)&fh2->fh_len;
15881610Sthurlow 			xfid = (fid_t *)&fh2->fh_xlen;
15891610Sthurlow 			break;
15901610Sthurlow 		case NFS_V3:
15911610Sthurlow 			fh3 = (nfs_fh3 *)fh;
15921610Sthurlow 			fsid = &fh3->fh3_fsid;
15931610Sthurlow 			fid = FH3TOFIDP(fh3);
15941610Sthurlow 			xfid = FH3TOXFIDP(fh3);
15951610Sthurlow 			break;
15961610Sthurlow 		}
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 		/*
15990Sstevel@tonic-gate 		 * Fix for bug 1038302 - corbin
16000Sstevel@tonic-gate 		 * There is a problem here if anonymous access is
16010Sstevel@tonic-gate 		 * disallowed.  If the current request is part of the
16020Sstevel@tonic-gate 		 * client's mount process for the requested filesystem,
16030Sstevel@tonic-gate 		 * then it will carry root (uid 0) credentials on it, and
16040Sstevel@tonic-gate 		 * will be denied by checkauth if that client does not
16050Sstevel@tonic-gate 		 * have explicit root=0 permission.  This will cause the
16060Sstevel@tonic-gate 		 * client's mount operation to fail.  As a work-around,
16070Sstevel@tonic-gate 		 * we check here to see if the request is a getattr or
16080Sstevel@tonic-gate 		 * statfs operation on the exported vnode itself, and
16090Sstevel@tonic-gate 		 * pass a flag to checkauth with the result of this test.
16100Sstevel@tonic-gate 		 *
16110Sstevel@tonic-gate 		 * The filehandle refers to the mountpoint itself if
16120Sstevel@tonic-gate 		 * the fh_data and fh_xdata portions of the filehandle
16130Sstevel@tonic-gate 		 * are equal.
16140Sstevel@tonic-gate 		 *
16150Sstevel@tonic-gate 		 * Added anon_ok argument to checkauth().
16160Sstevel@tonic-gate 		 */
16170Sstevel@tonic-gate 
16181610Sthurlow 		if ((dis_flags & RPC_ALLOWANON) && EQFID(fid, xfid))
16190Sstevel@tonic-gate 			anon_ok = 1;
16200Sstevel@tonic-gate 		else
16210Sstevel@tonic-gate 			anon_ok = 0;
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 		cr = xprt->xp_cred;
16240Sstevel@tonic-gate 		ASSERT(cr != NULL);
16250Sstevel@tonic-gate #ifdef DEBUG
16260Sstevel@tonic-gate 		if (crgetref(cr) != 1) {
16270Sstevel@tonic-gate 			crfree(cr);
16280Sstevel@tonic-gate 			cr = crget();
16290Sstevel@tonic-gate 			xprt->xp_cred = cr;
16300Sstevel@tonic-gate 			cred_misses++;
16310Sstevel@tonic-gate 		} else
16320Sstevel@tonic-gate 			cred_hits++;
16330Sstevel@tonic-gate #else
16340Sstevel@tonic-gate 		if (crgetref(cr) != 1) {
16350Sstevel@tonic-gate 			crfree(cr);
16360Sstevel@tonic-gate 			cr = crget();
16370Sstevel@tonic-gate 			xprt->xp_cred = cr;
16380Sstevel@tonic-gate 		}
16390Sstevel@tonic-gate #endif
16400Sstevel@tonic-gate 
16411610Sthurlow 		exi = checkexport(fsid, xfid);
164274Srg137905 
16430Sstevel@tonic-gate 		if (exi != NULL) {
16441610Sthurlow 			publicfh_ok = PUBLICFH_CHECK(disp, exi, fsid, xfid);
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 			/*
16470Sstevel@tonic-gate 			 * Don't allow non-V4 clients access
16480Sstevel@tonic-gate 			 * to pseudo exports
16490Sstevel@tonic-gate 			 */
16500Sstevel@tonic-gate 			if (PSEUDO(exi)) {
16510Sstevel@tonic-gate 				svcerr_weakauth(xprt);
16520Sstevel@tonic-gate 				error++;
16530Sstevel@tonic-gate 				goto done;
16540Sstevel@tonic-gate 			}
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 			authres = checkauth(exi, req, cr, anon_ok, publicfh_ok);
16570Sstevel@tonic-gate 			/*
16580Sstevel@tonic-gate 			 * authres >  0: authentication OK - proceed
16590Sstevel@tonic-gate 			 * authres == 0: authentication weak - return error
16600Sstevel@tonic-gate 			 * authres <  0: authentication timeout - drop
16610Sstevel@tonic-gate 			 */
16620Sstevel@tonic-gate 			if (authres <= 0) {
16630Sstevel@tonic-gate 				if (authres == 0) {
16640Sstevel@tonic-gate 					svcerr_weakauth(xprt);
16650Sstevel@tonic-gate 					error++;
16660Sstevel@tonic-gate 				}
16670Sstevel@tonic-gate 				goto done;
16680Sstevel@tonic-gate 			}
16690Sstevel@tonic-gate 		}
16700Sstevel@tonic-gate 	} else
16710Sstevel@tonic-gate 		cr = NULL;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) {
16740Sstevel@tonic-gate 		res = (char *)SVC_GETRES(xprt, disp->dis_ressz);
16750Sstevel@tonic-gate 		if (res == NULL)
16760Sstevel@tonic-gate 			res = (char *)&res_buf;
16770Sstevel@tonic-gate 	} else
16780Sstevel@tonic-gate 		res = (char *)&res_buf;
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	if (!(dis_flags & RPC_IDEMPOTENT)) {
16810Sstevel@tonic-gate 		dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr,
16827961SNatalie.Li@Sun.COM 		    &dupcached);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 		switch (dupstat) {
16850Sstevel@tonic-gate 		case DUP_ERROR:
16860Sstevel@tonic-gate 			svcerr_systemerr(xprt);
16870Sstevel@tonic-gate 			error++;
16880Sstevel@tonic-gate 			goto done;
16890Sstevel@tonic-gate 			/* NOTREACHED */
16900Sstevel@tonic-gate 		case DUP_INPROGRESS:
16910Sstevel@tonic-gate 			if (res != (char *)&res_buf)
16920Sstevel@tonic-gate 				SVC_FREERES(xprt);
16930Sstevel@tonic-gate 			error++;
16940Sstevel@tonic-gate 			goto done;
16950Sstevel@tonic-gate 			/* NOTREACHED */
16960Sstevel@tonic-gate 		case DUP_NEW:
16970Sstevel@tonic-gate 		case DUP_DROP:
16980Sstevel@tonic-gate 			curthread->t_flag |= T_DONTPEND;
169974Srg137905 
17000Sstevel@tonic-gate 			(*disp->dis_proc)(args, res, exi, req, cr);
170174Srg137905 
17020Sstevel@tonic-gate 			curthread->t_flag &= ~T_DONTPEND;
17030Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK) {
17040Sstevel@tonic-gate 				curthread->t_flag &= ~T_WOULDBLOCK;
17050Sstevel@tonic-gate 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
17067961SNatalie.Li@Sun.COM 				    disp->dis_ressz, DUP_DROP);
17070Sstevel@tonic-gate 				if (res != (char *)&res_buf)
17080Sstevel@tonic-gate 					SVC_FREERES(xprt);
17090Sstevel@tonic-gate 				error++;
17100Sstevel@tonic-gate 				goto done;
17110Sstevel@tonic-gate 			}
17120Sstevel@tonic-gate 			if (dis_flags & RPC_AVOIDWORK) {
17130Sstevel@tonic-gate 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
17147961SNatalie.Li@Sun.COM 				    disp->dis_ressz, DUP_DROP);
17150Sstevel@tonic-gate 			} else {
17160Sstevel@tonic-gate 				SVC_DUPDONE_EXT(xprt, dr, res,
17177961SNatalie.Li@Sun.COM 				    disp->dis_resfree == nullfree ? NULL :
17187961SNatalie.Li@Sun.COM 				    disp->dis_resfree,
17197961SNatalie.Li@Sun.COM 				    disp->dis_ressz, DUP_DONE);
17200Sstevel@tonic-gate 				dupcached = TRUE;
17210Sstevel@tonic-gate 			}
17220Sstevel@tonic-gate 			break;
17230Sstevel@tonic-gate 		case DUP_DONE:
17240Sstevel@tonic-gate 			break;
17250Sstevel@tonic-gate 		}
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	} else {
17280Sstevel@tonic-gate 		curthread->t_flag |= T_DONTPEND;
172974Srg137905 
17300Sstevel@tonic-gate 		(*disp->dis_proc)(args, res, exi, req, cr);
173174Srg137905 
17320Sstevel@tonic-gate 		curthread->t_flag &= ~T_DONTPEND;
17330Sstevel@tonic-gate 		if (curthread->t_flag & T_WOULDBLOCK) {
17340Sstevel@tonic-gate 			curthread->t_flag &= ~T_WOULDBLOCK;
17350Sstevel@tonic-gate 			if (res != (char *)&res_buf)
17360Sstevel@tonic-gate 				SVC_FREERES(xprt);
17370Sstevel@tonic-gate 			error++;
17380Sstevel@tonic-gate 			goto done;
17390Sstevel@tonic-gate 		}
17400Sstevel@tonic-gate 	}
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	if (auth_tooweak(req, res)) {
17430Sstevel@tonic-gate 		svcerr_weakauth(xprt);
17440Sstevel@tonic-gate 		error++;
17450Sstevel@tonic-gate 		goto done;
17460Sstevel@tonic-gate 	}
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	/*
17490Sstevel@tonic-gate 	 * Check to see if logging has been enabled on the server.
17500Sstevel@tonic-gate 	 * If so, then obtain the export info struct to be used for
17510Sstevel@tonic-gate 	 * the later writing of the log record.  This is done for
17520Sstevel@tonic-gate 	 * the case that a lookup is done across a non-logged public
17530Sstevel@tonic-gate 	 * file system.
17540Sstevel@tonic-gate 	 */
17550Sstevel@tonic-gate 	if (nfslog_buffer_list != NULL) {
17560Sstevel@tonic-gate 		nfslog_exi = nfslog_get_exi(exi, req, res, &nfslog_rec_id);
17570Sstevel@tonic-gate 		/*
17580Sstevel@tonic-gate 		 * Is logging enabled?
17590Sstevel@tonic-gate 		 */
17600Sstevel@tonic-gate 		logging_enabled = (nfslog_exi != NULL);
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 		/*
17630Sstevel@tonic-gate 		 * Copy the netbuf for logging purposes, before it is
17640Sstevel@tonic-gate 		 * freed by svc_sendreply().
17650Sstevel@tonic-gate 		 */
17660Sstevel@tonic-gate 		if (logging_enabled) {
17670Sstevel@tonic-gate 			NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb);
17680Sstevel@tonic-gate 			/*
17690Sstevel@tonic-gate 			 * If RPC_MAPRESP flag set (i.e. in V2 ops) the
17700Sstevel@tonic-gate 			 * res gets copied directly into the mbuf and
17710Sstevel@tonic-gate 			 * may be freed soon after the sendreply. So we
17720Sstevel@tonic-gate 			 * must copy it here to a safe place...
17730Sstevel@tonic-gate 			 */
17740Sstevel@tonic-gate 			if (res != (char *)&res_buf) {
17750Sstevel@tonic-gate 				bcopy(res, (char *)&res_buf, disp->dis_ressz);
17760Sstevel@tonic-gate 			}
17770Sstevel@tonic-gate 		}
17780Sstevel@tonic-gate 	}
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	/*
17810Sstevel@tonic-gate 	 * Serialize and send results struct
17820Sstevel@tonic-gate 	 */
17830Sstevel@tonic-gate #ifdef DEBUG
17841610Sthurlow 	if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf)
17850Sstevel@tonic-gate #else
17861610Sthurlow 	if (res != (char *)&res_buf)
17870Sstevel@tonic-gate #endif
17881610Sthurlow 	{
17890Sstevel@tonic-gate 		if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) {
17900Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
1791*12553SKaren.Rochford@Sun.COM 			svcerr_systemerr(xprt);
17920Sstevel@tonic-gate 			error++;
17930Sstevel@tonic-gate 		}
17940Sstevel@tonic-gate 	} else {
17950Sstevel@tonic-gate 		if (!svc_sendreply(xprt, disp->dis_xdrres, res)) {
17960Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
1797*12553SKaren.Rochford@Sun.COM 			svcerr_systemerr(xprt);
17980Sstevel@tonic-gate 			error++;
17990Sstevel@tonic-gate 		}
18000Sstevel@tonic-gate 	}
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 	/*
18030Sstevel@tonic-gate 	 * Log if needed
18040Sstevel@tonic-gate 	 */
18050Sstevel@tonic-gate 	if (logging_enabled) {
18060Sstevel@tonic-gate 		nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf,
18077961SNatalie.Li@Sun.COM 		    cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
18080Sstevel@tonic-gate 		exi_rele(nfslog_exi);
18090Sstevel@tonic-gate 		kmem_free((&nb)->buf, (&nb)->len);
18100Sstevel@tonic-gate 	}
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 	/*
18130Sstevel@tonic-gate 	 * Free results struct. With the addition of NFS V4 we can
18140Sstevel@tonic-gate 	 * have non-idempotent procedures with functions.
18150Sstevel@tonic-gate 	 */
18160Sstevel@tonic-gate 	if (disp->dis_resfree != nullfree && dupcached == FALSE) {
18170Sstevel@tonic-gate 		(*disp->dis_resfree)(res);
18180Sstevel@tonic-gate 	}
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate done:
18210Sstevel@tonic-gate 	/*
18220Sstevel@tonic-gate 	 * Free arguments struct
18230Sstevel@tonic-gate 	 */
18240Sstevel@tonic-gate 	if (disp) {
18250Sstevel@tonic-gate 		if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) {
18260Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
18270Sstevel@tonic-gate 			error++;
18280Sstevel@tonic-gate 		}
18290Sstevel@tonic-gate 	} else {
18300Sstevel@tonic-gate 		if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) {
18310Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
18320Sstevel@tonic-gate 			error++;
18330Sstevel@tonic-gate 		}
18340Sstevel@tonic-gate 	}
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	if (exi != NULL)
18370Sstevel@tonic-gate 		exi_rele(exi);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error;
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++;
18420Sstevel@tonic-gate }
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate static void
rfs_dispatch(struct svc_req * req,SVCXPRT * xprt)18450Sstevel@tonic-gate rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
18460Sstevel@tonic-gate {
18470Sstevel@tonic-gate 	common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
18487961SNatalie.Li@Sun.COM 	    "NFS", rfs_disptable);
18490Sstevel@tonic-gate }
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate static char *aclcallnames_v2[] = {
18520Sstevel@tonic-gate 	"ACL2_NULL",
18530Sstevel@tonic-gate 	"ACL2_GETACL",
18540Sstevel@tonic-gate 	"ACL2_SETACL",
18550Sstevel@tonic-gate 	"ACL2_GETATTR",
18560Sstevel@tonic-gate 	"ACL2_ACCESS",
18570Sstevel@tonic-gate 	"ACL2_GETXATTRDIR"
18580Sstevel@tonic-gate };
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate static struct rpcdisp acldisptab_v2[] = {
18610Sstevel@tonic-gate 	/*
18620Sstevel@tonic-gate 	 * ACL VERSION 2
18630Sstevel@tonic-gate 	 */
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	/* ACL2_NULL = 0 */
18660Sstevel@tonic-gate 	{rpc_null,
18670Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
18680Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
18690Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
18700Sstevel@tonic-gate 	    0},
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	/* ACL2_GETACL = 1 */
18730Sstevel@tonic-gate 	{acl2_getacl,
18740Sstevel@tonic-gate 	    xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args),
18750Sstevel@tonic-gate 	    xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res),
18760Sstevel@tonic-gate 	    acl2_getacl_free, RPC_IDEMPOTENT,
18770Sstevel@tonic-gate 	    acl2_getacl_getfh},
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	/* ACL2_SETACL = 2 */
18800Sstevel@tonic-gate 	{acl2_setacl,
18810Sstevel@tonic-gate 	    xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args),
18820Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
18830Sstevel@tonic-gate 	    xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res),
18840Sstevel@tonic-gate #else
18850Sstevel@tonic-gate 	    xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res),
18860Sstevel@tonic-gate #endif
18870Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
18880Sstevel@tonic-gate 	    acl2_setacl_getfh},
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	/* ACL2_GETATTR = 3 */
18910Sstevel@tonic-gate 	{acl2_getattr,
18920Sstevel@tonic-gate 	    xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args),
18930Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
18940Sstevel@tonic-gate 	    xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res),
18950Sstevel@tonic-gate #else
18960Sstevel@tonic-gate 	    xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res),
18970Sstevel@tonic-gate #endif
18980Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
18990Sstevel@tonic-gate 	    acl2_getattr_getfh},
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	/* ACL2_ACCESS = 4 */
19020Sstevel@tonic-gate 	{acl2_access,
19030Sstevel@tonic-gate 	    xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args),
19040Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
19050Sstevel@tonic-gate 	    xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res),
19060Sstevel@tonic-gate #else
19070Sstevel@tonic-gate 	    xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res),
19080Sstevel@tonic-gate #endif
19090Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP,
19100Sstevel@tonic-gate 	    acl2_access_getfh},
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate 	/* ACL2_GETXATTRDIR = 5 */
19130Sstevel@tonic-gate 	{acl2_getxattrdir,
19140Sstevel@tonic-gate 	    xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args),
19150Sstevel@tonic-gate 	    xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res),
19160Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
19170Sstevel@tonic-gate 	    acl2_getxattrdir_getfh},
19180Sstevel@tonic-gate };
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate static char *aclcallnames_v3[] = {
19210Sstevel@tonic-gate 	"ACL3_NULL",
19220Sstevel@tonic-gate 	"ACL3_GETACL",
19230Sstevel@tonic-gate 	"ACL3_SETACL",
19240Sstevel@tonic-gate 	"ACL3_GETXATTRDIR"
19250Sstevel@tonic-gate };
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate static struct rpcdisp acldisptab_v3[] = {
19280Sstevel@tonic-gate 	/*
19290Sstevel@tonic-gate 	 * ACL VERSION 3
19300Sstevel@tonic-gate 	 */
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	/* ACL3_NULL = 0 */
19330Sstevel@tonic-gate 	{rpc_null,
19340Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
19350Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
19360Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
19370Sstevel@tonic-gate 	    0},
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	/* ACL3_GETACL = 1 */
19400Sstevel@tonic-gate 	{acl3_getacl,
19410Sstevel@tonic-gate 	    xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args),
19420Sstevel@tonic-gate 	    xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res),
19430Sstevel@tonic-gate 	    acl3_getacl_free, RPC_IDEMPOTENT,
19440Sstevel@tonic-gate 	    acl3_getacl_getfh},
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/* ACL3_SETACL = 2 */
19470Sstevel@tonic-gate 	{acl3_setacl,
19480Sstevel@tonic-gate 	    xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args),
19490Sstevel@tonic-gate 	    xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res),
19500Sstevel@tonic-gate 	    nullfree, 0,
19510Sstevel@tonic-gate 	    acl3_setacl_getfh},
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	/* ACL3_GETXATTRDIR = 3 */
19540Sstevel@tonic-gate 	{acl3_getxattrdir,
19550Sstevel@tonic-gate 	    xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args),
19560Sstevel@tonic-gate 	    xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res),
19570Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
19580Sstevel@tonic-gate 	    acl3_getxattrdir_getfh},
19590Sstevel@tonic-gate };
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate static struct rpc_disptable acl_disptable[] = {
19620Sstevel@tonic-gate 	{sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]),
19630Sstevel@tonic-gate 		aclcallnames_v2,
19640Sstevel@tonic-gate 		&aclproccnt_v2_ptr, acldisptab_v2},
19650Sstevel@tonic-gate 	{sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]),
19660Sstevel@tonic-gate 		aclcallnames_v3,
19670Sstevel@tonic-gate 		&aclproccnt_v3_ptr, acldisptab_v3},
19680Sstevel@tonic-gate };
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate static void
acl_dispatch(struct svc_req * req,SVCXPRT * xprt)19710Sstevel@tonic-gate acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
19720Sstevel@tonic-gate {
19730Sstevel@tonic-gate 	common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
19747961SNatalie.Li@Sun.COM 	    "ACL", acl_disptable);
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate int
checkwin(int flavor,int window,struct svc_req * req)19780Sstevel@tonic-gate checkwin(int flavor, int window, struct svc_req *req)
19790Sstevel@tonic-gate {
19800Sstevel@tonic-gate 	struct authdes_cred *adc;
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate 	switch (flavor) {
19830Sstevel@tonic-gate 	case AUTH_DES:
19840Sstevel@tonic-gate 		adc = (struct authdes_cred *)req->rq_clntcred;
19850Sstevel@tonic-gate 		if (adc->adc_fullname.window > window)
19860Sstevel@tonic-gate 			return (0);
19870Sstevel@tonic-gate 		break;
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 	default:
19900Sstevel@tonic-gate 		break;
19910Sstevel@tonic-gate 	}
19920Sstevel@tonic-gate 	return (1);
19930Sstevel@tonic-gate }
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate /*
19970Sstevel@tonic-gate  * checkauth() will check the access permission against the export
19980Sstevel@tonic-gate  * information.  Then map root uid/gid to appropriate uid/gid.
19990Sstevel@tonic-gate  *
20000Sstevel@tonic-gate  * This routine is used by NFS V3 and V2 code.
20010Sstevel@tonic-gate  */
20020Sstevel@tonic-gate static int
checkauth(struct exportinfo * exi,struct svc_req * req,cred_t * cr,int anon_ok,bool_t publicfh_ok)20030Sstevel@tonic-gate checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok,
20040Sstevel@tonic-gate     bool_t publicfh_ok)
20050Sstevel@tonic-gate {
20060Sstevel@tonic-gate 	int i, nfsflavor, rpcflavor, stat, access;
20070Sstevel@tonic-gate 	struct secinfo *secp;
20080Sstevel@tonic-gate 	caddr_t principal;
20090Sstevel@tonic-gate 	char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */
20100Sstevel@tonic-gate 	int anon_res = 0;
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	/*
20139987SThomas.Haynes@Sun.COM 	 * Check for privileged port number
20149987SThomas.Haynes@Sun.COM 	 * N.B.:  this assumes that we know the format of a netbuf.
20150Sstevel@tonic-gate 	 */
20160Sstevel@tonic-gate 	if (nfs_portmon) {
20170Sstevel@tonic-gate 		struct sockaddr *ca;
20180Sstevel@tonic-gate 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 		if (ca == NULL)
20210Sstevel@tonic-gate 			return (0);
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 		if ((ca->sa_family == AF_INET &&
20240Sstevel@tonic-gate 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
20250Sstevel@tonic-gate 		    IPPORT_RESERVED) ||
20260Sstevel@tonic-gate 		    (ca->sa_family == AF_INET6 &&
20270Sstevel@tonic-gate 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
20280Sstevel@tonic-gate 		    IPPORT_RESERVED)) {
20290Sstevel@tonic-gate 			cmn_err(CE_NOTE,
20300Sstevel@tonic-gate 			    "nfs_server: client %s%ssent NFS request from "
20310Sstevel@tonic-gate 			    "unprivileged port",
20320Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf));
20330Sstevel@tonic-gate 			return (0);
20340Sstevel@tonic-gate 		}
20350Sstevel@tonic-gate 	}
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 	/*
20380Sstevel@tonic-gate 	 *  return 1 on success or 0 on failure
20390Sstevel@tonic-gate 	 */
20400Sstevel@tonic-gate 	stat = sec_svc_getcred(req, cr, &principal, &nfsflavor);
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 	/*
20430Sstevel@tonic-gate 	 * A failed AUTH_UNIX svc_get_cred() implies we couldn't set
20440Sstevel@tonic-gate 	 * the credentials; below we map that to anonymous.
20450Sstevel@tonic-gate 	 */
20460Sstevel@tonic-gate 	if (!stat && nfsflavor != AUTH_UNIX) {
20470Sstevel@tonic-gate 		cmn_err(CE_NOTE,
20480Sstevel@tonic-gate 		    "nfs_server: couldn't get unix cred for %s",
20490Sstevel@tonic-gate 		    client_name(req));
20500Sstevel@tonic-gate 		return (0);
20510Sstevel@tonic-gate 	}
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	/*
20540Sstevel@tonic-gate 	 * Short circuit checkauth() on operations that support the
20550Sstevel@tonic-gate 	 * public filehandle, and if the request for that operation
20560Sstevel@tonic-gate 	 * is using the public filehandle. Note that we must call
20570Sstevel@tonic-gate 	 * sec_svc_getcred() first so that xp_cookie is set to the
20580Sstevel@tonic-gate 	 * right value. Normally xp_cookie is just the RPC flavor
20590Sstevel@tonic-gate 	 * of the the request, but in the case of RPCSEC_GSS it
20600Sstevel@tonic-gate 	 * could be a pseudo flavor.
20610Sstevel@tonic-gate 	 */
20620Sstevel@tonic-gate 	if (publicfh_ok)
20630Sstevel@tonic-gate 		return (1);
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	rpcflavor = req->rq_cred.oa_flavor;
20660Sstevel@tonic-gate 	/*
20670Sstevel@tonic-gate 	 * Check if the auth flavor is valid for this export
20680Sstevel@tonic-gate 	 */
20690Sstevel@tonic-gate 	access = nfsauth_access(exi, req);
20700Sstevel@tonic-gate 	if (access & NFSAUTH_DROP)
20710Sstevel@tonic-gate 		return (-1);	/* drop the request */
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	if (access & NFSAUTH_DENIED) {
20740Sstevel@tonic-gate 		/*
20750Sstevel@tonic-gate 		 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was
20760Sstevel@tonic-gate 		 * probably due to the flavor not matching during the
20770Sstevel@tonic-gate 		 * the mount attempt. So map the flavor to AUTH_NONE
20780Sstevel@tonic-gate 		 * so that the credentials get mapped to the anonymous
20790Sstevel@tonic-gate 		 * user.
20800Sstevel@tonic-gate 		 */
20810Sstevel@tonic-gate 		if (anon_ok == 1)
20820Sstevel@tonic-gate 			rpcflavor = AUTH_NONE;
20830Sstevel@tonic-gate 		else
20840Sstevel@tonic-gate 			return (0);	/* deny access */
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	} else if (access & NFSAUTH_MAPNONE) {
20870Sstevel@tonic-gate 		/*
20880Sstevel@tonic-gate 		 * Access was granted even though the flavor mismatched
20890Sstevel@tonic-gate 		 * because AUTH_NONE was one of the exported flavors.
20900Sstevel@tonic-gate 		 */
20910Sstevel@tonic-gate 		rpcflavor = AUTH_NONE;
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	} else if (access & NFSAUTH_WRONGSEC) {
20940Sstevel@tonic-gate 		/*
20958395SThomas.Haynes@Sun.COM 		 * NFSAUTH_WRONGSEC is used for NFSv4. If we get here,
20968395SThomas.Haynes@Sun.COM 		 * it means a client ignored the list of allowed flavors
20978395SThomas.Haynes@Sun.COM 		 * returned via the MOUNT protocol. So we just disallow it!
20980Sstevel@tonic-gate 		 */
20998395SThomas.Haynes@Sun.COM 		return (0);
21000Sstevel@tonic-gate 	}
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	switch (rpcflavor) {
21030Sstevel@tonic-gate 	case AUTH_NONE:
21040Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
21057961SNatalie.Li@Sun.COM 		    exi->exi_export.ex_anon);
21060Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
21070Sstevel@tonic-gate 		break;
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate 	case AUTH_UNIX:
21100Sstevel@tonic-gate 		if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
21110Sstevel@tonic-gate 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
21127961SNatalie.Li@Sun.COM 			    exi->exi_export.ex_anon);
21130Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
21147961SNatalie.Li@Sun.COM 		} else if (!stat || crgetuid(cr) == 0 &&
21157961SNatalie.Li@Sun.COM 		    access & NFSAUTH_ROOT) {
21167961SNatalie.Li@Sun.COM 			/*
21177961SNatalie.Li@Sun.COM 			 * It is root, so apply rootid to get real UID
21187961SNatalie.Li@Sun.COM 			 * Find the secinfo structure.  We should be able
21197961SNatalie.Li@Sun.COM 			 * to find it by the time we reach here.
21207961SNatalie.Li@Sun.COM 			 * nfsauth_access() has done the checking.
21217961SNatalie.Li@Sun.COM 			 */
21227961SNatalie.Li@Sun.COM 			secp = NULL;
21237961SNatalie.Li@Sun.COM 			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
21247961SNatalie.Li@Sun.COM 				struct secinfo *sptr;
21257961SNatalie.Li@Sun.COM 				sptr = &exi->exi_export.ex_secinfo[i];
21267961SNatalie.Li@Sun.COM 				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
21277961SNatalie.Li@Sun.COM 					secp = sptr;
21287961SNatalie.Li@Sun.COM 					break;
21297961SNatalie.Li@Sun.COM 				}
21307961SNatalie.Li@Sun.COM 			}
21317961SNatalie.Li@Sun.COM 			if (secp != NULL) {
21327961SNatalie.Li@Sun.COM 				(void) crsetugid(cr, secp->s_rootid,
21337961SNatalie.Li@Sun.COM 				    secp->s_rootid);
21347961SNatalie.Li@Sun.COM 				(void) crsetgroups(cr, 0, NULL);
21357961SNatalie.Li@Sun.COM 			}
21360Sstevel@tonic-gate 		}
21370Sstevel@tonic-gate 		break;
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	case AUTH_DES:
21400Sstevel@tonic-gate 	case RPCSEC_GSS:
21410Sstevel@tonic-gate 		/*
21420Sstevel@tonic-gate 		 *  Find the secinfo structure.  We should be able
21430Sstevel@tonic-gate 		 *  to find it by the time we reach here.
21440Sstevel@tonic-gate 		 *  nfsauth_access() has done the checking.
21450Sstevel@tonic-gate 		 */
21460Sstevel@tonic-gate 		secp = NULL;
21470Sstevel@tonic-gate 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
21480Sstevel@tonic-gate 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
21490Sstevel@tonic-gate 			    nfsflavor) {
21500Sstevel@tonic-gate 				secp = &exi->exi_export.ex_secinfo[i];
21510Sstevel@tonic-gate 				break;
21520Sstevel@tonic-gate 			}
21530Sstevel@tonic-gate 		}
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 		if (!secp) {
21560Sstevel@tonic-gate 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
21570Sstevel@tonic-gate 			    "no secinfo data for flavor %d",
21580Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf),
21590Sstevel@tonic-gate 			    nfsflavor);
21600Sstevel@tonic-gate 			return (0);
21610Sstevel@tonic-gate 		}
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 		if (!checkwin(rpcflavor, secp->s_window, req)) {
21640Sstevel@tonic-gate 			cmn_err(CE_NOTE,
21650Sstevel@tonic-gate 			    "nfs_server: client %s%sused invalid "
21660Sstevel@tonic-gate 			    "auth window value",
21670Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf));
21680Sstevel@tonic-gate 			return (0);
21690Sstevel@tonic-gate 		}
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 		/*
21720Sstevel@tonic-gate 		 * Map root principals listed in the share's root= list to root,
21730Sstevel@tonic-gate 		 * and map any others principals that were mapped to root by RPC
21740Sstevel@tonic-gate 		 * to anon.
21750Sstevel@tonic-gate 		 */
21760Sstevel@tonic-gate 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
21777961SNatalie.Li@Sun.COM 		    secp->s_rootcnt, secp->s_rootnames)) {
21787961SNatalie.Li@Sun.COM 			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
21790Sstevel@tonic-gate 				return (1);
21800Sstevel@tonic-gate 
21817961SNatalie.Li@Sun.COM 
21827961SNatalie.Li@Sun.COM 			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 			/*
21850Sstevel@tonic-gate 			 * NOTE: If and when kernel-land privilege tracing is
21860Sstevel@tonic-gate 			 * added this may have to be replaced with code that
21870Sstevel@tonic-gate 			 * retrieves root's supplementary groups (e.g., using
21880Sstevel@tonic-gate 			 * kgss_get_group_info().  In the meantime principals
21890Sstevel@tonic-gate 			 * mapped to uid 0 get all privileges, so setting cr's
21900Sstevel@tonic-gate 			 * supplementary groups for them does nothing.
21910Sstevel@tonic-gate 			 */
21920Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 			return (1);
21950Sstevel@tonic-gate 		}
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 		/*
21980Sstevel@tonic-gate 		 * Not a root princ, or not in root list, map UID 0/nobody to
21990Sstevel@tonic-gate 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
22000Sstevel@tonic-gate 		 * UID_NOBODY and GID_NOBODY, respectively.)
22010Sstevel@tonic-gate 		 */
22020Sstevel@tonic-gate 		if (crgetuid(cr) != 0 &&
22030Sstevel@tonic-gate 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
22040Sstevel@tonic-gate 			return (1);
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
22077961SNatalie.Li@Sun.COM 		    exi->exi_export.ex_anon);
22080Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
22090Sstevel@tonic-gate 		break;
22100Sstevel@tonic-gate 	default:
22110Sstevel@tonic-gate 		return (0);
22120Sstevel@tonic-gate 	} /* switch on rpcflavor */
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 	/*
22150Sstevel@tonic-gate 	 * Even if anon access is disallowed via ex_anon == -1, we allow
22160Sstevel@tonic-gate 	 * this access if anon_ok is set.  So set creds to the default
22170Sstevel@tonic-gate 	 * "nobody" id.
22180Sstevel@tonic-gate 	 */
22190Sstevel@tonic-gate 	if (anon_res != 0) {
22200Sstevel@tonic-gate 		if (anon_ok == 0) {
22210Sstevel@tonic-gate 			cmn_err(CE_NOTE,
22220Sstevel@tonic-gate 			    "nfs_server: client %s%ssent wrong "
22230Sstevel@tonic-gate 			    "authentication for %s",
22240Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf),
22250Sstevel@tonic-gate 			    exi->exi_export.ex_path ?
22260Sstevel@tonic-gate 			    exi->exi_export.ex_path : "?");
22270Sstevel@tonic-gate 			return (0);
22280Sstevel@tonic-gate 		}
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 		if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0)
22310Sstevel@tonic-gate 			return (0);
22320Sstevel@tonic-gate 	}
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	return (1);
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate /*
22380Sstevel@tonic-gate  * returns 0 on failure, -1 on a drop, -2 on wrong security flavor,
22390Sstevel@tonic-gate  * and 1 on success
22400Sstevel@tonic-gate  */
22410Sstevel@tonic-gate int
checkauth4(struct compound_state * cs,struct svc_req * req)22420Sstevel@tonic-gate checkauth4(struct compound_state *cs, struct svc_req *req)
22430Sstevel@tonic-gate {
22440Sstevel@tonic-gate 	int i, rpcflavor, access;
22450Sstevel@tonic-gate 	struct secinfo *secp;
22460Sstevel@tonic-gate 	char buf[MAXHOST + 1];
22470Sstevel@tonic-gate 	int anon_res = 0, nfsflavor;
22480Sstevel@tonic-gate 	struct exportinfo *exi;
22490Sstevel@tonic-gate 	cred_t	*cr;
22500Sstevel@tonic-gate 	caddr_t	principal;
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 	exi = cs->exi;
22530Sstevel@tonic-gate 	cr = cs->cr;
22540Sstevel@tonic-gate 	principal = cs->principal;
22550Sstevel@tonic-gate 	nfsflavor = cs->nfsflavor;
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 	ASSERT(cr != NULL);
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate 	rpcflavor = req->rq_cred.oa_flavor;
22600Sstevel@tonic-gate 	cs->access &= ~CS_ACCESS_LIMITED;
22610Sstevel@tonic-gate 
22620Sstevel@tonic-gate 	/*
22639987SThomas.Haynes@Sun.COM 	 * Check for privileged port number
22649987SThomas.Haynes@Sun.COM 	 * N.B.:  this assumes that we know the format of a netbuf.
22659987SThomas.Haynes@Sun.COM 	 */
22669987SThomas.Haynes@Sun.COM 	if (nfs_portmon) {
22679987SThomas.Haynes@Sun.COM 		struct sockaddr *ca;
22689987SThomas.Haynes@Sun.COM 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
22699987SThomas.Haynes@Sun.COM 
22709987SThomas.Haynes@Sun.COM 		if (ca == NULL)
22719987SThomas.Haynes@Sun.COM 			return (0);
22729987SThomas.Haynes@Sun.COM 
22739987SThomas.Haynes@Sun.COM 		if ((ca->sa_family == AF_INET &&
22749987SThomas.Haynes@Sun.COM 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
22759987SThomas.Haynes@Sun.COM 		    IPPORT_RESERVED) ||
22769987SThomas.Haynes@Sun.COM 		    (ca->sa_family == AF_INET6 &&
22779987SThomas.Haynes@Sun.COM 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
22789987SThomas.Haynes@Sun.COM 		    IPPORT_RESERVED)) {
22799987SThomas.Haynes@Sun.COM 			cmn_err(CE_NOTE,
22809987SThomas.Haynes@Sun.COM 			    "nfs_server: client %s%ssent NFSv4 request from "
22819987SThomas.Haynes@Sun.COM 			    "unprivileged port",
22829987SThomas.Haynes@Sun.COM 			    client_name(req), client_addr(req, buf));
22839987SThomas.Haynes@Sun.COM 			return (0);
22849987SThomas.Haynes@Sun.COM 		}
22859987SThomas.Haynes@Sun.COM 	}
22869987SThomas.Haynes@Sun.COM 
22879987SThomas.Haynes@Sun.COM 	/*
22880Sstevel@tonic-gate 	 * Check the access right per auth flavor on the vnode of
22890Sstevel@tonic-gate 	 * this export for the given request.
22900Sstevel@tonic-gate 	 */
22910Sstevel@tonic-gate 	access = nfsauth4_access(cs->exi, cs->vp, req);
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	if (access & NFSAUTH_WRONGSEC)
22940Sstevel@tonic-gate 		return (-2);	/* no access for this security flavor */
22950Sstevel@tonic-gate 
22960Sstevel@tonic-gate 	if (access & NFSAUTH_DROP)
22970Sstevel@tonic-gate 		return (-1);	/* drop the request */
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 	if (access & NFSAUTH_DENIED) {
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 		if (exi->exi_export.ex_seccnt > 0)
23020Sstevel@tonic-gate 			return (0);	/* deny access */
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate 	} else if (access & NFSAUTH_LIMITED) {
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 		cs->access |= CS_ACCESS_LIMITED;
23070Sstevel@tonic-gate 
23080Sstevel@tonic-gate 	} else if (access & NFSAUTH_MAPNONE) {
23090Sstevel@tonic-gate 		/*
23100Sstevel@tonic-gate 		 * Access was granted even though the flavor mismatched
23110Sstevel@tonic-gate 		 * because AUTH_NONE was one of the exported flavors.
23120Sstevel@tonic-gate 		 */
23130Sstevel@tonic-gate 		rpcflavor = AUTH_NONE;
23140Sstevel@tonic-gate 	}
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	/*
23170Sstevel@tonic-gate 	 * XXX probably need to redo some of it for nfsv4?
23180Sstevel@tonic-gate 	 * return 1 on success or 0 on failure
23190Sstevel@tonic-gate 	 */
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	switch (rpcflavor) {
23220Sstevel@tonic-gate 	case AUTH_NONE:
23230Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
23247961SNatalie.Li@Sun.COM 		    exi->exi_export.ex_anon);
23250Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
23260Sstevel@tonic-gate 		break;
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	case AUTH_UNIX:
23290Sstevel@tonic-gate 		if (crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
23300Sstevel@tonic-gate 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
23317961SNatalie.Li@Sun.COM 			    exi->exi_export.ex_anon);
23320Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
23337961SNatalie.Li@Sun.COM 		} else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
23347961SNatalie.Li@Sun.COM 			/*
23357961SNatalie.Li@Sun.COM 			 * It is root, so apply rootid to get real UID
23367961SNatalie.Li@Sun.COM 			 * Find the secinfo structure.  We should be able
23377961SNatalie.Li@Sun.COM 			 * to find it by the time we reach here.
23387961SNatalie.Li@Sun.COM 			 * nfsauth_access() has done the checking.
23397961SNatalie.Li@Sun.COM 			 */
23407961SNatalie.Li@Sun.COM 			secp = NULL;
23417961SNatalie.Li@Sun.COM 			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
23427961SNatalie.Li@Sun.COM 				struct secinfo *sptr;
23437961SNatalie.Li@Sun.COM 				sptr = &exi->exi_export.ex_secinfo[i];
23447961SNatalie.Li@Sun.COM 				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
23457961SNatalie.Li@Sun.COM 					secp = &exi->exi_export.ex_secinfo[i];
23467961SNatalie.Li@Sun.COM 					break;
23477961SNatalie.Li@Sun.COM 				}
23487961SNatalie.Li@Sun.COM 			}
23497961SNatalie.Li@Sun.COM 			if (secp != NULL) {
23507961SNatalie.Li@Sun.COM 				(void) crsetugid(cr, secp->s_rootid,
23517961SNatalie.Li@Sun.COM 				    secp->s_rootid);
23527961SNatalie.Li@Sun.COM 				(void) crsetgroups(cr, 0, NULL);
23537961SNatalie.Li@Sun.COM 			}
23540Sstevel@tonic-gate 		}
23550Sstevel@tonic-gate 		break;
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	default:
23580Sstevel@tonic-gate 		/*
23590Sstevel@tonic-gate 		 *  Find the secinfo structure.  We should be able
23600Sstevel@tonic-gate 		 *  to find it by the time we reach here.
23610Sstevel@tonic-gate 		 *  nfsauth_access() has done the checking.
23620Sstevel@tonic-gate 		 */
23630Sstevel@tonic-gate 		secp = NULL;
23640Sstevel@tonic-gate 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
23650Sstevel@tonic-gate 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
23660Sstevel@tonic-gate 			    nfsflavor) {
23670Sstevel@tonic-gate 				secp = &exi->exi_export.ex_secinfo[i];
23680Sstevel@tonic-gate 				break;
23690Sstevel@tonic-gate 			}
23700Sstevel@tonic-gate 		}
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 		if (!secp) {
23730Sstevel@tonic-gate 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
23740Sstevel@tonic-gate 			    "no secinfo data for flavor %d",
23750Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf),
23760Sstevel@tonic-gate 			    nfsflavor);
23770Sstevel@tonic-gate 			return (0);
23780Sstevel@tonic-gate 		}
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 		if (!checkwin(rpcflavor, secp->s_window, req)) {
23810Sstevel@tonic-gate 			cmn_err(CE_NOTE,
23820Sstevel@tonic-gate 			    "nfs_server: client %s%sused invalid "
23830Sstevel@tonic-gate 			    "auth window value",
23840Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf));
23850Sstevel@tonic-gate 			return (0);
23860Sstevel@tonic-gate 		}
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 		/*
23890Sstevel@tonic-gate 		 * Map root principals listed in the share's root= list to root,
23900Sstevel@tonic-gate 		 * and map any others principals that were mapped to root by RPC
23917961SNatalie.Li@Sun.COM 		 * to anon. If not going to anon, set to rootid (root_mapping).
23920Sstevel@tonic-gate 		 */
23930Sstevel@tonic-gate 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
23947961SNatalie.Li@Sun.COM 		    secp->s_rootcnt, secp->s_rootnames)) {
23957961SNatalie.Li@Sun.COM 			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
23960Sstevel@tonic-gate 				return (1);
23970Sstevel@tonic-gate 
23987961SNatalie.Li@Sun.COM 			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
23990Sstevel@tonic-gate 
24000Sstevel@tonic-gate 			/*
24010Sstevel@tonic-gate 			 * NOTE: If and when kernel-land privilege tracing is
24020Sstevel@tonic-gate 			 * added this may have to be replaced with code that
24030Sstevel@tonic-gate 			 * retrieves root's supplementary groups (e.g., using
24040Sstevel@tonic-gate 			 * kgss_get_group_info().  In the meantime principals
24050Sstevel@tonic-gate 			 * mapped to uid 0 get all privileges, so setting cr's
24060Sstevel@tonic-gate 			 * supplementary groups for them does nothing.
24070Sstevel@tonic-gate 			 */
24080Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 			return (1);
24110Sstevel@tonic-gate 		}
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 		/*
24140Sstevel@tonic-gate 		 * Not a root princ, or not in root list, map UID 0/nobody to
24150Sstevel@tonic-gate 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
24160Sstevel@tonic-gate 		 * UID_NOBODY and GID_NOBODY, respectively.)
24170Sstevel@tonic-gate 		 */
24180Sstevel@tonic-gate 		if (crgetuid(cr) != 0 &&
24190Sstevel@tonic-gate 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
24200Sstevel@tonic-gate 			return (1);
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
24237961SNatalie.Li@Sun.COM 		    exi->exi_export.ex_anon);
24240Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
24250Sstevel@tonic-gate 		break;
24260Sstevel@tonic-gate 	} /* switch on rpcflavor */
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	/*
24290Sstevel@tonic-gate 	 * Even if anon access is disallowed via ex_anon == -1, we allow
24300Sstevel@tonic-gate 	 * this access if anon_ok is set.  So set creds to the default
24310Sstevel@tonic-gate 	 * "nobody" id.
24320Sstevel@tonic-gate 	 */
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	if (anon_res != 0) {
24350Sstevel@tonic-gate 		cmn_err(CE_NOTE,
24367961SNatalie.Li@Sun.COM 		    "nfs_server: client %s%ssent wrong "
24377961SNatalie.Li@Sun.COM 		    "authentication for %s",
24387961SNatalie.Li@Sun.COM 		    client_name(req), client_addr(req, buf),
24397961SNatalie.Li@Sun.COM 		    exi->exi_export.ex_path ?
24407961SNatalie.Li@Sun.COM 		    exi->exi_export.ex_path : "?");
24410Sstevel@tonic-gate 		return (0);
24420Sstevel@tonic-gate 	}
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	return (1);
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate static char *
client_name(struct svc_req * req)24490Sstevel@tonic-gate client_name(struct svc_req *req)
24500Sstevel@tonic-gate {
24510Sstevel@tonic-gate 	char *hostname = NULL;
24520Sstevel@tonic-gate 
24530Sstevel@tonic-gate 	/*
24540Sstevel@tonic-gate 	 * If it's a Unix cred then use the
24550Sstevel@tonic-gate 	 * hostname from the credential.
24560Sstevel@tonic-gate 	 */
24570Sstevel@tonic-gate 	if (req->rq_cred.oa_flavor == AUTH_UNIX) {
24580Sstevel@tonic-gate 		hostname = ((struct authunix_parms *)
24590Sstevel@tonic-gate 		    req->rq_clntcred)->aup_machname;
24600Sstevel@tonic-gate 	}
24610Sstevel@tonic-gate 	if (hostname == NULL)
24620Sstevel@tonic-gate 		hostname = "";
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	return (hostname);
24650Sstevel@tonic-gate }
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate static char *
client_addr(struct svc_req * req,char * buf)24680Sstevel@tonic-gate client_addr(struct svc_req *req, char *buf)
24690Sstevel@tonic-gate {
24700Sstevel@tonic-gate 	struct sockaddr *ca;
24710Sstevel@tonic-gate 	uchar_t *b;
24720Sstevel@tonic-gate 	char *frontspace = "";
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 	/*
24750Sstevel@tonic-gate 	 * We assume we are called in tandem with client_name and the
24760Sstevel@tonic-gate 	 * format string looks like "...client %s%sblah blah..."
24770Sstevel@tonic-gate 	 *
24780Sstevel@tonic-gate 	 * If it's a Unix cred then client_name returned
24790Sstevel@tonic-gate 	 * a host name, so we need insert a space between host name
24800Sstevel@tonic-gate 	 * and IP address.
24810Sstevel@tonic-gate 	 */
24820Sstevel@tonic-gate 	if (req->rq_cred.oa_flavor == AUTH_UNIX)
24830Sstevel@tonic-gate 		frontspace = " ";
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	/*
24860Sstevel@tonic-gate 	 * Convert the caller's IP address to a dotted string
24870Sstevel@tonic-gate 	 */
24880Sstevel@tonic-gate 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 	if (ca->sa_family == AF_INET) {
24917961SNatalie.Li@Sun.COM 		b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
24927961SNatalie.Li@Sun.COM 		(void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
24937961SNatalie.Li@Sun.COM 		    b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
24940Sstevel@tonic-gate 	} else if (ca->sa_family == AF_INET6) {
24950Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
24960Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)ca;
24970Sstevel@tonic-gate 		(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
24987961SNatalie.Li@Sun.COM 		    buf, INET6_ADDRSTRLEN);
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 	} else {
25010Sstevel@tonic-gate 
25020Sstevel@tonic-gate 		/*
25030Sstevel@tonic-gate 		 * No IP address to print. If there was a host name
25040Sstevel@tonic-gate 		 * printed, then we print a space.
25050Sstevel@tonic-gate 		 */
25060Sstevel@tonic-gate 		(void) sprintf(buf, frontspace);
25070Sstevel@tonic-gate 	}
25080Sstevel@tonic-gate 
25090Sstevel@tonic-gate 	return (buf);
25100Sstevel@tonic-gate }
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate /*
25130Sstevel@tonic-gate  * NFS Server initialization routine.  This routine should only be called
25140Sstevel@tonic-gate  * once.  It performs the following tasks:
25150Sstevel@tonic-gate  *	- Call sub-initialization routines (localize access to variables)
25160Sstevel@tonic-gate  *	- Initialize all locks
25170Sstevel@tonic-gate  *	- initialize the version 3 write verifier
25180Sstevel@tonic-gate  */
25190Sstevel@tonic-gate int
nfs_srvinit(void)25200Sstevel@tonic-gate nfs_srvinit(void)
25210Sstevel@tonic-gate {
25220Sstevel@tonic-gate 	int error;
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate 	error = nfs_exportinit();
25250Sstevel@tonic-gate 	if (error != 0)
25260Sstevel@tonic-gate 		return (error);
25270Sstevel@tonic-gate 	error = rfs4_srvrinit();
25280Sstevel@tonic-gate 	if (error != 0) {
25290Sstevel@tonic-gate 		nfs_exportfini();
25300Sstevel@tonic-gate 		return (error);
25310Sstevel@tonic-gate 	}
25320Sstevel@tonic-gate 	rfs_srvrinit();
25330Sstevel@tonic-gate 	rfs3_srvrinit();
25340Sstevel@tonic-gate 	nfsauth_init();
25350Sstevel@tonic-gate 
25360Sstevel@tonic-gate 	/* Init the stuff to control start/stop */
25370Sstevel@tonic-gate 	nfs_server_upordown = NFS_SERVER_STOPPED;
25380Sstevel@tonic-gate 	mutex_init(&nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL);
25390Sstevel@tonic-gate 	cv_init(&nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL);
25400Sstevel@tonic-gate 	mutex_init(&rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL);
25410Sstevel@tonic-gate 	cv_init(&rdma_wait_cv, NULL, CV_DEFAULT, NULL);
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 	return (0);
25440Sstevel@tonic-gate }
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate /*
25470Sstevel@tonic-gate  * NFS Server finalization routine. This routine is called to cleanup the
25480Sstevel@tonic-gate  * initialization work previously performed if the NFS server module could
25490Sstevel@tonic-gate  * not be loaded correctly.
25500Sstevel@tonic-gate  */
25510Sstevel@tonic-gate void
nfs_srvfini(void)25520Sstevel@tonic-gate nfs_srvfini(void)
25530Sstevel@tonic-gate {
25540Sstevel@tonic-gate 	nfsauth_fini();
25550Sstevel@tonic-gate 	rfs3_srvrfini();
25560Sstevel@tonic-gate 	rfs_srvrfini();
25570Sstevel@tonic-gate 	nfs_exportfini();
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	mutex_destroy(&nfs_server_upordown_lock);
25600Sstevel@tonic-gate 	cv_destroy(&nfs_server_upordown_cv);
25610Sstevel@tonic-gate 	mutex_destroy(&rdma_wait_mutex);
25620Sstevel@tonic-gate 	cv_destroy(&rdma_wait_cv);
25630Sstevel@tonic-gate }
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate /*
25660Sstevel@tonic-gate  * Set up an iovec array of up to cnt pointers.
25670Sstevel@tonic-gate  */
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate void
mblk_to_iov(mblk_t * m,int cnt,struct iovec * iovp)25700Sstevel@tonic-gate mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp)
25710Sstevel@tonic-gate {
25720Sstevel@tonic-gate 	while (m != NULL && cnt-- > 0) {
25730Sstevel@tonic-gate 		iovp->iov_base = (caddr_t)m->b_rptr;
25740Sstevel@tonic-gate 		iovp->iov_len = (m->b_wptr - m->b_rptr);
25750Sstevel@tonic-gate 		iovp++;
25760Sstevel@tonic-gate 		m = m->b_cont;
25770Sstevel@tonic-gate 	}
25780Sstevel@tonic-gate }
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate /*
25810Sstevel@tonic-gate  * Common code between NFS Version 2 and NFS Version 3 for the public
25820Sstevel@tonic-gate  * filehandle multicomponent lookups.
25830Sstevel@tonic-gate  */
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate /*
25860Sstevel@tonic-gate  * Public filehandle evaluation of a multi-component lookup, following
25870Sstevel@tonic-gate  * symbolic links, if necessary. This may result in a vnode in another
25880Sstevel@tonic-gate  * filesystem, which is OK as long as the other filesystem is exported.
25890Sstevel@tonic-gate  *
25900Sstevel@tonic-gate  * Note that the exi will be set either to NULL or a new reference to the
25910Sstevel@tonic-gate  * exportinfo struct that corresponds to the vnode of the multi-component path.
25920Sstevel@tonic-gate  * It is the callers responsibility to release this reference.
25930Sstevel@tonic-gate  */
25940Sstevel@tonic-gate int
rfs_publicfh_mclookup(char * p,vnode_t * dvp,cred_t * cr,vnode_t ** vpp,struct exportinfo ** exi,struct sec_ol * sec)25950Sstevel@tonic-gate rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
25960Sstevel@tonic-gate     struct exportinfo **exi, struct sec_ol *sec)
25970Sstevel@tonic-gate {
25980Sstevel@tonic-gate 	int pathflag;
25990Sstevel@tonic-gate 	vnode_t *mc_dvp = NULL;
26000Sstevel@tonic-gate 	vnode_t *realvp;
26010Sstevel@tonic-gate 	int error;
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate 	*exi = NULL;
26040Sstevel@tonic-gate 
26050Sstevel@tonic-gate 	/*
26060Sstevel@tonic-gate 	 * check if the given path is a url or native path. Since p is
26070Sstevel@tonic-gate 	 * modified by MCLpath(), it may be empty after returning from
26080Sstevel@tonic-gate 	 * there, and should be checked.
26090Sstevel@tonic-gate 	 */
26100Sstevel@tonic-gate 	if ((pathflag = MCLpath(&p)) == -1)
26110Sstevel@tonic-gate 		return (EIO);
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 	/*
26140Sstevel@tonic-gate 	 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit
26150Sstevel@tonic-gate 	 * on in sec->sec_flags. This bit will later serve as an
26160Sstevel@tonic-gate 	 * indication in makefh_ol() or makefh3_ol() to overload the
26170Sstevel@tonic-gate 	 * filehandle to contain the sec modes used by the server for
26180Sstevel@tonic-gate 	 * the path.
26190Sstevel@tonic-gate 	 */
26200Sstevel@tonic-gate 	if (pathflag == SECURITY_QUERY) {
26210Sstevel@tonic-gate 		if ((sec->sec_index = (uint_t)(*p)) > 0) {
26220Sstevel@tonic-gate 			sec->sec_flags |= SEC_QUERY;
26230Sstevel@tonic-gate 			p++;
26240Sstevel@tonic-gate 			if ((pathflag = MCLpath(&p)) == -1)
26250Sstevel@tonic-gate 				return (EIO);
26260Sstevel@tonic-gate 		} else {
26270Sstevel@tonic-gate 			cmn_err(CE_NOTE,
26280Sstevel@tonic-gate 			    "nfs_server: invalid security index %d, "
26290Sstevel@tonic-gate 			    "violating WebNFS SNEGO protocol.", sec->sec_index);
26300Sstevel@tonic-gate 			return (EIO);
26310Sstevel@tonic-gate 		}
26320Sstevel@tonic-gate 	}
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	if (p[0] == '\0') {
26350Sstevel@tonic-gate 		error = ENOENT;
26360Sstevel@tonic-gate 		goto publicfh_done;
26370Sstevel@tonic-gate 	}
26380Sstevel@tonic-gate 
26390Sstevel@tonic-gate 	error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag);
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	/*
26420Sstevel@tonic-gate 	 * If name resolves to "/" we get EINVAL since we asked for
26430Sstevel@tonic-gate 	 * the vnode of the directory that the file is in. Try again
26440Sstevel@tonic-gate 	 * with NULL directory vnode.
26450Sstevel@tonic-gate 	 */
26460Sstevel@tonic-gate 	if (error == EINVAL) {
26470Sstevel@tonic-gate 		error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag);
26480Sstevel@tonic-gate 		if (!error) {
26490Sstevel@tonic-gate 			ASSERT(*vpp != NULL);
26500Sstevel@tonic-gate 			if ((*vpp)->v_type == VDIR) {
26510Sstevel@tonic-gate 				VN_HOLD(*vpp);
26520Sstevel@tonic-gate 				mc_dvp = *vpp;
26530Sstevel@tonic-gate 			} else {
26540Sstevel@tonic-gate 				/*
26550Sstevel@tonic-gate 				 * This should not happen, the filesystem is
26560Sstevel@tonic-gate 				 * in an inconsistent state. Fail the lookup
26570Sstevel@tonic-gate 				 * at this point.
26580Sstevel@tonic-gate 				 */
26590Sstevel@tonic-gate 				VN_RELE(*vpp);
26600Sstevel@tonic-gate 				error = EINVAL;
26610Sstevel@tonic-gate 			}
26620Sstevel@tonic-gate 		}
26630Sstevel@tonic-gate 	}
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 	if (error)
26660Sstevel@tonic-gate 		goto publicfh_done;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	if (*vpp == NULL) {
26690Sstevel@tonic-gate 		error = ENOENT;
26700Sstevel@tonic-gate 		goto publicfh_done;
26710Sstevel@tonic-gate 	}
26720Sstevel@tonic-gate 
26730Sstevel@tonic-gate 	ASSERT(mc_dvp != NULL);
26740Sstevel@tonic-gate 	ASSERT(*vpp != NULL);
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 	if ((*vpp)->v_type == VDIR) {
26770Sstevel@tonic-gate 		do {
26780Sstevel@tonic-gate 			/*
26790Sstevel@tonic-gate 			 * *vpp may be an AutoFS node, so we perform
26800Sstevel@tonic-gate 			 * a VOP_ACCESS() to trigger the mount of the intended
26810Sstevel@tonic-gate 			 * filesystem, so we can perform the lookup in the
26820Sstevel@tonic-gate 			 * intended filesystem.
26830Sstevel@tonic-gate 			 */
26845331Samw 			(void) VOP_ACCESS(*vpp, 0, 0, cr, NULL);
26850Sstevel@tonic-gate 
26860Sstevel@tonic-gate 			/*
26870Sstevel@tonic-gate 			 * If vnode is covered, get the
26880Sstevel@tonic-gate 			 * the topmost vnode.
26890Sstevel@tonic-gate 			 */
26900Sstevel@tonic-gate 			if (vn_mountedvfs(*vpp) != NULL) {
26910Sstevel@tonic-gate 				error = traverse(vpp);
26920Sstevel@tonic-gate 				if (error) {
26930Sstevel@tonic-gate 					VN_RELE(*vpp);
26940Sstevel@tonic-gate 					goto publicfh_done;
26950Sstevel@tonic-gate 				}
26960Sstevel@tonic-gate 			}
26970Sstevel@tonic-gate 
26985331Samw 			if (VOP_REALVP(*vpp, &realvp, NULL) == 0 &&
26995331Samw 			    realvp != *vpp) {
27000Sstevel@tonic-gate 				/*
27010Sstevel@tonic-gate 				 * If realvp is different from *vpp
27020Sstevel@tonic-gate 				 * then release our reference on *vpp, so that
27030Sstevel@tonic-gate 				 * the export access check be performed on the
27040Sstevel@tonic-gate 				 * real filesystem instead.
27050Sstevel@tonic-gate 				 */
27060Sstevel@tonic-gate 				VN_HOLD(realvp);
27070Sstevel@tonic-gate 				VN_RELE(*vpp);
27080Sstevel@tonic-gate 				*vpp = realvp;
27097961SNatalie.Li@Sun.COM 			} else {
27107961SNatalie.Li@Sun.COM 				break;
27117961SNatalie.Li@Sun.COM 			}
27120Sstevel@tonic-gate 		/* LINTED */
27130Sstevel@tonic-gate 		} while (TRUE);
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate 		/*
27160Sstevel@tonic-gate 		 * Let nfs_vptexi() figure what the real parent is.
27170Sstevel@tonic-gate 		 */
27180Sstevel@tonic-gate 		VN_RELE(mc_dvp);
27190Sstevel@tonic-gate 		mc_dvp = NULL;
27200Sstevel@tonic-gate 
27210Sstevel@tonic-gate 	} else {
27220Sstevel@tonic-gate 		/*
27230Sstevel@tonic-gate 		 * If vnode is covered, get the
27240Sstevel@tonic-gate 		 * the topmost vnode.
27250Sstevel@tonic-gate 		 */
27260Sstevel@tonic-gate 		if (vn_mountedvfs(mc_dvp) != NULL) {
27270Sstevel@tonic-gate 			error = traverse(&mc_dvp);
27280Sstevel@tonic-gate 			if (error) {
27297961SNatalie.Li@Sun.COM 				VN_RELE(*vpp);
27307961SNatalie.Li@Sun.COM 				goto publicfh_done;
27310Sstevel@tonic-gate 			}
27320Sstevel@tonic-gate 		}
27330Sstevel@tonic-gate 
27345331Samw 		if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 &&
27355331Samw 		    realvp != mc_dvp) {
27360Sstevel@tonic-gate 			/*
27370Sstevel@tonic-gate 			 * *vpp is a file, obtain realvp of the parent
27380Sstevel@tonic-gate 			 * directory vnode.
27390Sstevel@tonic-gate 			 */
27400Sstevel@tonic-gate 			VN_HOLD(realvp);
27410Sstevel@tonic-gate 			VN_RELE(mc_dvp);
27420Sstevel@tonic-gate 			mc_dvp = realvp;
27430Sstevel@tonic-gate 		}
27440Sstevel@tonic-gate 	}
27450Sstevel@tonic-gate 
27460Sstevel@tonic-gate 	/*
27470Sstevel@tonic-gate 	 * The pathname may take us from the public filesystem to another.
27480Sstevel@tonic-gate 	 * If that's the case then just set the exportinfo to the new export
27490Sstevel@tonic-gate 	 * and build filehandle for it. Thanks to per-access checking there's
27500Sstevel@tonic-gate 	 * no security issues with doing this. If the client is not allowed
27510Sstevel@tonic-gate 	 * access to this new export then it will get an access error when it
27520Sstevel@tonic-gate 	 * tries to use the filehandle
27530Sstevel@tonic-gate 	 */
27540Sstevel@tonic-gate 	if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
27550Sstevel@tonic-gate 		VN_RELE(*vpp);
27560Sstevel@tonic-gate 		goto publicfh_done;
27570Sstevel@tonic-gate 	}
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	/*
27600Sstevel@tonic-gate 	 * Not allowed access to pseudo exports.
27610Sstevel@tonic-gate 	 */
27620Sstevel@tonic-gate 	if (PSEUDO(*exi)) {
27630Sstevel@tonic-gate 		error = ENOENT;
27640Sstevel@tonic-gate 		VN_RELE(*vpp);
27650Sstevel@tonic-gate 		goto publicfh_done;
27660Sstevel@tonic-gate 	}
27670Sstevel@tonic-gate 
27680Sstevel@tonic-gate 	/*
27690Sstevel@tonic-gate 	 * Do a lookup for the index file. We know the index option doesn't
27700Sstevel@tonic-gate 	 * allow paths through handling in the share command, so mc_dvp will
27710Sstevel@tonic-gate 	 * be the parent for the index file vnode, if its present. Use
27720Sstevel@tonic-gate 	 * temporary pointers to preserve and reuse the vnode pointers of the
27730Sstevel@tonic-gate 	 * original directory in case there's no index file. Note that the
27740Sstevel@tonic-gate 	 * index file is a native path, and should not be interpreted by
27750Sstevel@tonic-gate 	 * the URL parser in rfs_pathname()
27760Sstevel@tonic-gate 	 */
27770Sstevel@tonic-gate 	if (((*exi)->exi_export.ex_flags & EX_INDEX) &&
27780Sstevel@tonic-gate 	    ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) {
27790Sstevel@tonic-gate 		vnode_t *tvp, *tmc_dvp;	/* temporary vnode pointers */
27800Sstevel@tonic-gate 
27810Sstevel@tonic-gate 		tmc_dvp = mc_dvp;
27820Sstevel@tonic-gate 		mc_dvp = tvp = *vpp;
27830Sstevel@tonic-gate 
27840Sstevel@tonic-gate 		error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp,
27850Sstevel@tonic-gate 		    mc_dvp, cr, NATIVEPATH);
27860Sstevel@tonic-gate 
27870Sstevel@tonic-gate 		if (error == ENOENT) {
27880Sstevel@tonic-gate 			*vpp = tvp;
27890Sstevel@tonic-gate 			mc_dvp = tmc_dvp;
27900Sstevel@tonic-gate 			error = 0;
27910Sstevel@tonic-gate 		} else {	/* ok or error other than ENOENT */
27920Sstevel@tonic-gate 			if (tmc_dvp)
27930Sstevel@tonic-gate 				VN_RELE(tmc_dvp);
27940Sstevel@tonic-gate 			if (error)
27950Sstevel@tonic-gate 				goto publicfh_done;
27960Sstevel@tonic-gate 
27970Sstevel@tonic-gate 			/*
27980Sstevel@tonic-gate 			 * Found a valid vp for index "filename". Sanity check
27990Sstevel@tonic-gate 			 * for odd case where a directory is provided as index
28000Sstevel@tonic-gate 			 * option argument and leads us to another filesystem
28010Sstevel@tonic-gate 			 */
28020Sstevel@tonic-gate 
28030Sstevel@tonic-gate 			/* Release the reference on the old exi value */
28040Sstevel@tonic-gate 			ASSERT(*exi != NULL);
28050Sstevel@tonic-gate 			exi_rele(*exi);
28060Sstevel@tonic-gate 
28070Sstevel@tonic-gate 			if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
28080Sstevel@tonic-gate 				VN_RELE(*vpp);
28090Sstevel@tonic-gate 				goto publicfh_done;
28100Sstevel@tonic-gate 			}
28110Sstevel@tonic-gate 		}
28120Sstevel@tonic-gate 	}
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate publicfh_done:
28150Sstevel@tonic-gate 	if (mc_dvp)
28160Sstevel@tonic-gate 		VN_RELE(mc_dvp);
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate 	return (error);
28190Sstevel@tonic-gate }
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate /*
28220Sstevel@tonic-gate  * Evaluate a multi-component path
28230Sstevel@tonic-gate  */
28240Sstevel@tonic-gate int
rfs_pathname(char * path,vnode_t ** dirvpp,vnode_t ** compvpp,vnode_t * startdvp,cred_t * cr,int pathflag)28250Sstevel@tonic-gate rfs_pathname(
28260Sstevel@tonic-gate 	char *path,			/* pathname to evaluate */
28270Sstevel@tonic-gate 	vnode_t **dirvpp,		/* ret for ptr to parent dir vnode */
28280Sstevel@tonic-gate 	vnode_t **compvpp,		/* ret for ptr to component vnode */
28290Sstevel@tonic-gate 	vnode_t *startdvp,		/* starting vnode */
28300Sstevel@tonic-gate 	cred_t *cr,			/* user's credential */
28310Sstevel@tonic-gate 	int pathflag)			/* flag to identify path, e.g. URL */
28320Sstevel@tonic-gate {
28330Sstevel@tonic-gate 	char namebuf[TYPICALMAXPATHLEN];
28340Sstevel@tonic-gate 	struct pathname pn;
28350Sstevel@tonic-gate 	int error;
28360Sstevel@tonic-gate 
28370Sstevel@tonic-gate 	/*
28380Sstevel@tonic-gate 	 * If pathname starts with '/', then set startdvp to root.
28390Sstevel@tonic-gate 	 */
28400Sstevel@tonic-gate 	if (*path == '/') {
28410Sstevel@tonic-gate 		while (*path == '/')
28420Sstevel@tonic-gate 			path++;
28430Sstevel@tonic-gate 
28440Sstevel@tonic-gate 		startdvp = rootdir;
28450Sstevel@tonic-gate 	}
28460Sstevel@tonic-gate 
28470Sstevel@tonic-gate 	error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf));
28480Sstevel@tonic-gate 	if (error == 0) {
28490Sstevel@tonic-gate 		/*
28500Sstevel@tonic-gate 		 * Call the URL parser for URL paths to modify the original
28510Sstevel@tonic-gate 		 * string to handle any '%' encoded characters that exist.
28520Sstevel@tonic-gate 		 * Done here to avoid an extra bcopy in the lookup.
28530Sstevel@tonic-gate 		 * We need to be careful about pathlen's. We know that
28540Sstevel@tonic-gate 		 * rfs_pathname() is called with a non-empty path. However,
28550Sstevel@tonic-gate 		 * it could be emptied due to the path simply being all /'s,
28560Sstevel@tonic-gate 		 * which is valid to proceed with the lookup, or due to the
28570Sstevel@tonic-gate 		 * URL parser finding an encoded null character at the
28580Sstevel@tonic-gate 		 * beginning of path which should not proceed with the lookup.
28590Sstevel@tonic-gate 		 */
28600Sstevel@tonic-gate 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
28610Sstevel@tonic-gate 			URLparse(pn.pn_path);
28620Sstevel@tonic-gate 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0)
28630Sstevel@tonic-gate 				return (ENOENT);
28640Sstevel@tonic-gate 		}
28650Sstevel@tonic-gate 		VN_HOLD(startdvp);
28660Sstevel@tonic-gate 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
28670Sstevel@tonic-gate 		    rootdir, startdvp, cr);
28680Sstevel@tonic-gate 	}
28690Sstevel@tonic-gate 	if (error == ENAMETOOLONG) {
28700Sstevel@tonic-gate 		/*
28710Sstevel@tonic-gate 		 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
28720Sstevel@tonic-gate 		 */
28730Sstevel@tonic-gate 		if (error = pn_get(path, UIO_SYSSPACE, &pn))
28740Sstevel@tonic-gate 			return (error);
28750Sstevel@tonic-gate 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
28760Sstevel@tonic-gate 			URLparse(pn.pn_path);
28770Sstevel@tonic-gate 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) {
28780Sstevel@tonic-gate 				pn_free(&pn);
28790Sstevel@tonic-gate 				return (ENOENT);
28800Sstevel@tonic-gate 			}
28810Sstevel@tonic-gate 		}
28820Sstevel@tonic-gate 		VN_HOLD(startdvp);
28830Sstevel@tonic-gate 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
28840Sstevel@tonic-gate 		    rootdir, startdvp, cr);
28850Sstevel@tonic-gate 		pn_free(&pn);
28860Sstevel@tonic-gate 	}
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate 	return (error);
28890Sstevel@tonic-gate }
28900Sstevel@tonic-gate 
28910Sstevel@tonic-gate /*
28920Sstevel@tonic-gate  * Adapt the multicomponent lookup path depending on the pathtype
28930Sstevel@tonic-gate  */
28940Sstevel@tonic-gate static int
MCLpath(char ** path)28950Sstevel@tonic-gate MCLpath(char **path)
28960Sstevel@tonic-gate {
28970Sstevel@tonic-gate 	unsigned char c = (unsigned char)**path;
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate 	/*
29000Sstevel@tonic-gate 	 * If the MCL path is between 0x20 and 0x7E (graphic printable
29010Sstevel@tonic-gate 	 * character of the US-ASCII coded character set), its a URL path,
29020Sstevel@tonic-gate 	 * per RFC 1738.
29030Sstevel@tonic-gate 	 */
29040Sstevel@tonic-gate 	if (c >= 0x20 && c <= 0x7E)
29050Sstevel@tonic-gate 		return (URLPATH);
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 	/*
29080Sstevel@tonic-gate 	 * If the first octet of the MCL path is not an ASCII character
29090Sstevel@tonic-gate 	 * then it must be interpreted as a tag value that describes the
29100Sstevel@tonic-gate 	 * format of the remaining octets of the MCL path.
29110Sstevel@tonic-gate 	 *
29120Sstevel@tonic-gate 	 * If the first octet of the MCL path is 0x81 it is a query
29130Sstevel@tonic-gate 	 * for the security info.
29140Sstevel@tonic-gate 	 */
29150Sstevel@tonic-gate 	switch (c) {
29160Sstevel@tonic-gate 	case 0x80:	/* native path, i.e. MCL via mount protocol */
29170Sstevel@tonic-gate 		(*path)++;
29180Sstevel@tonic-gate 		return (NATIVEPATH);
29190Sstevel@tonic-gate 	case 0x81:	/* security query */
29200Sstevel@tonic-gate 		(*path)++;
29210Sstevel@tonic-gate 		return (SECURITY_QUERY);
29220Sstevel@tonic-gate 	default:
29230Sstevel@tonic-gate 		return (-1);
29240Sstevel@tonic-gate 	}
29250Sstevel@tonic-gate }
29260Sstevel@tonic-gate 
29270Sstevel@tonic-gate #define	fromhex(c)  ((c >= '0' && c <= '9') ? (c - '0') : \
29280Sstevel@tonic-gate 			((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
29290Sstevel@tonic-gate 			((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
29300Sstevel@tonic-gate 
29310Sstevel@tonic-gate /*
29325331Samw  * The implementation of URLparse guarantees that the final string will
29330Sstevel@tonic-gate  * fit in the original one. Replaces '%' occurrences followed by 2 characters
29340Sstevel@tonic-gate  * with its corresponding hexadecimal character.
29350Sstevel@tonic-gate  */
29360Sstevel@tonic-gate static void
URLparse(char * str)29370Sstevel@tonic-gate URLparse(char *str)
29380Sstevel@tonic-gate {
29390Sstevel@tonic-gate 	char *p, *q;
29400Sstevel@tonic-gate 
29410Sstevel@tonic-gate 	p = q = str;
29420Sstevel@tonic-gate 	while (*p) {
29430Sstevel@tonic-gate 		*q = *p;
29440Sstevel@tonic-gate 		if (*p++ == '%') {
29450Sstevel@tonic-gate 			if (*p) {
29460Sstevel@tonic-gate 				*q = fromhex(*p) * 16;
29470Sstevel@tonic-gate 				p++;
29480Sstevel@tonic-gate 				if (*p) {
29490Sstevel@tonic-gate 					*q += fromhex(*p);
29500Sstevel@tonic-gate 					p++;
29510Sstevel@tonic-gate 				}
29520Sstevel@tonic-gate 			}
29530Sstevel@tonic-gate 		}
29540Sstevel@tonic-gate 		q++;
29550Sstevel@tonic-gate 	}
29560Sstevel@tonic-gate 	*q = '\0';
29570Sstevel@tonic-gate }
29580Sstevel@tonic-gate 
29590Sstevel@tonic-gate 
29600Sstevel@tonic-gate /*
29610Sstevel@tonic-gate  * Get the export information for the lookup vnode, and verify its
29620Sstevel@tonic-gate  * useable.
29630Sstevel@tonic-gate  */
29640Sstevel@tonic-gate int
nfs_check_vpexi(vnode_t * mc_dvp,vnode_t * vp,cred_t * cr,struct exportinfo ** exi)29650Sstevel@tonic-gate nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
29660Sstevel@tonic-gate     struct exportinfo **exi)
29670Sstevel@tonic-gate {
29680Sstevel@tonic-gate 	int walk;
29690Sstevel@tonic-gate 	int error = 0;
29700Sstevel@tonic-gate 
29710Sstevel@tonic-gate 	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
29720Sstevel@tonic-gate 	if (*exi == NULL)
29730Sstevel@tonic-gate 		error = EACCES;
29740Sstevel@tonic-gate 	else {
29750Sstevel@tonic-gate 		/*
29760Sstevel@tonic-gate 		 * If nosub is set for this export then
29770Sstevel@tonic-gate 		 * a lookup relative to the public fh
29780Sstevel@tonic-gate 		 * must not terminate below the
29790Sstevel@tonic-gate 		 * exported directory.
29800Sstevel@tonic-gate 		 */
29810Sstevel@tonic-gate 		if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
29820Sstevel@tonic-gate 			error = EACCES;
29830Sstevel@tonic-gate 	}
29840Sstevel@tonic-gate 
29850Sstevel@tonic-gate 	return (error);
29860Sstevel@tonic-gate }
29872035Scalum 
29882035Scalum /*
29892035Scalum  * Do the main work of handling HA-NFSv4 Resource Group failover on
29902035Scalum  * Sun Cluster.
29912035Scalum  * We need to detect whether any RG admin paths have been added or removed,
29922035Scalum  * and adjust resources accordingly.
29932035Scalum  * Currently we're using a very inefficient algorithm, ~ 2 * O(n**2). In
29942035Scalum  * order to scale, the list and array of paths need to be held in more
29952035Scalum  * suitable data structures.
29962035Scalum  */
29972035Scalum static void
hanfsv4_failover(void)29982035Scalum hanfsv4_failover(void)
29992035Scalum {
30002035Scalum 	int i, start_grace, numadded_paths = 0;
30012035Scalum 	char **added_paths = NULL;
30022035Scalum 	rfs4_dss_path_t *dss_path;
30032035Scalum 
30042035Scalum 	/*
30052390Scalum 	 * Note: currently, rfs4_dss_pathlist cannot be NULL, since
30062390Scalum 	 * it will always include an entry for NFS4_DSS_VAR_DIR. If we
30072390Scalum 	 * make the latter dynamically specified too, the following will
30082390Scalum 	 * need to be adjusted.
30092390Scalum 	 */
30102390Scalum 
30112390Scalum 	/*
30122035Scalum 	 * First, look for removed paths: RGs that have been failed-over
30132035Scalum 	 * away from this node.
30142035Scalum 	 * Walk the "currently-serving" rfs4_dss_pathlist and, for each
30152035Scalum 	 * path, check if it is on the "passed-in" rfs4_dss_newpaths array
30162035Scalum 	 * from nfsd. If not, that RG path has been removed.
30172035Scalum 	 *
30182035Scalum 	 * Note that nfsd has sorted rfs4_dss_newpaths for us, and removed
30192035Scalum 	 * any duplicates.
30202035Scalum 	 */
30212035Scalum 	dss_path = rfs4_dss_pathlist;
30222035Scalum 	do {
30232035Scalum 		int found = 0;
30242035Scalum 		char *path = dss_path->path;
30252035Scalum 
30262035Scalum 		/* used only for non-HA so may not be removed */
30272035Scalum 		if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) {
30282035Scalum 			dss_path = dss_path->next;
30292035Scalum 			continue;
30302035Scalum 		}
30312035Scalum 
30322035Scalum 		for (i = 0; i < rfs4_dss_numnewpaths; i++) {
30332035Scalum 			int cmpret;
30342035Scalum 			char *newpath = rfs4_dss_newpaths[i];
30352035Scalum 
30362035Scalum 			/*
30372035Scalum 			 * Since nfsd has sorted rfs4_dss_newpaths for us,
30382390Scalum 			 * once the return from strcmp is negative we know
30392035Scalum 			 * we've passed the point where "path" should be,
30402035Scalum 			 * and can stop searching: "path" has been removed.
30412035Scalum 			 */
30422390Scalum 			cmpret = strcmp(path, newpath);
30432035Scalum 			if (cmpret < 0)
30442035Scalum 				break;
30452035Scalum 			if (cmpret == 0) {
30462035Scalum 				found = 1;
30472035Scalum 				break;
30482035Scalum 			}
30492035Scalum 		}
30502035Scalum 
30512035Scalum 		if (found == 0) {
30522035Scalum 			unsigned index = dss_path->index;
30532035Scalum 			rfs4_servinst_t *sip = dss_path->sip;
30542035Scalum 			rfs4_dss_path_t *path_next = dss_path->next;
30552035Scalum 
30562035Scalum 			/*
30572035Scalum 			 * This path has been removed.
30582035Scalum 			 * We must clear out the servinst reference to
30592035Scalum 			 * it, since it's now owned by another
30602035Scalum 			 * node: we should not attempt to touch it.
30612035Scalum 			 */
30622035Scalum 			ASSERT(dss_path == sip->dss_paths[index]);
30632035Scalum 			sip->dss_paths[index] = NULL;
30642035Scalum 
30652035Scalum 			/* remove from "currently-serving" list, and destroy */
30662035Scalum 			remque(dss_path);
30672390Scalum 			/* allow for NUL */
30682390Scalum 			kmem_free(dss_path->path, strlen(dss_path->path) + 1);
30692035Scalum 			kmem_free(dss_path, sizeof (rfs4_dss_path_t));
30702035Scalum 
30712035Scalum 			dss_path = path_next;
30722035Scalum 		} else {
30732035Scalum 			/* path was found; not removed */
30742035Scalum 			dss_path = dss_path->next;
30752035Scalum 		}
30762035Scalum 	} while (dss_path != rfs4_dss_pathlist);
30772035Scalum 
30782035Scalum 	/*
30792035Scalum 	 * Now, look for added paths: RGs that have been failed-over
30802035Scalum 	 * to this node.
30812035Scalum 	 * Walk the "passed-in" rfs4_dss_newpaths array from nfsd and,
30822035Scalum 	 * for each path, check if it is on the "currently-serving"
30832035Scalum 	 * rfs4_dss_pathlist. If not, that RG path has been added.
30842035Scalum 	 *
30852035Scalum 	 * Note: we don't do duplicate detection here; nfsd does that for us.
30862035Scalum 	 *
30872035Scalum 	 * Note: numadded_paths <= rfs4_dss_numnewpaths, which gives us
30882035Scalum 	 * an upper bound for the size needed for added_paths[numadded_paths].
30892035Scalum 	 */
30902035Scalum 
30912035Scalum 	/* probably more space than we need, but guaranteed to be enough */
30922035Scalum 	if (rfs4_dss_numnewpaths > 0) {
30932035Scalum 		size_t sz = rfs4_dss_numnewpaths * sizeof (char *);
30942035Scalum 		added_paths = kmem_zalloc(sz, KM_SLEEP);
30952035Scalum 	}
30962035Scalum 
30972035Scalum 	/* walk the "passed-in" rfs4_dss_newpaths array from nfsd */
30982035Scalum 	for (i = 0; i < rfs4_dss_numnewpaths; i++) {
30992035Scalum 		int found = 0;
31002035Scalum 		char *newpath = rfs4_dss_newpaths[i];
31012035Scalum 
31022035Scalum 		dss_path = rfs4_dss_pathlist;
31032035Scalum 		do {
31042035Scalum 			char *path = dss_path->path;
31052035Scalum 
31062035Scalum 			/* used only for non-HA */
31072035Scalum 			if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) {
31082035Scalum 				dss_path = dss_path->next;
31092035Scalum 				continue;
31102035Scalum 			}
31112035Scalum 
31122035Scalum 			if (strncmp(path, newpath, strlen(path)) == 0) {
31132035Scalum 				found = 1;
31142035Scalum 				break;
31152035Scalum 			}
31162035Scalum 
31172035Scalum 			dss_path = dss_path->next;
31182035Scalum 		} while (dss_path != rfs4_dss_pathlist);
31192035Scalum 
31202035Scalum 		if (found == 0) {
31212035Scalum 			added_paths[numadded_paths] = newpath;
31222035Scalum 			numadded_paths++;
31232035Scalum 		}
31242035Scalum 	}
31252035Scalum 
31262035Scalum 	/* did we find any added paths? */
31272035Scalum 	if (numadded_paths > 0) {
31282035Scalum 		/* create a new server instance, and start its grace period */
31292035Scalum 		start_grace = 1;
31302035Scalum 		rfs4_servinst_create(start_grace, numadded_paths, added_paths);
31312035Scalum 
31322035Scalum 		/* read in the stable storage state from these paths */
31332035Scalum 		rfs4_dss_readstate(numadded_paths, added_paths);
31342035Scalum 
31352035Scalum 		/*
31362035Scalum 		 * Multiple failovers during a grace period will cause
31372035Scalum 		 * clients of the same resource group to be partitioned
31382035Scalum 		 * into different server instances, with different
31392035Scalum 		 * grace periods.  Since clients of the same resource
31402035Scalum 		 * group must be subject to the same grace period,
31412035Scalum 		 * we need to reset all currently active grace periods.
31422035Scalum 		 */
31432035Scalum 		rfs4_grace_reset_all();
31442035Scalum 	}
31452035Scalum 
31462035Scalum 	if (rfs4_dss_numnewpaths > 0)
31472035Scalum 		kmem_free(added_paths, rfs4_dss_numnewpaths * sizeof (char *));
31482035Scalum }
31499871SJarrett.Lu@Sun.COM 
31509871SJarrett.Lu@Sun.COM /*
31519871SJarrett.Lu@Sun.COM  * Used by NFSv3 and NFSv4 server to query label of
31529871SJarrett.Lu@Sun.COM  * a pathname component during lookup/access ops.
31539871SJarrett.Lu@Sun.COM  */
31549871SJarrett.Lu@Sun.COM ts_label_t *
nfs_getflabel(vnode_t * vp,struct exportinfo * exi)31559871SJarrett.Lu@Sun.COM nfs_getflabel(vnode_t *vp, struct exportinfo *exi)
31569871SJarrett.Lu@Sun.COM {
31579871SJarrett.Lu@Sun.COM 	zone_t *zone;
31589871SJarrett.Lu@Sun.COM 	ts_label_t *zone_label;
31599871SJarrett.Lu@Sun.COM 	char *path;
31609871SJarrett.Lu@Sun.COM 
31619871SJarrett.Lu@Sun.COM 	mutex_enter(&vp->v_lock);
31629871SJarrett.Lu@Sun.COM 	if (vp->v_path != NULL) {
31639871SJarrett.Lu@Sun.COM 		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
31649871SJarrett.Lu@Sun.COM 		mutex_exit(&vp->v_lock);
31659871SJarrett.Lu@Sun.COM 	} else {
31669871SJarrett.Lu@Sun.COM 		/*
31679871SJarrett.Lu@Sun.COM 		 * v_path not cached. Fall back on pathname of exported
31689871SJarrett.Lu@Sun.COM 		 * file system as we rely on pathname from which we can
31699871SJarrett.Lu@Sun.COM 		 * derive a label. The exported file system portion of
31709871SJarrett.Lu@Sun.COM 		 * path is sufficient to obtain a label.
31719871SJarrett.Lu@Sun.COM 		 */
31729871SJarrett.Lu@Sun.COM 		path = exi->exi_export.ex_path;
31739871SJarrett.Lu@Sun.COM 		if (path == NULL) {
31749871SJarrett.Lu@Sun.COM 			mutex_exit(&vp->v_lock);
31759871SJarrett.Lu@Sun.COM 			return (NULL);
31769871SJarrett.Lu@Sun.COM 		}
31779871SJarrett.Lu@Sun.COM 		zone = zone_find_by_any_path(path, B_FALSE);
31789871SJarrett.Lu@Sun.COM 		mutex_exit(&vp->v_lock);
31799871SJarrett.Lu@Sun.COM 	}
31809871SJarrett.Lu@Sun.COM 	/*
31819871SJarrett.Lu@Sun.COM 	 * Caller has verified that the file is either
31829871SJarrett.Lu@Sun.COM 	 * exported or visible. So if the path falls in
31839871SJarrett.Lu@Sun.COM 	 * global zone, admin_low is returned; otherwise
31849871SJarrett.Lu@Sun.COM 	 * the zone's label is returned.
31859871SJarrett.Lu@Sun.COM 	 */
31869871SJarrett.Lu@Sun.COM 	zone_label = zone->zone_slabel;
31879871SJarrett.Lu@Sun.COM 	label_hold(zone_label);
31889871SJarrett.Lu@Sun.COM 	zone_rele(zone);
31899871SJarrett.Lu@Sun.COM 	return (zone_label);
31909871SJarrett.Lu@Sun.COM }
31919871SJarrett.Lu@Sun.COM 
31929871SJarrett.Lu@Sun.COM /*
31939871SJarrett.Lu@Sun.COM  * TX NFS routine used by NFSv3 and NFSv4 to do label check
31949871SJarrett.Lu@Sun.COM  * on client label and server's file object lable.
31959871SJarrett.Lu@Sun.COM  */
31969871SJarrett.Lu@Sun.COM boolean_t
do_rfs_label_check(bslabel_t * clabel,vnode_t * vp,int flag,struct exportinfo * exi)31979871SJarrett.Lu@Sun.COM do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag,
31989871SJarrett.Lu@Sun.COM     struct exportinfo *exi)
31999871SJarrett.Lu@Sun.COM {
32009871SJarrett.Lu@Sun.COM 	bslabel_t *slabel;
32019871SJarrett.Lu@Sun.COM 	ts_label_t *tslabel;
32029871SJarrett.Lu@Sun.COM 	boolean_t result;
32039871SJarrett.Lu@Sun.COM 
32049871SJarrett.Lu@Sun.COM 	if ((tslabel = nfs_getflabel(vp, exi)) == NULL) {
32059871SJarrett.Lu@Sun.COM 		return (B_FALSE);
32069871SJarrett.Lu@Sun.COM 	}
32079871SJarrett.Lu@Sun.COM 	slabel = label2bslabel(tslabel);
32089871SJarrett.Lu@Sun.COM 	DTRACE_PROBE4(tx__rfs__log__info__labelcheck, char *,
32099871SJarrett.Lu@Sun.COM 	    "comparing server's file label(1) with client label(2) (vp(3))",
32109871SJarrett.Lu@Sun.COM 	    bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp);
32119871SJarrett.Lu@Sun.COM 
32129871SJarrett.Lu@Sun.COM 	if (flag == EQUALITY_CHECK)
32139871SJarrett.Lu@Sun.COM 		result = blequal(clabel, slabel);
32149871SJarrett.Lu@Sun.COM 	else
32159871SJarrett.Lu@Sun.COM 		result = bldominates(clabel, slabel);
32169871SJarrett.Lu@Sun.COM 	label_rele(tslabel);
32179871SJarrett.Lu@Sun.COM 	return (result);
32189871SJarrett.Lu@Sun.COM }
321911539SChunli.Zhang@Sun.COM 
322011539SChunli.Zhang@Sun.COM /*
322111539SChunli.Zhang@Sun.COM  * Callback function to return the loaned buffers.
322211539SChunli.Zhang@Sun.COM  * Calls VOP_RETZCBUF() only after all uio_iov[]
322311539SChunli.Zhang@Sun.COM  * buffers are returned. nu_ref maintains the count.
322411539SChunli.Zhang@Sun.COM  */
322511539SChunli.Zhang@Sun.COM void
rfs_free_xuio(void * free_arg)322611539SChunli.Zhang@Sun.COM rfs_free_xuio(void *free_arg)
322711539SChunli.Zhang@Sun.COM {
322811539SChunli.Zhang@Sun.COM 	uint_t ref;
322911539SChunli.Zhang@Sun.COM 	nfs_xuio_t *nfsuiop = (nfs_xuio_t *)free_arg;
323011539SChunli.Zhang@Sun.COM 
323111539SChunli.Zhang@Sun.COM 	ref = atomic_dec_uint_nv(&nfsuiop->nu_ref);
323211539SChunli.Zhang@Sun.COM 
323311539SChunli.Zhang@Sun.COM 	/*
323411539SChunli.Zhang@Sun.COM 	 * Call VOP_RETZCBUF() only when all the iov buffers
323511539SChunli.Zhang@Sun.COM 	 * are sent OTW.
323611539SChunli.Zhang@Sun.COM 	 */
323711539SChunli.Zhang@Sun.COM 	if (ref != 0)
323811539SChunli.Zhang@Sun.COM 		return;
323911539SChunli.Zhang@Sun.COM 
324011539SChunli.Zhang@Sun.COM 	if (((uio_t *)nfsuiop)->uio_extflg & UIO_XUIO) {
324111539SChunli.Zhang@Sun.COM 		(void) VOP_RETZCBUF(nfsuiop->nu_vp, (xuio_t *)free_arg, NULL,
324211539SChunli.Zhang@Sun.COM 		    NULL);
324311539SChunli.Zhang@Sun.COM 		VN_RELE(nfsuiop->nu_vp);
324411539SChunli.Zhang@Sun.COM 	}
324511539SChunli.Zhang@Sun.COM 
324611539SChunli.Zhang@Sun.COM 	kmem_cache_free(nfs_xuio_cache, free_arg);
324711539SChunli.Zhang@Sun.COM }
324811539SChunli.Zhang@Sun.COM 
324911539SChunli.Zhang@Sun.COM xuio_t *
rfs_setup_xuio(vnode_t * vp)325011539SChunli.Zhang@Sun.COM rfs_setup_xuio(vnode_t *vp)
325111539SChunli.Zhang@Sun.COM {
325211539SChunli.Zhang@Sun.COM 	nfs_xuio_t *nfsuiop;
325311539SChunli.Zhang@Sun.COM 
325411539SChunli.Zhang@Sun.COM 	nfsuiop = kmem_cache_alloc(nfs_xuio_cache, KM_SLEEP);
325511539SChunli.Zhang@Sun.COM 
325611539SChunli.Zhang@Sun.COM 	bzero(nfsuiop, sizeof (nfs_xuio_t));
325711539SChunli.Zhang@Sun.COM 	nfsuiop->nu_vp = vp;
325811539SChunli.Zhang@Sun.COM 
325911539SChunli.Zhang@Sun.COM 	/*
326011539SChunli.Zhang@Sun.COM 	 * ref count set to 1. more may be added
326111539SChunli.Zhang@Sun.COM 	 * if multiple mblks refer to multiple iov's.
326211539SChunli.Zhang@Sun.COM 	 * This is done in uio_to_mblk().
326311539SChunli.Zhang@Sun.COM 	 */
326411539SChunli.Zhang@Sun.COM 
326511539SChunli.Zhang@Sun.COM 	nfsuiop->nu_ref = 1;
326611539SChunli.Zhang@Sun.COM 
326711539SChunli.Zhang@Sun.COM 	nfsuiop->nu_frtn.free_func = rfs_free_xuio;
326811539SChunli.Zhang@Sun.COM 	nfsuiop->nu_frtn.free_arg = (char *)nfsuiop;
326911539SChunli.Zhang@Sun.COM 
327011539SChunli.Zhang@Sun.COM 	nfsuiop->nu_uio.xu_type = UIOTYPE_ZEROCOPY;
327111539SChunli.Zhang@Sun.COM 
327211539SChunli.Zhang@Sun.COM 	return (&nfsuiop->nu_uio);
327311539SChunli.Zhang@Sun.COM }
327411539SChunli.Zhang@Sun.COM 
327511539SChunli.Zhang@Sun.COM mblk_t *
uio_to_mblk(uio_t * uiop)327611539SChunli.Zhang@Sun.COM uio_to_mblk(uio_t *uiop)
327711539SChunli.Zhang@Sun.COM {
327811539SChunli.Zhang@Sun.COM 	struct iovec *iovp;
327911539SChunli.Zhang@Sun.COM 	int i;
328011539SChunli.Zhang@Sun.COM 	mblk_t *mp, *mp1;
328111539SChunli.Zhang@Sun.COM 	nfs_xuio_t *nfsuiop = (nfs_xuio_t *)uiop;
328211539SChunli.Zhang@Sun.COM 
328311539SChunli.Zhang@Sun.COM 	if (uiop->uio_iovcnt == 0)
328411539SChunli.Zhang@Sun.COM 		return (NULL);
328511539SChunli.Zhang@Sun.COM 
328611539SChunli.Zhang@Sun.COM 	iovp = uiop->uio_iov;
328711539SChunli.Zhang@Sun.COM 	mp = mp1 = esballoca((uchar_t *)iovp->iov_base, iovp->iov_len,
328811539SChunli.Zhang@Sun.COM 	    BPRI_MED, &nfsuiop->nu_frtn);
328911539SChunli.Zhang@Sun.COM 	ASSERT(mp != NULL);
329011539SChunli.Zhang@Sun.COM 
329111539SChunli.Zhang@Sun.COM 	mp->b_wptr += iovp->iov_len;
329211539SChunli.Zhang@Sun.COM 	mp->b_datap->db_type = M_DATA;
329311539SChunli.Zhang@Sun.COM 
329411539SChunli.Zhang@Sun.COM 	for (i = 1; i < uiop->uio_iovcnt; i++) {
329511539SChunli.Zhang@Sun.COM 		iovp = (uiop->uio_iov + i);
329611539SChunli.Zhang@Sun.COM 
329711539SChunli.Zhang@Sun.COM 		mp1->b_cont = esballoca(
329811539SChunli.Zhang@Sun.COM 		    (uchar_t *)iovp->iov_base, iovp->iov_len, BPRI_MED,
329911539SChunli.Zhang@Sun.COM 		    &nfsuiop->nu_frtn);
330011539SChunli.Zhang@Sun.COM 
330111539SChunli.Zhang@Sun.COM 		mp1 = mp1->b_cont;
330211539SChunli.Zhang@Sun.COM 		ASSERT(mp1 != NULL);
330311539SChunli.Zhang@Sun.COM 		mp1->b_wptr += iovp->iov_len;
330411539SChunli.Zhang@Sun.COM 		mp1->b_datap->db_type = M_DATA;
330511539SChunli.Zhang@Sun.COM 	}
330611539SChunli.Zhang@Sun.COM 
330711539SChunli.Zhang@Sun.COM 	nfsuiop->nu_ref = uiop->uio_iovcnt;
330811539SChunli.Zhang@Sun.COM 
330911539SChunli.Zhang@Sun.COM 	return (mp);
331011539SChunli.Zhang@Sun.COM }
331111539SChunli.Zhang@Sun.COM 
331211539SChunli.Zhang@Sun.COM void
rfs_rndup_mblks(mblk_t * mp,uint_t len,int buf_loaned)331311539SChunli.Zhang@Sun.COM rfs_rndup_mblks(mblk_t *mp, uint_t len, int buf_loaned)
331411539SChunli.Zhang@Sun.COM {
331511539SChunli.Zhang@Sun.COM 	int i, rndup;
331611539SChunli.Zhang@Sun.COM 	int alloc_err = 0;
331711539SChunli.Zhang@Sun.COM 	mblk_t *rmp;
331811539SChunli.Zhang@Sun.COM 
331911539SChunli.Zhang@Sun.COM 	rndup = BYTES_PER_XDR_UNIT - (len % BYTES_PER_XDR_UNIT);
332011539SChunli.Zhang@Sun.COM 
332111539SChunli.Zhang@Sun.COM 	/* single mblk_t non copy-reduction case */
332211539SChunli.Zhang@Sun.COM 	if (!buf_loaned) {
332311539SChunli.Zhang@Sun.COM 		mp->b_wptr += len;
332411539SChunli.Zhang@Sun.COM 		if (rndup != BYTES_PER_XDR_UNIT) {
332511539SChunli.Zhang@Sun.COM 			for (i = 0; i < rndup; i++)
332611539SChunli.Zhang@Sun.COM 				*mp->b_wptr++ = '\0';
332711539SChunli.Zhang@Sun.COM 		}
332811539SChunli.Zhang@Sun.COM 		return;
332911539SChunli.Zhang@Sun.COM 	}
333011539SChunli.Zhang@Sun.COM 
333111539SChunli.Zhang@Sun.COM 	/* no need for extra rndup */
333211539SChunli.Zhang@Sun.COM 	if (rndup == BYTES_PER_XDR_UNIT)
333311539SChunli.Zhang@Sun.COM 		return;
333411539SChunli.Zhang@Sun.COM 
333511539SChunli.Zhang@Sun.COM 	while (mp->b_cont)
333611539SChunli.Zhang@Sun.COM 		mp = mp->b_cont;
333711539SChunli.Zhang@Sun.COM 
333811539SChunli.Zhang@Sun.COM 	/*
333911539SChunli.Zhang@Sun.COM 	 * In case of copy-reduction mblks, the size of the mblks
334011539SChunli.Zhang@Sun.COM 	 * are fixed and are of the size of the loaned buffers.
334111539SChunli.Zhang@Sun.COM 	 * Allocate a roundup mblk and chain it to the data
334211539SChunli.Zhang@Sun.COM 	 * buffers. This is sub-optimal, but not expected to
334311539SChunli.Zhang@Sun.COM 	 * happen in regular common workloads.
334411539SChunli.Zhang@Sun.COM 	 */
334511539SChunli.Zhang@Sun.COM 
334611539SChunli.Zhang@Sun.COM 	rmp = allocb_wait(rndup, BPRI_MED, STR_NOSIG, &alloc_err);
334711539SChunli.Zhang@Sun.COM 	ASSERT(rmp != NULL);
334811539SChunli.Zhang@Sun.COM 	ASSERT(alloc_err == 0);
334911539SChunli.Zhang@Sun.COM 
335011539SChunli.Zhang@Sun.COM 	for (i = 0; i < rndup; i++)
335111539SChunli.Zhang@Sun.COM 		*rmp->b_wptr++ = '\0';
335211539SChunli.Zhang@Sun.COM 
335311539SChunli.Zhang@Sun.COM 	rmp->b_datap->db_type = M_DATA;
335411539SChunli.Zhang@Sun.COM 	mp->b_cont = rmp;
335511539SChunli.Zhang@Sun.COM }
3356