xref: /titanic_51/usr/src/uts/common/fs/nfs/nfs_server.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
29  *	All rights reserved.
30  *	Use is subject to license terms.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/systm.h>
38 #include <sys/cred.h>
39 #include <sys/proc.h>
40 #include <sys/user.h>
41 #include <sys/buf.h>
42 #include <sys/vfs.h>
43 #include <sys/vnode.h>
44 #include <sys/pathname.h>
45 #include <sys/uio.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include <sys/errno.h>
49 #include <sys/socket.h>
50 #include <sys/sysmacros.h>
51 #include <sys/siginfo.h>
52 #include <sys/tiuser.h>
53 #include <sys/statvfs.h>
54 #include <sys/stream.h>
55 #include <sys/strsubr.h>
56 #include <sys/stropts.h>
57 #include <sys/timod.h>
58 #include <sys/t_kuser.h>
59 #include <sys/kmem.h>
60 #include <sys/kstat.h>
61 #include <sys/dirent.h>
62 #include <sys/cmn_err.h>
63 #include <sys/debug.h>
64 #include <sys/unistd.h>
65 #include <sys/vtrace.h>
66 #include <sys/mode.h>
67 #include <sys/acl.h>
68 #include <sys/sdt.h>
69 
70 #include <rpc/types.h>
71 #include <rpc/auth.h>
72 #include <rpc/auth_unix.h>
73 #include <rpc/auth_des.h>
74 #include <rpc/svc.h>
75 #include <rpc/xdr.h>
76 
77 #include <nfs/nfs.h>
78 #include <nfs/export.h>
79 #include <nfs/nfssys.h>
80 #include <nfs/nfs_clnt.h>
81 #include <nfs/nfs_acl.h>
82 #include <nfs/nfs_log.h>
83 #include <nfs/lm.h>
84 
85 #include <rpcsvc/nfsauth_prot.h>
86 
87 #include <sys/modctl.h>
88 #include <sys/cladm.h>
89 #include <sys/clconf.h>
90 
91 #define	MAXHOST 32
92 const char *kinet_ntop6(uchar_t *, char *, size_t);
93 
94 /*
95  * Module linkage information.
96  */
97 
98 static struct modlmisc modlmisc = {
99 	&mod_miscops, "NFS server module"
100 };
101 
102 static struct modlinkage modlinkage = {
103 	MODREV_1, (void *)&modlmisc, NULL
104 };
105 
106 char _depends_on[] = "misc/klmmod";
107 
108 int
109 _init(void)
110 {
111 	int status;
112 
113 	if ((status = nfs_srvinit()) != 0) {
114 		cmn_err(CE_WARN, "_init: nfs_srvinit failed");
115 		return (status);
116 	}
117 
118 	status = mod_install((struct modlinkage *)&modlinkage);
119 	if (status != 0) {
120 		/*
121 		 * Could not load module, cleanup previous
122 		 * initialization work.
123 		 */
124 		nfs_srvfini();
125 	}
126 
127 	nfs_srv_quiesce_func = nfs_srv_quiesce_all;
128 
129 	return (status);
130 }
131 
132 int
133 _fini()
134 {
135 	return (EBUSY);
136 }
137 
138 int
139 _info(struct modinfo *modinfop)
140 {
141 	return (mod_info(&modlinkage, modinfop));
142 }
143 
144 /*
145  * RPC dispatch table
146  * Indexed by version, proc
147  */
148 
149 struct rpcdisp {
150 	void	  (*dis_proc)();	/* proc to call */
151 	xdrproc_t dis_xdrargs;		/* xdr routine to get args */
152 	xdrproc_t dis_fastxdrargs;	/* `fast' xdr routine to get args */
153 	int	  dis_argsz;		/* sizeof args */
154 	xdrproc_t dis_xdrres;		/* xdr routine to put results */
155 	xdrproc_t dis_fastxdrres;	/* `fast' xdr routine to put results */
156 	int	  dis_ressz;		/* size of results */
157 	void	  (*dis_resfree)();	/* frees space allocated by proc */
158 	int	  dis_flags;		/* flags, see below */
159 	fhandle_t *(*dis_getfh)();	/* returns the fhandle for the req */
160 	void	  (*dis_flagproc)();	/* calculate dis_flags (nfsv4 only) */
161 };
162 
163 #define	RPC_IDEMPOTENT	0x1	/* idempotent or not */
164 /*
165  * Be very careful about which NFS procedures get the RPC_ALLOWANON bit.
166  * Right now, it this bit is on, we ignore the results of per NFS request
167  * access control.
168  */
169 #define	RPC_ALLOWANON	0x2	/* allow anonymous access */
170 #define	RPC_MAPRESP	0x4	/* use mapped response buffer */
171 #define	RPC_AVOIDWORK	0x8	/* do work avoidance for dups */
172 #define	RPC_PUBLICFH_OK	0x10	/* allow use of public filehandle */
173 
174 /*
175  * PUBLICFH_CHECK() checks if the dispatch routine supports
176  * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the
177  * incoming request is using the public filehandle. The check duplicates
178  * the exportmatch() call done in checkexport(), and we should consider
179  * modifying those routines to avoid the duplication. For now, we optimize
180  * by calling exportmatch() only after checking that the dispatch routine
181  * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported
182  * public (i.e., not the placeholder).
183  */
184 #define	PUBLICFH_CHECK(disp, exi, fh) \
185 		((disp->dis_flags & RPC_PUBLICFH_OK) && \
186 		((exi->exi_export.ex_flags & EX_PUBLIC) || \
187 		(exi == exi_public && exportmatch(exi_root, \
188 		&fh->fh_fsid, (fid_t *)&fh->fh_xlen))))
189 
190 struct rpc_disptable {
191 	int dis_nprocs;
192 	char **dis_procnames;
193 	kstat_named_t **dis_proccntp;
194 	struct rpcdisp *dis_table;
195 };
196 
197 static void	nfs_srv_shutdown_all(int);
198 static void	rfs4_server_start(int);
199 static void	rpc_null(caddr_t *, caddr_t *);
200 static void	rfs_error(caddr_t *, caddr_t *);
201 static void	nullfree(void);
202 static void	rfs_dispatch(struct svc_req *, SVCXPRT *);
203 static void	acl_dispatch(struct svc_req *, SVCXPRT *);
204 static void	common_dispatch(struct svc_req *, SVCXPRT *,
205 		rpcvers_t, rpcvers_t, char *,
206 		struct rpc_disptable *);
207 static	int	checkauth(struct exportinfo *, struct svc_req *, cred_t *, int,
208 			bool_t);
209 static char	*client_name(struct svc_req *req);
210 static char	*client_addr(struct svc_req *req, char *buf);
211 extern	int	sec_svc_getcred(struct svc_req *, cred_t *cr, char **, int *);
212 extern	bool_t	sec_svc_inrootlist(int, caddr_t, int, caddr_t *);
213 
214 #define	NFSLOG_COPY_NETBUF(exi, xprt, nb)	{		\
215 	(nb)->maxlen = (xprt)->xp_rtaddr.maxlen;		\
216 	(nb)->len = (xprt)->xp_rtaddr.len;			\
217 	(nb)->buf = kmem_alloc((nb)->len, KM_SLEEP);		\
218 	bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len);	\
219 	}
220 
221 /*
222  * Public Filehandle common nfs routines
223  */
224 static int	MCLpath(char **);
225 static void	URLparse(char *);
226 
227 /*
228  * NFS callout table.
229  * This table is used by svc_getreq() to dispatch a request with
230  * a given prog/vers pair to an appropriate service provider
231  * dispatch routine.
232  *
233  * NOTE: ordering is relied upon below when resetting the version min/max
234  * for NFS_PROGRAM.  Careful, if this is ever changed.
235  */
236 static SVC_CALLOUT __nfs_sc_clts[] = {
237 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
238 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
239 };
240 
241 static SVC_CALLOUT_TABLE nfs_sct_clts = {
242 	sizeof (__nfs_sc_clts) / sizeof (__nfs_sc_clts[0]), FALSE,
243 	__nfs_sc_clts
244 };
245 
246 static SVC_CALLOUT __nfs_sc_cots[] = {
247 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
248 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
249 };
250 
251 static SVC_CALLOUT_TABLE nfs_sct_cots = {
252 	sizeof (__nfs_sc_cots) / sizeof (__nfs_sc_cots[0]), FALSE, __nfs_sc_cots
253 };
254 
255 static SVC_CALLOUT __nfs_sc_rdma[] = {
256 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
257 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
258 };
259 
260 static SVC_CALLOUT_TABLE nfs_sct_rdma = {
261 	sizeof (__nfs_sc_rdma) / sizeof (__nfs_sc_rdma[0]), FALSE, __nfs_sc_rdma
262 };
263 rpcvers_t nfs_versmin = NFS_VERSMIN_DEFAULT;
264 rpcvers_t nfs_versmax = NFS_VERSMAX_DEFAULT;
265 
266 /*
267  * Used to track the state of the server so that initialization
268  * can be done properly.
269  */
270 typedef enum {
271 	NFS_SERVER_STOPPED,	/* server state destroyed */
272 	NFS_SERVER_STOPPING,	/* server state being destroyed */
273 	NFS_SERVER_RUNNING,
274 	NFS_SERVER_QUIESCED,	/* server state preserved */
275 	NFS_SERVER_OFFLINE	/* server pool offline */
276 } nfs_server_running_t;
277 
278 static nfs_server_running_t nfs_server_upordown;
279 static kmutex_t nfs_server_upordown_lock;
280 static	kcondvar_t nfs_server_upordown_cv;
281 
282 /*
283  * RDMA wait variables.
284  */
285 static kcondvar_t rdma_wait_cv;
286 static kmutex_t rdma_wait_mutex;
287 
288 /*
289  * Will be called at the point the server pool is being unregistered
290  * from the pool list. From that point onwards, the pool is waiting
291  * to be drained and as such the server state is stale and pertains
292  * to the old instantiation of the NFS server pool.
293  */
294 void
295 nfs_srv_offline(void)
296 {
297 	mutex_enter(&nfs_server_upordown_lock);
298 	if (nfs_server_upordown == NFS_SERVER_RUNNING) {
299 		nfs_server_upordown = NFS_SERVER_OFFLINE;
300 	}
301 	mutex_exit(&nfs_server_upordown_lock);
302 }
303 
304 /*
305  * Will be called at the point the server pool is being destroyed so
306  * all transports have been closed and no service threads are in
307  * existence.
308  *
309  * If we quiesce the server, we're shutting it down without destroying the
310  * server state. This allows it to warm start subsequently.
311  */
312 void
313 nfs_srv_stop_all(void)
314 {
315 	int quiesce = 0;
316 	nfs_srv_shutdown_all(quiesce);
317 }
318 
319 /*
320  * This alternative shutdown routine can be requested via nfssys()
321  */
322 void
323 nfs_srv_quiesce_all(void)
324 {
325 	int quiesce = 1;
326 	nfs_srv_shutdown_all(quiesce);
327 }
328 
329 static void
330 nfs_srv_shutdown_all(int quiesce) {
331 	mutex_enter(&nfs_server_upordown_lock);
332 	if (quiesce) {
333 		if (nfs_server_upordown == NFS_SERVER_RUNNING ||
334 			nfs_server_upordown == NFS_SERVER_OFFLINE) {
335 			nfs_server_upordown = NFS_SERVER_QUIESCED;
336 			cv_signal(&nfs_server_upordown_cv);
337 			cmn_err(CE_NOTE, "nfs_server: server is now quiesced; "
338 			    "NFSv4 state has been preserved");
339 		}
340 	} else {
341 		if (nfs_server_upordown == NFS_SERVER_OFFLINE) {
342 			nfs_server_upordown = NFS_SERVER_STOPPING;
343 			mutex_exit(&nfs_server_upordown_lock);
344 			rfs4_state_fini();
345 			mutex_enter(&nfs_server_upordown_lock);
346 			nfs_server_upordown = NFS_SERVER_STOPPED;
347 			cv_signal(&nfs_server_upordown_cv);
348 		}
349 	}
350 	mutex_exit(&nfs_server_upordown_lock);
351 }
352 
353 static int
354 nfs_srv_set_sc_versions(struct file *fp, SVC_CALLOUT_TABLE **sctpp,
355 			rpcvers_t versmin, rpcvers_t versmax)
356 {
357 	struct strioctl strioc;
358 	struct T_info_ack tinfo;
359 	int		error, retval;
360 
361 	/*
362 	 * Find out what type of transport this is.
363 	 */
364 	strioc.ic_cmd = TI_GETINFO;
365 	strioc.ic_timout = -1;
366 	strioc.ic_len = sizeof (tinfo);
367 	strioc.ic_dp = (char *)&tinfo;
368 	tinfo.PRIM_type = T_INFO_REQ;
369 
370 	error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
371 	    CRED(), &retval);
372 	if (error || retval)
373 		return (error);
374 
375 	/*
376 	 * Based on our query of the transport type...
377 	 *
378 	 * Reset the min/max versions based on the caller's request
379 	 * NOTE: This assumes that NFS_PROGRAM is first in the array!!
380 	 * And the second entry is the NFS_ACL_PROGRAM.
381 	 */
382 	switch (tinfo.SERV_type) {
383 	case T_CLTS:
384 		if (versmax == NFS_V4)
385 			return (EINVAL);
386 		__nfs_sc_clts[0].sc_versmin = versmin;
387 		__nfs_sc_clts[0].sc_versmax = versmax;
388 		__nfs_sc_clts[1].sc_versmin = versmin;
389 		__nfs_sc_clts[1].sc_versmax = versmax;
390 		*sctpp = &nfs_sct_clts;
391 		break;
392 	case T_COTS:
393 	case T_COTS_ORD:
394 		__nfs_sc_cots[0].sc_versmin = versmin;
395 		__nfs_sc_cots[0].sc_versmax = versmax;
396 		/* For the NFS_ACL program, check the max version */
397 		if (versmax > NFS_ACL_VERSMAX)
398 			versmax = NFS_ACL_VERSMAX;
399 		__nfs_sc_cots[1].sc_versmin = versmin;
400 		__nfs_sc_cots[1].sc_versmax = versmax;
401 		*sctpp = &nfs_sct_cots;
402 		break;
403 	default:
404 		error = EINVAL;
405 	}
406 
407 	return (error);
408 }
409 
410 /*
411  * NFS Server system call.
412  * Does all of the work of running a NFS server.
413  * uap->fd is the fd of an open transport provider
414  */
415 int
416 nfs_svc(struct nfs_svc_args *arg, model_t model)
417 {
418 	file_t *fp;
419 	SVCMASTERXPRT *xprt;
420 	int error;
421 	int readsize;
422 	char buf[KNC_STRSIZE];
423 	size_t len;
424 	STRUCT_HANDLE(nfs_svc_args, uap);
425 	struct netbuf addrmask;
426 	SVC_CALLOUT_TABLE *sctp = NULL;
427 
428 #ifdef lint
429 	model = model;		/* STRUCT macros don't always refer to it */
430 #endif
431 
432 	STRUCT_SET_HANDLE(uap, model, arg);
433 
434 	/* Check privileges in nfssys() */
435 
436 	if ((fp = getf(STRUCT_FGET(uap, fd))) == NULL)
437 		return (EBADF);
438 
439 	/*
440 	 * Set read buffer size to rsize
441 	 * and add room for RPC headers.
442 	 */
443 	readsize = nfs3tsize() + (RPC_MAXDATASIZE - NFS_MAXDATA);
444 	if (readsize < RPC_MAXDATASIZE)
445 		readsize = RPC_MAXDATASIZE;
446 
447 	error = copyinstr((const char *)STRUCT_FGETP(uap, netid), buf,
448 	    KNC_STRSIZE, &len);
449 	if (error) {
450 		releasef(STRUCT_FGET(uap, fd));
451 		return (error);
452 	}
453 
454 	addrmask.len = STRUCT_FGET(uap, addrmask.len);
455 	addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen);
456 	addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP);
457 	error = copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf,
458 	    addrmask.len);
459 	if (error) {
460 		releasef(STRUCT_FGET(uap, fd));
461 		kmem_free(addrmask.buf, addrmask.maxlen);
462 		return (error);
463 	}
464 
465 	nfs_versmin = STRUCT_FGET(uap, versmin);
466 	nfs_versmax = STRUCT_FGET(uap, versmax);
467 
468 	/* Double check the vers min/max ranges */
469 	if ((nfs_versmin > nfs_versmax) ||
470 		(nfs_versmin < NFS_VERSMIN) ||
471 		(nfs_versmax > NFS_VERSMAX)) {
472 		nfs_versmin = NFS_VERSMIN_DEFAULT;
473 		nfs_versmax = NFS_VERSMAX_DEFAULT;
474 	}
475 
476 	if (error =
477 	    nfs_srv_set_sc_versions(fp, &sctp, nfs_versmin, nfs_versmax)) {
478 		releasef(STRUCT_FGET(uap, fd));
479 		kmem_free(addrmask.buf, addrmask.maxlen);
480 		return (error);
481 	}
482 
483 	/* Initialize nfsv4 server */
484 	if (nfs_versmax == (rpcvers_t)NFS_V4)
485 		rfs4_server_start(STRUCT_FGET(uap, delegation));
486 
487 	/* Create a transport handle. */
488 	error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt,
489 				sctp, NULL, NFS_SVCPOOL_ID, TRUE);
490 
491 	if (error)
492 		kmem_free(addrmask.buf, addrmask.maxlen);
493 
494 	releasef(STRUCT_FGET(uap, fd));
495 
496 	/* save the cluster nodeid */
497 	if (cluster_bootflags & CLUSTER_BOOTED)
498 		lm_global_nlmid = clconf_get_nodeid();
499 
500 	return (error);
501 }
502 
503 static void
504 rfs4_server_start(int nfs4_srv_delegation)
505 {
506 	/*
507 	 * Determine if the server has previously been "started" and
508 	 * if not, do the per instance initialization
509 	 */
510 	mutex_enter(&nfs_server_upordown_lock);
511 
512 	if (nfs_server_upordown != NFS_SERVER_RUNNING) {
513 		/* Do we need to stop and wait on the previous server? */
514 		while (nfs_server_upordown == NFS_SERVER_STOPPING ||
515 			nfs_server_upordown == NFS_SERVER_OFFLINE)
516 			cv_wait(&nfs_server_upordown_cv,
517 			    &nfs_server_upordown_lock);
518 
519 		if (nfs_server_upordown != NFS_SERVER_RUNNING) {
520 			(void) svc_pool_control(NFS_SVCPOOL_ID,
521 			    SVCPSET_UNREGISTER_PROC, (void *)&nfs_srv_offline);
522 			(void) svc_pool_control(NFS_SVCPOOL_ID,
523 			    SVCPSET_SHUTDOWN_PROC, (void *)&nfs_srv_stop_all);
524 
525 			/* is this an nfsd warm start? */
526 			if (nfs_server_upordown == NFS_SERVER_QUIESCED) {
527 				int start_grace;
528 
529 				cmn_err(CE_NOTE, "nfs_server: "
530 				    "server was previously quiesced; "
531 				    "existing NFSv4 state will be re-used");
532 
533 				/*
534 				 * Cluster: this is also the signal that
535 				 * a failover has occurred, so create a new
536 				 * server instance, and start its grace period.
537 				 * We also need to reset all currently
538 				 * active grace periods in case of multiple
539 				 * failovers within the grace duration,
540 				 * to avoid partitioning clients of the same
541 				 * resource into different instances.
542 				 */
543 				if (cluster_bootflags & CLUSTER_BOOTED) {
544 					rfs4_grace_reset_all();
545 					start_grace = 1;
546 					rfs4_servinst_create(start_grace);
547 				}
548 			} else {
549 				rfs4_state_init();
550 			}
551 
552 			/*
553 			 * Check to see if delegation is to be
554 			 * enabled at the server
555 			 */
556 			if (nfs4_srv_delegation != FALSE)
557 				rfs4_set_deleg_policy(SRV_NORMAL_DELEGATE);
558 
559 			nfs_server_upordown = NFS_SERVER_RUNNING;
560 		}
561 		cv_signal(&nfs_server_upordown_cv);
562 	}
563 	mutex_exit(&nfs_server_upordown_lock);
564 }
565 
566 /*
567  * If RDMA device available,
568  * start RDMA listener.
569  */
570 int
571 rdma_start(struct rdma_svc_args *rsa)
572 {
573 	int error;
574 	rdma_xprt_group_t started_rdma_xprts;
575 
576 	/* Double check the vers min/max ranges */
577 	if ((rsa->nfs_versmin > rsa->nfs_versmax) ||
578 		(rsa->nfs_versmin < NFS_VERSMIN) ||
579 		(rsa->nfs_versmax > NFS_VERSMAX)) {
580 		rsa->nfs_versmin = NFS_VERSMIN_DEFAULT;
581 		rsa->nfs_versmax = NFS_VERSMAX_DEFAULT;
582 	}
583 	nfs_versmin = rsa->nfs_versmin;
584 	nfs_versmax = rsa->nfs_versmax;
585 
586 	/* Set the versions in the callout table */
587 	__nfs_sc_rdma[0].sc_versmin = rsa->nfs_versmin;
588 	__nfs_sc_rdma[0].sc_versmax = rsa->nfs_versmax;
589 	/* For the NFS_ACL program, check the max version */
590 	__nfs_sc_rdma[1].sc_versmin = rsa->nfs_versmin;
591 	if (rsa->nfs_versmax > NFS_ACL_VERSMAX)
592 		__nfs_sc_rdma[1].sc_versmax = NFS_ACL_VERSMAX;
593 	else
594 		__nfs_sc_rdma[1].sc_versmax = rsa->nfs_versmax;
595 
596 	/* Initialize nfsv4 server */
597 	if (rsa->nfs_versmax == (rpcvers_t)NFS_V4)
598 		rfs4_server_start(rsa->delegation);
599 
600 	started_rdma_xprts.rtg_count = 0;
601 	started_rdma_xprts.rtg_listhead = NULL;
602 	started_rdma_xprts.rtg_poolid = rsa->poolid;
603 	error = svc_rdma_kcreate(rsa->netid, &nfs_sct_rdma, rsa->poolid,
604 	    &started_rdma_xprts);
605 
606 	if (error == 0) {
607 		mutex_enter(&rdma_wait_mutex);
608 		if (!cv_wait_sig(&rdma_wait_cv, &rdma_wait_mutex)) {
609 			rdma_stop(started_rdma_xprts);
610 		}
611 		mutex_exit(&rdma_wait_mutex);
612 	}
613 
614 	return (error);
615 }
616 
617 /* ARGSUSED */
618 static void
619 rpc_null(caddr_t *argp, caddr_t *resp)
620 {
621 }
622 
623 /* ARGSUSED */
624 static void
625 rfs_error(caddr_t *argp, caddr_t *resp)
626 {
627 	/* return (EOPNOTSUPP); */
628 }
629 
630 static void
631 nullfree(void)
632 {
633 }
634 
635 static char *rfscallnames_v2[] = {
636 	"RFS2_NULL",
637 	"RFS2_GETATTR",
638 	"RFS2_SETATTR",
639 	"RFS2_ROOT",
640 	"RFS2_LOOKUP",
641 	"RFS2_READLINK",
642 	"RFS2_READ",
643 	"RFS2_WRITECACHE",
644 	"RFS2_WRITE",
645 	"RFS2_CREATE",
646 	"RFS2_REMOVE",
647 	"RFS2_RENAME",
648 	"RFS2_LINK",
649 	"RFS2_SYMLINK",
650 	"RFS2_MKDIR",
651 	"RFS2_RMDIR",
652 	"RFS2_READDIR",
653 	"RFS2_STATFS"
654 };
655 
656 static struct rpcdisp rfsdisptab_v2[] = {
657 	/*
658 	 * NFS VERSION 2
659 	 */
660 
661 	/* RFS_NULL = 0 */
662 	{rpc_null,
663 	    xdr_void, NULL_xdrproc_t, 0,
664 	    xdr_void, NULL_xdrproc_t, 0,
665 	    nullfree, RPC_IDEMPOTENT,
666 	    0, 0},
667 
668 	/* RFS_GETATTR = 1 */
669 	{rfs_getattr,
670 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
671 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
672 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
673 	    rfs_getattr_getfh, 0},
674 
675 	/* RFS_SETATTR = 2 */
676 	{rfs_setattr,
677 	    xdr_saargs, NULL_xdrproc_t, sizeof (struct nfssaargs),
678 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
679 	    nullfree, RPC_MAPRESP,
680 	    rfs_setattr_getfh, 0},
681 
682 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
683 	{rfs_error,
684 	    xdr_void, NULL_xdrproc_t, 0,
685 	    xdr_void, NULL_xdrproc_t, 0,
686 	    nullfree, RPC_IDEMPOTENT,
687 	    0, 0},
688 
689 	/* RFS_LOOKUP = 4 */
690 	{rfs_lookup,
691 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
692 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
693 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP|RPC_PUBLICFH_OK,
694 	    rfs_lookup_getfh, 0},
695 
696 	/* RFS_READLINK = 5 */
697 	{rfs_readlink,
698 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
699 	    xdr_rdlnres, NULL_xdrproc_t, sizeof (struct nfsrdlnres),
700 	    rfs_rlfree, RPC_IDEMPOTENT,
701 	    rfs_readlink_getfh, 0},
702 
703 	/* RFS_READ = 6 */
704 	{rfs_read,
705 	    xdr_readargs, NULL_xdrproc_t, sizeof (struct nfsreadargs),
706 	    xdr_rdresult, NULL_xdrproc_t, sizeof (struct nfsrdresult),
707 	    rfs_rdfree, RPC_IDEMPOTENT,
708 	    rfs_read_getfh, 0},
709 
710 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
711 	{rfs_error,
712 	    xdr_void, NULL_xdrproc_t, 0,
713 	    xdr_void, NULL_xdrproc_t, 0,
714 	    nullfree, RPC_IDEMPOTENT,
715 	    0, 0},
716 
717 	/* RFS_WRITE = 8 */
718 	{rfs_write,
719 	    xdr_writeargs, NULL_xdrproc_t, sizeof (struct nfswriteargs),
720 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
721 	    nullfree, RPC_MAPRESP,
722 	    rfs_write_getfh, 0},
723 
724 	/* RFS_CREATE = 9 */
725 	{rfs_create,
726 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
727 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
728 	    nullfree, RPC_MAPRESP,
729 	    rfs_create_getfh, 0},
730 
731 	/* RFS_REMOVE = 10 */
732 	{rfs_remove,
733 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
734 #ifdef _LITTLE_ENDIAN
735 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
736 #else
737 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
738 #endif
739 	    nullfree, RPC_MAPRESP,
740 	    rfs_remove_getfh, 0},
741 
742 	/* RFS_RENAME = 11 */
743 	{rfs_rename,
744 	    xdr_rnmargs, NULL_xdrproc_t, sizeof (struct nfsrnmargs),
745 #ifdef _LITTLE_ENDIAN
746 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
747 #else
748 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
749 #endif
750 	    nullfree, RPC_MAPRESP,
751 	    rfs_rename_getfh, 0},
752 
753 	/* RFS_LINK = 12 */
754 	{rfs_link,
755 	    xdr_linkargs, NULL_xdrproc_t, sizeof (struct nfslinkargs),
756 #ifdef _LITTLE_ENDIAN
757 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
758 #else
759 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
760 #endif
761 	    nullfree, RPC_MAPRESP,
762 	    rfs_link_getfh, 0},
763 
764 	/* RFS_SYMLINK = 13 */
765 	{rfs_symlink,
766 	    xdr_slargs, NULL_xdrproc_t, sizeof (struct nfsslargs),
767 #ifdef _LITTLE_ENDIAN
768 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
769 #else
770 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
771 #endif
772 	    nullfree, RPC_MAPRESP,
773 	    rfs_symlink_getfh, 0},
774 
775 	/* RFS_MKDIR = 14 */
776 	{rfs_mkdir,
777 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
778 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
779 	    nullfree, RPC_MAPRESP,
780 	    rfs_mkdir_getfh, 0},
781 
782 	/* RFS_RMDIR = 15 */
783 	{rfs_rmdir,
784 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
785 #ifdef _LITTLE_ENDIAN
786 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
787 #else
788 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
789 #endif
790 	    nullfree, RPC_MAPRESP,
791 	    rfs_rmdir_getfh, 0},
792 
793 	/* RFS_READDIR = 16 */
794 	{rfs_readdir,
795 	    xdr_rddirargs, NULL_xdrproc_t, sizeof (struct nfsrddirargs),
796 	    xdr_putrddirres, NULL_xdrproc_t, sizeof (struct nfsrddirres),
797 	    rfs_rddirfree, RPC_IDEMPOTENT,
798 	    rfs_readdir_getfh, 0},
799 
800 	/* RFS_STATFS = 17 */
801 	{rfs_statfs,
802 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
803 	    xdr_statfs, xdr_faststatfs, sizeof (struct nfsstatfs),
804 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
805 	    rfs_statfs_getfh, 0},
806 };
807 
808 static char *rfscallnames_v3[] = {
809 	"RFS3_NULL",
810 	"RFS3_GETATTR",
811 	"RFS3_SETATTR",
812 	"RFS3_LOOKUP",
813 	"RFS3_ACCESS",
814 	"RFS3_READLINK",
815 	"RFS3_READ",
816 	"RFS3_WRITE",
817 	"RFS3_CREATE",
818 	"RFS3_MKDIR",
819 	"RFS3_SYMLINK",
820 	"RFS3_MKNOD",
821 	"RFS3_REMOVE",
822 	"RFS3_RMDIR",
823 	"RFS3_RENAME",
824 	"RFS3_LINK",
825 	"RFS3_READDIR",
826 	"RFS3_READDIRPLUS",
827 	"RFS3_FSSTAT",
828 	"RFS3_FSINFO",
829 	"RFS3_PATHCONF",
830 	"RFS3_COMMIT"
831 };
832 
833 static struct rpcdisp rfsdisptab_v3[] = {
834 	/*
835 	 * NFS VERSION 3
836 	 */
837 
838 	/* RFS_NULL = 0 */
839 	{rpc_null,
840 	    xdr_void, NULL_xdrproc_t, 0,
841 	    xdr_void, NULL_xdrproc_t, 0,
842 	    nullfree, RPC_IDEMPOTENT,
843 	    0, 0},
844 
845 	/* RFS3_GETATTR = 1 */
846 	{rfs3_getattr,
847 	    xdr_nfs_fh3, xdr_fastnfs_fh3, sizeof (GETATTR3args),
848 	    xdr_GETATTR3res, NULL_xdrproc_t, sizeof (GETATTR3res),
849 	    nullfree, (RPC_IDEMPOTENT | RPC_ALLOWANON),
850 	    rfs3_getattr_getfh, 0},
851 
852 	/* RFS3_SETATTR = 2 */
853 	{rfs3_setattr,
854 	    xdr_SETATTR3args, NULL_xdrproc_t, sizeof (SETATTR3args),
855 	    xdr_SETATTR3res, NULL_xdrproc_t, sizeof (SETATTR3res),
856 	    nullfree, 0,
857 	    rfs3_setattr_getfh, 0},
858 
859 	/* RFS3_LOOKUP = 3 */
860 	{rfs3_lookup,
861 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (LOOKUP3args),
862 	    xdr_LOOKUP3res, NULL_xdrproc_t, sizeof (LOOKUP3res),
863 	    nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
864 	    rfs3_lookup_getfh, 0},
865 
866 	/* RFS3_ACCESS = 4 */
867 	{rfs3_access,
868 	    xdr_ACCESS3args, NULL_xdrproc_t, sizeof (ACCESS3args),
869 	    xdr_ACCESS3res, NULL_xdrproc_t, sizeof (ACCESS3res),
870 	    nullfree, RPC_IDEMPOTENT,
871 	    rfs3_access_getfh, 0},
872 
873 	/* RFS3_READLINK = 5 */
874 	{rfs3_readlink,
875 	    xdr_nfs_fh3, xdr_fastnfs_fh3, sizeof (READLINK3args),
876 	    xdr_READLINK3res, NULL_xdrproc_t, sizeof (READLINK3res),
877 	    rfs3_readlink_free, RPC_IDEMPOTENT,
878 	    rfs3_readlink_getfh, 0},
879 
880 	/* RFS3_READ = 6 */
881 	{rfs3_read,
882 	    xdr_READ3args, NULL_xdrproc_t, sizeof (READ3args),
883 	    xdr_READ3res, NULL_xdrproc_t, sizeof (READ3res),
884 	    rfs3_read_free, RPC_IDEMPOTENT,
885 	    rfs3_read_getfh, 0},
886 
887 	/* RFS3_WRITE = 7 */
888 	{rfs3_write,
889 	    xdr_WRITE3args, NULL_xdrproc_t, sizeof (WRITE3args),
890 	    xdr_WRITE3res, NULL_xdrproc_t, sizeof (WRITE3res),
891 	    nullfree, 0,
892 	    rfs3_write_getfh, 0},
893 
894 	/* RFS3_CREATE = 8 */
895 	{rfs3_create,
896 	    xdr_CREATE3args, NULL_xdrproc_t, sizeof (CREATE3args),
897 	    xdr_CREATE3res, NULL_xdrproc_t, sizeof (CREATE3res),
898 	    nullfree, 0,
899 	    rfs3_create_getfh, 0},
900 
901 	/* RFS3_MKDIR = 9 */
902 	{rfs3_mkdir,
903 	    xdr_MKDIR3args, NULL_xdrproc_t, sizeof (MKDIR3args),
904 	    xdr_MKDIR3res, NULL_xdrproc_t, sizeof (MKDIR3res),
905 	    nullfree, 0,
906 	    rfs3_mkdir_getfh, 0},
907 
908 	/* RFS3_SYMLINK = 10 */
909 	{rfs3_symlink,
910 	    xdr_SYMLINK3args, NULL_xdrproc_t, sizeof (SYMLINK3args),
911 	    xdr_SYMLINK3res, NULL_xdrproc_t, sizeof (SYMLINK3res),
912 	    nullfree, 0,
913 	    rfs3_symlink_getfh, 0},
914 
915 	/* RFS3_MKNOD = 11 */
916 	{rfs3_mknod,
917 	    xdr_MKNOD3args, NULL_xdrproc_t, sizeof (MKNOD3args),
918 	    xdr_MKNOD3res, NULL_xdrproc_t, sizeof (MKNOD3res),
919 	    nullfree, 0,
920 	    rfs3_mknod_getfh, 0},
921 
922 	/* RFS3_REMOVE = 12 */
923 	{rfs3_remove,
924 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (REMOVE3args),
925 	    xdr_REMOVE3res, NULL_xdrproc_t, sizeof (REMOVE3res),
926 	    nullfree, 0,
927 	    rfs3_remove_getfh, 0},
928 
929 	/* RFS3_RMDIR = 13 */
930 	{rfs3_rmdir,
931 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (RMDIR3args),
932 	    xdr_RMDIR3res, NULL_xdrproc_t, sizeof (RMDIR3res),
933 	    nullfree, 0,
934 	    rfs3_rmdir_getfh, 0},
935 
936 	/* RFS3_RENAME = 14 */
937 	{rfs3_rename,
938 	    xdr_RENAME3args, NULL_xdrproc_t, sizeof (RENAME3args),
939 	    xdr_RENAME3res, NULL_xdrproc_t, sizeof (RENAME3res),
940 	    nullfree, 0,
941 	    rfs3_rename_getfh, 0},
942 
943 	/* RFS3_LINK = 15 */
944 	{rfs3_link,
945 	    xdr_LINK3args, NULL_xdrproc_t, sizeof (LINK3args),
946 	    xdr_LINK3res, NULL_xdrproc_t, sizeof (LINK3res),
947 	    nullfree, 0,
948 	    rfs3_link_getfh, 0},
949 
950 	/* RFS3_READDIR = 16 */
951 	{rfs3_readdir,
952 	    xdr_READDIR3args, NULL_xdrproc_t, sizeof (READDIR3args),
953 	    xdr_READDIR3res, NULL_xdrproc_t, sizeof (READDIR3res),
954 	    rfs3_readdir_free, RPC_IDEMPOTENT,
955 	    rfs3_readdir_getfh, 0},
956 
957 	/* RFS3_READDIRPLUS = 17 */
958 	{rfs3_readdirplus,
959 	    xdr_READDIRPLUS3args, NULL_xdrproc_t, sizeof (READDIRPLUS3args),
960 	    xdr_READDIRPLUS3res, NULL_xdrproc_t, sizeof (READDIRPLUS3res),
961 	    rfs3_readdirplus_free, RPC_AVOIDWORK,
962 	    rfs3_readdirplus_getfh, 0},
963 
964 	/* RFS3_FSSTAT = 18 */
965 	{rfs3_fsstat,
966 	    xdr_nfs_fh3, xdr_fastnfs_fh3, sizeof (FSSTAT3args),
967 	    xdr_FSSTAT3res, NULL_xdrproc_t, sizeof (FSSTAT3res),
968 	    nullfree, RPC_IDEMPOTENT,
969 	    rfs3_fsstat_getfh, 0},
970 
971 	/* RFS3_FSINFO = 19 */
972 	{rfs3_fsinfo,
973 	    xdr_nfs_fh3, xdr_fastnfs_fh3, sizeof (FSINFO3args),
974 	    xdr_FSINFO3res, NULL_xdrproc_t, sizeof (FSINFO3res),
975 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON,
976 	    rfs3_fsinfo_getfh, 0},
977 
978 	/* RFS3_PATHCONF = 20 */
979 	{rfs3_pathconf,
980 	    xdr_nfs_fh3, xdr_fastnfs_fh3, sizeof (PATHCONF3args),
981 	    xdr_PATHCONF3res, NULL_xdrproc_t, sizeof (PATHCONF3res),
982 	    nullfree, RPC_IDEMPOTENT,
983 	    rfs3_pathconf_getfh, 0},
984 
985 	/* RFS3_COMMIT = 21 */
986 	{rfs3_commit,
987 	    xdr_COMMIT3args, NULL_xdrproc_t, sizeof (COMMIT3args),
988 	    xdr_COMMIT3res, NULL_xdrproc_t, sizeof (COMMIT3res),
989 	    nullfree, RPC_IDEMPOTENT,
990 	    rfs3_commit_getfh, 0},
991 };
992 
993 static char *rfscallnames_v4[] = {
994 	"RFS4_NULL",
995 	"RFS4_COMPOUND",
996 	"RFS4_NULL",
997 	"RFS4_NULL",
998 	"RFS4_NULL",
999 	"RFS4_NULL",
1000 	"RFS4_NULL",
1001 	"RFS4_NULL",
1002 	"RFS4_CREATE"
1003 };
1004 
1005 static struct rpcdisp rfsdisptab_v4[] = {
1006 	/*
1007 	 * NFS VERSION 4
1008 	 */
1009 
1010 	/* RFS_NULL = 0 */
1011 	{rpc_null,
1012 	    xdr_void, NULL_xdrproc_t, 0,
1013 	    xdr_void, NULL_xdrproc_t, 0,
1014 	    nullfree, RPC_IDEMPOTENT, 0, 0},
1015 
1016 	/* RFS4_compound = 1 */
1017 	{rfs4_compound,
1018 	    xdr_COMPOUND4args, NULL_xdrproc_t, sizeof (COMPOUND4args),
1019 	    xdr_COMPOUND4res, NULL_xdrproc_t, sizeof (COMPOUND4res),
1020 	    rfs4_compound_free, 0 /* XXX? RPC_IDEMPOTENT */,
1021 	    0, rfs4_compound_flagproc},
1022 };
1023 
1024 union rfs_args {
1025 	/*
1026 	 * NFS VERSION 2
1027 	 */
1028 
1029 	/* RFS_NULL = 0 */
1030 
1031 	/* RFS_GETATTR = 1 */
1032 	fhandle_t nfs2_getattr_args;
1033 
1034 	/* RFS_SETATTR = 2 */
1035 	struct nfssaargs nfs2_setattr_args;
1036 
1037 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1038 
1039 	/* RFS_LOOKUP = 4 */
1040 	struct nfsdiropargs nfs2_lookup_args;
1041 
1042 	/* RFS_READLINK = 5 */
1043 	fhandle_t nfs2_readlink_args;
1044 
1045 	/* RFS_READ = 6 */
1046 	struct nfsreadargs nfs2_read_args;
1047 
1048 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1049 
1050 	/* RFS_WRITE = 8 */
1051 	struct nfswriteargs nfs2_write_args;
1052 
1053 	/* RFS_CREATE = 9 */
1054 	struct nfscreatargs nfs2_create_args;
1055 
1056 	/* RFS_REMOVE = 10 */
1057 	struct nfsdiropargs nfs2_remove_args;
1058 
1059 	/* RFS_RENAME = 11 */
1060 	struct nfsrnmargs nfs2_rename_args;
1061 
1062 	/* RFS_LINK = 12 */
1063 	struct nfslinkargs nfs2_link_args;
1064 
1065 	/* RFS_SYMLINK = 13 */
1066 	struct nfsslargs nfs2_symlink_args;
1067 
1068 	/* RFS_MKDIR = 14 */
1069 	struct nfscreatargs nfs2_mkdir_args;
1070 
1071 	/* RFS_RMDIR = 15 */
1072 	struct nfsdiropargs nfs2_rmdir_args;
1073 
1074 	/* RFS_READDIR = 16 */
1075 	struct nfsrddirargs nfs2_readdir_args;
1076 
1077 	/* RFS_STATFS = 17 */
1078 	fhandle_t nfs2_statfs_args;
1079 
1080 	/*
1081 	 * NFS VERSION 3
1082 	 */
1083 
1084 	/* RFS_NULL = 0 */
1085 
1086 	/* RFS3_GETATTR = 1 */
1087 	GETATTR3args nfs3_getattr_args;
1088 
1089 	/* RFS3_SETATTR = 2 */
1090 	SETATTR3args nfs3_setattr_args;
1091 
1092 	/* RFS3_LOOKUP = 3 */
1093 	LOOKUP3args nfs3_lookup_args;
1094 
1095 	/* RFS3_ACCESS = 4 */
1096 	ACCESS3args nfs3_access_args;
1097 
1098 	/* RFS3_READLINK = 5 */
1099 	READLINK3args nfs3_readlink_args;
1100 
1101 	/* RFS3_READ = 6 */
1102 	READ3args nfs3_read_args;
1103 
1104 	/* RFS3_WRITE = 7 */
1105 	WRITE3args nfs3_write_args;
1106 
1107 	/* RFS3_CREATE = 8 */
1108 	CREATE3args nfs3_create_args;
1109 
1110 	/* RFS3_MKDIR = 9 */
1111 	MKDIR3args nfs3_mkdir_args;
1112 
1113 	/* RFS3_SYMLINK = 10 */
1114 	SYMLINK3args nfs3_symlink_args;
1115 
1116 	/* RFS3_MKNOD = 11 */
1117 	MKNOD3args nfs3_mknod_args;
1118 
1119 	/* RFS3_REMOVE = 12 */
1120 	REMOVE3args nfs3_remove_args;
1121 
1122 	/* RFS3_RMDIR = 13 */
1123 	RMDIR3args nfs3_rmdir_args;
1124 
1125 	/* RFS3_RENAME = 14 */
1126 	RENAME3args nfs3_rename_args;
1127 
1128 	/* RFS3_LINK = 15 */
1129 	LINK3args nfs3_link_args;
1130 
1131 	/* RFS3_READDIR = 16 */
1132 	READDIR3args nfs3_readdir_args;
1133 
1134 	/* RFS3_READDIRPLUS = 17 */
1135 	READDIRPLUS3args nfs3_readdirplus_args;
1136 
1137 	/* RFS3_FSSTAT = 18 */
1138 	FSSTAT3args nfs3_fsstat_args;
1139 
1140 	/* RFS3_FSINFO = 19 */
1141 	FSINFO3args nfs3_fsinfo_args;
1142 
1143 	/* RFS3_PATHCONF = 20 */
1144 	PATHCONF3args nfs3_pathconf_args;
1145 
1146 	/* RFS3_COMMIT = 21 */
1147 	COMMIT3args nfs3_commit_args;
1148 
1149 	/*
1150 	 * NFS VERSION 4
1151 	 */
1152 
1153 	/* RFS_NULL = 0 */
1154 
1155 	/* COMPUND = 1 */
1156 	COMPOUND4args nfs4_compound_args;
1157 };
1158 
1159 union rfs_res {
1160 	/*
1161 	 * NFS VERSION 2
1162 	 */
1163 
1164 	/* RFS_NULL = 0 */
1165 
1166 	/* RFS_GETATTR = 1 */
1167 	struct nfsattrstat nfs2_getattr_res;
1168 
1169 	/* RFS_SETATTR = 2 */
1170 	struct nfsattrstat nfs2_setattr_res;
1171 
1172 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1173 
1174 	/* RFS_LOOKUP = 4 */
1175 	struct nfsdiropres nfs2_lookup_res;
1176 
1177 	/* RFS_READLINK = 5 */
1178 	struct nfsrdlnres nfs2_readlink_res;
1179 
1180 	/* RFS_READ = 6 */
1181 	struct nfsrdresult nfs2_read_res;
1182 
1183 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1184 
1185 	/* RFS_WRITE = 8 */
1186 	struct nfsattrstat nfs2_write_res;
1187 
1188 	/* RFS_CREATE = 9 */
1189 	struct nfsdiropres nfs2_create_res;
1190 
1191 	/* RFS_REMOVE = 10 */
1192 	enum nfsstat nfs2_remove_res;
1193 
1194 	/* RFS_RENAME = 11 */
1195 	enum nfsstat nfs2_rename_res;
1196 
1197 	/* RFS_LINK = 12 */
1198 	enum nfsstat nfs2_link_res;
1199 
1200 	/* RFS_SYMLINK = 13 */
1201 	enum nfsstat nfs2_symlink_res;
1202 
1203 	/* RFS_MKDIR = 14 */
1204 	struct nfsdiropres nfs2_mkdir_res;
1205 
1206 	/* RFS_RMDIR = 15 */
1207 	enum nfsstat nfs2_rmdir_res;
1208 
1209 	/* RFS_READDIR = 16 */
1210 	struct nfsrddirres nfs2_readdir_res;
1211 
1212 	/* RFS_STATFS = 17 */
1213 	struct nfsstatfs nfs2_statfs_res;
1214 
1215 	/*
1216 	 * NFS VERSION 3
1217 	 */
1218 
1219 	/* RFS_NULL = 0 */
1220 
1221 	/* RFS3_GETATTR = 1 */
1222 	GETATTR3res nfs3_getattr_res;
1223 
1224 	/* RFS3_SETATTR = 2 */
1225 	SETATTR3res nfs3_setattr_res;
1226 
1227 	/* RFS3_LOOKUP = 3 */
1228 	LOOKUP3res nfs3_lookup_res;
1229 
1230 	/* RFS3_ACCESS = 4 */
1231 	ACCESS3res nfs3_access_res;
1232 
1233 	/* RFS3_READLINK = 5 */
1234 	READLINK3res nfs3_readlink_res;
1235 
1236 	/* RFS3_READ = 6 */
1237 	READ3res nfs3_read_res;
1238 
1239 	/* RFS3_WRITE = 7 */
1240 	WRITE3res nfs3_write_res;
1241 
1242 	/* RFS3_CREATE = 8 */
1243 	CREATE3res nfs3_create_res;
1244 
1245 	/* RFS3_MKDIR = 9 */
1246 	MKDIR3res nfs3_mkdir_res;
1247 
1248 	/* RFS3_SYMLINK = 10 */
1249 	SYMLINK3res nfs3_symlink_res;
1250 
1251 	/* RFS3_MKNOD = 11 */
1252 	MKNOD3res nfs3_mknod_res;
1253 
1254 	/* RFS3_REMOVE = 12 */
1255 	REMOVE3res nfs3_remove_res;
1256 
1257 	/* RFS3_RMDIR = 13 */
1258 	RMDIR3res nfs3_rmdir_res;
1259 
1260 	/* RFS3_RENAME = 14 */
1261 	RENAME3res nfs3_rename_res;
1262 
1263 	/* RFS3_LINK = 15 */
1264 	LINK3res nfs3_link_res;
1265 
1266 	/* RFS3_READDIR = 16 */
1267 	READDIR3res nfs3_readdir_res;
1268 
1269 	/* RFS3_READDIRPLUS = 17 */
1270 	READDIRPLUS3res nfs3_readdirplus_res;
1271 
1272 	/* RFS3_FSSTAT = 18 */
1273 	FSSTAT3res nfs3_fsstat_res;
1274 
1275 	/* RFS3_FSINFO = 19 */
1276 	FSINFO3res nfs3_fsinfo_res;
1277 
1278 	/* RFS3_PATHCONF = 20 */
1279 	PATHCONF3res nfs3_pathconf_res;
1280 
1281 	/* RFS3_COMMIT = 21 */
1282 	COMMIT3res nfs3_commit_res;
1283 
1284 	/*
1285 	 * NFS VERSION 4
1286 	 */
1287 
1288 	/* RFS_NULL = 0 */
1289 
1290 	/* RFS4_COMPOUND = 1 */
1291 	COMPOUND4res nfs4_compound_res;
1292 
1293 };
1294 
1295 static struct rpc_disptable rfs_disptable[] = {
1296 	{sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]),
1297 	    rfscallnames_v2,
1298 	    &rfsproccnt_v2_ptr, rfsdisptab_v2},
1299 	{sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]),
1300 	    rfscallnames_v3,
1301 	    &rfsproccnt_v3_ptr, rfsdisptab_v3},
1302 	{sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]),
1303 	    rfscallnames_v4,
1304 	    &rfsproccnt_v4_ptr, rfsdisptab_v4},
1305 };
1306 
1307 /*
1308  * If nfs_portmon is set, then clients are required to use privileged
1309  * ports (ports < IPPORT_RESERVED) in order to get NFS services.
1310  *
1311  * N.B.: this attempt to carry forward the already ill-conceived notion
1312  * of privileged ports for TCP/UDP is really quite ineffectual.  Not only
1313  * is it transport-dependent, it's laughably easy to spoof.  If you're
1314  * really interested in security, you must start with secure RPC instead.
1315  */
1316 static int nfs_portmon = 0;
1317 
1318 #ifdef DEBUG
1319 static int cred_hits = 0;
1320 static int cred_misses = 0;
1321 #endif
1322 
1323 
1324 #ifdef DEBUG
1325 /*
1326  * Debug code to allow disabling of rfs_dispatch() use of
1327  * fastxdrargs() and fastxdrres() calls for testing purposes.
1328  */
1329 static int rfs_no_fast_xdrargs = 0;
1330 static int rfs_no_fast_xdrres = 0;
1331 #endif
1332 
1333 union acl_args {
1334 	/*
1335 	 * ACL VERSION 2
1336 	 */
1337 
1338 	/* ACL2_NULL = 0 */
1339 
1340 	/* ACL2_GETACL = 1 */
1341 	GETACL2args acl2_getacl_args;
1342 
1343 	/* ACL2_SETACL = 2 */
1344 	SETACL2args acl2_setacl_args;
1345 
1346 	/* ACL2_GETATTR = 3 */
1347 	GETATTR2args acl2_getattr_args;
1348 
1349 	/* ACL2_ACCESS = 4 */
1350 	ACCESS2args acl2_access_args;
1351 
1352 	/* ACL2_GETXATTRDIR = 5 */
1353 	GETXATTRDIR2args acl2_getxattrdir_args;
1354 
1355 	/*
1356 	 * ACL VERSION 3
1357 	 */
1358 
1359 	/* ACL3_NULL = 0 */
1360 
1361 	/* ACL3_GETACL = 1 */
1362 	GETACL3args acl3_getacl_args;
1363 
1364 	/* ACL3_SETACL = 2 */
1365 	SETACL3args acl3_setacl;
1366 
1367 	/* ACL3_GETXATTRDIR = 3 */
1368 	GETXATTRDIR3args acl3_getxattrdir_args;
1369 
1370 };
1371 
1372 union acl_res {
1373 	/*
1374 	 * ACL VERSION 2
1375 	 */
1376 
1377 	/* ACL2_NULL = 0 */
1378 
1379 	/* ACL2_GETACL = 1 */
1380 	GETACL2res acl2_getacl_res;
1381 
1382 	/* ACL2_SETACL = 2 */
1383 	SETACL2res acl2_setacl_res;
1384 
1385 	/* ACL2_GETATTR = 3 */
1386 	GETATTR2res acl2_getattr_res;
1387 
1388 	/* ACL2_ACCESS = 4 */
1389 	ACCESS2res acl2_access_res;
1390 
1391 	/* ACL2_GETXATTRDIR = 5 */
1392 	GETXATTRDIR2args acl2_getxattrdir_res;
1393 
1394 	/*
1395 	 * ACL VERSION 3
1396 	 */
1397 
1398 	/* ACL3_NULL = 0 */
1399 
1400 	/* ACL3_GETACL = 1 */
1401 	GETACL3res acl3_getacl_res;
1402 
1403 	/* ACL3_SETACL = 2 */
1404 	SETACL3res acl3_setacl_res;
1405 
1406 	/* ACL3_GETXATTRDIR = 3 */
1407 	GETXATTRDIR3res acl3_getxattrdir_res;
1408 
1409 };
1410 
1411 static bool_t
1412 auth_tooweak(struct svc_req *req, char *res)
1413 {
1414 
1415 	if (req->rq_vers == NFS_VERSION && req->rq_proc == RFS_LOOKUP) {
1416 		struct nfsdiropres *dr = (struct nfsdiropres *)res;
1417 		if (dr->dr_status == WNFSERR_CLNT_FLAVOR)
1418 			return (TRUE);
1419 	} else if (req->rq_vers == NFS_V3 && req->rq_proc == NFSPROC3_LOOKUP) {
1420 		LOOKUP3res *resp = (LOOKUP3res *)res;
1421 		if (resp->status == WNFSERR_CLNT_FLAVOR)
1422 			return (TRUE);
1423 	}
1424 	return (FALSE);
1425 }
1426 
1427 static void
1428 common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
1429 		rpcvers_t max_vers, char *pgmname,
1430 		struct rpc_disptable *disptable)
1431 {
1432 	int which;
1433 	rpcvers_t vers;
1434 	char *args;
1435 	union {
1436 			union rfs_args ra;
1437 			union acl_args aa;
1438 		} args_buf;
1439 	char *res;
1440 	union {
1441 			union rfs_res rr;
1442 			union acl_res ar;
1443 		} res_buf;
1444 	struct rpcdisp *disp = NULL;
1445 	int dis_flags = 0;
1446 	cred_t *cr;
1447 	int error = 0;
1448 	int anon_ok;
1449 	struct exportinfo *exi = NULL;
1450 	unsigned int nfslog_rec_id;
1451 	int dupstat;
1452 	struct dupreq *dr;
1453 	int authres;
1454 	bool_t publicfh_ok = FALSE;
1455 	enum_t auth_flavor;
1456 	bool_t dupcached = FALSE;
1457 	struct netbuf	nb;
1458 	bool_t logging_enabled = FALSE;
1459 	struct exportinfo *nfslog_exi = NULL;
1460 
1461 	vers = req->rq_vers;
1462 
1463 	if (vers < min_vers || vers > max_vers) {
1464 		TRACE_3(TR_FAC_NFS, TR_CMN_DISPATCH_START,
1465 			"common_dispatch_start:(%S) proc_num %d xid %x",
1466 			"bad version", (int)vers, 0);
1467 		svcerr_progvers(req->rq_xprt, min_vers, max_vers);
1468 		error++;
1469 		cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers);
1470 		goto done;
1471 	}
1472 	vers -= min_vers;
1473 
1474 	which = req->rq_proc;
1475 	if (which < 0 || which >= disptable[(int)vers].dis_nprocs) {
1476 		TRACE_3(TR_FAC_NFS, TR_CMN_DISPATCH_START,
1477 			"common_dispatch_start:(%S) proc_num %d xid %x",
1478 			"bad proc", which, 0);
1479 		svcerr_noproc(req->rq_xprt);
1480 		error++;
1481 		goto done;
1482 	}
1483 
1484 	(*(disptable[(int)vers].dis_proccntp))[which].value.ui64++;
1485 	DTRACE_PROBE2(nfs__dispatch, struct svc_req *, req, SVCXPRT *, xprt);
1486 
1487 	disp = &disptable[(int)vers].dis_table[which];
1488 
1489 	auth_flavor = req->rq_cred.oa_flavor;
1490 	/*
1491 	 * Deserialize into the args struct.
1492 	 */
1493 
1494 	args = (char *)&args_buf;
1495 	TRACE_0(TR_FAC_NFS, TR_SVC_GETARGS_START,
1496 		"svc_getargs_start:");
1497 #ifdef DEBUG
1498 	if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) ||
1499 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
1500 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args)) {
1501 #else
1502 	if ((auth_flavor == RPCSEC_GSS) ||
1503 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
1504 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args)) {
1505 #endif
1506 		bzero(args, disp->dis_argsz);
1507 		if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) {
1508 			TRACE_1(TR_FAC_NFS, TR_SVC_GETARGS_END,
1509 				"svc_getargs_end:(%S)", "bad");
1510 			svcerr_decode(xprt);
1511 			error++;
1512 			cmn_err(CE_NOTE, "%s: bad getargs for %u/%d",
1513 			    pgmname, vers + min_vers, which);
1514 			goto done;
1515 		}
1516 	}
1517 	TRACE_1(TR_FAC_NFS, TR_SVC_GETARGS_END,
1518 		"svc_getargs_end:(%S)", "good");
1519 
1520 	/*
1521 	 * Calculate flags (only relevant for nfsv4 compounds)
1522 	 */
1523 	if (disp->dis_flagproc)
1524 		(*disp->dis_flagproc)(args, &dis_flags);
1525 
1526 	else
1527 		dis_flags = disp->dis_flags;
1528 
1529 	/*
1530 	 * Find export information and check authentication,
1531 	 * setting the credential if everything is ok.
1532 	 * *** NFSv4 Does not do this.
1533 	 */
1534 	if (disp->dis_getfh != NULL) {
1535 		fhandle_t *fh;
1536 
1537 		fh = (*disp->dis_getfh)(args);
1538 
1539 		/*
1540 		 * Fix for bug 1038302 - corbin
1541 		 * There is a problem here if anonymous access is
1542 		 * disallowed.  If the current request is part of the
1543 		 * client's mount process for the requested filesystem,
1544 		 * then it will carry root (uid 0) credentials on it, and
1545 		 * will be denied by checkauth if that client does not
1546 		 * have explicit root=0 permission.  This will cause the
1547 		 * client's mount operation to fail.  As a work-around,
1548 		 * we check here to see if the request is a getattr or
1549 		 * statfs operation on the exported vnode itself, and
1550 		 * pass a flag to checkauth with the result of this test.
1551 		 *
1552 		 * The filehandle refers to the mountpoint itself if
1553 		 * the fh_data and fh_xdata portions of the filehandle
1554 		 * are equal.
1555 		 *
1556 		 * Added anon_ok argument to checkauth().
1557 		 */
1558 
1559 		if ((dis_flags & RPC_ALLOWANON) &&
1560 		    EQFID((fid_t *)&fh->fh_len, (fid_t *)&fh->fh_xlen))
1561 			anon_ok = 1;
1562 		else
1563 			anon_ok = 0;
1564 
1565 		cr = xprt->xp_cred;
1566 		ASSERT(cr != NULL);
1567 #ifdef DEBUG
1568 		if (crgetref(cr) != 1) {
1569 			crfree(cr);
1570 			cr = crget();
1571 			xprt->xp_cred = cr;
1572 			cred_misses++;
1573 		} else
1574 			cred_hits++;
1575 #else
1576 		if (crgetref(cr) != 1) {
1577 			crfree(cr);
1578 			cr = crget();
1579 			xprt->xp_cred = cr;
1580 		}
1581 #endif
1582 
1583 		TRACE_0(TR_FAC_NFS, TR_CHECKEXPORT_START,
1584 			"checkexport_start:");
1585 		exi = checkexport(&fh->fh_fsid, (fid_t *)&fh->fh_xlen);
1586 		TRACE_0(TR_FAC_NFS, TR_CHECKEXPORT_END,
1587 			"checkexport_end:");
1588 		if (exi != NULL) {
1589 			publicfh_ok = PUBLICFH_CHECK(disp, exi, fh);
1590 
1591 			/*
1592 			 * Don't allow non-V4 clients access
1593 			 * to pseudo exports
1594 			 */
1595 			if (PSEUDO(exi)) {
1596 				svcerr_weakauth(xprt);
1597 				error++;
1598 				goto done;
1599 			}
1600 
1601 			authres = checkauth(exi, req, cr, anon_ok, publicfh_ok);
1602 			/*
1603 			 * authres >  0: authentication OK - proceed
1604 			 * authres == 0: authentication weak - return error
1605 			 * authres <  0: authentication timeout - drop
1606 			 */
1607 			if (authres <= 0) {
1608 				if (authres == 0) {
1609 					svcerr_weakauth(xprt);
1610 					error++;
1611 				}
1612 				goto done;
1613 			}
1614 		}
1615 	} else
1616 		cr = NULL;
1617 
1618 	if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) {
1619 		res = (char *)SVC_GETRES(xprt, disp->dis_ressz);
1620 		if (res == NULL)
1621 			res = (char *)&res_buf;
1622 	} else
1623 		res = (char *)&res_buf;
1624 
1625 	if (!(dis_flags & RPC_IDEMPOTENT)) {
1626 		dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr,
1627 				&dupcached);
1628 
1629 		switch (dupstat) {
1630 		case DUP_ERROR:
1631 			svcerr_systemerr(xprt);
1632 			error++;
1633 			goto done;
1634 			/* NOTREACHED */
1635 		case DUP_INPROGRESS:
1636 			if (res != (char *)&res_buf)
1637 				SVC_FREERES(xprt);
1638 			error++;
1639 			goto done;
1640 			/* NOTREACHED */
1641 		case DUP_NEW:
1642 		case DUP_DROP:
1643 			curthread->t_flag |= T_DONTPEND;
1644 			TRACE_4(TR_FAC_NFS, TR_CMN_PROC_START,
1645 				"cmn_proc_start:%p vers %d proc_num %d req %x",
1646 				disptable, vers, which, req);
1647 			(*disp->dis_proc)(args, res, exi, req, cr);
1648 			TRACE_0(TR_FAC_NFS, TR_CMN_PROC_END,
1649 				"cmn_proc_end:");
1650 			curthread->t_flag &= ~T_DONTPEND;
1651 			if (curthread->t_flag & T_WOULDBLOCK) {
1652 				curthread->t_flag &= ~T_WOULDBLOCK;
1653 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
1654 					disp->dis_ressz, DUP_DROP);
1655 				if (res != (char *)&res_buf)
1656 					SVC_FREERES(xprt);
1657 				error++;
1658 				goto done;
1659 			}
1660 			if (dis_flags & RPC_AVOIDWORK) {
1661 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
1662 					disp->dis_ressz, DUP_DROP);
1663 			} else {
1664 				SVC_DUPDONE_EXT(xprt, dr, res,
1665 					disp->dis_resfree == nullfree ? NULL :
1666 					disp->dis_resfree,
1667 					disp->dis_ressz, DUP_DONE);
1668 				dupcached = TRUE;
1669 			}
1670 			break;
1671 		case DUP_DONE:
1672 			break;
1673 		}
1674 
1675 	} else {
1676 		curthread->t_flag |= T_DONTPEND;
1677 		TRACE_4(TR_FAC_NFS, TR_CMN_PROC_START,
1678 			"cmn_proc_start:%p vers %d proc_num %d req %x",
1679 			disptable, vers, which, req);
1680 		(*disp->dis_proc)(args, res, exi, req, cr);
1681 		TRACE_0(TR_FAC_NFS, TR_CMN_PROC_END,
1682 			"cmn_proc_end:");
1683 		curthread->t_flag &= ~T_DONTPEND;
1684 		if (curthread->t_flag & T_WOULDBLOCK) {
1685 			curthread->t_flag &= ~T_WOULDBLOCK;
1686 			if (res != (char *)&res_buf)
1687 				SVC_FREERES(xprt);
1688 			error++;
1689 			goto done;
1690 		}
1691 	}
1692 
1693 	if (auth_tooweak(req, res)) {
1694 		svcerr_weakauth(xprt);
1695 		error++;
1696 		goto done;
1697 	}
1698 
1699 	/*
1700 	 * Check to see if logging has been enabled on the server.
1701 	 * If so, then obtain the export info struct to be used for
1702 	 * the later writing of the log record.  This is done for
1703 	 * the case that a lookup is done across a non-logged public
1704 	 * file system.
1705 	 */
1706 	if (nfslog_buffer_list != NULL) {
1707 		nfslog_exi = nfslog_get_exi(exi, req, res, &nfslog_rec_id);
1708 		/*
1709 		 * Is logging enabled?
1710 		 */
1711 		logging_enabled = (nfslog_exi != NULL);
1712 
1713 		/*
1714 		 * Copy the netbuf for logging purposes, before it is
1715 		 * freed by svc_sendreply().
1716 		 */
1717 		if (logging_enabled) {
1718 			NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb);
1719 			/*
1720 			 * If RPC_MAPRESP flag set (i.e. in V2 ops) the
1721 			 * res gets copied directly into the mbuf and
1722 			 * may be freed soon after the sendreply. So we
1723 			 * must copy it here to a safe place...
1724 			 */
1725 			if (res != (char *)&res_buf) {
1726 				bcopy(res, (char *)&res_buf, disp->dis_ressz);
1727 			}
1728 		}
1729 	}
1730 
1731 	/*
1732 	 * Serialize and send results struct
1733 	 */
1734 	TRACE_0(TR_FAC_NFS, TR_SVC_SENDREPLY_START,
1735 		"svc_sendreply_start:");
1736 #ifdef DEBUG
1737 	if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf) {
1738 #else
1739 	if (res != (char *)&res_buf) {
1740 #endif
1741 		if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) {
1742 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
1743 			error++;
1744 		}
1745 	} else {
1746 		if (!svc_sendreply(xprt, disp->dis_xdrres, res)) {
1747 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
1748 			error++;
1749 		}
1750 	}
1751 	TRACE_0(TR_FAC_NFS, TR_SVC_SENDREPLY_END,
1752 		"svc_sendreply_end:");
1753 
1754 	/*
1755 	 * Log if needed
1756 	 */
1757 	if (logging_enabled) {
1758 		nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf,
1759 			cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
1760 		exi_rele(nfslog_exi);
1761 		kmem_free((&nb)->buf, (&nb)->len);
1762 	}
1763 
1764 	/*
1765 	 * Free results struct. With the addition of NFS V4 we can
1766 	 * have non-idempotent procedures with functions.
1767 	 */
1768 	if (disp->dis_resfree != nullfree && dupcached == FALSE) {
1769 		TRACE_0(TR_FAC_NFS, TR_SVC_FREERES_START,
1770 			"svc_freeres_start:");
1771 		(*disp->dis_resfree)(res);
1772 		TRACE_0(TR_FAC_NFS, TR_SVC_FREERES_END,
1773 			"svc_freeres_end:");
1774 	}
1775 
1776 done:
1777 	/*
1778 	 * Free arguments struct
1779 	 */
1780 	TRACE_0(TR_FAC_NFS, TR_SVC_FREEARGS_START,
1781 		"svc_freeargs_start:");
1782 	if (disp) {
1783 		if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) {
1784 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
1785 			error++;
1786 		}
1787 	} else {
1788 		if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) {
1789 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
1790 			error++;
1791 		}
1792 	}
1793 
1794 	TRACE_0(TR_FAC_NFS, TR_SVC_FREEARGS_END,
1795 		"svc_freeargs_end:");
1796 
1797 	if (exi != NULL)
1798 		exi_rele(exi);
1799 
1800 	global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error;
1801 
1802 	global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++;
1803 
1804 
1805 	TRACE_1(TR_FAC_NFS, TR_CMN_DISPATCH_END,
1806 		"common_dispatch_end:proc_num %d",
1807 		which);
1808 }
1809 
1810 static void
1811 rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
1812 {
1813 	common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
1814 		"nfs_server", rfs_disptable);
1815 }
1816 
1817 static char *aclcallnames_v2[] = {
1818 	"ACL2_NULL",
1819 	"ACL2_GETACL",
1820 	"ACL2_SETACL",
1821 	"ACL2_GETATTR",
1822 	"ACL2_ACCESS",
1823 	"ACL2_GETXATTRDIR"
1824 };
1825 
1826 static struct rpcdisp acldisptab_v2[] = {
1827 	/*
1828 	 * ACL VERSION 2
1829 	 */
1830 
1831 	/* ACL2_NULL = 0 */
1832 	{rpc_null,
1833 	    xdr_void, NULL_xdrproc_t, 0,
1834 	    xdr_void, NULL_xdrproc_t, 0,
1835 	    nullfree, RPC_IDEMPOTENT,
1836 	    0},
1837 
1838 	/* ACL2_GETACL = 1 */
1839 	{acl2_getacl,
1840 	    xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args),
1841 	    xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res),
1842 	    acl2_getacl_free, RPC_IDEMPOTENT,
1843 	    acl2_getacl_getfh},
1844 
1845 	/* ACL2_SETACL = 2 */
1846 	{acl2_setacl,
1847 	    xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args),
1848 #ifdef _LITTLE_ENDIAN
1849 	    xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res),
1850 #else
1851 	    xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res),
1852 #endif
1853 	    nullfree, RPC_MAPRESP,
1854 	    acl2_setacl_getfh},
1855 
1856 	/* ACL2_GETATTR = 3 */
1857 	{acl2_getattr,
1858 	    xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args),
1859 #ifdef _LITTLE_ENDIAN
1860 	    xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res),
1861 #else
1862 	    xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res),
1863 #endif
1864 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
1865 	    acl2_getattr_getfh},
1866 
1867 	/* ACL2_ACCESS = 4 */
1868 	{acl2_access,
1869 	    xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args),
1870 #ifdef _LITTLE_ENDIAN
1871 	    xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res),
1872 #else
1873 	    xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res),
1874 #endif
1875 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP,
1876 	    acl2_access_getfh},
1877 
1878 	/* ACL2_GETXATTRDIR = 5 */
1879 	{acl2_getxattrdir,
1880 	    xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args),
1881 	    xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res),
1882 	    nullfree, RPC_IDEMPOTENT,
1883 	    acl2_getxattrdir_getfh},
1884 };
1885 
1886 static char *aclcallnames_v3[] = {
1887 	"ACL3_NULL",
1888 	"ACL3_GETACL",
1889 	"ACL3_SETACL",
1890 	"ACL3_GETXATTRDIR"
1891 };
1892 
1893 static struct rpcdisp acldisptab_v3[] = {
1894 	/*
1895 	 * ACL VERSION 3
1896 	 */
1897 
1898 	/* ACL3_NULL = 0 */
1899 	{rpc_null,
1900 	    xdr_void, NULL_xdrproc_t, 0,
1901 	    xdr_void, NULL_xdrproc_t, 0,
1902 	    nullfree, RPC_IDEMPOTENT,
1903 	    0},
1904 
1905 	/* ACL3_GETACL = 1 */
1906 	{acl3_getacl,
1907 	    xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args),
1908 	    xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res),
1909 	    acl3_getacl_free, RPC_IDEMPOTENT,
1910 	    acl3_getacl_getfh},
1911 
1912 	/* ACL3_SETACL = 2 */
1913 	{acl3_setacl,
1914 	    xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args),
1915 	    xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res),
1916 	    nullfree, 0,
1917 	    acl3_setacl_getfh},
1918 
1919 	/* ACL3_GETXATTRDIR = 3 */
1920 	{acl3_getxattrdir,
1921 	    xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args),
1922 	    xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res),
1923 	    nullfree, RPC_IDEMPOTENT,
1924 	    acl3_getxattrdir_getfh},
1925 };
1926 
1927 static struct rpc_disptable acl_disptable[] = {
1928 	{sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]),
1929 		aclcallnames_v2,
1930 		&aclproccnt_v2_ptr, acldisptab_v2},
1931 	{sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]),
1932 		aclcallnames_v3,
1933 		&aclproccnt_v3_ptr, acldisptab_v3},
1934 };
1935 
1936 static void
1937 acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
1938 {
1939 	common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
1940 		"acl_server", acl_disptable);
1941 }
1942 
1943 int
1944 checkwin(int flavor, int window, struct svc_req *req)
1945 {
1946 	struct authdes_cred *adc;
1947 
1948 	switch (flavor) {
1949 	case AUTH_DES:
1950 		adc = (struct authdes_cred *)req->rq_clntcred;
1951 		if (adc->adc_fullname.window > window)
1952 			return (0);
1953 		break;
1954 
1955 	default:
1956 		break;
1957 	}
1958 	return (1);
1959 }
1960 
1961 
1962 /*
1963  * checkauth() will check the access permission against the export
1964  * information.  Then map root uid/gid to appropriate uid/gid.
1965  *
1966  * This routine is used by NFS V3 and V2 code.
1967  */
1968 static int
1969 checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok,
1970     bool_t publicfh_ok)
1971 {
1972 	int i, nfsflavor, rpcflavor, stat, access;
1973 	struct secinfo *secp;
1974 	caddr_t principal;
1975 	char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */
1976 	int anon_res = 0;
1977 
1978 	/*
1979 	 *	Check for privileged port number
1980 	 *	N.B.:  this assumes that we know the format of a netbuf.
1981 	 */
1982 	if (nfs_portmon) {
1983 		struct sockaddr *ca;
1984 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1985 
1986 		if (ca == NULL)
1987 			return (0);
1988 
1989 		if ((ca->sa_family == AF_INET &&
1990 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
1991 		    IPPORT_RESERVED) ||
1992 		    (ca->sa_family == AF_INET6 &&
1993 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
1994 		    IPPORT_RESERVED)) {
1995 			cmn_err(CE_NOTE,
1996 			    "nfs_server: client %s%ssent NFS request from "
1997 			    "unprivileged port",
1998 			    client_name(req), client_addr(req, buf));
1999 			return (0);
2000 		}
2001 	}
2002 
2003 	/*
2004 	 *  return 1 on success or 0 on failure
2005 	 */
2006 	stat = sec_svc_getcred(req, cr, &principal, &nfsflavor);
2007 
2008 	/*
2009 	 * A failed AUTH_UNIX svc_get_cred() implies we couldn't set
2010 	 * the credentials; below we map that to anonymous.
2011 	 */
2012 	if (!stat && nfsflavor != AUTH_UNIX) {
2013 		cmn_err(CE_NOTE,
2014 		    "nfs_server: couldn't get unix cred for %s",
2015 		    client_name(req));
2016 		return (0);
2017 	}
2018 
2019 	/*
2020 	 * Short circuit checkauth() on operations that support the
2021 	 * public filehandle, and if the request for that operation
2022 	 * is using the public filehandle. Note that we must call
2023 	 * sec_svc_getcred() first so that xp_cookie is set to the
2024 	 * right value. Normally xp_cookie is just the RPC flavor
2025 	 * of the the request, but in the case of RPCSEC_GSS it
2026 	 * could be a pseudo flavor.
2027 	 */
2028 	if (publicfh_ok)
2029 		return (1);
2030 
2031 	rpcflavor = req->rq_cred.oa_flavor;
2032 	/*
2033 	 * Check if the auth flavor is valid for this export
2034 	 */
2035 	access = nfsauth_access(exi, req);
2036 	if (access & NFSAUTH_DROP)
2037 		return (-1);	/* drop the request */
2038 
2039 	if (access & NFSAUTH_DENIED) {
2040 		/*
2041 		 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was
2042 		 * probably due to the flavor not matching during the
2043 		 * the mount attempt. So map the flavor to AUTH_NONE
2044 		 * so that the credentials get mapped to the anonymous
2045 		 * user.
2046 		 */
2047 		if (anon_ok == 1)
2048 			rpcflavor = AUTH_NONE;
2049 		else
2050 			return (0);	/* deny access */
2051 
2052 	} else if (access & NFSAUTH_MAPNONE) {
2053 		/*
2054 		 * Access was granted even though the flavor mismatched
2055 		 * because AUTH_NONE was one of the exported flavors.
2056 		 */
2057 		rpcflavor = AUTH_NONE;
2058 
2059 	} else if (access & NFSAUTH_WRONGSEC) {
2060 		/*
2061 		 * NFSAUTH_WRONGSEC is used for NFSv4. Since V2/V3 already
2062 		 * negotiates the security flavor thru MOUNT protocol, the
2063 		 * only way it can get NFSAUTH_WRONGSEC here is from
2064 		 * NFS_ACL for V4. This could be for a limited view, so
2065 		 * map it to RO access. V4 lookup/readdir will take care
2066 		 * of the limited view portion.
2067 		 */
2068 		access |= NFSAUTH_RO;
2069 		access &= ~NFSAUTH_WRONGSEC;
2070 	}
2071 
2072 	switch (rpcflavor) {
2073 	case AUTH_NONE:
2074 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2075 				exi->exi_export.ex_anon);
2076 		(void) crsetgroups(cr, 0, NULL);
2077 		break;
2078 
2079 	case AUTH_UNIX:
2080 		if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
2081 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2082 					exi->exi_export.ex_anon);
2083 			(void) crsetgroups(cr, 0, NULL);
2084 		}
2085 		break;
2086 
2087 	case AUTH_DES:
2088 	case RPCSEC_GSS:
2089 		/*
2090 		 *  Find the secinfo structure.  We should be able
2091 		 *  to find it by the time we reach here.
2092 		 *  nfsauth_access() has done the checking.
2093 		 */
2094 		secp = NULL;
2095 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2096 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
2097 			    nfsflavor) {
2098 				secp = &exi->exi_export.ex_secinfo[i];
2099 				break;
2100 			}
2101 		}
2102 
2103 		if (!secp) {
2104 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
2105 			    "no secinfo data for flavor %d",
2106 			    client_name(req), client_addr(req, buf),
2107 			    nfsflavor);
2108 			return (0);
2109 		}
2110 
2111 		if (!checkwin(rpcflavor, secp->s_window, req)) {
2112 			cmn_err(CE_NOTE,
2113 			    "nfs_server: client %s%sused invalid "
2114 			    "auth window value",
2115 			    client_name(req), client_addr(req, buf));
2116 			return (0);
2117 		}
2118 
2119 		/*
2120 		 * Map root principals listed in the share's root= list to root,
2121 		 * and map any others principals that were mapped to root by RPC
2122 		 * to anon.
2123 		 */
2124 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
2125 			secp->s_rootcnt, secp->s_rootnames)) {
2126 			if (crgetuid(cr) == 0)
2127 				return (1);
2128 
2129 			(void) crsetugid(cr, 0, 0);
2130 
2131 			/*
2132 			 * NOTE: If and when kernel-land privilege tracing is
2133 			 * added this may have to be replaced with code that
2134 			 * retrieves root's supplementary groups (e.g., using
2135 			 * kgss_get_group_info().  In the meantime principals
2136 			 * mapped to uid 0 get all privileges, so setting cr's
2137 			 * supplementary groups for them does nothing.
2138 			 */
2139 			(void) crsetgroups(cr, 0, NULL);
2140 
2141 			return (1);
2142 		}
2143 
2144 		/*
2145 		 * Not a root princ, or not in root list, map UID 0/nobody to
2146 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
2147 		 * UID_NOBODY and GID_NOBODY, respectively.)
2148 		 */
2149 		if (crgetuid(cr) != 0 &&
2150 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
2151 			return (1);
2152 
2153 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2154 			exi->exi_export.ex_anon);
2155 		(void) crsetgroups(cr, 0, NULL);
2156 		break;
2157 	default:
2158 		return (0);
2159 	} /* switch on rpcflavor */
2160 
2161 	/*
2162 	 * Even if anon access is disallowed via ex_anon == -1, we allow
2163 	 * this access if anon_ok is set.  So set creds to the default
2164 	 * "nobody" id.
2165 	 */
2166 	if (anon_res != 0) {
2167 		if (anon_ok == 0) {
2168 			cmn_err(CE_NOTE,
2169 			    "nfs_server: client %s%ssent wrong "
2170 			    "authentication for %s",
2171 			    client_name(req), client_addr(req, buf),
2172 			    exi->exi_export.ex_path ?
2173 			    exi->exi_export.ex_path : "?");
2174 			return (0);
2175 		}
2176 
2177 		if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0)
2178 			return (0);
2179 	}
2180 
2181 	return (1);
2182 }
2183 
2184 /*
2185  * returns 0 on failure, -1 on a drop, -2 on wrong security flavor,
2186  * and 1 on success
2187  */
2188 int
2189 checkauth4(struct compound_state *cs, struct svc_req *req)
2190 {
2191 	int i, rpcflavor, access;
2192 	struct secinfo *secp;
2193 	char buf[MAXHOST + 1];
2194 	int anon_res = 0, nfsflavor;
2195 	struct exportinfo *exi;
2196 	cred_t	*cr;
2197 	caddr_t	principal;
2198 
2199 	exi = cs->exi;
2200 	cr = cs->cr;
2201 	principal = cs->principal;
2202 	nfsflavor = cs->nfsflavor;
2203 
2204 	ASSERT(cr != NULL);
2205 
2206 	rpcflavor = req->rq_cred.oa_flavor;
2207 	cs->access &= ~CS_ACCESS_LIMITED;
2208 
2209 	/*
2210 	 * Check the access right per auth flavor on the vnode of
2211 	 * this export for the given request.
2212 	 */
2213 	access = nfsauth4_access(cs->exi, cs->vp, req);
2214 
2215 	if (access & NFSAUTH_WRONGSEC)
2216 		return (-2);	/* no access for this security flavor */
2217 
2218 	if (access & NFSAUTH_DROP)
2219 		return (-1);	/* drop the request */
2220 
2221 	if (access & NFSAUTH_DENIED) {
2222 
2223 		if (exi->exi_export.ex_seccnt > 0)
2224 			return (0);	/* deny access */
2225 
2226 	} else if (access & NFSAUTH_LIMITED) {
2227 
2228 		cs->access |= CS_ACCESS_LIMITED;
2229 
2230 	} else if (access & NFSAUTH_MAPNONE) {
2231 		/*
2232 		 * Access was granted even though the flavor mismatched
2233 		 * because AUTH_NONE was one of the exported flavors.
2234 		 */
2235 		rpcflavor = AUTH_NONE;
2236 	}
2237 
2238 	/*
2239 	 * XXX probably need to redo some of it for nfsv4?
2240 	 * return 1 on success or 0 on failure
2241 	 */
2242 
2243 	switch (rpcflavor) {
2244 	case AUTH_NONE:
2245 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2246 				exi->exi_export.ex_anon);
2247 		(void) crsetgroups(cr, 0, NULL);
2248 		break;
2249 
2250 	case AUTH_UNIX:
2251 		if (crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
2252 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2253 					exi->exi_export.ex_anon);
2254 			(void) crsetgroups(cr, 0, NULL);
2255 		}
2256 		break;
2257 
2258 	default:
2259 		/*
2260 		 *  Find the secinfo structure.  We should be able
2261 		 *  to find it by the time we reach here.
2262 		 *  nfsauth_access() has done the checking.
2263 		 */
2264 		secp = NULL;
2265 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2266 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
2267 			    nfsflavor) {
2268 				secp = &exi->exi_export.ex_secinfo[i];
2269 				break;
2270 			}
2271 		}
2272 
2273 		if (!secp) {
2274 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
2275 			    "no secinfo data for flavor %d",
2276 			    client_name(req), client_addr(req, buf),
2277 			    nfsflavor);
2278 			return (0);
2279 		}
2280 
2281 		if (!checkwin(rpcflavor, secp->s_window, req)) {
2282 			cmn_err(CE_NOTE,
2283 			    "nfs_server: client %s%sused invalid "
2284 			    "auth window value",
2285 			    client_name(req), client_addr(req, buf));
2286 			return (0);
2287 		}
2288 
2289 		/*
2290 		 * Map root principals listed in the share's root= list to root,
2291 		 * and map any others principals that were mapped to root by RPC
2292 		 * to anon.
2293 		 */
2294 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
2295 			secp->s_rootcnt, secp->s_rootnames)) {
2296 			if (crgetuid(cr) == 0)
2297 				return (1);
2298 
2299 			(void) crsetugid(cr, 0, 0);
2300 
2301 			/*
2302 			 * NOTE: If and when kernel-land privilege tracing is
2303 			 * added this may have to be replaced with code that
2304 			 * retrieves root's supplementary groups (e.g., using
2305 			 * kgss_get_group_info().  In the meantime principals
2306 			 * mapped to uid 0 get all privileges, so setting cr's
2307 			 * supplementary groups for them does nothing.
2308 			 */
2309 			(void) crsetgroups(cr, 0, NULL);
2310 
2311 			return (1);
2312 		}
2313 
2314 		/*
2315 		 * Not a root princ, or not in root list, map UID 0/nobody to
2316 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
2317 		 * UID_NOBODY and GID_NOBODY, respectively.)
2318 		 */
2319 		if (crgetuid(cr) != 0 &&
2320 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
2321 			return (1);
2322 
2323 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2324 			exi->exi_export.ex_anon);
2325 		(void) crsetgroups(cr, 0, NULL);
2326 		break;
2327 	} /* switch on rpcflavor */
2328 
2329 	/*
2330 	 * Even if anon access is disallowed via ex_anon == -1, we allow
2331 	 * this access if anon_ok is set.  So set creds to the default
2332 	 * "nobody" id.
2333 	 */
2334 
2335 	if (anon_res != 0) {
2336 		cmn_err(CE_NOTE,
2337 			"nfs_server: client %s%ssent wrong "
2338 			"authentication for %s",
2339 			client_name(req), client_addr(req, buf),
2340 			exi->exi_export.ex_path ?
2341 			exi->exi_export.ex_path : "?");
2342 		return (0);
2343 	}
2344 
2345 	return (1);
2346 }
2347 
2348 
2349 static char *
2350 client_name(struct svc_req *req)
2351 {
2352 	char *hostname = NULL;
2353 
2354 	/*
2355 	 * If it's a Unix cred then use the
2356 	 * hostname from the credential.
2357 	 */
2358 	if (req->rq_cred.oa_flavor == AUTH_UNIX) {
2359 		hostname = ((struct authunix_parms *)
2360 		    req->rq_clntcred)->aup_machname;
2361 	}
2362 	if (hostname == NULL)
2363 		hostname = "";
2364 
2365 	return (hostname);
2366 }
2367 
2368 static char *
2369 client_addr(struct svc_req *req, char *buf)
2370 {
2371 	struct sockaddr *ca;
2372 	uchar_t *b;
2373 	char *frontspace = "";
2374 
2375 	/*
2376 	 * We assume we are called in tandem with client_name and the
2377 	 * format string looks like "...client %s%sblah blah..."
2378 	 *
2379 	 * If it's a Unix cred then client_name returned
2380 	 * a host name, so we need insert a space between host name
2381 	 * and IP address.
2382 	 */
2383 	if (req->rq_cred.oa_flavor == AUTH_UNIX)
2384 		frontspace = " ";
2385 
2386 	/*
2387 	 * Convert the caller's IP address to a dotted string
2388 	 */
2389 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2390 
2391 	if (ca->sa_family == AF_INET) {
2392 	    b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
2393 	    (void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
2394 		b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
2395 	} else if (ca->sa_family == AF_INET6) {
2396 		struct sockaddr_in6 *sin6;
2397 		sin6 = (struct sockaddr_in6 *)ca;
2398 		(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
2399 				buf, INET6_ADDRSTRLEN);
2400 
2401 	} else {
2402 
2403 		/*
2404 		 * No IP address to print. If there was a host name
2405 		 * printed, then we print a space.
2406 		 */
2407 		(void) sprintf(buf, frontspace);
2408 	}
2409 
2410 	return (buf);
2411 }
2412 
2413 /*
2414  * NFS Server initialization routine.  This routine should only be called
2415  * once.  It performs the following tasks:
2416  *	- Call sub-initialization routines (localize access to variables)
2417  *	- Initialize all locks
2418  *	- initialize the version 3 write verifier
2419  */
2420 int
2421 nfs_srvinit(void)
2422 {
2423 	int error;
2424 
2425 	error = nfs_exportinit();
2426 	if (error != 0)
2427 		return (error);
2428 	error = rfs4_srvrinit();
2429 	if (error != 0) {
2430 		nfs_exportfini();
2431 		return (error);
2432 	}
2433 	rfs_srvrinit();
2434 	rfs3_srvrinit();
2435 	nfsauth_init();
2436 
2437 	/* Init the stuff to control start/stop */
2438 	nfs_server_upordown = NFS_SERVER_STOPPED;
2439 	mutex_init(&nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL);
2440 	cv_init(&nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL);
2441 	mutex_init(&rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL);
2442 	cv_init(&rdma_wait_cv, NULL, CV_DEFAULT, NULL);
2443 
2444 	return (0);
2445 }
2446 
2447 /*
2448  * NFS Server finalization routine. This routine is called to cleanup the
2449  * initialization work previously performed if the NFS server module could
2450  * not be loaded correctly.
2451  */
2452 void
2453 nfs_srvfini(void)
2454 {
2455 	nfsauth_fini();
2456 	rfs3_srvrfini();
2457 	rfs_srvrfini();
2458 	nfs_exportfini();
2459 
2460 	mutex_destroy(&nfs_server_upordown_lock);
2461 	cv_destroy(&nfs_server_upordown_cv);
2462 	mutex_destroy(&rdma_wait_mutex);
2463 	cv_destroy(&rdma_wait_cv);
2464 }
2465 
2466 /*
2467  * Set up an iovec array of up to cnt pointers.
2468  */
2469 
2470 void
2471 mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp)
2472 {
2473 	while (m != NULL && cnt-- > 0) {
2474 		iovp->iov_base = (caddr_t)m->b_rptr;
2475 		iovp->iov_len = (m->b_wptr - m->b_rptr);
2476 		iovp++;
2477 		m = m->b_cont;
2478 	}
2479 }
2480 
2481 /*
2482  * Common code between NFS Version 2 and NFS Version 3 for the public
2483  * filehandle multicomponent lookups.
2484  */
2485 
2486 /*
2487  * Public filehandle evaluation of a multi-component lookup, following
2488  * symbolic links, if necessary. This may result in a vnode in another
2489  * filesystem, which is OK as long as the other filesystem is exported.
2490  *
2491  * Note that the exi will be set either to NULL or a new reference to the
2492  * exportinfo struct that corresponds to the vnode of the multi-component path.
2493  * It is the callers responsibility to release this reference.
2494  */
2495 int
2496 rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
2497     struct exportinfo **exi, struct sec_ol *sec)
2498 {
2499 	int pathflag;
2500 	vnode_t *mc_dvp = NULL;
2501 	vnode_t *realvp;
2502 	int error;
2503 
2504 	*exi = NULL;
2505 
2506 	/*
2507 	 * check if the given path is a url or native path. Since p is
2508 	 * modified by MCLpath(), it may be empty after returning from
2509 	 * there, and should be checked.
2510 	 */
2511 	if ((pathflag = MCLpath(&p)) == -1)
2512 		return (EIO);
2513 
2514 	/*
2515 	 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit
2516 	 * on in sec->sec_flags. This bit will later serve as an
2517 	 * indication in makefh_ol() or makefh3_ol() to overload the
2518 	 * filehandle to contain the sec modes used by the server for
2519 	 * the path.
2520 	 */
2521 	if (pathflag == SECURITY_QUERY) {
2522 		if ((sec->sec_index = (uint_t)(*p)) > 0) {
2523 			sec->sec_flags |= SEC_QUERY;
2524 			p++;
2525 			if ((pathflag = MCLpath(&p)) == -1)
2526 				return (EIO);
2527 		} else {
2528 			cmn_err(CE_NOTE,
2529 			    "nfs_server: invalid security index %d, "
2530 			    "violating WebNFS SNEGO protocol.", sec->sec_index);
2531 			return (EIO);
2532 		}
2533 	}
2534 
2535 	if (p[0] == '\0') {
2536 		error = ENOENT;
2537 		goto publicfh_done;
2538 	}
2539 
2540 	error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag);
2541 
2542 	/*
2543 	 * If name resolves to "/" we get EINVAL since we asked for
2544 	 * the vnode of the directory that the file is in. Try again
2545 	 * with NULL directory vnode.
2546 	 */
2547 	if (error == EINVAL) {
2548 		error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag);
2549 		if (!error) {
2550 			ASSERT(*vpp != NULL);
2551 			if ((*vpp)->v_type == VDIR) {
2552 				VN_HOLD(*vpp);
2553 				mc_dvp = *vpp;
2554 			} else {
2555 				/*
2556 				 * This should not happen, the filesystem is
2557 				 * in an inconsistent state. Fail the lookup
2558 				 * at this point.
2559 				 */
2560 				VN_RELE(*vpp);
2561 				error = EINVAL;
2562 			}
2563 		}
2564 	}
2565 
2566 	if (error)
2567 		goto publicfh_done;
2568 
2569 	if (*vpp == NULL) {
2570 		error = ENOENT;
2571 		goto publicfh_done;
2572 	}
2573 
2574 	ASSERT(mc_dvp != NULL);
2575 	ASSERT(*vpp != NULL);
2576 
2577 	if ((*vpp)->v_type == VDIR) {
2578 		do {
2579 			/*
2580 			 * *vpp may be an AutoFS node, so we perform
2581 			 * a VOP_ACCESS() to trigger the mount of the intended
2582 			 * filesystem, so we can perform the lookup in the
2583 			 * intended filesystem.
2584 			 */
2585 			(void) VOP_ACCESS(*vpp, 0, 0, cr);
2586 
2587 			/*
2588 			 * If vnode is covered, get the
2589 			 * the topmost vnode.
2590 			 */
2591 			if (vn_mountedvfs(*vpp) != NULL) {
2592 				error = traverse(vpp);
2593 				if (error) {
2594 					VN_RELE(*vpp);
2595 					goto publicfh_done;
2596 				}
2597 			}
2598 
2599 			if (VOP_REALVP(*vpp, &realvp) == 0 && realvp != *vpp) {
2600 				/*
2601 				 * If realvp is different from *vpp
2602 				 * then release our reference on *vpp, so that
2603 				 * the export access check be performed on the
2604 				 * real filesystem instead.
2605 				 */
2606 				VN_HOLD(realvp);
2607 				VN_RELE(*vpp);
2608 				*vpp = realvp;
2609 			} else
2610 			    break;
2611 		/* LINTED */
2612 		} while (TRUE);
2613 
2614 		/*
2615 		 * Let nfs_vptexi() figure what the real parent is.
2616 		 */
2617 		VN_RELE(mc_dvp);
2618 		mc_dvp = NULL;
2619 
2620 	} else {
2621 		/*
2622 		 * If vnode is covered, get the
2623 		 * the topmost vnode.
2624 		 */
2625 		if (vn_mountedvfs(mc_dvp) != NULL) {
2626 			error = traverse(&mc_dvp);
2627 			if (error) {
2628 			    VN_RELE(*vpp);
2629 			    goto publicfh_done;
2630 			}
2631 		}
2632 
2633 		if (VOP_REALVP(mc_dvp, &realvp) == 0 && realvp != mc_dvp) {
2634 			/*
2635 			 * *vpp is a file, obtain realvp of the parent
2636 			 * directory vnode.
2637 			 */
2638 			VN_HOLD(realvp);
2639 			VN_RELE(mc_dvp);
2640 			mc_dvp = realvp;
2641 		}
2642 	}
2643 
2644 	/*
2645 	 * The pathname may take us from the public filesystem to another.
2646 	 * If that's the case then just set the exportinfo to the new export
2647 	 * and build filehandle for it. Thanks to per-access checking there's
2648 	 * no security issues with doing this. If the client is not allowed
2649 	 * access to this new export then it will get an access error when it
2650 	 * tries to use the filehandle
2651 	 */
2652 	if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
2653 		VN_RELE(*vpp);
2654 		goto publicfh_done;
2655 	}
2656 
2657 	/*
2658 	 * Not allowed access to pseudo exports.
2659 	 */
2660 	if (PSEUDO(*exi)) {
2661 		error = ENOENT;
2662 		VN_RELE(*vpp);
2663 		goto publicfh_done;
2664 	}
2665 
2666 	/*
2667 	 * Do a lookup for the index file. We know the index option doesn't
2668 	 * allow paths through handling in the share command, so mc_dvp will
2669 	 * be the parent for the index file vnode, if its present. Use
2670 	 * temporary pointers to preserve and reuse the vnode pointers of the
2671 	 * original directory in case there's no index file. Note that the
2672 	 * index file is a native path, and should not be interpreted by
2673 	 * the URL parser in rfs_pathname()
2674 	 */
2675 	if (((*exi)->exi_export.ex_flags & EX_INDEX) &&
2676 	    ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) {
2677 		vnode_t *tvp, *tmc_dvp;	/* temporary vnode pointers */
2678 
2679 		tmc_dvp = mc_dvp;
2680 		mc_dvp = tvp = *vpp;
2681 
2682 		error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp,
2683 		    mc_dvp, cr, NATIVEPATH);
2684 
2685 		if (error == ENOENT) {
2686 			*vpp = tvp;
2687 			mc_dvp = tmc_dvp;
2688 			error = 0;
2689 		} else {	/* ok or error other than ENOENT */
2690 			if (tmc_dvp)
2691 				VN_RELE(tmc_dvp);
2692 			if (error)
2693 				goto publicfh_done;
2694 
2695 			/*
2696 			 * Found a valid vp for index "filename". Sanity check
2697 			 * for odd case where a directory is provided as index
2698 			 * option argument and leads us to another filesystem
2699 			 */
2700 
2701 			/* Release the reference on the old exi value */
2702 			ASSERT(*exi != NULL);
2703 			exi_rele(*exi);
2704 
2705 			if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
2706 				VN_RELE(*vpp);
2707 				goto publicfh_done;
2708 			}
2709 		}
2710 	}
2711 
2712 publicfh_done:
2713 	if (mc_dvp)
2714 		VN_RELE(mc_dvp);
2715 
2716 	return (error);
2717 }
2718 
2719 /*
2720  * Evaluate a multi-component path
2721  */
2722 int
2723 rfs_pathname(
2724 	char *path,			/* pathname to evaluate */
2725 	vnode_t **dirvpp,		/* ret for ptr to parent dir vnode */
2726 	vnode_t **compvpp,		/* ret for ptr to component vnode */
2727 	vnode_t *startdvp,		/* starting vnode */
2728 	cred_t *cr,			/* user's credential */
2729 	int pathflag)			/* flag to identify path, e.g. URL */
2730 {
2731 	char namebuf[TYPICALMAXPATHLEN];
2732 	struct pathname pn;
2733 	int error;
2734 
2735 	/*
2736 	 * If pathname starts with '/', then set startdvp to root.
2737 	 */
2738 	if (*path == '/') {
2739 		while (*path == '/')
2740 			path++;
2741 
2742 		startdvp = rootdir;
2743 	}
2744 
2745 	error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf));
2746 	if (error == 0) {
2747 		/*
2748 		 * Call the URL parser for URL paths to modify the original
2749 		 * string to handle any '%' encoded characters that exist.
2750 		 * Done here to avoid an extra bcopy in the lookup.
2751 		 * We need to be careful about pathlen's. We know that
2752 		 * rfs_pathname() is called with a non-empty path. However,
2753 		 * it could be emptied due to the path simply being all /'s,
2754 		 * which is valid to proceed with the lookup, or due to the
2755 		 * URL parser finding an encoded null character at the
2756 		 * beginning of path which should not proceed with the lookup.
2757 		 */
2758 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
2759 			URLparse(pn.pn_path);
2760 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0)
2761 				return (ENOENT);
2762 		}
2763 		VN_HOLD(startdvp);
2764 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
2765 		    rootdir, startdvp, cr);
2766 	}
2767 	if (error == ENAMETOOLONG) {
2768 		/*
2769 		 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
2770 		 */
2771 		if (error = pn_get(path, UIO_SYSSPACE, &pn))
2772 			return (error);
2773 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
2774 			URLparse(pn.pn_path);
2775 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) {
2776 				pn_free(&pn);
2777 				return (ENOENT);
2778 			}
2779 		}
2780 		VN_HOLD(startdvp);
2781 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
2782 		    rootdir, startdvp, cr);
2783 		pn_free(&pn);
2784 	}
2785 
2786 	return (error);
2787 }
2788 
2789 /*
2790  * Adapt the multicomponent lookup path depending on the pathtype
2791  */
2792 static int
2793 MCLpath(char **path)
2794 {
2795 	unsigned char c = (unsigned char)**path;
2796 
2797 	/*
2798 	 * If the MCL path is between 0x20 and 0x7E (graphic printable
2799 	 * character of the US-ASCII coded character set), its a URL path,
2800 	 * per RFC 1738.
2801 	 */
2802 	if (c >= 0x20 && c <= 0x7E)
2803 		return (URLPATH);
2804 
2805 	/*
2806 	 * If the first octet of the MCL path is not an ASCII character
2807 	 * then it must be interpreted as a tag value that describes the
2808 	 * format of the remaining octets of the MCL path.
2809 	 *
2810 	 * If the first octet of the MCL path is 0x81 it is a query
2811 	 * for the security info.
2812 	 */
2813 	switch (c) {
2814 	case 0x80:	/* native path, i.e. MCL via mount protocol */
2815 		(*path)++;
2816 		return (NATIVEPATH);
2817 	case 0x81:	/* security query */
2818 		(*path)++;
2819 		return (SECURITY_QUERY);
2820 	default:
2821 		return (-1);
2822 	}
2823 }
2824 
2825 #define	fromhex(c)  ((c >= '0' && c <= '9') ? (c - '0') : \
2826 			((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
2827 			((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
2828 
2829 /*
2830  * The implementation of URLparse gaurantees that the final string will
2831  * fit in the original one. Replaces '%' occurrences followed by 2 characters
2832  * with its corresponding hexadecimal character.
2833  */
2834 static void
2835 URLparse(char *str)
2836 {
2837 	char *p, *q;
2838 
2839 	p = q = str;
2840 	while (*p) {
2841 		*q = *p;
2842 		if (*p++ == '%') {
2843 			if (*p) {
2844 				*q = fromhex(*p) * 16;
2845 				p++;
2846 				if (*p) {
2847 					*q += fromhex(*p);
2848 					p++;
2849 				}
2850 			}
2851 		}
2852 		q++;
2853 	}
2854 	*q = '\0';
2855 }
2856 
2857 
2858 /*
2859  * Get the export information for the lookup vnode, and verify its
2860  * useable.
2861  */
2862 int
2863 nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
2864     struct exportinfo **exi)
2865 {
2866 	int walk;
2867 	int error = 0;
2868 
2869 	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
2870 	if (*exi == NULL)
2871 		error = EACCES;
2872 	else {
2873 		/*
2874 		 * If nosub is set for this export then
2875 		 * a lookup relative to the public fh
2876 		 * must not terminate below the
2877 		 * exported directory.
2878 		 */
2879 		if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
2880 			error = EACCES;
2881 	}
2882 
2883 	return (error);
2884 }
2885