Home | History | Annotate | Download | only in rpc
      1      0       stevel /*
      2      0       stevel  * CDDL HEADER START
      3      0       stevel  *
      4      0       stevel  * The contents of this file are subject to the terms of the
      5   1676          jpk  * Common Development and Distribution License (the "License").
      6   1676          jpk  * You may not use this file except in compliance with the License.
      7      0       stevel  *
      8      0       stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0       stevel  * or http://www.opensolaris.org/os/licensing.
     10      0       stevel  * See the License for the specific language governing permissions
     11      0       stevel  * and limitations under the License.
     12      0       stevel  *
     13      0       stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0       stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0       stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0       stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0       stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0       stevel  *
     19      0       stevel  * CDDL HEADER END
     20      0       stevel  */
     21      0       stevel /*
     22   8778         Erik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0       stevel  * Use is subject to license terms.
     24      0       stevel  */
     25      0       stevel 
     26      0       stevel /*
     27      0       stevel  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
     28      0       stevel  *		All Rights Reserved
     29      0       stevel  */
     30      0       stevel 
     31      0       stevel /*
     32      0       stevel  * Portions of this source code were derived from Berkeley 4.3 BSD
     33      0       stevel  * under license from the Regents of the University of California.
     34      0       stevel  */
     35      0       stevel 
     36      0       stevel 
     37      0       stevel /*
     38      0       stevel  * Implements a kernel based, client side RPC over Connection Oriented
     39      0       stevel  * Transports (COTS).
     40      0       stevel  */
     41      0       stevel 
     42      0       stevel /*
     43      0       stevel  * Much of this file has been re-written to let NFS work better over slow
     44      0       stevel  * transports. A description follows.
     45      0       stevel  *
     46      0       stevel  * One of the annoying things about kRPC/COTS is that it will temporarily
     47      0       stevel  * create more than one connection between a client and server. This
     48      0       stevel  * happens because when a connection is made, the end-points entry in the
     49      0       stevel  * linked list of connections (headed by cm_hd), is removed so that other
     50      0       stevel  * threads don't mess with it. Went ahead and bit the bullet by keeping
     51      0       stevel  * the endpoint on the connection list and introducing state bits,
     52      0       stevel  * condition variables etc. to the connection entry data structure (struct
     53      0       stevel  * cm_xprt).
     54      0       stevel  *
     55      0       stevel  * Here is a summary of the changes to cm-xprt:
     56      0       stevel  *
     57      0       stevel  *	x_ctime is the timestamp of when the endpoint was last
     58      0       stevel  *	connected or disconnected. If an end-point is ever disconnected
     59      0       stevel  *	or re-connected, then any outstanding RPC request is presumed
     60      0       stevel  *	lost, telling clnt_cots_kcallit that it needs to re-send the
     61      0       stevel  *	request, not just wait for the original request's reply to
     62      0       stevel  *	arrive.
     63      0       stevel  *
     64      0       stevel  *	x_thread flag which tells us if a thread is doing a connection attempt.
     65      0       stevel  *
     66      0       stevel  *	x_waitdis flag which tells us we are waiting a disconnect ACK.
     67      0       stevel  *
     68      0       stevel  *	x_needdis flag which tells us we need to send a T_DISCONN_REQ
     69      0       stevel  *	to kill the connection.
     70      0       stevel  *
     71      0       stevel  *	x_needrel flag which tells us we need to send a T_ORDREL_REQ to
     72      0       stevel  *	gracefully close the connection.
     73      0       stevel  *
     74      0       stevel  *	#defined bitmasks for the all the b_* bits so that more
     75      0       stevel  *	efficient (and at times less clumsy) masks can be used to
     76      0       stevel  *	manipulated state in cases where multiple bits have to
     77      0       stevel  *	set/cleared/checked in the same critical section.
     78      0       stevel  *
     79      0       stevel  *	x_conn_cv and x_dis-_cv are new condition variables to let
     80      0       stevel  *	threads knows when the connection attempt is done, and to let
     81      0       stevel  *	the connecting thread know when the disconnect handshake is
     82      0       stevel  *	done.
     83      0       stevel  *
     84      0       stevel  * Added the CONN_HOLD() macro so that all reference holds have the same
     85      0       stevel  * look and feel.
     86      0       stevel  *
     87      0       stevel  * In the private (cku_private) portion of the client handle,
     88      0       stevel  *
     89      0       stevel  *	cku_flags replaces the cku_sent a boolean. cku_flags keeps
     90      0       stevel  *	track of whether a request as been sent, and whether the
     91      0       stevel  *	client's handles call record is on the dispatch list (so that
     92      0       stevel  *	the reply can be matched by XID to the right client handle).
     93      0       stevel  *	The idea of CKU_ONQUEUE is that we can exit clnt_cots_kcallit()
     94      0       stevel  *	and still have the response find the right client handle so
     95      0       stevel  *	that the retry of CLNT_CALL() gets the result. Testing, found
     96      0       stevel  *	situations where if the timeout was increased, performance
     97      0       stevel  *	degraded. This was due to us hitting a window where the thread
     98      0       stevel  *	was back in rfscall() (probably printing server not responding)
     99      0       stevel  *	while the response came back but no place to put it.
    100      0       stevel  *
    101      0       stevel  *	cku_ctime is just a cache of x_ctime. If they match,
    102      0       stevel  *	clnt_cots_kcallit() won't to send a retry (unless the maximum
    103      0       stevel  *	receive count limit as been reached). If the don't match, then
    104      0       stevel  *	we assume the request has been lost, and a retry of the request
    105      0       stevel  *	is needed.
    106      0       stevel  *
    107      0       stevel  *	cku_recv_attempts counts the number of receive count attempts
    108      0       stevel  *	after one try is sent on the wire.
    109      0       stevel  *
    110      0       stevel  * Added the clnt_delay() routine so that interruptible and
    111      0       stevel  * noninterruptible delays are possible.
    112      0       stevel  *
    113      0       stevel  * CLNT_MIN_TIMEOUT has been bumped to 10 seconds from 3. This is used to
    114      0       stevel  * control how long the client delays before returned after getting
    115      0       stevel  * ECONNREFUSED. At 3 seconds, 8 client threads per mount really does bash
    116      0       stevel  * a server that may be booting and not yet started nfsd.
    117      0       stevel  *
    118      0       stevel  * CLNT_MAXRECV_WITHOUT_RETRY is a new macro (value of 3) (with a tunable)
    119      0       stevel  * Why don't we just wait forever (receive an infinite # of times)?
    120      0       stevel  * Because the server may have rebooted. More insidious is that some
    121      0       stevel  * servers (ours) will drop NFS/TCP requests in some cases. This is bad,
    122      0       stevel  * but it is a reality.
    123      0       stevel  *
    124      0       stevel  * The case of a server doing orderly release really messes up the
    125      0       stevel  * client's recovery, especially if the server's TCP implementation is
    126      0       stevel  * buggy.  It was found was that the kRPC/COTS client was breaking some
    127      0       stevel  * TPI rules, such as not waiting for the acknowledgement of a
    128      0       stevel  * T_DISCON_REQ (hence the added case statements T_ERROR_ACK, T_OK_ACK and
    129      0       stevel  * T_DISCON_REQ in clnt_dispatch_notifyall()).
    130      0       stevel  *
    131      0       stevel  * One of things that we've seen is that a kRPC TCP endpoint goes into
    132      0       stevel  * TIMEWAIT and a thus a reconnect takes a long time to satisfy because
    133      0       stevel  * that the TIMEWAIT state takes a while to finish.  If a server sends a
    134      0       stevel  * T_ORDREL_IND, there is little point in an RPC client doing a
    135      0       stevel  * T_ORDREL_REQ, because the RPC request isn't going to make it (the
    136      0       stevel  * server is saying that it won't accept any more data). So kRPC was
    137      0       stevel  * changed to send a T_DISCON_REQ when we get a T_ORDREL_IND. So now the
    138      0       stevel  * connection skips the TIMEWAIT state and goes straight to a bound state
    139      0       stevel  * that kRPC can quickly switch to connected.
    140      0       stevel  *
    141      0       stevel  * Code that issues TPI request must use waitforack() to wait for the
    142      0       stevel  * corresponding ack (assuming there is one) in any future modifications.
    143      0       stevel  * This works around problems that may be introduced by breaking TPI rules
    144      0       stevel  * (by submitting new calls before earlier requests have been acked) in the
    145      0       stevel  * case of a signal or other early return.  waitforack() depends on
    146      0       stevel  * clnt_dispatch_notifyconn() to issue the wakeup when the ack
    147      0       stevel  * arrives, so adding new TPI calls may require corresponding changes
    148      0       stevel  * to clnt_dispatch_notifyconn(). Presently, the timeout period is based on
    149      0       stevel  * CLNT_MIN_TIMEOUT which is 10 seconds. If you modify this value, be sure
    150      0       stevel  * not to set it too low or TPI ACKS will be lost.
    151      0       stevel  */
    152      0       stevel 
    153      0       stevel #include <sys/param.h>
    154      0       stevel #include <sys/types.h>
    155      0       stevel #include <sys/user.h>
    156      0       stevel #include <sys/systm.h>
    157      0       stevel #include <sys/sysmacros.h>
    158      0       stevel #include <sys/proc.h>
    159      0       stevel #include <sys/socket.h>
    160      0       stevel #include <sys/file.h>
    161      0       stevel #include <sys/stream.h>
    162      0       stevel #include <sys/strsubr.h>
    163      0       stevel #include <sys/stropts.h>
    164      0       stevel #include <sys/strsun.h>
    165      0       stevel #include <sys/timod.h>
    166      0       stevel #include <sys/tiuser.h>
    167      0       stevel #include <sys/tihdr.h>
    168      0       stevel #include <sys/t_kuser.h>
    169      0       stevel #include <sys/fcntl.h>
    170      0       stevel #include <sys/errno.h>
    171      0       stevel #include <sys/kmem.h>
    172      0       stevel #include <sys/debug.h>
    173      0       stevel #include <sys/systm.h>
    174      0       stevel #include <sys/kstat.h>
    175      0       stevel #include <sys/t_lock.h>
    176      0       stevel #include <sys/ddi.h>
    177      0       stevel #include <sys/cmn_err.h>
    178      0       stevel #include <sys/time.h>
    179      0       stevel #include <sys/isa_defs.h>
    180      0       stevel #include <sys/callb.h>
    181      0       stevel #include <sys/sunddi.h>
    182      0       stevel #include <sys/atomic.h>
    183   8205  Siddheshwar #include <sys/sdt.h>
    184      0       stevel 
    185      0       stevel #include <netinet/in.h>
    186      0       stevel #include <netinet/tcp.h>
    187      0       stevel 
    188      0       stevel #include <rpc/types.h>
    189      0       stevel #include <rpc/xdr.h>
    190      0       stevel #include <rpc/auth.h>
    191      0       stevel #include <rpc/clnt.h>
    192      0       stevel #include <rpc/rpc_msg.h>
    193      0       stevel 
    194      0       stevel #define	COTS_DEFAULT_ALLOCSIZE	2048
    195      0       stevel 
    196      0       stevel #define	WIRE_HDR_SIZE	20	/* serialized call header, sans proc number */
    197      0       stevel #define	MSG_OFFSET	128	/* offset of call into the mblk */
    198      0       stevel 
    199      0       stevel const char *kinet_ntop6(uchar_t *, char *, size_t);
    200      0       stevel 
    201      0       stevel static int	clnt_cots_ksettimers(CLIENT *, struct rpc_timers *,
    202      0       stevel     struct rpc_timers *, int, void(*)(int, int, caddr_t), caddr_t, uint32_t);
    203      0       stevel static enum clnt_stat	clnt_cots_kcallit(CLIENT *, rpcproc_t, xdrproc_t,
    204      0       stevel     caddr_t, xdrproc_t, caddr_t, struct timeval);
    205      0       stevel static void	clnt_cots_kabort(CLIENT *);
    206      0       stevel static void	clnt_cots_kerror(CLIENT *, struct rpc_err *);
    207      0       stevel static bool_t	clnt_cots_kfreeres(CLIENT *, xdrproc_t, caddr_t);
    208      0       stevel static void	clnt_cots_kdestroy(CLIENT *);
    209      0       stevel static bool_t	clnt_cots_kcontrol(CLIENT *, int, char *);
    210      0       stevel 
    211      0       stevel 
    212      0       stevel /* List of transports managed by the connection manager. */
    213      0       stevel struct cm_xprt {
    214      0       stevel 	TIUSER		*x_tiptr;	/* transport handle */
    215      0       stevel 	queue_t		*x_wq;		/* send queue */
    216      0       stevel 	clock_t		x_time;		/* last time we handed this xprt out */
    217      0       stevel 	clock_t		x_ctime;	/* time we went to CONNECTED */
    218      0       stevel 	int		x_tidu_size;    /* TIDU size of this transport */
    219      0       stevel 	union {
    220      0       stevel 	    struct {
    221      0       stevel 		unsigned int
    222      0       stevel #ifdef	_BIT_FIELDS_HTOL
    223      0       stevel 		b_closing:	1,	/* we've sent a ord rel on this conn */
    224      0       stevel 		b_dead:		1,	/* transport is closed or disconn */
    225      0       stevel 		b_doomed:	1,	/* too many conns, let this go idle */
    226      0       stevel 		b_connected:	1,	/* this connection is connected */
    227      0       stevel 
    228      0       stevel 		b_ordrel:	1,	/* do an orderly release? */
    229      0       stevel 		b_thread:	1,	/* thread doing connect */
    230      0       stevel 		b_waitdis:	1,	/* waiting for disconnect ACK */
    231      0       stevel 		b_needdis:	1,	/* need T_DISCON_REQ */
    232      0       stevel 
    233      0       stevel 		b_needrel:	1,	/* need T_ORDREL_REQ */
    234      0       stevel 		b_early_disc:	1,	/* got a T_ORDREL_IND or T_DISCON_IND */
    235      0       stevel 					/* disconnect during connect */
    236      0       stevel 
    237      0       stevel 		b_pad:		22;
    238      0       stevel 
    239      0       stevel #endif
    240      0       stevel 
    241      0       stevel #ifdef	_BIT_FIELDS_LTOH
    242      0       stevel 		b_pad:		22,
    243      0       stevel 
    244      0       stevel 		b_early_disc:	1,	/* got a T_ORDREL_IND or T_DISCON_IND */
    245      0       stevel 					/* disconnect during connect */
    246      0       stevel 		b_needrel:	1,	/* need T_ORDREL_REQ */
    247      0       stevel 
    248      0       stevel 		b_needdis:	1,	/* need T_DISCON_REQ */
    249      0       stevel 		b_waitdis:	1,	/* waiting for disconnect ACK */
    250      0       stevel 		b_thread:	1,	/* thread doing connect */
    251      0       stevel 		b_ordrel:	1,	/* do an orderly release? */
    252      0       stevel 
    253      0       stevel 		b_connected:	1,	/* this connection is connected */
    254      0       stevel 		b_doomed:	1,	/* too many conns, let this go idle */
    255      0       stevel 		b_dead:		1,	/* transport is closed or disconn */
    256      0       stevel 		b_closing:	1;	/* we've sent a ord rel on this conn */
    257      0       stevel #endif
    258      0       stevel 	    } bit;	    unsigned int word;
    259      0       stevel 
    260      0       stevel #define	x_closing	x_state.bit.b_closing
    261      0       stevel #define	x_dead		x_state.bit.b_dead
    262      0       stevel #define	x_doomed	x_state.bit.b_doomed
    263      0       stevel #define	x_connected	x_state.bit.b_connected
    264      0       stevel 
    265      0       stevel #define	x_ordrel	x_state.bit.b_ordrel
    266      0       stevel #define	x_thread	x_state.bit.b_thread
    267      0       stevel #define	x_waitdis	x_state.bit.b_waitdis
    268      0       stevel #define	x_needdis	x_state.bit.b_needdis
    269      0       stevel 
    270      0       stevel #define	x_needrel	x_state.bit.b_needrel
    271      0       stevel #define	x_early_disc    x_state.bit.b_early_disc
    272      0       stevel 
    273      0       stevel #define	x_state_flags	x_state.word
    274      0       stevel 
    275      0       stevel #define	X_CLOSING	0x80000000
    276      0       stevel #define	X_DEAD		0x40000000
    277      0       stevel #define	X_DOOMED	0x20000000
    278      0       stevel #define	X_CONNECTED	0x10000000
    279      0       stevel 
    280      0       stevel #define	X_ORDREL	0x08000000
    281      0       stevel #define	X_THREAD	0x04000000
    282      0       stevel #define	X_WAITDIS	0x02000000
    283      0       stevel #define	X_NEEDDIS	0x01000000
    284      0       stevel 
    285      0       stevel #define	X_NEEDREL	0x00800000
    286      0       stevel #define	X_EARLYDISC	0x00400000
    287      0       stevel 
    288      0       stevel #define	X_BADSTATES	(X_CLOSING | X_DEAD | X_DOOMED)
    289      0       stevel 
    290      0       stevel 	}		x_state;
    291      0       stevel 	int		x_ref;		/* number of users of this xprt */
    292      0       stevel 	int		x_family;	/* address family of transport */
    293      0       stevel 	dev_t		x_rdev;		/* device number of transport */
    294      0       stevel 	struct cm_xprt	*x_next;
    295      0       stevel 
    296      0       stevel 	struct netbuf	x_server;	/* destination address */
    297      0       stevel 	struct netbuf	x_src;		/* src address (for retries) */
    298      0       stevel 	kmutex_t	x_lock;		/* lock on this entry */
    299      0       stevel 	kcondvar_t	x_cv;		/* to signal when can be closed */
    300      0       stevel 	kcondvar_t	x_conn_cv;	/* to signal when connection attempt */
    301      0       stevel 					/* is complete */
    302      0       stevel 	kstat_t		*x_ksp;
    303      0       stevel 
    304      0       stevel 	kcondvar_t	x_dis_cv;	/* to signal when disconnect attempt */
    305      0       stevel 					/* is complete */
    306      0       stevel 	zoneid_t	x_zoneid;	/* zone this xprt belongs to */
    307      0       stevel };
    308      0       stevel 
    309      0       stevel typedef struct cm_kstat_xprt {
    310      0       stevel 	kstat_named_t	x_wq;
    311      0       stevel 	kstat_named_t	x_server;
    312      0       stevel 	kstat_named_t	x_family;
    313      0       stevel 	kstat_named_t	x_rdev;
    314      0       stevel 	kstat_named_t	x_time;
    315      0       stevel 	kstat_named_t	x_state;
    316      0       stevel 	kstat_named_t	x_ref;
    317      0       stevel 	kstat_named_t	x_port;
    318      0       stevel } cm_kstat_xprt_t;
    319      0       stevel 
    320      0       stevel static cm_kstat_xprt_t cm_kstat_template = {
    321      0       stevel 	{ "write_queue", KSTAT_DATA_UINT32 },
    322      0       stevel 	{ "server",	KSTAT_DATA_STRING },
    323      0       stevel 	{ "addr_family", KSTAT_DATA_UINT32 },
    324      0       stevel 	{ "device",	KSTAT_DATA_UINT32 },
    325      0       stevel 	{ "time_stamp",	KSTAT_DATA_UINT32 },
    326      0       stevel 	{ "status",	KSTAT_DATA_UINT32 },
    327      0       stevel 	{ "ref_count",	KSTAT_DATA_INT32 },
    328      0       stevel 	{ "port",	KSTAT_DATA_UINT32 },
    329      0       stevel };
    330      0       stevel 
    331      0       stevel /*
    332      0       stevel  * The inverse of this is connmgr_release().
    333      0       stevel  */
    334      0       stevel #define	CONN_HOLD(Cm_entry)	{\
    335      0       stevel 	mutex_enter(&(Cm_entry)->x_lock);	\
    336      0       stevel 	(Cm_entry)->x_ref++;	\
    337      0       stevel 	mutex_exit(&(Cm_entry)->x_lock);	\
    338      0       stevel }
    339      0       stevel 
    340      0       stevel 
    341      0       stevel /*
    342      0       stevel  * Private data per rpc handle.  This structure is allocated by
    343      0       stevel  * clnt_cots_kcreate, and freed by clnt_cots_kdestroy.
    344      0       stevel  */
    345      0       stevel typedef struct cku_private_s {
    346      0       stevel 	CLIENT			cku_client;	/* client handle */
    347      0       stevel 	calllist_t		cku_call;	/* for dispatching calls */
    348      0       stevel 	struct rpc_err		cku_err;	/* error status */
    349      0       stevel 
    350      0       stevel 	struct netbuf		cku_srcaddr;	/* source address for retries */
    351      0       stevel 	int			cku_addrfmly;  /* for binding port */
    352      0       stevel 	struct netbuf		cku_addr;	/* remote address */
    353      0       stevel 	dev_t			cku_device;	/* device to use */
    354      0       stevel 	uint_t			cku_flags;
    355      0       stevel #define	CKU_ONQUEUE		0x1
    356      0       stevel #define	CKU_SENT		0x2
    357      0       stevel 
    358      0       stevel 	bool_t			cku_progress;	/* for CLSET_PROGRESS */
    359      0       stevel 	uint32_t		cku_xid;	/* current XID */
    360      0       stevel 	clock_t			cku_ctime;	/* time stamp of when */
    361      0       stevel 						/* connection was created */
    362      0       stevel 	uint_t			cku_recv_attempts;
    363      0       stevel 	XDR			cku_outxdr;	/* xdr routine for output */
    364      0       stevel 	XDR			cku_inxdr;	/* xdr routine for input */
    365      0       stevel 	char			cku_rpchdr[WIRE_HDR_SIZE + 4];
    366      0       stevel 						/* pre-serialized rpc header */
    367      0       stevel 
    368      0       stevel 	uint_t			cku_outbuflen;	/* default output mblk length */
    369      0       stevel 	struct cred		*cku_cred;	/* credentials */
    370      0       stevel 	bool_t			cku_nodelayonerr;
    371      0       stevel 						/* for CLSET_NODELAYONERR */
    372      0       stevel 	int			cku_useresvport; /* Use reserved port */
    373      0       stevel 	struct rpc_cots_client	*cku_stats;	/* stats for zone */
    374      0       stevel } cku_private_t;
    375      0       stevel 
    376      0       stevel static struct cm_xprt *connmgr_wrapconnect(struct cm_xprt *,
    377      0       stevel 	const struct timeval *, struct netbuf *, int, struct netbuf *,
    378   8778         Erik 	struct rpc_err *, bool_t, bool_t, cred_t *);
    379      0       stevel 
    380      0       stevel static bool_t	connmgr_connect(struct cm_xprt *, queue_t *, struct netbuf *,
    381      0       stevel 				int, calllist_t *, int *, bool_t reconnect,
    382   8778         Erik 				const struct timeval *, bool_t, cred_t *);
    383      0       stevel 
    384  10004          dai static void	*connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset,
    385  10004          dai 				t_uscalar_t length, uint_t align_size);
    386  10004          dai static bool_t	connmgr_setbufsz(calllist_t *e, queue_t *wq, cred_t *cr);
    387  10004          dai static bool_t	connmgr_getopt_int(queue_t *wq, int level, int name, int *val,
    388  10004          dai 				calllist_t *e, cred_t *cr);
    389  10004          dai static bool_t	connmgr_setopt_int(queue_t *wq, int level, int name, int val,
    390  10004          dai 				calllist_t *e, cred_t *cr);
    391   8778         Erik static bool_t	connmgr_setopt(queue_t *, int, int, calllist_t *, cred_t *cr);
    392      0       stevel static void	connmgr_sndrel(struct cm_xprt *);
    393      0       stevel static void	connmgr_snddis(struct cm_xprt *);
    394      0       stevel static void	connmgr_close(struct cm_xprt *);
    395      0       stevel static void	connmgr_release(struct cm_xprt *);
    396      0       stevel static struct cm_xprt *connmgr_wrapget(struct netbuf *, const struct timeval *,
    397      0       stevel 	cku_private_t *);
    398      0       stevel 
    399      0       stevel static struct cm_xprt *connmgr_get(struct netbuf *, const struct timeval *,
    400      0       stevel 	struct netbuf *, int, struct netbuf *, struct rpc_err *, dev_t,
    401   8778         Erik 	bool_t, int, cred_t *);
    402      0       stevel 
    403      0       stevel static void connmgr_cancelconn(struct cm_xprt *);
    404      0       stevel static enum clnt_stat connmgr_cwait(struct cm_xprt *, const struct timeval *,
    405      0       stevel 	bool_t);
    406      0       stevel static void connmgr_dis_and_wait(struct cm_xprt *);
    407      0       stevel 
    408   8205  Siddheshwar static int	clnt_dispatch_send(queue_t *, mblk_t *, calllist_t *, uint_t,
    409      0       stevel 					uint_t);
    410      0       stevel 
    411      0       stevel static int clnt_delay(clock_t, bool_t);
    412      0       stevel 
    413      0       stevel static int waitforack(calllist_t *, t_scalar_t, const struct timeval *, bool_t);
    414      0       stevel 
    415      0       stevel /*
    416      0       stevel  * Operations vector for TCP/IP based RPC
    417      0       stevel  */
    418      0       stevel static struct clnt_ops tcp_ops = {
    419      0       stevel 	clnt_cots_kcallit,	/* do rpc call */
    420      0       stevel 	clnt_cots_kabort,	/* abort call */
    421      0       stevel 	clnt_cots_kerror,	/* return error status */
    422      0       stevel 	clnt_cots_kfreeres,	/* free results */
    423      0       stevel 	clnt_cots_kdestroy,	/* destroy rpc handle */
    424      0       stevel 	clnt_cots_kcontrol,	/* the ioctl() of rpc */
    425      0       stevel 	clnt_cots_ksettimers,	/* set retry timers */
    426      0       stevel };
    427      0       stevel 
    428      0       stevel static int rpc_kstat_instance = 0;  /* keeps the current instance */
    429      0       stevel 				/* number for the next kstat_create */
    430      0       stevel 
    431      0       stevel static struct cm_xprt *cm_hd = NULL;
    432      0       stevel static kmutex_t connmgr_lock;	/* for connection mngr's list of transports */
    433      0       stevel 
    434      0       stevel extern kmutex_t clnt_max_msg_lock;
    435      0       stevel 
    436      0       stevel static calllist_t *clnt_pending = NULL;
    437      0       stevel extern kmutex_t clnt_pending_lock;
    438      0       stevel 
    439      0       stevel static int clnt_cots_hash_size = DEFAULT_HASH_SIZE;
    440      0       stevel 
    441      0       stevel static call_table_t *cots_call_ht;
    442      0       stevel 
    443      0       stevel static const struct rpc_cots_client {
    444      0       stevel 	kstat_named_t	rccalls;
    445      0       stevel 	kstat_named_t	rcbadcalls;
    446      0       stevel 	kstat_named_t	rcbadxids;
    447      0       stevel 	kstat_named_t	rctimeouts;
    448      0       stevel 	kstat_named_t	rcnewcreds;
    449      0       stevel 	kstat_named_t	rcbadverfs;
    450      0       stevel 	kstat_named_t	rctimers;
    451      0       stevel 	kstat_named_t	rccantconn;
    452      0       stevel 	kstat_named_t	rcnomem;
    453      0       stevel 	kstat_named_t	rcintrs;
    454      0       stevel } cots_rcstat_tmpl = {
    455      0       stevel 	{ "calls",	KSTAT_DATA_UINT64 },
    456      0       stevel 	{ "badcalls",	KSTAT_DATA_UINT64 },
    457      0       stevel 	{ "badxids",	KSTAT_DATA_UINT64 },
    458      0       stevel 	{ "timeouts",	KSTAT_DATA_UINT64 },
    459      0       stevel 	{ "newcreds",	KSTAT_DATA_UINT64 },
    460      0       stevel 	{ "badverfs",	KSTAT_DATA_UINT64 },
    461      0       stevel 	{ "timers",	KSTAT_DATA_UINT64 },
    462      0       stevel 	{ "cantconn",	KSTAT_DATA_UINT64 },
    463      0       stevel 	{ "nomem",	KSTAT_DATA_UINT64 },
    464      0       stevel 	{ "interrupts", KSTAT_DATA_UINT64 }
    465      0       stevel };
    466      0       stevel 
    467      0       stevel #define	COTSRCSTAT_INCR(p, x)	\
    468      0       stevel 	atomic_add_64(&(p)->x.value.ui64, 1)
    469      0       stevel 
    470      0       stevel #define	CLNT_MAX_CONNS	1	/* concurrent connections between clnt/srvr */
    471   9806          dai int clnt_max_conns = CLNT_MAX_CONNS;
    472      0       stevel 
    473      0       stevel #define	CLNT_MIN_TIMEOUT	10	/* seconds to wait after we get a */
    474      0       stevel 					/* connection reset */
    475      0       stevel #define	CLNT_MIN_CONNTIMEOUT	5	/* seconds to wait for a connection */
    476      0       stevel 
    477      0       stevel 
    478   9806          dai int clnt_cots_min_tout = CLNT_MIN_TIMEOUT;
    479   9806          dai int clnt_cots_min_conntout = CLNT_MIN_CONNTIMEOUT;
    480      0       stevel 
    481      0       stevel /*
    482      0       stevel  * Limit the number of times we will attempt to receive a reply without
    483      0       stevel  * re-sending a response.
    484      0       stevel  */
    485      0       stevel #define	CLNT_MAXRECV_WITHOUT_RETRY	3
    486   9806          dai uint_t clnt_cots_maxrecv	= CLNT_MAXRECV_WITHOUT_RETRY;
    487      0       stevel 
    488      0       stevel uint_t *clnt_max_msg_sizep;
    489      0       stevel void (*clnt_stop_idle)(queue_t *wq);
    490      0       stevel 
    491      0       stevel #define	ptoh(p)		(&((p)->cku_client))
    492      0       stevel #define	htop(h)		((cku_private_t *)((h)->cl_private))
    493      0       stevel 
    494      0       stevel /*
    495      0       stevel  * Times to retry
    496      0       stevel  */
    497      0       stevel #define	REFRESHES	2	/* authentication refreshes */
    498      0       stevel 
    499    681     rg137905 /*
    500    681     rg137905  * The following is used to determine the global default behavior for
    501    681     rg137905  * COTS when binding to a local port.
    502    681     rg137905  *
    503    681     rg137905  * If the value is set to 1 the default will be to select a reserved
    504    681     rg137905  * (aka privileged) port, if the value is zero the default will be to
    505    681     rg137905  * use non-reserved ports.  Users of kRPC may override this by using
    506    681     rg137905  * CLNT_CONTROL() and CLSET_BINDRESVPORT.
    507    681     rg137905  */
    508   9806          dai int clnt_cots_do_bindresvport = 1;
    509      0       stevel 
    510      0       stevel static zone_key_t zone_cots_key;
    511  10004          dai 
    512  10004          dai /*
    513  10004          dai  * Defaults TCP send and receive buffer size for RPC connections.
    514  10004          dai  * These values can be tuned by /etc/system.
    515  10004          dai  */
    516  10004          dai int rpc_send_bufsz = 1024*1024;
    517  10004          dai int rpc_recv_bufsz = 1024*1024;
    518  10004          dai /*
    519  10004          dai  * To use system-wide default for TCP send and receive buffer size,
    520  10004          dai  * use /etc/system to set rpc_default_tcp_bufsz to 1:
    521  10004          dai  *
    522  10004          dai  * set rpcmod:rpc_default_tcp_bufsz=1
    523  10004          dai  */
    524  10004          dai int rpc_default_tcp_bufsz = 0;
    525      0       stevel 
    526      0       stevel /*
    527      0       stevel  * We need to do this after all kernel threads in the zone have exited.
    528      0       stevel  */
    529      0       stevel /* ARGSUSED */
    530      0       stevel static void
    531      0       stevel clnt_zone_destroy(zoneid_t zoneid, void *unused)
    532      0       stevel {
    533      0       stevel 	struct cm_xprt **cmp;
    534      0       stevel 	struct cm_xprt *cm_entry;
    535      0       stevel 	struct cm_xprt *freelist = NULL;
    536      0       stevel 
    537      0       stevel 	mutex_enter(&connmgr_lock);
    538      0       stevel 	cmp = &cm_hd;
    539      0       stevel 	while ((cm_entry = *cmp) != NULL) {
    540      0       stevel 		if (cm_entry->x_zoneid == zoneid) {
    541      0       stevel 			*cmp = cm_entry->x_next;
    542      0       stevel 			cm_entry->x_next = freelist;
    543      0       stevel 			freelist = cm_entry;
    544      0       stevel 		} else {
    545      0       stevel 			cmp = &cm_entry->x_next;
    546      0       stevel 		}
    547      0       stevel 	}
    548      0       stevel 	mutex_exit(&connmgr_lock);
    549      0       stevel 	while ((cm_entry = freelist) != NULL) {
    550      0       stevel 		freelist = cm_entry->x_next;
    551      0       stevel 		connmgr_close(cm_entry);
    552      0       stevel 	}
    553      0       stevel }
    554      0       stevel 
    555      0       stevel int
    556      0       stevel clnt_cots_kcreate(dev_t dev, struct netbuf *addr, int family, rpcprog_t prog,
    557      0       stevel 	rpcvers_t vers, uint_t max_msgsize, cred_t *cred, CLIENT **ncl)
    558      0       stevel {
    559      0       stevel 	CLIENT *h;
    560      0       stevel 	cku_private_t *p;
    561      0       stevel 	struct rpc_msg call_msg;
    562      0       stevel 	struct rpcstat *rpcstat;
    563      0       stevel 
    564      0       stevel 	RPCLOG(8, "clnt_cots_kcreate: prog %u\n", prog);
    565      0       stevel 
    566    766     carlsonj 	rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone());
    567      0       stevel 	ASSERT(rpcstat != NULL);
    568      0       stevel 
    569      0       stevel 	/* Allocate and intialize the client handle. */
    570      0       stevel 	p = kmem_zalloc(sizeof (*p), KM_SLEEP);
    571      0       stevel 
    572      0       stevel 	h = ptoh(p);
    573      0       stevel 
    574      0       stevel 	h->cl_private = (caddr_t)p;
    575      0       stevel 	h->cl_auth = authkern_create();
    576      0       stevel 	h->cl_ops = &tcp_ops;
    577      0       stevel 
    578      0       stevel 	cv_init(&p->cku_call.call_cv, NULL, CV_DEFAULT, NULL);
    579      0       stevel 	mutex_init(&p->cku_call.call_lock, NULL, MUTEX_DEFAULT, NULL);
    580      0       stevel 
    581      0       stevel 	/*
    582      0       stevel 	 * If the current sanity check size in rpcmod is smaller
    583      0       stevel 	 * than the size needed, then increase the sanity check.
    584      0       stevel 	 */
    585      0       stevel 	if (max_msgsize != 0 && clnt_max_msg_sizep != NULL &&
    586      0       stevel 	    max_msgsize > *clnt_max_msg_sizep) {
    587      0       stevel 		mutex_enter(&clnt_max_msg_lock);
    588      0       stevel 		if (max_msgsize > *clnt_max_msg_sizep)
    589      0       stevel 			*clnt_max_msg_sizep = max_msgsize;
    590      0       stevel 		mutex_exit(&clnt_max_msg_lock);
    591      0       stevel 	}
    592      0       stevel 
    593      0       stevel 	p->cku_outbuflen = COTS_DEFAULT_ALLOCSIZE;
    594      0       stevel 
    595      0       stevel 	/* Preserialize the call message header */
    596      0       stevel 
    597      0       stevel 	call_msg.rm_xid = 0;
    598      0       stevel 	call_msg.rm_direction = CALL;
    599      0       stevel 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
    600      0       stevel 	call_msg.rm_call.cb_prog = prog;
    601      0       stevel 	call_msg.rm_call.cb_vers = vers;
    602      0       stevel 
    603      0       stevel 	xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, WIRE_HDR_SIZE, XDR_ENCODE);
    604      0       stevel 
    605      0       stevel 	if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) {
    606      0       stevel 		RPCLOG0(1, "clnt_cots_kcreate - Fatal header serialization "
    607      0       stevel 		    "error\n");
    608      0       stevel 		auth_destroy(h->cl_auth);
    609      0       stevel 		kmem_free(p, sizeof (cku_private_t));
    610      0       stevel 		RPCLOG0(1, "clnt_cots_kcreate: create failed error EINVAL\n");
    611      0       stevel 		return (EINVAL);		/* XXX */
    612      0       stevel 	}
    613      0       stevel 
    614      0       stevel 	/*
    615      0       stevel 	 * The zalloc initialized the fields below.
    616      0       stevel 	 * p->cku_xid = 0;
    617      0       stevel 	 * p->cku_flags = 0;
    618      0       stevel 	 * p->cku_srcaddr.len = 0;
    619      0       stevel 	 * p->cku_srcaddr.maxlen = 0;
    620      0       stevel 	 */
    621      0       stevel 
    622      0       stevel 	p->cku_cred = cred;
    623      0       stevel 	p->cku_device = dev;
    624      0       stevel 	p->cku_addrfmly = family;
    625      0       stevel 	p->cku_addr.buf = kmem_zalloc(addr->maxlen, KM_SLEEP);
    626      0       stevel 	p->cku_addr.maxlen = addr->maxlen;
    627      0       stevel 	p->cku_addr.len = addr->len;
    628      0       stevel 	bcopy(addr->buf, p->cku_addr.buf, addr->len);
    629      0       stevel 	p->cku_stats = rpcstat->rpc_cots_client;
    630      0       stevel 	p->cku_useresvport = -1; /* value is has not been set */
    631      0       stevel 
    632      0       stevel 	*ncl = h;
    633      0       stevel 	return (0);
    634      0       stevel }
    635      0       stevel 
    636      0       stevel /*ARGSUSED*/
    637      0       stevel static void
    638      0       stevel clnt_cots_kabort(CLIENT *h)
    639      0       stevel {
    640      0       stevel }
    641      0       stevel 
    642      0       stevel /*
    643      0       stevel  * Return error info on this handle.
    644      0       stevel  */
    645      0       stevel static void
    646      0       stevel clnt_cots_kerror(CLIENT *h, struct rpc_err *err)
    647      0       stevel {
    648      0       stevel 	/* LINTED pointer alignment */
    649      0       stevel 	cku_private_t *p = htop(h);
    650      0       stevel 
    651      0       stevel 	*err = p->cku_err;
    652      0       stevel }
    653      0       stevel 
    654      0       stevel static bool_t
    655      0       stevel clnt_cots_kfreeres(CLIENT *h, xdrproc_t xdr_res, caddr_t res_ptr)
    656      0       stevel {
    657      0       stevel 	/* LINTED pointer alignment */
    658      0       stevel 	cku_private_t *p = htop(h);
    659      0       stevel 	XDR *xdrs;
    660      0       stevel 
    661      0       stevel 	xdrs = &(p->cku_outxdr);
    662      0       stevel 	xdrs->x_op = XDR_FREE;
    663      0       stevel 	return ((*xdr_res)(xdrs, res_ptr));
    664      0       stevel }
    665      0       stevel 
    666      0       stevel static bool_t
    667      0       stevel clnt_cots_kcontrol(CLIENT *h, int cmd, char *arg)
    668      0       stevel {
    669      0       stevel 	cku_private_t *p = htop(h);
    670      0       stevel 
    671      0       stevel 	switch (cmd) {
    672      0       stevel 	case CLSET_PROGRESS:
    673      0       stevel 		p->cku_progress = TRUE;
    674      0       stevel 		return (TRUE);
    675      0       stevel 
    676      0       stevel 	case CLSET_XID:
    677      0       stevel 		if (arg == NULL)
    678      0       stevel 			return (FALSE);
    679      0       stevel 
    680      0       stevel 		p->cku_xid = *((uint32_t *)arg);
    681      0       stevel 		return (TRUE);
    682      0       stevel 
    683      0       stevel 	case CLGET_XID:
    684      0       stevel 		if (arg == NULL)
    685      0       stevel 			return (FALSE);
    686      0       stevel 
    687      0       stevel 		*((uint32_t *)arg) = p->cku_xid;
    688      0       stevel 		return (TRUE);
    689      0       stevel 
    690      0       stevel 	case CLSET_NODELAYONERR:
    691      0       stevel 		if (arg == NULL)
    692      0       stevel 			return (FALSE);
    693      0       stevel 
    694      0       stevel 		if (*((bool_t *)arg) == TRUE) {
    695      0       stevel 			p->cku_nodelayonerr = TRUE;
    696      0       stevel 			return (TRUE);
    697      0       stevel 		}
    698      0       stevel 		if (*((bool_t *)arg) == FALSE) {
    699      0       stevel 			p->cku_nodelayonerr = FALSE;
    700      0       stevel 			return (TRUE);
    701      0       stevel 		}
    702      0       stevel 		return (FALSE);
    703      0       stevel 
    704      0       stevel 	case CLGET_NODELAYONERR:
    705      0       stevel 		if (arg == NULL)
    706      0       stevel 			return (FALSE);
    707      0       stevel 
    708      0       stevel 		*((bool_t *)arg) = p->cku_nodelayonerr;
    709      0       stevel 		return (TRUE);
    710      0       stevel 
    711      0       stevel 	case CLSET_BINDRESVPORT:
    712      0       stevel 		if (arg == NULL)
    713      0       stevel 			return (FALSE);
    714      0       stevel 
    715      0       stevel 		if (*(int *)arg != 1 && *(int *)arg != 0)
    716      0       stevel 			return (FALSE);
    717      0       stevel 
    718      0       stevel 		p->cku_useresvport = *(int *)arg;
    719      0       stevel 
    720      0       stevel 		return (TRUE);
    721      0       stevel 
    722      0       stevel 	case CLGET_BINDRESVPORT:
    723      0       stevel 		if (arg == NULL)
    724      0       stevel 			return (FALSE);
    725      0       stevel 
    726      0       stevel 		*(int *)arg = p->cku_useresvport;
    727      0       stevel 
    728      0       stevel 		return (TRUE);
    729      0       stevel 
    730      0       stevel 	default:
    731      0       stevel 		return (FALSE);
    732      0       stevel 	}
    733      0       stevel }
    734      0       stevel 
    735      0       stevel /*
    736      0       stevel  * Destroy rpc handle.  Frees the space used for output buffer,
    737      0       stevel  * private data, and handle structure.
    738      0       stevel  */
    739      0       stevel static void
    740      0       stevel clnt_cots_kdestroy(CLIENT *h)
    741      0       stevel {
    742      0       stevel 	/* LINTED pointer alignment */
    743      0       stevel 	cku_private_t *p = htop(h);
    744      0       stevel 	calllist_t *call = &p->cku_call;
    745      0       stevel 
    746      0       stevel 	RPCLOG(8, "clnt_cots_kdestroy h: %p\n", (void *)h);
    747      0       stevel 	RPCLOG(8, "clnt_cots_kdestroy h: xid=0x%x\n", p->cku_xid);
    748      0       stevel 
    749      0       stevel 	if (p->cku_flags & CKU_ONQUEUE) {
    750      0       stevel 		RPCLOG(64, "clnt_cots_kdestroy h: removing call for xid 0x%x "
    751      0       stevel 		    "from dispatch list\n", p->cku_xid);
    752      0       stevel 		call_table_remove(call);
    753      0       stevel 	}
    754      0       stevel 
    755      0       stevel 	if (call->call_reply)
    756      0       stevel 		freemsg(call->call_reply);
    757      0       stevel 	cv_destroy(&call->call_cv);
    758      0       stevel 	mutex_destroy(&call->call_lock);
    759      0       stevel 
    760      0       stevel 	kmem_free(p->cku_srcaddr.buf, p->cku_srcaddr.maxlen);
    761      0       stevel 	kmem_free(p->cku_addr.buf, p->cku_addr.maxlen);
    762      0       stevel 	kmem_free(p, sizeof (*p));
    763      0       stevel }
    764      0       stevel 
    765      0       stevel static int clnt_cots_pulls;
    766      0       stevel #define	RM_HDR_SIZE	4	/* record mark header size */
    767      0       stevel 
    768      0       stevel /*
    769      0       stevel  * Call remote procedure.
    770      0       stevel  */
    771      0       stevel static enum clnt_stat
    772      0       stevel clnt_cots_kcallit(CLIENT *h, rpcproc_t procnum, xdrproc_t xdr_args,
    773      0       stevel     caddr_t argsp, xdrproc_t xdr_results, caddr_t resultsp, struct timeval wait)
    774      0       stevel {
    775      0       stevel 	/* LINTED pointer alignment */
    776      0       stevel 	cku_private_t *p = htop(h);
    777      0       stevel 	calllist_t *call = &p->cku_call;
    778      0       stevel 	XDR *xdrs;
    779      0       stevel 	struct rpc_msg reply_msg;
    780      0       stevel 	mblk_t *mp;
    781      0       stevel #ifdef	RPCDEBUG
    782      0       stevel 	clock_t time_sent;
    783      0       stevel #endif
    784      0       stevel 	struct netbuf *retryaddr;
    785      0       stevel 	struct cm_xprt *cm_entry = NULL;
    786      0       stevel 	queue_t *wq;
    787   9675          dai 	int len, waitsecs, max_waitsecs;
    788      0       stevel 	int mpsize;
    789      0       stevel 	int refreshes = REFRESHES;
    790      0       stevel 	int interrupted;
    791      0       stevel 	int tidu_size;
    792      0       stevel 	enum clnt_stat status;
    793      0       stevel 	struct timeval cwait;
    794      0       stevel 	bool_t delay_first = FALSE;
    795  11066       rafael 	clock_t ticks, now;
    796      0       stevel 
    797      0       stevel 	RPCLOG(2, "clnt_cots_kcallit, procnum %u\n", procnum);
    798      0       stevel 	COTSRCSTAT_INCR(p->cku_stats, rccalls);
    799      0       stevel 
    800      0       stevel 	RPCLOG(2, "clnt_cots_kcallit: wait.tv_sec: %ld\n", wait.tv_sec);
    801      0       stevel 	RPCLOG(2, "clnt_cots_kcallit: wait.tv_usec: %ld\n", wait.tv_usec);
    802      0       stevel 	/*
    803      0       stevel 	 * Bug ID 1240234:
    804      0       stevel 	 * Look out for zero length timeouts. We don't want to
    805      0       stevel 	 * wait zero seconds for a connection to be established.
    806      0       stevel 	 */
    807      0       stevel 	if (wait.tv_sec < clnt_cots_min_conntout) {
    808      0       stevel 		cwait.tv_sec = clnt_cots_min_conntout;
    809      0       stevel 		cwait.tv_usec = 0;
    810      0       stevel 		RPCLOG(8, "clnt_cots_kcallit: wait.tv_sec (%ld) too low,",
    811      0       stevel 		    wait.tv_sec);
    812      0       stevel 		RPCLOG(8, " setting to: %d\n", clnt_cots_min_conntout);
    813      0       stevel 	} else {
    814      0       stevel 		cwait = wait;
    815      0       stevel 	}
    816      0       stevel 
    817      0       stevel call_again:
    818      0       stevel 	if (cm_entry) {
    819      0       stevel 		connmgr_release(cm_entry);
    820      0       stevel 		cm_entry = NULL;
    821      0       stevel 	}
    822      0       stevel 
    823      0       stevel 	mp = NULL;
    824      0       stevel 
    825      0       stevel 	/*
    826      0       stevel 	 * If the call is not a retry, allocate a new xid and cache it
    827      0       stevel 	 * for future retries.
    828      0       stevel 	 * Bug ID 1246045:
    829      0       stevel 	 * Treat call as a retry for purposes of binding the source
    830      0       stevel 	 * port only if we actually attempted to send anything on
    831      0       stevel 	 * the previous call.
    832      0       stevel 	 */
    833      0       stevel 	if (p->cku_xid == 0) {
    834      0       stevel 		p->cku_xid = alloc_xid();
    835   6403      gt29601 		call->call_zoneid = rpc_zoneid();
    836   6403      gt29601 
    837      0       stevel 		/*
    838      0       stevel 		 * We need to ASSERT here that our xid != 0 because this
    839      0       stevel 		 * determines whether or not our call record gets placed on
    840      0       stevel 		 * the hash table or the linked list.  By design, we mandate
    841      0       stevel 		 * that RPC calls over cots must have xid's != 0, so we can
    842      0       stevel 		 * ensure proper management of the hash table.
    843      0       stevel 		 */
    844      0       stevel 		ASSERT(p->cku_xid != 0);
    845      0       stevel 
    846      0       stevel 		retryaddr = NULL;
    847      0       stevel 		p->cku_flags &= ~CKU_SENT;
    848      0       stevel 
    849      0       stevel 		if (p->cku_flags & CKU_ONQUEUE) {
    850      0       stevel 			RPCLOG(8, "clnt_cots_kcallit: new call, dequeuing old"
    851      0       stevel 			    " one (%p)\n", (void *)call);
    852      0       stevel 			call_table_remove(call);
    853      0       stevel 			p->cku_flags &= ~CKU_ONQUEUE;
    854      0       stevel 			RPCLOG(64, "clnt_cots_kcallit: removing call from "
    855      0       stevel 			    "dispatch list because xid was zero (now 0x%x)\n",
    856      0       stevel 			    p->cku_xid);
    857      0       stevel 		}
    858      0       stevel 
    859      0       stevel 		if (call->call_reply != NULL) {
    860      0       stevel 			freemsg(call->call_reply);
    861      0       stevel 			call->call_reply = NULL;
    862      0       stevel 		}
    863      0       stevel 	} else if (p->cku_srcaddr.buf == NULL || p->cku_srcaddr.len == 0) {
    864      0       stevel 		retryaddr = NULL;
    865      0       stevel 
    866      0       stevel 	} else if (p->cku_flags & CKU_SENT) {
    867      0       stevel 		retryaddr = &p->cku_srcaddr;
    868      0       stevel 
    869      0       stevel 	} else {
    870      0       stevel 		/*
    871      0       stevel 		 * Bug ID 1246045: Nothing was sent, so set retryaddr to
    872      0       stevel 		 * NULL and let connmgr_get() bind to any source port it
    873      0       stevel 		 * can get.
    874      0       stevel 		 */
    875      0       stevel 		retryaddr = NULL;
    876      0       stevel 	}
    877      0       stevel 
    878      0       stevel 	RPCLOG(64, "clnt_cots_kcallit: xid = 0x%x", p->cku_xid);
    879      0       stevel 	RPCLOG(64, " flags = 0x%x\n", p->cku_flags);
    880      0       stevel 
    881      0       stevel 	p->cku_err.re_status = RPC_TIMEDOUT;
    882      0       stevel 	p->cku_err.re_errno = p->cku_err.re_terrno = 0;
    883      0       stevel 
    884      0       stevel 	cm_entry = connmgr_wrapget(retryaddr, &cwait, p);
    885      0       stevel 
    886      0       stevel 	if (cm_entry == NULL) {
    887      0       stevel 		RPCLOG(1, "clnt_cots_kcallit: can't connect status %s\n",
    888      0       stevel 		    clnt_sperrno(p->cku_err.re_status));
    889      0       stevel 
    890      0       stevel 		/*
    891      0       stevel 		 * The reasons why we fail to create a connection are
    892      0       stevel 		 * varied. In most cases we don't want the caller to
    893      0       stevel 		 * immediately retry. This could have one or more
    894      0       stevel 		 * bad effects. This includes flooding the net with
    895      0       stevel 		 * connect requests to ports with no listener; a hard
    896      0       stevel 		 * kernel loop due to all the "reserved" TCP ports being
    897      0       stevel 		 * in use.
    898      0       stevel 		 */
    899      0       stevel 		delay_first = TRUE;
    900      0       stevel 
    901      0       stevel 		/*
    902      0       stevel 		 * Even if we end up returning EINTR, we still count a
    903      0       stevel 		 * a "can't connect", because the connection manager
    904      0       stevel 		 * might have been committed to waiting for or timing out on
    905      0       stevel 		 * a connection.
    906      0       stevel 		 */
    907      0       stevel 		COTSRCSTAT_INCR(p->cku_stats, rccantconn);
    908      0       stevel 		switch (p->cku_err.re_status) {
    909      0       stevel 		case RPC_INTR:
    910      0       stevel 			p->cku_err.re_errno = EINTR;
    911      0       stevel 
    912      0       stevel 			/*
    913      0       stevel 			 * No need to delay because a UNIX signal(2)
    914      0       stevel 			 * interrupted us. The caller likely won't
    915      0       stevel 			 * retry the CLNT_CALL() and even if it does,
    916      0       stevel 			 * we assume the caller knows what it is doing.
    917      0       stevel 			 */
    918      0       stevel 			delay_first = FALSE;
    919      0       stevel 			break;
    920      0       stevel 
    921      0       stevel 		case RPC_TIMEDOUT:
    922      0       stevel 			p->cku_err.re_errno = ETIMEDOUT;
    923      0       stevel 
    924      0       stevel 			/*
    925      0       stevel 			 * No need to delay because timed out already
    926      0       stevel 			 * on the connection request and assume that the
    927      0       stevel 			 * transport time out is longer than our minimum
    928      0       stevel 			 * timeout, or least not too much smaller.
    929      0       stevel 			 */
    930      0       stevel 			delay_first = FALSE;
    931      0       stevel 			break;
    932      0       stevel 
    933      0       stevel 		case RPC_SYSTEMERROR:
    934      0       stevel 		case RPC_TLIERROR:
    935      0       stevel 			/*
    936      0       stevel 			 * We want to delay here because a transient
    937      0       stevel 			 * system error has a better chance of going away
    938      0       stevel 			 * if we delay a bit. If it's not transient, then
    939      0       stevel 			 * we don't want end up in a hard kernel loop
    940      0       stevel 			 * due to retries.
    941      0       stevel 			 */
    942      0       stevel 			ASSERT(p->cku_err.re_errno != 0);
    943      0       stevel 			break;
    944      0       stevel 
    945      0       stevel 
    946      0       stevel 		case RPC_CANTCONNECT:
    947      0       stevel 			/*
    948      0       stevel 			 * RPC_CANTCONNECT is set on T_ERROR_ACK which
    949      0       stevel 			 * implies some error down in the TCP layer or
    950      0       stevel 			 * below. If cku_nodelayonerror is set then we
    951      0       stevel 			 * assume the caller knows not to try too hard.
    952      0       stevel 			 */
    953      0       stevel 			RPCLOG0(8, "clnt_cots_kcallit: connection failed,");
    954      0       stevel 			RPCLOG0(8, " re_status=RPC_CANTCONNECT,");
    955      0       stevel 			RPCLOG(8, " re_errno=%d,", p->cku_err.re_errno);
    956      0       stevel 			RPCLOG(8, " cku_nodelayonerr=%d", p->cku_nodelayonerr);
    957      0       stevel 			if (p->cku_nodelayonerr == TRUE)
    958      0       stevel 				delay_first = FALSE;
    959      0       stevel 
    960      0       stevel 			p->cku_err.re_errno = EIO;
    961      0       stevel 
    962      0       stevel 			break;
    963      0       stevel 
    964      0       stevel 		case RPC_XPRTFAILED:
    965      0       stevel 			/*
    966      0       stevel 			 * We want to delay here because we likely
    967      0       stevel 			 * got a refused connection.
    968      0       stevel 			 */
    969   4457     vv149972 			if (p->cku_err.re_errno == 0)
    970   4457     vv149972 				p->cku_err.re_errno = EIO;
    971      0       stevel 
    972   4457     vv149972 			RPCLOG(1, "clnt_cots_kcallit: transport failed: %d\n",
    973   4457     vv149972 			    p->cku_err.re_errno);
    974   4457     vv149972 
    975   4457     vv149972 			break;
    976      0       stevel 
    977      0       stevel 		default:
    978      0       stevel 			/*
    979      0       stevel 			 * We delay here because it is better to err
    980      0       stevel 			 * on the side of caution. If we got here then
    981      0       stevel 			 * status could have been RPC_SUCCESS, but we
    982      0       stevel 			 * know that we did not get a connection, so
    983      0       stevel 			 * force the rpc status to RPC_CANTCONNECT.
    984      0       stevel 			 */
    985      0       stevel 			p->cku_err.re_status = RPC_CANTCONNECT;
    986      0       stevel 			p->cku_err.re_errno = EIO;
    987      0       stevel 			break;
    988      0       stevel 		}
    989      0       stevel 		if (delay_first == TRUE)
    990      0       stevel 			ticks = clnt_cots_min_tout * drv_usectohz(1000000);
    991      0       stevel 		goto cots_done;
    992      0       stevel 	}
    993      0       stevel 
    994      0       stevel 	/*
    995      0       stevel 	 * If we've never sent any request on this connection (send count
    996      0       stevel 	 * is zero, or the connection has been reset), cache the
    997      0       stevel 	 * the connection's create time and send a request (possibly a retry)
    998      0       stevel 	 */
    999      0       stevel 	if ((p->cku_flags & CKU_SENT) == 0 ||
   1000      0       stevel 	    p->cku_ctime != cm_entry->x_ctime) {
   1001      0       stevel 		p->cku_ctime = cm_entry->x_ctime;
   1002      0       stevel 
   1003      0       stevel 	} else if ((p->cku_flags & CKU_SENT) && (p->cku_flags & CKU_ONQUEUE) &&
   1004      0       stevel 	    (call->call_reply != NULL ||
   1005      0       stevel 	    p->cku_recv_attempts < clnt_cots_maxrecv)) {
   1006      0       stevel 
   1007      0       stevel 		/*
   1008      0       stevel 		 * If we've sent a request and our call is on the dispatch
   1009      0       stevel 		 * queue and we haven't made too many receive attempts, then
   1010      0       stevel 		 * don't re-send, just receive.
   1011      0       stevel 		 */
   1012      0       stevel 		p->cku_recv_attempts++;
   1013      0       stevel 		goto read_again;
   1014      0       stevel 	}
   1015      0       stevel 
   1016      0       stevel 	/*
   1017      0       stevel 	 * Now we create the RPC request in a STREAMS message.  We have to do
   1018      0       stevel 	 * this after the call to connmgr_get so that we have the correct
   1019      0       stevel 	 * TIDU size for the transport.
   1020      0       stevel 	 */
   1021      0       stevel 	tidu_size = cm_entry->x_tidu_size;
   1022      0       stevel 	len = MSG_OFFSET + MAX(tidu_size, RM_HDR_SIZE + WIRE_HDR_SIZE);
   1023      0       stevel 
   1024      0       stevel 	while ((mp = allocb(len, BPRI_MED)) == NULL) {
   1025      0       stevel 		if (strwaitbuf(len, BPRI_MED)) {
   1026      0       stevel 			p->cku_err.re_status = RPC_SYSTEMERROR;
   1027      0       stevel 			p->cku_err.re_errno = ENOSR;
   1028      0       stevel 			COTSRCSTAT_INCR(p->cku_stats, rcnomem);
   1029      0       stevel 			goto cots_done;
   1030      0       stevel 		}
   1031      0       stevel 	}
   1032      0       stevel 	xdrs = &p->cku_outxdr;
   1033      0       stevel 	xdrmblk_init(xdrs, mp, XDR_ENCODE, tidu_size);
   1034      0       stevel 	mpsize = MBLKSIZE(mp);
   1035      0       stevel 	ASSERT(mpsize >= len);
   1036      0       stevel 	ASSERT(mp->b_rptr == mp->b_datap->db_base);
   1037      0       stevel 
   1038      0       stevel 	/*
   1039      0       stevel 	 * If the size of mblk is not appreciably larger than what we
   1040      0       stevel 	 * asked, then resize the mblk to exactly len bytes. The reason for
   1041      0       stevel 	 * this: suppose len is 1600 bytes, the tidu is 1460 bytes
   1042      0       stevel 	 * (from TCP over ethernet), and the arguments to the RPC require
   1043      0       stevel 	 * 2800 bytes. Ideally we want the protocol to render two
   1044      0       stevel 	 * ~1400 byte segments over the wire. However if allocb() gives us a 2k
   1045      0       stevel 	 * mblk, and we allocate a second mblk for the remainder, the protocol
   1046      0       stevel 	 * module may generate 3 segments over the wire:
   1047      0       stevel 	 * 1460 bytes for the first, 448 (2048 - 1600) for the second, and
   1048      0       stevel 	 * 892 for the third. If we "waste" 448 bytes in the first mblk,
   1049      0       stevel 	 * the XDR encoding will generate two ~1400 byte mblks, and the
   1050      0       stevel 	 * protocol module is more likely to produce properly sized segments.
   1051      0       stevel 	 */
   1052      0       stevel 	if ((mpsize >> 1) <= len)
   1053      0       stevel 		mp->b_rptr += (mpsize - len);
   1054      0       stevel 
   1055      0       stevel 	/*
   1056      0       stevel 	 * Adjust b_rptr to reserve space for the non-data protocol headers
   1057      0       stevel 	 * any downstream modules might like to add, and for the
   1058      0       stevel 	 * record marking header.
   1059      0       stevel 	 */
   1060      0       stevel 	mp->b_rptr += (MSG_OFFSET + RM_HDR_SIZE);
   1061      0       stevel 
   1062      0       stevel 	if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
   1063      0       stevel 		/* Copy in the preserialized RPC header information. */
   1064      0       stevel 		bcopy(p->cku_rpchdr, mp->b_rptr, WIRE_HDR_SIZE);
   1065      0       stevel 
   1066      0       stevel 		/* Use XDR_SETPOS() to set the b_wptr to past the RPC header. */
   1067      0       stevel 		XDR_SETPOS(xdrs, (uint_t)(mp->b_rptr - mp->b_datap->db_base +
   1068      0       stevel 		    WIRE_HDR_SIZE));
   1069      0       stevel 
   1070      0       stevel 		ASSERT((mp->b_wptr - mp->b_rptr) == WIRE_HDR_SIZE);
   1071      0       stevel 
   1072      0       stevel 		/* Serialize the procedure number and the arguments. */
   1073      0       stevel 		if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) ||
   1074      0       stevel 		    (!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) ||
   1075      0       stevel 		    (!(*xdr_args)(xdrs, argsp))) {
   1076      0       stevel 			p->cku_err.re_status = RPC_CANTENCODEARGS;
   1077      0       stevel 			p->cku_err.re_errno = EIO;
   1078      0       stevel 			goto cots_done;
   1079      0       stevel 		}
   1080      0       stevel 
   1081      0       stevel 		(*(uint32_t *)(mp->b_rptr)) = p->cku_xid;
   1082      0       stevel 	} else {
   1083      0       stevel 		uint32_t *uproc = (uint32_t *)&p->cku_rpchdr[WIRE_HDR_SIZE];
   1084      0       stevel 		IXDR_PUT_U_INT32(uproc, procnum);
   1085      0       stevel 
   1086      0       stevel 		(*(uint32_t *)(&p->cku_rpchdr[0])) = p->cku_xid;
   1087      0       stevel 
   1088      0       stevel 		/* Use XDR_SETPOS() to set the b_wptr. */
   1089      0       stevel 		XDR_SETPOS(xdrs, (uint_t)(mp->b_rptr - mp->b_datap->db_base));
   1090      0       stevel 
   1091      0       stevel 		/* Serialize the procedure number and the arguments. */
   1092      0       stevel 		if (!AUTH_WRAP(h->cl_auth, p->cku_rpchdr, WIRE_HDR_SIZE+4,
   1093      0       stevel 		    xdrs, xdr_args, argsp)) {
   1094      0       stevel 			p->cku_err.re_status = RPC_CANTENCODEARGS;
   1095      0       stevel 			p->cku_err.re_errno = EIO;
   1096      0       stevel 			goto cots_done;
   1097      0       stevel 		}
   1098      0       stevel 	}
   1099      0       stevel 
   1100      0       stevel 	RPCLOG(2, "clnt_cots_kcallit: connected, sending call, tidu_size %d\n",
   1101      0       stevel 	    tidu_size);
   1102      0       stevel 
   1103      0       stevel 	wq = cm_entry->x_wq;
   1104   9675          dai 	waitsecs = 0;
   1105   9675          dai 
   1106   9675          dai dispatch_again:
   1107   8205  Siddheshwar 	status = clnt_dispatch_send(wq, mp, call, p->cku_xid,
   1108   6403      gt29601 	    (p->cku_flags & CKU_ONQUEUE));
   1109   8205  Siddheshwar 
   1110   9675          dai 	if ((status == RPC_CANTSEND) && (call->call_reason == ENOBUFS)) {
   1111   9675          dai 		/*
   1112   9675          dai 		 * QFULL condition, allow some time for queue to drain
   1113   9675          dai 		 * and try again. Give up after waiting for all timeout
   1114   9675          dai 		 * specified for the call, or zone is going away.
   1115   9675          dai 		 */
   1116   9675          dai 		max_waitsecs = wait.tv_sec ? wait.tv_sec : clnt_cots_min_tout;
   1117   9675          dai 		if ((waitsecs++ < max_waitsecs) &&
   1118   9675          dai 		    !(zone_status_get(curproc->p_zone) >=
   1119   9675          dai 		    ZONE_IS_SHUTTING_DOWN)) {
   1120   9675          dai 
   1121   9675          dai 			/* wait 1 sec for queue to drain */
   1122   9675          dai 			if (clnt_delay(drv_usectohz(1000000),
   1123   9675          dai 			    h->cl_nosignal) == EINTR) {
   1124   9675          dai 				p->cku_err.re_errno = EINTR;
   1125   9675          dai 				p->cku_err.re_status = RPC_INTR;
   1126   9675          dai 
   1127   9675          dai 				goto cots_done;
   1128   9675          dai 			}
   1129   9675          dai 
   1130   9675          dai 			/* and try again */
   1131   9675          dai 			goto dispatch_again;
   1132   9675          dai 		}
   1133   8205  Siddheshwar 		p->cku_err.re_status = status;
   1134   9675          dai 		p->cku_err.re_errno = call->call_reason;
   1135   8205  Siddheshwar 		DTRACE_PROBE(krpc__e__clntcots__kcallit__cantsend);
   1136   8205  Siddheshwar 
   1137   9675          dai 		goto cots_done;
   1138   9675          dai 	}
   1139   8205  Siddheshwar 
   1140   9675          dai 	if (waitsecs) {
   1141   9675          dai 		/* adjust timeout to account for time wait to send */
   1142   9675          dai 		wait.tv_sec -= waitsecs;
   1143   9675          dai 		if (wait.tv_sec < 0) {
   1144   9675          dai 			/* pick up reply on next retry */
   1145   9675          dai 			wait.tv_sec = 0;
   1146   9675          dai 		}
   1147   9675          dai 		DTRACE_PROBE2(clnt_cots__sendwait, CLIENT *, h,
   1148   9675          dai 		    int, waitsecs);
   1149   8205  Siddheshwar 	}
   1150      0       stevel 
   1151      0       stevel 	RPCLOG(64, "clnt_cots_kcallit: sent call for xid 0x%x\n",
   1152   6403      gt29601 	    (uint_t)p->cku_xid);
   1153      0       stevel 	p->cku_flags = (CKU_ONQUEUE|CKU_SENT);
   1154      0       stevel 	p->cku_recv_attempts = 1;
   1155      0       stevel 
   1156      0       stevel #ifdef	RPCDEBUG
   1157  11066       rafael 	time_sent = ddi_get_lbolt();
   1158      0       stevel #endif
   1159      0       stevel 
   1160      0       stevel 	/*
   1161      0       stevel 	 * Wait for a reply or a timeout.  If there is no error or timeout,
   1162      0       stevel 	 * (both indicated by call_status), call->call_reply will contain
   1163      0       stevel 	 * the RPC reply message.
   1164      0       stevel 	 */
   1165      0       stevel read_again:
   1166      0       stevel 	mutex_enter(&call->call_lock);
   1167      0       stevel 	interrupted = 0;
   1168      0       stevel 	if (call->call_status == RPC_TIMEDOUT) {
   1169      0       stevel 		/*
   1170      0       stevel 		 * Indicate that the lwp is not to be stopped while waiting
   1171      0       stevel 		 * for this network traffic.  This is to avoid deadlock while
   1172      0       stevel 		 * debugging a process via /proc and also to avoid recursive
   1173      0       stevel 		 * mutex_enter()s due to NFS page faults while stopping
   1174      0       stevel 		 * (NFS holds locks when it calls here).
   1175      0       stevel 		 */
   1176      0       stevel 		clock_t cv_wait_ret;
   1177      0       stevel 		clock_t timout;
   1178      0       stevel 		clock_t oldlbolt;
   1179      0       stevel 
   1180      0       stevel 		klwp_t *lwp = ttolwp(curthread);
   1181      0       stevel 
   1182      0       stevel 		if (lwp != NULL)
   1183      0       stevel 			lwp->lwp_nostop++;
   1184      0       stevel 
   1185  11066       rafael 		oldlbolt = ddi_get_lbolt();
   1186      0       stevel 		timout = wait.tv_sec * drv_usectohz(1000000) +
   1187      0       stevel 		    drv_usectohz(wait.tv_usec) + oldlbolt;
   1188      0       stevel 		/*
   1189      0       stevel 		 * Iterate until the call_status is changed to something
   1190      0       stevel 		 * other that RPC_TIMEDOUT, or if cv_timedwait_sig() returns
   1191      0       stevel 		 * something <=0 zero. The latter means that we timed
   1192      0       stevel 		 * out.
   1193      0       stevel 		 */
   1194      0       stevel 		if (h->cl_nosignal)
   1195      0       stevel 			while ((cv_wait_ret = cv_timedwait(&call->call_cv,
   1196      0       stevel 			    &call->call_lock, timout)) > 0 &&
   1197   6403      gt29601 			    call->call_status == RPC_TIMEDOUT)
   1198   6403      gt29601 				;
   1199      0       stevel 		else
   1200      0       stevel 			while ((cv_wait_ret = cv_timedwait_sig(
   1201      0       stevel 			    &call->call_cv,
   1202      0       stevel 			    &call->call_lock, timout)) > 0 &&
   1203   6403      gt29601 			    call->call_status == RPC_TIMEDOUT)
   1204   6403      gt29601 				;
   1205      0       stevel 
   1206      0       stevel 		switch (cv_wait_ret) {
   1207      0       stevel 		case 0:
   1208      0       stevel 			/*
   1209      0       stevel 			 * If we got out of the above loop with
   1210      0       stevel 			 * cv_timedwait_sig() returning 0, then we were
   1211      0       stevel 			 * interrupted regardless what call_status is.
   1212      0       stevel 			 */
   1213      0       stevel 			interrupted = 1;
   1214      0       stevel 			break;
   1215      0       stevel 		case -1:
   1216      0       stevel 			/* cv_timedwait_sig() timed out */
   1217      0       stevel 			break;
   1218      0       stevel 		default:
   1219      0       stevel 
   1220      0       stevel 			/*
   1221      0       stevel 			 * We were cv_signaled(). If we didn't
   1222      0       stevel 			 * get a successful call_status and returned
   1223      0       stevel 			 * before time expired, delay up to clnt_cots_min_tout
   1224      0       stevel 			 * seconds so that the caller doesn't immediately
   1225      0       stevel 			 * try to call us again and thus force the
   1226      0       stevel 			 * same condition that got us here (such
   1227      0       stevel 			 * as a RPC_XPRTFAILED due to the server not
   1228      0       stevel 			 * listening on the end-point.
   1229      0       stevel 			 */
   1230      0       stevel 			if (call->call_status != RPC_SUCCESS) {
   1231      0       stevel 				clock_t curlbolt;
   1232      0       stevel 				clock_t diff;
   1233      0       stevel 
   1234      0       stevel 				curlbolt = ddi_get_lbolt();
   1235      0       stevel 				ticks = clnt_cots_min_tout *
   1236      0       stevel 				    drv_usectohz(1000000);
   1237      0       stevel 				diff = curlbolt - oldlbolt;
   1238      0       stevel 				if (diff < ticks) {
   1239      0       stevel 					delay_first = TRUE;
   1240      0       stevel 					if (diff > 0)
   1241      0       stevel 						ticks -= diff;
   1242      0       stevel 				}
   1243      0       stevel 			}
   1244      0       stevel 			break;
   1245      0       stevel 		}
   1246      0       stevel 
   1247      0       stevel 		if (lwp != NULL)
   1248      0       stevel 			lwp->lwp_nostop--;
   1249      0       stevel 	}
   1250      0       stevel 	/*
   1251      0       stevel 	 * Get the reply message, if any.  This will be freed at the end
   1252      0       stevel 	 * whether or not an error occurred.
   1253      0       stevel 	 */
   1254      0       stevel 	mp = call->call_reply;
   1255      0       stevel 	call->call_reply = NULL;
   1256      0       stevel 
   1257      0       stevel 	/*
   1258      0       stevel 	 * call_err is the error info when the call is on dispatch queue.
   1259      0       stevel 	 * cku_err is the error info returned to the caller.
   1260      0       stevel 	 * Sync cku_err with call_err for local message processing.
   1261      0       stevel 	 */
   1262      0       stevel 
   1263      0       stevel 	status = call->call_status;
   1264      0       stevel 	p->cku_err = call->call_err;
   1265      0       stevel 	mutex_exit(&call->call_lock);
   1266      0       stevel 
   1267      0       stevel 	if (status != RPC_SUCCESS) {
   1268      0       stevel 		switch (status) {
   1269      0       stevel 		case RPC_TIMEDOUT:
   1270  11066       rafael 			now = ddi_get_lbolt();
   1271      0       stevel 			if (interrupted) {
   1272      0       stevel 				COTSRCSTAT_INCR(p->cku_stats, rcintrs);
   1273      0       stevel 				p->cku_err.re_status = RPC_INTR;
   1274      0       stevel 				p->cku_err.re_errno = EINTR;
   1275      0       stevel 				RPCLOG(1, "clnt_cots_kcallit: xid 0x%x",
   1276      0       stevel 				    p->cku_xid);
   1277  11066       rafael 				RPCLOG(1, "signal interrupted at %ld", now);
   1278      0       stevel 				RPCLOG(1, ", was sent at %ld\n", time_sent);
   1279      0       stevel 			} else {
   1280      0       stevel 				COTSRCSTAT_INCR(p->cku_stats, rctimeouts);
   1281      0       stevel 				p->cku_err.re_errno = ETIMEDOUT;
   1282      0       stevel 				RPCLOG(1, "clnt_cots_kcallit: timed out at %ld",
   1283  11066       rafael 				    now);
   1284      0       stevel 				RPCLOG(1, ", was sent at %ld\n", time_sent);
   1285      0       stevel 			}
   1286      0       stevel 			break;
   1287      0       stevel 
   1288      0       stevel 		case RPC_XPRTFAILED:
   1289      0       stevel 			if (p->cku_err.re_errno == 0)
   1290      0       stevel 				p->cku_err.re_errno = EIO;
   1291      0       stevel 
   1292      0       stevel 			RPCLOG(1, "clnt_cots_kcallit: transport failed: %d\n",
   1293      0       stevel 			    p->cku_err.re_errno);
   1294      0       stevel 			break;
   1295      0       stevel 
   1296      0       stevel 		case RPC_SYSTEMERROR:
   1297      0       stevel 			ASSERT(p->cku_err.re_errno);
   1298      0       stevel 			RPCLOG(1, "clnt_cots_kcallit: system error: %d\n",
   1299      0       stevel 			    p->cku_err.re_errno);
   1300      0       stevel 			break;
   1301      0       stevel 
   1302      0       stevel 		default:
   1303      0       stevel 			p->cku_err.re_status = RPC_SYSTEMERROR;
   1304      0       stevel 			p->cku_err.re_errno = EIO;
   1305      0       stevel 			RPCLOG(1, "clnt_cots_kcallit: error: %s\n",
   1306      0       stevel 			    clnt_sperrno(status));
   1307      0       stevel 			break;
   1308      0       stevel 		}
   1309      0       stevel 		if (p->cku_err.re_status != RPC_TIMEDOUT) {
   1310      0       stevel 
   1311      0       stevel 			if (p->cku_flags & CKU_ONQUEUE) {
   1312      0       stevel 				call_table_remove(call);
   1313      0       stevel 				p->cku_flags &= ~CKU_ONQUEUE;
   1314      0       stevel 			}
   1315      0       stevel 
   1316      0       stevel 			RPCLOG(64, "clnt_cots_kcallit: non TIMEOUT so xid 0x%x "
   1317      0       stevel 			    "taken off dispatch list\n", p->cku_xid);
   1318      0       stevel 			if (call->call_reply) {
   1319      0       stevel 				freemsg(call->call_reply);
   1320      0       stevel 				call->call_reply = NULL;
   1321      0       stevel 			}
   1322      0       stevel 		} else if (wait.tv_sec != 0) {
   1323      0       stevel 			/*
   1324      0       stevel 			 * We've sent the request over TCP and so we have
   1325      0       stevel 			 * every reason to believe it will get
   1326      0       stevel 			 * delivered. In which case returning a timeout is not
   1327      0       stevel 			 * appropriate.
   1328      0       stevel 			 */
   1329      0       stevel 			if (p->cku_progress == TRUE &&
   1330      0       stevel 			    p->cku_recv_attempts < clnt_cots_maxrecv) {
   1331      0       stevel 				p->cku_err.re_status = RPC_INPROGRESS;
   1332      0       stevel 			}
   1333      0       stevel 		}
   1334      0       stevel 		goto cots_done;
   1335      0       stevel 	}
   1336      0       stevel 
   1337      0       stevel 	xdrs = &p->cku_inxdr;
   1338      0       stevel 	xdrmblk_init(xdrs, mp, XDR_DECODE, 0);
   1339      0       stevel 
   1340      0       stevel 	reply_msg.rm_direction = REPLY;
   1341      0       stevel 	reply_msg.rm_reply.rp_stat = MSG_ACCEPTED;
   1342      0       stevel 	reply_msg.acpted_rply.ar_stat = SUCCESS;
   1343      0       stevel 
   1344      0       stevel 	reply_msg.acpted_rply.ar_verf = _null_auth;
   1345      0       stevel 	/*
   1346      0       stevel 	 *  xdr_results will be done in AUTH_UNWRAP.
   1347      0       stevel 	 */
   1348      0       stevel 	reply_msg.acpted_rply.ar_results.where = NULL;
   1349      0       stevel 	reply_msg.acpted_rply.ar_results.proc = xdr_void;
   1350      0       stevel 
   1351      0       stevel 	if (xdr_replymsg(xdrs, &reply_msg)) {
   1352      0       stevel 		enum clnt_stat re_status;
   1353      0       stevel 
   1354      0       stevel 		_seterr_reply(&reply_msg, &p->cku_err);
   1355      0       stevel 
   1356      0       stevel 		re_status = p->cku_err.re_status;
   1357      0       stevel 		if (re_status == RPC_SUCCESS) {
   1358      0       stevel 			/*
   1359      0       stevel 			 * Reply is good, check auth.
   1360      0       stevel 			 */
   1361      0       stevel 			if (!AUTH_VALIDATE(h->cl_auth,
   1362   6403      gt29601 			    &reply_msg.acpted_rply.ar_verf)) {
   1363      0       stevel 				COTSRCSTAT_INCR(p->cku_stats, rcbadverfs);
   1364      0       stevel 				RPCLOG0(1, "clnt_cots_kcallit: validation "
   1365   6403      gt29601 				    "failure\n");
   1366      0       stevel 				freemsg(mp);
   1367      0       stevel 				(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
   1368      0       stevel 				mutex_enter(&call->call_lock);
   1369      0       stevel 				if (call->call_reply == NULL)
   1370      0       stevel 					call->call_status = RPC_TIMEDOUT;
   1371      0       stevel 				mutex_exit(&call->call_lock);
   1372      0       stevel 				goto read_again;
   1373      0       stevel 			} else if (!AUTH_UNWRAP(h->cl_auth, xdrs,
   1374   6403      gt29601 			    xdr_results, resultsp)) {
   1375      0       stevel 				RPCLOG0(1, "clnt_cots_kcallit: validation "
   1376   6403      gt29601 				    "failure (unwrap)\n");
   1377      0       stevel 				p->cku_err.re_status = RPC_CANTDECODERES;
   1378      0       stevel 				p->cku_err.re_errno = EIO;
   1379      0       stevel 			}
   1380      0       stevel 		} else {
   1381      0       stevel 			/* set errno in case we can't recover */
   1382      0       stevel 			if (re_status != RPC_VERSMISMATCH &&
   1383      0       stevel 			    re_status != RPC_AUTHERROR &&
   1384      0       stevel 			    re_status != RPC_PROGVERSMISMATCH)
   1385      0       stevel 				p->cku_err.re_errno = EIO;
   1386      0       stevel 
   1387      0       stevel 			if (re_status == RPC_AUTHERROR) {
   1388      0       stevel 				/*
   1389    589     rg137905 				 * Maybe our credential need to be refreshed
   1390      0       stevel 				 */
   1391    571     rg137905 				if (cm_entry) {
   1392    571     rg137905 					/*
   1393    571     rg137905 					 * There is the potential that the
   1394    571     rg137905 					 * cm_entry has/will be marked dead,
   1395    589     rg137905 					 * so drop the connection altogether,
   1396    589     rg137905 					 * force REFRESH to establish new
   1397    589     rg137905 					 * connection.
   1398    571     rg137905 					 */
   1399    589     rg137905 					connmgr_cancelconn(cm_entry);
   1400    571     rg137905 					cm_entry = NULL;
   1401      0       stevel 				}
   1402      0       stevel 
   1403    571     rg137905 				if ((refreshes > 0) &&
   1404    571     rg137905 				    AUTH_REFRESH(h->cl_auth, &reply_msg,
   1405   6403      gt29601 				    p->cku_cred)) {
   1406    571     rg137905 					refreshes--;
   1407    571     rg137905 					(void) xdr_rpc_free_verifier(xdrs,
   1408   6403      gt29601 					    &reply_msg);
   1409    571     rg137905 					freemsg(mp);
   1410    571     rg137905 					mp = NULL;
   1411    571     rg137905 
   1412    571     rg137905 					if (p->cku_flags & CKU_ONQUEUE) {
   1413    571     rg137905 						call_table_remove(call);
   1414    571     rg137905 						p->cku_flags &= ~CKU_ONQUEUE;
   1415    571     rg137905 					}
   1416    571     rg137905 
   1417    571     rg137905 					RPCLOG(64,
   1418    571     rg137905 					    "clnt_cots_kcallit: AUTH_ERROR, xid"
   1419    571     rg137905 					    " 0x%x removed off dispatch list\n",
   1420    571     rg137905 					    p->cku_xid);
   1421    571     rg137905 					if (call->call_reply) {
   1422    571     rg137905 						freemsg(call->call_reply);
   1423    571     rg137905 						call->call_reply = NULL;
   1424    571     rg137905 					}
   1425    571     rg137905 
   1426    571     rg137905 					COTSRCSTAT_INCR(p->cku_stats,
   1427   6403      gt29601 					    rcbadcalls);
   1428    571     rg137905 					COTSRCSTAT_INCR(p->cku_stats,
   1429   6403      gt29601 					    rcnewcreds);
   1430    571     rg137905 					goto call_again;
   1431    589     rg137905 				}
   1432    589     rg137905 
   1433      0       stevel 				/*
   1434      0       stevel 				 * We have used the client handle to
   1435      0       stevel 				 * do an AUTH_REFRESH and the RPC status may
   1436      0       stevel 				 * be set to RPC_SUCCESS; Let's make sure to
   1437      0       stevel 				 * set it to RPC_AUTHERROR.
   1438      0       stevel 				 */
   1439      0       stevel 				p->cku_err.re_status = RPC_AUTHERROR;
   1440    589     rg137905 
   1441      0       stevel 				/*
   1442      0       stevel 				 * Map recoverable and unrecoverable
   1443      0       stevel 				 * authentication errors to appropriate errno
   1444      0       stevel 				 */
   1445      0       stevel 				switch (p->cku_err.re_why) {
   1446    342     nd150628 				case AUTH_TOOWEAK:
   1447    342     nd150628 					/*
   1448    571     rg137905 					 * This could be a failure where the
   1449    571     rg137905 					 * server requires use of a reserved
   1450    571     rg137905 					 * port,  check and optionally set the
   1451    571     rg137905 					 * client handle useresvport trying
   1452    571     rg137905 					 * one more time. Next go round we
   1453    571     rg137905 					 * fall out with the tooweak error.
   1454    342     nd150628 					 */
   1455    342     nd150628 					if (p->cku_useresvport != 1) {
   1456    342     nd150628 						p->cku_useresvport = 1;
   1457    342     nd150628 						p->cku_xid = 0;
   1458    342     nd150628 						(void) xdr_rpc_free_verifier
   1459   6403      gt29601 						    (xdrs, &reply_msg);
   1460    342     nd150628 						freemsg(mp);
   1461    342     nd150628 						goto call_again;
   1462    342     nd150628 					}
   1463    342     nd150628 					/* FALLTHRU */
   1464      0       stevel 				case AUTH_BADCRED:
   1465      0       stevel 				case AUTH_BADVERF:
   1466      0       stevel 				case AUTH_INVALIDRESP:
   1467      0       stevel 				case AUTH_FAILED:
   1468      0       stevel 				case RPCSEC_GSS_NOCRED:
   1469      0       stevel 				case RPCSEC_GSS_FAILED:
   1470      0       stevel 						p->cku_err.re_errno = EACCES;
   1471      0       stevel 						break;
   1472      0       stevel 				case AUTH_REJECTEDCRED:
   1473      0       stevel 				case AUTH_REJECTEDVERF:
   1474      0       stevel 				default:	p->cku_err.re_errno = EIO;
   1475      0       stevel 						break;
   1476      0       stevel 				}
   1477      0       stevel 				RPCLOG(1, "clnt_cots_kcallit : authentication"
   1478      0       stevel 				    " failed with RPC_AUTHERROR of type %d\n",
   1479      0       stevel 				    (int)p->cku_err.re_why);
   1480      0       stevel 			}
   1481      0       stevel 		}
   1482      0       stevel 	} else {
   1483      0       stevel 		/* reply didn't decode properly. */
   1484      0       stevel 		p->cku_err.re_status = RPC_CANTDECODERES;
   1485      0       stevel 		p->cku_err.re_errno = EIO;
   1486      0       stevel 		RPCLOG0(1, "clnt_cots_kcallit: decode failure\n");
   1487      0       stevel 	}
   1488      0       stevel 
   1489      0       stevel 	(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
   1490      0       stevel 
   1491      0       stevel 	if (p->cku_flags & CKU_ONQUEUE) {
   1492      0       stevel 		call_table_remove(call);
   1493      0       stevel 		p->cku_flags &= ~CKU_ONQUEUE;
   1494      0       stevel 	}
   1495      0       stevel 
   1496      0       stevel 	RPCLOG(64, "clnt_cots_kcallit: xid 0x%x taken off dispatch list",
   1497      0       stevel 	    p->cku_xid);
   1498      0       stevel 	RPCLOG(64, " status is %s\n", clnt_sperrno(p->cku_err.re_status));
   1499      0       stevel cots_done:
   1500      0       stevel 	if (cm_entry)
   1501      0       stevel 		connmgr_release(cm_entry);
   1502      0       stevel 
   1503      0       stevel 	if (mp != NULL)
   1504      0       stevel 		freemsg(mp);
   1505      0       stevel 	if ((p->cku_flags & CKU_ONQUEUE) == 0 && call->call_reply) {
   1506      0       stevel 		freemsg(call->call_reply);
   1507      0       stevel 		call->call_reply = NULL;
   1508      0       stevel 	}
   1509      0       stevel 	if (p->cku_err.re_status != RPC_SUCCESS) {
   1510      0       stevel 		RPCLOG0(1, "clnt_cots_kcallit: tail-end failure\n");
   1511      0       stevel 		COTSRCSTAT_INCR(p->cku_stats, rcbadcalls);
   1512      0       stevel 	}
   1513      0       stevel 
   1514      0       stevel 	/*
   1515      0       stevel 	 * No point in delaying if the zone is going away.
   1516      0       stevel 	 */
   1517      0       stevel 	if (delay_first == TRUE &&
   1518      0       stevel 	    !(zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)) {
   1519      0       stevel 		if (clnt_delay(ticks, h->cl_nosignal) == EINTR) {
   1520      0       stevel 			p->cku_err.re_errno = EINTR;
   1521      0       stevel 			p->cku_err.re_status = RPC_INTR;
   1522      0       stevel 		}
   1523      0       stevel 	}
   1524      0       stevel 	return (p->cku_err.re_status);
   1525      0       stevel }
   1526      0       stevel 
   1527      0       stevel /*
   1528      0       stevel  * Kinit routine for cots.  This sets up the correct operations in
   1529      0       stevel  * the client handle, as the handle may have previously been a clts
   1530      0       stevel  * handle, and clears the xid field so there is no way a new call
   1531      0       stevel  * could be mistaken for a retry.  It also sets in the handle the
   1532      0       stevel  * information that is passed at create/kinit time but needed at
   1533      0       stevel  * call time, as cots creates the transport at call time - device,
   1534      0       stevel  * address of the server, protocol family.
   1535      0       stevel  */
   1536      0       stevel void
   1537      0       stevel clnt_cots_kinit(CLIENT *h, dev_t dev, int family, struct netbuf *addr,
   1538      0       stevel 	int max_msgsize, cred_t *cred)
   1539      0       stevel {
   1540      0       stevel 	/* LINTED pointer alignment */
   1541      0       stevel 	cku_private_t *p = htop(h);
   1542      0       stevel 	calllist_t *call = &p->cku_call;
   1543      0       stevel 
   1544      0       stevel 	h->cl_ops = &tcp_ops;
   1545      0       stevel 	if (p->cku_flags & CKU_ONQUEUE) {
   1546      0       stevel 		call_table_remove(call);
   1547      0       stevel 		p->cku_flags &= ~CKU_ONQUEUE;
   1548      0       stevel 		RPCLOG(64, "clnt_cots_kinit: removing call for xid 0x%x from"
   1549      0       stevel 		    " dispatch list\n", p->cku_xid);
   1550      0       stevel 	}
   1551      0       stevel 
   1552      0       stevel 	if (call->call_reply != NULL) {
   1553      0       stevel 		freemsg(call->call_reply);
   1554      0       stevel 		call->call_reply = NULL;
   1555      0       stevel 	}
   1556      0       stevel 
   1557      0       stevel 	call->call_bucket = NULL;
   1558      0       stevel 	call->call_hash = 0;
   1559      0       stevel 
   1560      0       stevel 	/*
   1561      0       stevel 	 * We don't clear cku_flags here, because clnt_cots_kcallit()
   1562      0       stevel 	 * takes care of handling the cku_flags reset.
   1563      0       stevel 	 */
   1564      0       stevel 	p->cku_xid = 0;
   1565      0       stevel 	p->cku_device = dev;
   1566      0       stevel 	p->cku_addrfmly = family;
   1567      0       stevel 	p->cku_cred = cred;
   1568      0       stevel 
   1569      0       stevel 	if (p->cku_addr.maxlen < addr->len) {
   1570      0       stevel 		if (p->cku_addr.maxlen != 0 && p->cku_addr.buf != NULL)
   1571      0       stevel 			kmem_free(p->cku_addr.buf, p->cku_addr.maxlen);
   1572      0       stevel 		p->cku_addr.buf = kmem_zalloc(addr->maxlen, KM_SLEEP);
   1573      0       stevel 		p->cku_addr.maxlen = addr->maxlen;
   1574      0       stevel 	}
   1575      0       stevel 
   1576      0       stevel 	p->cku_addr.len = addr->len;
   1577      0       stevel 	bcopy(addr->buf, p->cku_addr.buf, addr->len);
   1578      0       stevel 
   1579      0       stevel 	/*
   1580      0       stevel 	 * If the current sanity check size in rpcmod is smaller
   1581      0       stevel 	 * than the size needed, then increase the sanity check.
   1582      0       stevel 	 */
   1583      0       stevel 	if (max_msgsize != 0 && clnt_max_msg_sizep != NULL &&
   1584      0       stevel 	    max_msgsize > *clnt_max_msg_sizep) {
   1585      0       stevel 		mutex_enter(&clnt_max_msg_lock);
   1586      0       stevel 		if (max_msgsize > *clnt_max_msg_sizep)
   1587      0       stevel 			*clnt_max_msg_sizep = max_msgsize;
   1588      0       stevel 		mutex_exit(&clnt_max_msg_lock);
   1589      0       stevel 	}
   1590      0       stevel }
   1591      0       stevel 
   1592      0       stevel /*
   1593      0       stevel  * ksettimers is a no-op for cots, with the exception of setting the xid.
   1594      0       stevel  */
   1595      0       stevel /* ARGSUSED */
   1596      0       stevel static int
   1597      0       stevel clnt_cots_ksettimers(CLIENT *h, struct rpc_timers *t, struct rpc_timers *all,
   1598      0       stevel 	int minimum, void (*feedback)(int, int, caddr_t), caddr_t arg,
   1599      0       stevel 	uint32_t xid)
   1600      0       stevel {
   1601      0       stevel 	/* LINTED pointer alignment */
   1602      0       stevel 	cku_private_t *p = htop(h);
   1603      0       stevel 
   1604      0       stevel 	if (xid)
   1605      0       stevel 		p->cku_xid = xid;
   1606      0       stevel 	COTSRCSTAT_INCR(p->cku_stats, rctimers);
   1607      0       stevel 	return (0);
   1608      0       stevel }
   1609      0       stevel 
   1610      0       stevel extern void rpc_poptimod(struct vnode *);
   1611      0       stevel extern int kstr_push(struct vnode *, char *);
   1612      0       stevel 
   1613      0       stevel int
   1614      0       stevel conn_kstat_update(kstat_t *ksp, int rw)
   1615      0       stevel {
   1616      0       stevel 	struct cm_xprt *cm_entry;
   1617      0       stevel 	struct cm_kstat_xprt *cm_ksp_data;
   1618      0       stevel 	uchar_t *b;
   1619      0       stevel 	char *fbuf;
   1620      0       stevel 
   1621      0       stevel 	if (rw == KSTAT_WRITE)
   1622      0       stevel 		return (EACCES);
   1623      0       stevel 	if (ksp == NULL || ksp->ks_private == NULL)
   1624      0       stevel 		return (EIO);
   1625      0       stevel 	cm_entry  = (struct cm_xprt *)ksp->ks_private;
   1626      0       stevel 	cm_ksp_data = (struct cm_kstat_xprt *)ksp->ks_data;
   1627      0       stevel 
   1628      0       stevel 	cm_ksp_data->x_wq.value.ui32 = (uint32_t)(uintptr_t)cm_entry->x_wq;
   1629      0       stevel 	cm_ksp_data->x_family.value.ui32 = cm_entry->x_family;
   1630      0       stevel 	cm_ksp_data->x_rdev.value.ui32 = (uint32_t)cm_entry->x_rdev;
   1631      0       stevel 	cm_ksp_data->x_time.value.ui32 = cm_entry->x_time;
   1632      0       stevel 	cm_ksp_data->x_ref.value.ui32 = cm_entry->x_ref;
   1633      0       stevel 	cm_ksp_data->x_state.value.ui32 = cm_entry->x_state_flags;
   1634      0       stevel 
   1635      0       stevel 	if (cm_entry->x_server.buf) {
   1636    457          bmc 		fbuf = cm_ksp_data->x_server.value.str.addr.ptr;
   1637      0       stevel 		if (cm_entry->x_family == AF_INET &&
   1638      0       stevel 		    cm_entry->x_server.len ==
   1639      0       stevel 		    sizeof (struct sockaddr_in)) {
   1640      0       stevel 			struct sockaddr_in  *sa;
   1641      0       stevel 			sa = (struct sockaddr_in *)
   1642      0       stevel 				cm_entry->x_server.buf;
   1643      0       stevel 			b = (uchar_t *)&sa->sin_addr;
   1644      0       stevel 			(void) sprintf(fbuf,
   1645      0       stevel 			    "%03d.%03d.%03d.%03d", b[0] & 0xFF, b[1] & 0xFF,
   1646      0       stevel 			    b[2] & 0xFF, b[3] & 0xFF);
   1647      0       stevel 			cm_ksp_data->x_port.value.ui32 =
   1648      0       stevel 				(uint32_t)sa->sin_port;
   1649      0       stevel 		} else if (cm_entry->x_family == AF_INET6 &&
   1650      0       stevel 				cm_entry->x_server.len >=
   1651      0       stevel 				sizeof (struct sockaddr_in6)) {
   1652      0       stevel 			/* extract server IP address & port */
   1653      0       stevel 			struct sockaddr_in6 *sin6;
   1654      0       stevel 			sin6 = (struct sockaddr_in6 *)cm_entry->x_server.buf;
   1655      0       stevel 			(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr, fbuf,
   1656      0       stevel 				INET6_ADDRSTRLEN);
   1657      0       stevel 			cm_ksp_data->x_port.value.ui32 = sin6->sin6_port;
   1658      0       stevel 		} else {
   1659      0       stevel 			struct sockaddr_in  *sa;
   1660      0       stevel 
   1661      0       stevel 			sa = (struct sockaddr_in *)cm_entry->x_server.buf;
   1662      0       stevel 			b = (uchar_t *)&sa->sin_addr;
   1663      0       stevel 			(void) sprintf(fbuf,
   1664      0       stevel 			    "%03d.%03d.%03d.%03d", b[0] & 0xFF, b[1] & 0xFF,
   1665      0       stevel 			    b[2] & 0xFF, b[3] & 0xFF);
   1666      0       stevel 		}
   1667      0       stevel 		KSTAT_NAMED_STR_BUFLEN(&cm_ksp_data->x_server) =
   1668   6403      gt29601 		    strlen(fbuf) + 1;
   1669      0       stevel 	}
   1670      0       stevel 
   1671      0       stevel 	return (0);
   1672      0       stevel }
   1673      0       stevel 
   1674      0       stevel 
   1675      0       stevel /*
   1676      0       stevel  * We want a version of delay which is interruptible by a UNIX signal
   1677      0       stevel  * Return EINTR if an interrupt occured.
   1678      0       stevel  */
   1679      0       stevel static int
   1680      0       stevel clnt_delay(clock_t ticks, bool_t nosignal)
   1681      0       stevel {
   1682      0       stevel 	if (nosignal == TRUE) {
   1683      0       stevel 		delay(ticks);
   1684      0       stevel 		return (0);
   1685      0       stevel 	}
   1686      0       stevel 	return (delay_sig(ticks));
   1687      0       stevel }
   1688      0       stevel 
   1689      0       stevel /*
   1690      0       stevel  * Wait for a connection until a timeout, or until we are
   1691      0       stevel  * signalled that there has been a connection state change.
   1692      0       stevel  */
   1693      0       stevel static enum clnt_stat
   1694      0       stevel connmgr_cwait(struct cm_xprt *cm_entry, const struct timeval *waitp,
   1695      0       stevel 	bool_t nosignal)
   1696      0       stevel {
   1697      0       stevel 	bool_t interrupted;
   1698      0       stevel 	clock_t timout, cv_stat;
   1699      0       stevel 	enum clnt_stat clstat;
   1700      0       stevel 	unsigned int old_state;
   1701      0       stevel 
   1702      0       stevel 	ASSERT(MUTEX_HELD(&connmgr_lock));
   1703      0       stevel 	/*
   1704      0       stevel 	 * We wait for the transport connection to be made, or an
   1705      0       stevel 	 * indication that it could not be made.
   1706      0       stevel 	 */
   1707      0       stevel 	clstat = RPC_TIMEDOUT;
   1708      0       stevel 	interrupted = FALSE;
   1709      0       stevel 
   1710      0       stevel 	old_state = cm_entry->x_state_flags;
   1711      0       stevel 	/*
   1712      0       stevel 	 * Now loop until cv_timedwait{_sig} returns because of
   1713      0       stevel 	 * a signal(0) or timeout(-1) or cv_signal(>0). But it may be
   1714      0       stevel 	 * cv_signalled for various other reasons too. So loop
   1715      0       stevel 	 * until there is a state change on the connection.
   1716      0       stevel 	 */
   1717      0       stevel 
   1718      0       stevel 	timout = waitp->tv_sec * drv_usectohz(1000000) +
   1719  11066       rafael 	    drv_usectohz(waitp->tv_usec) + ddi_get_lbolt();
   1720      0       stevel 
   1721      0       stevel 	if (nosignal) {
   1722      0       stevel 		while ((cv_stat = cv_timedwait(&cm_entry->x_conn_cv,
   1723      0       stevel 		    &connmgr_lock, timout)) > 0 &&
   1724      0       stevel 		    cm_entry->x_state_flags == old_state)
   1725      0       stevel 			;
   1726      0       stevel 	} else {
   1727      0       stevel 		while ((cv_stat = cv_timedwait_sig(&cm_entry->x_conn_cv,
   1728      0       stevel 		    &connmgr_lock, timout)) > 0 &&
   1729      0       stevel 		    cm_entry->x_state_flags == old_state)
   1730      0       stevel 			;
   1731      0       stevel 
   1732      0       stevel 		if (cv_stat == 0) /* got intr signal? */
   1733      0       stevel 			interrupted = TRUE;
   1734      0       stevel 	}
   1735      0       stevel 
   1736      0       stevel 	if ((cm_entry->x_state_flags & (X_BADSTATES|X_CONNECTED)) ==
   1737      0       stevel 	    X_CONNECTED) {
   1738      0       stevel 		clstat = RPC_SUCCESS;
   1739      0       stevel 	} else {
   1740      0       stevel 		if (interrupted == TRUE)
   1741      0       stevel 			clstat = RPC_INTR;
   1742      0       stevel 		RPCLOG(1, "connmgr_cwait: can't connect, error: %s\n",
   1743      0       stevel 		    clnt_sperrno(clstat));
   1744      0       stevel 	}
   1745      0       stevel 
   1746      0       stevel 	return (clstat);
   1747      0       stevel }
   1748      0       stevel 
   1749      0       stevel /*
   1750      0       stevel  * Primary interface for how RPC grabs a connection.
   1751      0       stevel  */
   1752      0       stevel static struct cm_xprt *
   1753      0       stevel connmgr_wrapget(
   1754      0       stevel 	struct netbuf *retryaddr,
   1755      0       stevel 	const struct timeval *waitp,
   1756      0       stevel 	cku_private_t *p)
   1757      0       stevel {
   1758      0       stevel 	struct cm_xprt *cm_entry;
   1759      0       stevel 
   1760      0       stevel 	cm_entry = connmgr_get(retryaddr, waitp, &p->cku_addr, p->cku_addrfmly,
   1761      0       stevel 	    &p->cku_srcaddr, &p->cku_err, p->cku_device,
   1762   8778         Erik 	    p->cku_client.cl_nosignal, p->cku_useresvport, p->cku_cred);
   1763      0       stevel 
   1764      0       stevel 	if (cm_entry == NULL) {
   1765      0       stevel 		/*
   1766      0       stevel 		 * Re-map the call status to RPC_INTR if the err code is
   1767      0       stevel 		 * EINTR. This can happen if calls status is RPC_TLIERROR.
   1768      0       stevel 		 * However, don't re-map if signalling has been turned off.
   1769      0       stevel 		 * XXX Really need to create a separate thread whenever
   1770      0       stevel 		 * there isn't an existing connection.
   1771      0       stevel 		 */
   1772      0       stevel 		if (p->cku_err.re_errno == EINTR) {
   1773      0       stevel 			if (p->cku_client.cl_nosignal == TRUE)
   1774      0       stevel 				p->cku_err.re_errno = EIO;
   1775      0       stevel 			else
   1776      0       stevel 				p->cku_err.re_status = RPC_INTR;
   1777      0       stevel 		}
   1778      0       stevel 	}
   1779      0       stevel 
   1780      0       stevel 	return (cm_entry);
   1781      0       stevel }
   1782      0       stevel 
   1783      0       stevel /*
   1784      0       stevel  * Obtains a transport to the server specified in addr.  If a suitable transport
   1785      0       stevel  * does not already exist in the list of cached transports, a new connection
   1786      0       stevel  * is created, connected, and added to the list. The connection is for sending
   1787      0       stevel  * only - the reply message may come back on another transport connection.
   1788   9806          dai  *
   1789   9806          dai  * To implement round-robin load balancing with multiple client connections,
   1790   9806          dai  * the last entry on the list is always selected. Once the entry is selected
   1791   9806          dai  * it's re-inserted to the head of the list.
   1792      0       stevel  */
   1793      0       stevel static struct cm_xprt *
   1794      0       stevel connmgr_get(
   1795      0       stevel 	struct netbuf	*retryaddr,
   1796      0       stevel 	const struct timeval	*waitp,	/* changed to a ptr to converse stack */
   1797      0       stevel 	struct netbuf	*destaddr,
   1798      0       stevel 	int		addrfmly,
   1799      0       stevel 	struct netbuf	*srcaddr,
   1800      0       stevel 	struct rpc_err	*rpcerr,
   1801      0       stevel 	dev_t		device,
   1802      0       stevel 	bool_t		nosignal,
   1803   8778         Erik 	int		useresvport,
   1804   8778         Erik 	cred_t		*cr)
   1805      0       stevel {
   1806      0       stevel 	struct cm_xprt *cm_entry;
   1807      0       stevel 	struct cm_xprt *lru_entry;
   1808   9806          dai 	struct cm_xprt **cmp, **prev;
   1809      0       stevel 	queue_t *wq;
   1810      0       stevel 	TIUSER *tiptr;
   1811      0       stevel 	int i;
   1812      0       stevel 	int retval;
   1813      0       stevel 	int tidu_size;
   1814      0       stevel 	bool_t	connected;
   1815    766     carlsonj 	zoneid_t zoneid = rpc_zoneid();
   1816      0       stevel 
   1817      0       stevel 	/*
   1818      0       stevel 	 * If the call is not a retry, look for a transport entry that
   1819      0       stevel 	 * goes to the server of interest.
   1820      0       stevel 	 */
   1821      0       stevel 	mutex_enter(&connmgr_lock);
   1822      0       stevel 
   1823      0       stevel 	if (retryaddr == NULL) {
   1824      0       stevel use_new_conn:
   1825      0       stevel 		i = 0;
   1826      0       stevel 		cm_entry = lru_entry = NULL;
   1827      0       stevel 
   1828   9806          dai 		prev = cmp = &cm_hd;
   1829      0       stevel 		while ((cm_entry = *cmp) != NULL) {
   1830      0       stevel 			ASSERT(cm_entry != cm_entry->x_next);
   1831      0       stevel 			/*
   1832      0       stevel 			 * Garbage collect conections that are marked
   1833      0       stevel 			 * for needs disconnect.
   1834      0       stevel 			 */
   1835      0       stevel 			if (cm_entry->x_needdis) {
   1836    154      shepler 				CONN_HOLD(cm_entry);
   1837      0       stevel 				connmgr_dis_and_wait(cm_entry);
   1838    154      shepler 				connmgr_release(cm_entry);
   1839      0       stevel 				/*
   1840      0       stevel 				 * connmgr_lock could have been
   1841      0       stevel 				 * dropped for the disconnect
   1842      0       stevel 				 * processing so start over.
   1843      0       stevel 				 */
   1844      0       stevel 				goto use_new_conn;
   1845      0       stevel 			}
   1846      0       stevel 
   1847      0       stevel 			/*
   1848      0       stevel 			 * Garbage collect the dead connections that have
   1849      0       stevel 			 * no threads working on them.
   1850      0       stevel 			 */
   1851      0       stevel 			if ((cm_entry->x_state_flags & (X_DEAD|X_THREAD)) ==
   1852      0       stevel 			    X_DEAD) {
   1853   3017     maheshvs 				mutex_enter(&cm_entry->x_lock);
   1854   3017     maheshvs 				if (cm_entry->x_ref != 0) {
   1855   3017     maheshvs 					/*
   1856   3017     maheshvs 					 * Currently in use.
   1857   3017     maheshvs 					 * Cleanup later.
   1858   3017     maheshvs 					 */
   1859   3017     maheshvs 					cmp = &cm_entry->x_next;
   1860   3017     maheshvs 					mutex_exit(&cm_entry->x_lock);
   1861   3017     maheshvs 					continue;
   1862   3017     maheshvs 				}
   1863   3017     maheshvs 				mutex_exit(&cm_entry->x_lock);
   1864      0       stevel 				*cmp = cm_entry->x_next;
   1865      0       stevel 				mutex_exit(&connmgr_lock);
   1866      0       stevel 				connmgr_close(cm_entry);
   1867      0       stevel 				mutex_enter(&connmgr_lock);
   1868      0       stevel 				goto use_new_conn;
   1869      0       stevel 			}
   1870      0       stevel 
   1871      0       stevel 
   1872      0       stevel 			if ((cm_entry->x_state_flags & X_BADSTATES) == 0 &&
   1873      0       stevel 			    cm_entry->x_zoneid == zoneid &&
   1874      0       stevel 			    cm_entry->x_rdev == device &&
   1875      0       stevel 			    destaddr->len == cm_entry->x_server.len &&
   1876      0       stevel 			    bcmp(destaddr->buf, cm_entry->x_server.buf,
   1877      0       stevel 			    destaddr->len) == 0) {
   1878      0       stevel 				/*
   1879      0       stevel 				 * If the matching entry isn't connected,
   1880      0       stevel 				 * attempt to reconnect it.
   1881      0       stevel 				 */
   1882      0       stevel 				if (cm_entry->x_connected == FALSE) {
   1883      0       stevel 					/*
   1884      0       stevel 					 * We don't go through trying
   1885      0       stevel 					 * to find the least recently
   1886      0       stevel 					 * used connected because
   1887      0       stevel 					 * connmgr_reconnect() briefly
   1888      0       stevel 					 * dropped the connmgr_lock,
   1889      0       stevel 					 * allowing a window for our
   1890      0       stevel 					 * accounting to be messed up.
   1891      0       stevel 					 * In any case, a re-connected
   1892      0       stevel 					 * connection is as good as
   1893      0       stevel 					 * a LRU connection.
   1894      0       stevel 					 */
   1895      0       stevel 					return (connmgr_wrapconnect(cm_entry,
   1896      0       stevel 					    waitp, destaddr, addrfmly, srcaddr,
   1897   8778         Erik 					    rpcerr, TRUE, nosignal, cr));
   1898      0       stevel 				}
   1899      0       stevel 				i++;
   1900   9806          dai 
   1901   9806          dai 				/* keep track of the last entry */
   1902   9806          dai 				lru_entry = cm_entry;
   1903   9806          dai 				prev = cmp;
   1904      0       stevel 			}
   1905      0       stevel 			cmp = &cm_entry->x_next;
   1906      0       stevel 		}
   1907      0       stevel 
   1908      0       stevel 		if (i > clnt_max_conns) {
   1909      0       stevel 			RPCLOG(8, "connmgr_get: too many conns, dooming entry"
   1910      0       stevel 			    " %p\n", (void *)lru_entry->x_tiptr);
   1911      0       stevel 			lru_entry->x_doomed = TRUE;
   1912      0       stevel 			goto use_new_conn;
   1913      0       stevel 		}
   1914      0       stevel 
   1915      0       stevel 		/*
   1916      0       stevel 		 * If we are at the maximum number of connections to
   1917      0       stevel 		 * the server, hand back the least recently used one.
   1918      0       stevel 		 */
   1919      0       stevel 		if (i == clnt_max_conns) {
   1920      0       stevel 			/*
   1921      0       stevel 			 * Copy into the handle the source address of
   1922      0       stevel 			 * the connection, which we will use in case of
   1923      0       stevel 			 * a later retry.
   1924      0       stevel 			 */
   1925      0       stevel 			if (srcaddr->len != lru_entry->x_src.len) {
   1926      0       stevel 				if (srcaddr->len > 0)
   1927      0       stevel 					kmem_free(srcaddr->buf,
   1928      0       stevel 					    srcaddr->maxlen);
   1929      0       stevel 				srcaddr->buf = kmem_zalloc(
   1930      0       stevel 				    lru_entry->x_src.len, KM_SLEEP);
   1931      0       stevel 				srcaddr->maxlen = srcaddr->len =
   1932      0       stevel 				    lru_entry->x_src.len;
   1933      0       stevel 			}
   1934      0       stevel 			bcopy(lru_entry->x_src.buf, srcaddr->buf, srcaddr->len);
   1935      0       stevel 			RPCLOG(2, "connmgr_get: call going out on %p\n",
   1936      0       stevel 			    (void *)lru_entry);
   1937  11066       rafael 			lru_entry->x_time = ddi_get_lbolt();
   1938      0       stevel 			CONN_HOLD(lru_entry);
   1939   9806          dai 
   1940   9806          dai 			if ((i > 1) && (prev != &cm_hd)) {
   1941   9806          dai 				/*
   1942   9806          dai 				 * remove and re-insert entry at head of list.
   1943   9806          dai 				 */
   1944   9806          dai 				*prev = lru_entry->x_next;
   1945   9806          dai 				lru_entry->x_next = cm_hd;
   1946   9806          dai 				cm_hd = lru_entry;
   1947   9806          dai 			}
   1948   9806          dai 
   1949      0       stevel 			mutex_exit(&connmgr_lock);
   1950      0       stevel 			return (lru_entry);
   1951      0       stevel 		}
   1952      0       stevel 
   1953      0       stevel 	} else {
   1954      0       stevel 		/*
   1955      0       stevel 		 * This is the retry case (retryaddr != NULL).  Retries must
   1956      0       stevel 		 * be sent on the same source port as the original call.
   1957      0       stevel 		 */
   1958      0       stevel 
   1959      0       stevel 		/*
   1960      0       stevel 		 * Walk the list looking for a connection with a source address
   1961      0       stevel 		 * that matches the retry address.
   1962      0       stevel 		 */
   1963   8806       Gerald start_retry_loop:
   1964      0       stevel 		cmp = &cm_hd;
   1965      0       stevel 		while ((cm_entry = *cmp) != NULL) {
   1966      0       stevel 			ASSERT(cm_entry != cm_entry->x_next);
   1967   8806       Gerald 
   1968   8806       Gerald 			/*
   1969   8806       Gerald 			 * determine if this connection matches the passed
   1970   8806       Gerald 			 * in retry address.  If it does not match, advance
   1971   8806       Gerald 			 * to the next element on the list.
   1972   8806       Gerald 			 */
   1973      0       stevel 			if (zoneid != cm_entry->x_zoneid ||
   1974      0       stevel 			    device != cm_entry->x_rdev ||
   1975      0       stevel 			    retryaddr->len != cm_entry->x_src.len ||
   1976      0       stevel 			    bcmp(retryaddr->buf, cm_entry->x_src.buf,
   1977   6403      gt29601 			    retryaddr->len) != 0) {
   1978      0       stevel 				cmp = &cm_entry->x_next;
   1979      0       stevel 				continue;
   1980   8806       Gerald 			}
   1981   8806       Gerald 			/*
   1982   8806       Gerald 			 * Garbage collect conections that are marked
   1983   8806       Gerald 			 * for needs disconnect.
   1984   8806       Gerald 			 */
   1985   8806       Gerald 			if (cm_entry->x_needdis) {
   1986   8806       Gerald 				CONN_HOLD(cm_entry);
   1987   8806       Gerald 				connmgr_dis_and_wait(cm_entry);
   1988   8806       Gerald 				connmgr_release(cm_entry);
   1989   8806       Gerald 				/*
   1990   8806       Gerald 				 * connmgr_lock could have been
   1991   8806       Gerald 				 * dropped for the disconnect
   1992   8806       Gerald 				 * processing so start over.
   1993   8806       Gerald 				 */
   1994   8806       Gerald 				goto start_retry_loop;
   1995   8806       Gerald 			}
   1996   8806       Gerald 			/*
   1997   8806       Gerald 			 * Garbage collect the dead connections that have
   1998   8806       Gerald 			 * no threads working on them.
   1999   8806       Gerald 			 */
   2000   8806       Gerald 			if ((cm_entry->x_state_flags & (X_DEAD|X_THREAD)) ==
   2001   8806       Gerald 			    X_DEAD) {
   2002   8806       Gerald 				mutex_enter(&cm_entry->x_lock);
   2003   8806       Gerald 				if (cm_entry->x_ref != 0) {
   2004   8806       Gerald 					/*
   2005   8806       Gerald 					 * Currently in use.
   2006   8806       Gerald 					 * Cleanup later.
   2007   8806       Gerald 					 */
   2008   8806       Gerald 					cmp = &cm_entry->x_next;
   2009   8806       Gerald 					mutex_exit(&cm_entry->x_lock);
   2010   8806       Gerald 					continue;
   2011   8806       Gerald 				}
   2012   8806       Gerald 				mutex_exit(&cm_entry->x_lock);
   2013   8806       Gerald 				*cmp = cm_entry->x_next;
   2014   8806       Gerald 				mutex_exit(&connmgr_lock);
   2015   8806       Gerald 				connmgr_close(cm_entry);
   2016   8806       Gerald 				mutex_enter(&connmgr_lock);
   2017   8806       Gerald 				goto start_retry_loop;
   2018      0       stevel 			}
   2019      0       stevel 
   2020      0       stevel 			/*
   2021      0       stevel 			 * Sanity check: if the connection with our source
   2022      0       stevel 			 * port is going to some other server, something went
   2023      0       stevel 			 * wrong, as we never delete connections (i.e. release
   2024      0       stevel 			 * ports) unless they have been idle.  In this case,
   2025      0       stevel 			 * it is probably better to send the call out using
   2026      0       stevel 			 * a new source address than to fail it altogether,
   2027      0       stevel 			 * since that port may never be released.
   2028      0       stevel 			 */
   2029      0       stevel 			if (destaddr->len != cm_entry->x_server.len ||
   2030   6403      gt29601 			    bcmp(destaddr->buf, cm_entry->x_server.buf,
   2031   6403      gt29601 			    destaddr->len) != 0) {
   2032      0       stevel 				RPCLOG(1, "connmgr_get: tiptr %p"
   2033      0       stevel 				    " is going to a different server"
   2034      0       stevel 				    " with the port that belongs"
   2035      0       stevel 				    " to us!\n", (void *)cm_entry->x_tiptr);
   2036      0       stevel 				retryaddr = NULL;
   2037      0       stevel 				goto use_new_conn;
   2038      0       stevel 			}
   2039      0       stevel 
   2040      0       stevel 			/*
   2041      0       stevel 			 * If the connection of interest is not connected and we
   2042      0       stevel 			 * can't reconnect it, then the server is probably
   2043      0       stevel 			 * still down.  Return NULL to the caller and let it
   2044      0       stevel 			 * retry later if it wants to.  We have a delay so the
   2045      0       stevel 			 * machine doesn't go into a tight retry loop.  If the
   2046      0       stevel 			 * entry was already connected, or the reconnected was
   2047      0       stevel 			 * successful, return this entry.
   2048      0       stevel 			 */
   2049      0       stevel 			if (cm_entry->x_connected == FALSE) {
   2050      0       stevel 				return (connmgr_wrapconnect(cm_entry,
   2051      0       stevel 				    waitp, destaddr, addrfmly, NULL,
   2052   8778         Erik 				    rpcerr, TRUE, nosignal, cr));
   2053      0       stevel 			} else {
   2054      0       stevel 				CONN_HOLD(cm_entry);
   2055      0       stevel 
   2056  11066       rafael 				cm_entry->x_time = ddi_get_lbolt();
   2057      0       stevel 				mutex_exit(&connmgr_lock);
   2058      0       stevel 				RPCLOG(2, "connmgr_get: found old "
   2059      0       stevel 				    "transport %p for retry\n",
   2060      0       stevel 				    (void *)cm_entry);
   2061      0       stevel 				return (cm_entry);
   2062      0       stevel 			}
   2063      0       stevel 		}
   2064      0       stevel 
   2065      0       stevel 		/*
   2066      0       stevel 		 * We cannot find an entry in the list for this retry.
   2067      0       stevel 		 * Either the entry has been removed temporarily to be
   2068      0       stevel 		 * reconnected by another thread, or the original call
   2069      0       stevel 		 * got a port but never got connected,
   2070      0       stevel 		 * and hence the transport never got put in the
   2071      0       stevel 		 * list.  Fall through to the "create new connection" code -
   2072      0       stevel 		 * the former case will fail there trying to rebind the port,
   2073      0       stevel 		 * and the later case (and any other pathological cases) will
   2074      0       stevel 		 * rebind and reconnect and not hang the client machine.
   2075      0       stevel 		 */
   2076      0       stevel 		RPCLOG0(8, "connmgr_get: no entry in list for retry\n");
   2077      0       stevel 	}
   2078      0       stevel 	/*
   2079      0       stevel 	 * Set up a transport entry in the connection manager's list.
   2080      0       stevel 	 */
   2081      0       stevel 	cm_entry = (struct cm_xprt *)
   2082      0       stevel 	    kmem_zalloc(sizeof (struct cm_xprt), KM_SLEEP);
   2083      0       stevel 
   2084      0       stevel 	cm_entry->x_server.buf = kmem_zalloc(destaddr->len, KM_SLEEP);
   2085      0       stevel 	bcopy(destaddr->buf, cm_entry->x_server.buf, destaddr->len);
   2086      0       stevel 	cm_entry->x_server.len = cm_entry->x_server.maxlen = destaddr->len;
   2087      0       stevel 
   2088      0       stevel 	cm_entry->x_state_flags = X_THREAD;
   2089      0       stevel 	cm_entry->x_ref = 1;
   2090      0       stevel 	cm_entry->x_family = addrfmly;
   2091      0       stevel 	cm_entry->x_rdev = device;
   2092      0       stevel 	cm_entry->x_zoneid = zoneid;
   2093      0       stevel 	mutex_init(&cm_entry->x_lock, NULL, MUTEX_DEFAULT, NULL);
   2094      0       stevel 	cv_init(&cm_entry->x_cv, NULL, CV_DEFAULT, NULL);
   2095      0       stevel 	cv_init(&cm_entry->x_conn_cv, NULL, CV_DEFAULT, NULL);
   2096      0       stevel 	cv_init(&cm_entry->x_dis_cv, NULL, CV_DEFAULT, NULL);
   2097      0       stevel 
   2098      0       stevel 	/*
   2099      0       stevel 	 * Note that we add this partially initialized entry to the
   2100      0       stevel 	 * connection list. This is so that we don't have connections to
   2101      0       stevel 	 * the same server.
   2102      0       stevel 	 *
   2103      0       stevel 	 * Note that x_src is not initialized at this point. This is because
   2104      0       stevel 	 * retryaddr might be NULL in which case x_src is whatever
   2105      0       stevel 	 * t_kbind/bindresvport gives us. If another thread wants a
   2106      0       stevel 	 * connection to the same server, seemingly we have an issue, but we
   2107      0       stevel 	 * don't. If the other thread comes in with retryaddr == NULL, then it
   2108      0       stevel 	 * will never look at x_src, and it will end up waiting in
   2109      0       stevel 	 * connmgr_cwait() for the first thread to finish the connection
   2110      0       stevel 	 * attempt. If the other thread comes in with retryaddr != NULL, then
   2111      0       stevel 	 * that means there was a request sent on a connection, in which case
   2112      0       stevel 	 * the the connection should already exist. Thus the first thread
   2113      0       stevel 	 * never gets here ... it finds the connection it its server in the
   2114      0       stevel 	 * connection list.
   2115      0       stevel 	 *
   2116      0       stevel 	 * But even if theory is wrong, in the retryaddr != NULL case, the 2nd
   2117      0       stevel 	 * thread will skip us because x_src.len == 0.
   2118      0       stevel 	 */
   2119      0       stevel 	cm_entry->x_next = cm_hd;
   2120      0       stevel 	cm_hd = cm_entry;
   2121      0       stevel 	mutex_exit(&connmgr_lock);
   2122      0       stevel 
   2123      0       stevel 	/*
   2124      0       stevel 	 * Either we didn't find an entry to the server of interest, or we
   2125      0       stevel 	 * don't have the maximum number of connections to that server -
   2126      0       stevel 	 * create a new connection.
   2127      0       stevel 	 */
   2128      0       stevel 	RPCLOG0(8, "connmgr_get: creating new connection\n");
   2129      0       stevel 	rpcerr->re_status = RPC_TLIERROR;
   2130      0       stevel 
   2131   1676          jpk 	i = t_kopen(NULL, device, FREAD|FWRITE|FNDELAY, &tiptr, zone_kcred());
   2132      0       stevel 	if (i) {
   2133      0       stevel 		RPCLOG(1, "connmgr_get: can't open cots device, error %d\n", i);
   2134      0       stevel 		rpcerr->re_errno = i;
   2135      0       stevel 		connmgr_cancelconn(cm_entry);
   2136      0       stevel 		return (NULL);
   2137      0       stevel 	}
   2138      0       stevel 	rpc_poptimod(tiptr->fp->f_vnode);
   2139      0       stevel 
   2140      0       stevel 	if (i = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"rpcmod", 0,
   2141   6403      gt29601 	    K_TO_K, kcred, &retval)) {
   2142      0       stevel 		RPCLOG(1, "connmgr_get: can't push cots module, %d\n", i);
   2143      0       stevel 		(void) t_kclose(tiptr, 1);
   2144      0       stevel 		rpcerr->re_errno = i;
   2145      0       stevel 		connmgr_cancelconn(cm_entry);
   2146      0       stevel 		return (NULL);
   2147      0       stevel 	}
   2148      0       stevel 
   2149      0       stevel 	if (i = strioctl(tiptr->fp->f_vnode, RPC_CLIENT, 0, 0, K_TO_K,
   2150   6403      gt29601 	    kcred, &retval)) {
   2151      0       stevel 		RPCLOG(1, "connmgr_get: can't set client status with cots "
   2152      0       stevel 		    "module, %d\n", i);
   2153      0       stevel 		(void) t_kclose(tiptr, 1);
   2154      0       stevel 		rpcerr->re_errno = i;
   2155      0       stevel 		connmgr_cancelconn(cm_entry);
   2156      0       stevel 		return (NULL);
   2157      0       stevel 	}
   2158      0       stevel 
   2159      0       stevel 	mutex_enter(&connmgr_lock);
   2160      0       stevel 
   2161      0       stevel 	wq = tiptr->fp->f_vnode->v_stream->sd_wrq->q_next;
   2162      0       stevel 	cm_entry->x_wq = wq;
   2163      0       stevel 
   2164      0       stevel 	mutex_exit(&connmgr_lock);
   2165      0       stevel 
   2166      0       stevel 	if (i = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"timod", 0,
   2167   6403      gt29601 	    K_TO_K, kcred, &retval)) {
   2168      0       stevel 		RPCLOG(1, "connmgr_get: can't push timod, %d\n", i);
   2169      0       stevel 		(void) t_kclose(tiptr, 1);
   2170      0       stevel 		rpcerr->re_errno = i;
   2171      0       stevel 		connmgr_cancelconn(cm_entry);
   2172      0       stevel 		return (NULL);
   2173      0       stevel 	}
   2174      0       stevel 
   2175      0       stevel 	/*
   2176      0       stevel 	 * If the caller has not specified reserved port usage then
   2177      0       stevel 	 * take the system default.
   2178      0       stevel 	 */
   2179      0       stevel 	if (useresvport == -1)
   2180      0       stevel 		useresvport = clnt_cots_do_bindresvport;
   2181      0       stevel 
   2182      0       stevel 	if ((useresvport || retryaddr != NULL) &&
   2183      0       stevel 	    (addrfmly == AF_INET || addrfmly == AF_INET6)) {
   2184      0       stevel 		bool_t alloc_src = FALSE;
   2185      0       stevel 
   2186      0       stevel 		if (srcaddr->len != destaddr->len) {
   2187      0       stevel 			kmem_free(srcaddr->buf, srcaddr->maxlen);
   2188      0       stevel 			srcaddr->buf = kmem_zalloc(destaddr->len, KM_SLEEP);
   2189      0       stevel 			srcaddr->maxlen = destaddr->len;
   2190      0       stevel 			srcaddr->len = destaddr->len;
   2191      0       stevel 			alloc_src = TRUE;
   2192      0       stevel 		}
   2193      0       stevel 
   2194      0       stevel 		if ((i = bindresvport(tiptr, retryaddr, srcaddr, TRUE)) != 0) {
   2195      0       stevel 			(void) t_kclose(tiptr, 1);
   2196      0       stevel 			RPCLOG(1, "connmgr_get: couldn't bind, retryaddr: "
   2197   6403      gt29601 			    "%p\n", (void *)retryaddr);
   2198      0       stevel 
   2199      0       stevel 			/*
   2200      0       stevel 			 * 1225408: If we allocated a source address, then it
   2201      0       stevel 			 * is either garbage or all zeroes. In that case
   2202      0       stevel 			 * we need to clear srcaddr.
   2203      0       stevel 			 */
   2204      0       stevel 			if (alloc_src == TRUE) {
   2205      0       stevel 				kmem_free(srcaddr->buf, srcaddr->maxlen);
   2206      0       stevel 				srcaddr->maxlen = srcaddr->len = 0;
   2207      0       stevel 				srcaddr->buf = NULL;
   2208      0       stevel 			}
   2209      0       stevel 			rpcerr->re_errno = i;
   2210      0       stevel 			connmgr_cancelconn(cm_entry);
   2211      0       stevel 			return (NULL);
   2212      0       stevel 		}
   2213      0       stevel 	} else {
   2214      0       stevel 		if ((i = t_kbind(tiptr, NULL, NULL)) != 0) {
   2215      0       stevel 			RPCLOG(1, "clnt_cots_kcreate: t_kbind: %d\n", i);
   2216      0       stevel 			(void) t_kclose(tiptr, 1);
   2217      0       stevel 			rpcerr->re_errno = i;
   2218      0       stevel 			connmgr_cancelconn(cm_entry);
   2219      0       stevel 			return (NULL);
   2220      0       stevel 		}
   2221      0       stevel 	}
   2222      0       stevel 
   2223      0       stevel 	{
   2224      0       stevel 		/*
   2225      0       stevel 		 * Keep the kernel stack lean. Don't move this call
   2226      0       stevel 		 * declaration to the top of this function because a
   2227      0       stevel 		 * call is declared in connmgr_wrapconnect()
   2228      0       stevel 		 */
   2229      0       stevel 		calllist_t call;
   2230      0       stevel 
   2231      0       stevel 		bzero(&call, sizeof (call));
   2232      0       stevel 		cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL);
   2233      0       stevel 
   2234      0       stevel 		/*
   2235      0       stevel 		 * This is a bound end-point so don't close it's stream.
   2236      0       stevel 		 */
   2237      0       stevel 		connected = connmgr_connect(cm_entry, wq, destaddr, addrfmly,
   2238   8778         Erik 		    &call, &tidu_size, FALSE, waitp, nosignal, cr);
   2239      0       stevel 		*rpcerr = call.call_err;
   2240      0       stevel 		cv_destroy(&call.call_cv);
   2241      0       stevel 
   2242      0       stevel 	}
   2243      0       stevel 
   2244      0       stevel 	mutex_enter(&connmgr_lock);
   2245      0       stevel 
   2246      0       stevel 	/*
   2247      0       stevel 	 * Set up a transport entry in the connection manager's list.
   2248      0       stevel 	 */
   2249      0       stevel 	cm_entry->x_src.buf = kmem_zalloc(srcaddr->len, KM_SLEEP);
   2250      0       stevel 	bcopy(srcaddr->buf, cm_entry->x_src.buf, srcaddr->len);
   2251      0       stevel 	cm_entry->x_src.len = cm_entry->x_src.maxlen = srcaddr->len;
   2252      0       stevel 
   2253      0       stevel 	cm_entry->x_tiptr = tiptr;
   2254  11066       rafael 	cm_entry->x_time = ddi_get_lbolt();
   2255      0       stevel 
   2256      0       stevel 	if (tiptr->tp_info.servtype == T_COTS_ORD)
   2257      0       stevel 		cm_entry->x_ordrel = TRUE;
   2258      0       stevel 	else
   2259      0       stevel 		cm_entry->x_ordrel = FALSE;
   2260      0       stevel 
   2261      0       stevel 	cm_entry->x_tidu_size = tidu_size;
   2262      0       stevel 
   2263   4457     vv149972 	if (cm_entry->x_early_disc) {
   2264   4457     vv149972 		/*
   2265   4457     vv149972 		 * We need to check if a disconnect request has come
   2266   4457     vv149972 		 * while we are connected, if so, then we need to
   2267   4457     vv149972 		 * set rpcerr->re_status appropriately before returning
   2268   4457     vv149972 		 * NULL to caller.
   2269   4457     vv149972 		 */
   2270   4457     vv149972 		if (rpcerr->re_status == RPC_SUCCESS)
   2271   4457     vv149972 			rpcerr->re_status = RPC_XPRTFAILED;
   2272      0       stevel 		cm_entry->x_connected = FALSE;
   2273   4457     vv149972 	} else
   2274      0       stevel 		cm_entry->x_connected = connected;
   2275      0       stevel 
   2276      0       stevel 	/*
   2277      0       stevel 	 * There could be a discrepancy here such that
   2278      0       stevel 	 * x_early_disc is TRUE yet connected is TRUE as well
   2279      0       stevel 	 * and the connection is actually connected. In that case
   2280      0       stevel 	 * lets be conservative and declare the connection as not
   2281      0       stevel 	 * connected.
   2282      0       stevel 	 */
   2283      0       stevel 	cm_entry->x_early_disc = FALSE;
   2284      0       stevel 	cm_entry->x_needdis = (cm_entry->x_connected == FALSE);
   2285  11066       rafael 	cm_entry->x_ctime = ddi_get_lbolt();
   2286      0       stevel 
   2287      0       stevel 	/*
   2288      0       stevel 	 * Notify any threads waiting that the connection attempt is done.
   2289      0       stevel 	 */
   2290      0       stevel 	cm_entry->x_thread = FALSE;
   2291      0       stevel 	cv_broadcast(&cm_entry->x_conn_cv);
   2292      0       stevel 
   2293      0       stevel 	if (cm_entry->x_connected == FALSE) {
   2294   4457     vv149972 		mutex_exit(&connmgr_lock);
   2295      0       stevel 		connmgr_release(cm_entry);
   2296      0       stevel 		return (NULL);
   2297      0       stevel 	}
   2298   4457     vv149972 
   2299   4457     vv149972 	mutex_exit(&connmgr_lock);
   2300   4457     vv149972 
   2301      0       stevel 	return (cm_entry);
   2302      0       stevel }
   2303      0       stevel 
   2304      0       stevel /*
   2305      0       stevel  * Keep the cm_xprt entry on the connecton list when making a connection. This
   2306      0       stevel  * is to prevent multiple connections to a slow server from appearing.
   2307      0       stevel  * We use the bit field x_thread to tell if a thread is doing a connection
   2308      0       stevel  * which keeps other interested threads from messing with connection.
   2309      0       stevel  * Those other threads just wait if x_thread is set.
   2310      0       stevel  *
   2311      0       stevel  * If x_thread is not set, then we do the actual work of connecting via
   2312      0       stevel  * connmgr_connect().
   2313      0       stevel  *
   2314      0       stevel  * mutex convention: called with connmgr_lock held, returns with it released.
   2315      0       stevel  */
   2316      0       stevel static struct cm_xprt *
   2317      0       stevel connmgr_wrapconnect(
   2318      0       stevel 	struct cm_xprt	*cm_entry,
   2319      0       stevel 	const struct timeval	*waitp,
   2320      0       stevel 	struct netbuf	*destaddr,
   2321      0       stevel 	int		addrfmly,
   2322      0       stevel 	struct netbuf	*srcaddr,
   2323      0       stevel 	struct rpc_err	*rpcerr,
   2324      0       stevel 	bool_t		reconnect,
   2325   8778         Erik 	bool_t		nosignal,
   2326   8778         Erik 	cred_t		*cr)
   2327      0       stevel {
   2328      0       stevel 	ASSERT(MUTEX_HELD(&connmgr_lock));
   2329      0       stevel 	/*
   2330      0       stevel 	 * Hold this entry as we are about to drop connmgr_lock.
   2331      0       stevel 	 */
   2332      0       stevel 	CONN_HOLD(cm_entry);
   2333      0       stevel 
   2334      0       stevel 	/*
   2335      0       stevel 	 * If there is a thread already making a connection for us, then
   2336      0       stevel 	 * wait for it to complete the connection.
   2337      0       stevel 	 */
   2338      0       stevel 	if (cm_entry->x_thread == TRUE) {
   2339      0       stevel 		rpcerr->re_status = connmgr_cwait(cm_entry, waitp, nosignal);
   2340      0       stevel 
   2341      0       stevel 		if (rpcerr->re_status != RPC_SUCCESS) {
   2342      0       stevel 			mutex_exit(&connmgr_lock);
   2343      0       stevel 			connmgr_release(cm_entry);
   2344      0       stevel 			return (NULL);
   2345      0       stevel 		}
   2346      0       stevel 	} else {
   2347      0       stevel 		bool_t connected;
   2348      0       stevel 		calllist_t call;
   2349      0       stevel 
   2350      0       stevel 		cm_entry->x_thread = TRUE;
   2351      0       stevel 
   2352      0       stevel 		while (cm_entry->x_needrel == TRUE) {
   2353      0       stevel 			cm_entry->x_needrel = FALSE;
   2354      0       stevel 
   2355      0       stevel 			connmgr_sndrel(cm_entry);
   2356      0       stevel 			delay(drv_usectohz(1000000));
   2357      0       stevel 
   2358      0       stevel 			mutex_enter(&connmgr_lock);
   2359      0       stevel 		}
   2360      0       stevel 
   2361      0       stevel 		/*
   2362      0       stevel 		 * If we need to send a T_DISCON_REQ, send one.
   2363      0       stevel 		 */
   2364      0       stevel 		connmgr_dis_and_wait(cm_entry);
   2365      0       stevel 
   2366      0       stevel 		mutex_exit(&connmgr_lock);
   2367      0       stevel 
   2368      0       stevel 		bzero(&call, sizeof (call));
   2369      0       stevel 		cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL);
   2370      0       stevel 
   2371      0       stevel 		connected = connmgr_connect(cm_entry, cm_entry->x_wq,
   2372   6403      gt29601 		    destaddr, addrfmly, &call, &cm_entry->x_tidu_size,
   2373   8778         Erik 		    reconnect, waitp, nosignal, cr);
   2374      0       stevel 
   2375      0       stevel 		*rpcerr = call.call_err;
   2376      0       stevel 		cv_destroy(&call.call_cv);
   2377      0       stevel 
   2378      0       stevel 		mutex_enter(&connmgr_lock);
   2379      0       stevel 
   2380      0       stevel 
   2381   4457     vv149972 		if (cm_entry->x_early_disc) {
   2382   4457     vv149972 			/*
   2383   4457     vv149972 			 * We need to check if a disconnect request has come
   2384   4457     vv149972 			 * while we are connected, if so, then we need to
   2385   4457     vv149972 			 * set rpcerr->re_status appropriately before returning
   2386   4457     vv149972 			 * NULL to caller.
   2387   4457     vv149972 			 */
   2388   4457     vv149972 			if (rpcerr->re_status == RPC_SUCCESS)
   2389   4457     vv149972 				rpcerr->re_status = RPC_XPRTFAILED;
   2390      0       stevel 			cm_entry->x_connected = FALSE;
   2391   4457     vv149972 		} else
   2392      0       stevel 			cm_entry->x_connected = connected;
   2393      0       stevel 
   2394      0       stevel 		/*
   2395      0       stevel 		 * There could be a discrepancy here such that
   2396      0       stevel 		 * x_early_disc is TRUE yet connected is TRUE as well
   2397      0       stevel 		 * and the connection is actually connected. In that case
   2398      0       stevel 		 * lets be conservative and declare the connection as not
   2399      0       stevel 		 * connected.
   2400      0       stevel 		 */
   2401      0       stevel 
   2402      0       stevel 		cm_entry->x_early_disc = FALSE;
   2403      0       stevel 		cm_entry->x_needdis = (cm_entry->x_connected == FALSE);
   2404      0       stevel 
   2405      0       stevel 
   2406      0       stevel 		/*
   2407      0       stevel 		 * connmgr_connect() may have given up before the connection
   2408      0       stevel 		 * actually timed out. So ensure that before the next
   2409      0       stevel 		 * connection attempt we do a disconnect.
   2410      0       stevel 		 */
   2411  11066       rafael 		cm_entry->x_ctime = ddi_get_lbolt();
   2412      0       stevel 		cm_entry->x_thread = FALSE;
   2413      0       stevel 
   2414      0       stevel 		cv_broadcast(&cm_entry->x_conn_cv);
   2415      0       stevel 
   2416      0       stevel 		if (cm_entry->x_connected == FALSE) {
   2417      0       stevel 			mutex_exit(&connmgr_lock);
   2418      0       stevel 			connmgr_release(cm_entry);
   2419      0       stevel 			return (NULL);
   2420      0       stevel 		}
   2421      0       stevel 	}
   2422      0       stevel 
   2423      0       stevel 	if (srcaddr != NULL) {
   2424      0       stevel 		/*
   2425      0       stevel 		 * Copy into the handle the
   2426      0       stevel 		 * source address of the
   2427      0       stevel 		 * connection, which we will use
   2428      0       stevel 		 * in case of a later retry.
   2429      0       stevel 		 */
   2430      0       stevel 		if (srcaddr->len != cm_entry->x_src.len) {
   2431      0       stevel 			if (srcaddr->maxlen > 0)
   2432      0       stevel 				kmem_free(srcaddr->buf, srcaddr->maxlen);
   2433      0       stevel 			srcaddr->buf = kmem_zalloc(cm_entry->x_src.len,
   2434      0       stevel 			    KM_SLEEP);
   2435      0       stevel 			srcaddr->maxlen = srcaddr->len =
   2436      0       stevel 			    cm_entry->x_src.len;
   2437      0       stevel 		}
   2438      0       stevel 		bcopy(cm_entry->x_src.buf, srcaddr->buf, srcaddr->len);
   2439      0       stevel 	}
   2440  11066       rafael 	cm_entry->x_time = ddi_get_lbolt();
   2441      0       stevel 	mutex_exit(&connmgr_lock);
   2442      0       stevel 	return (cm_entry);
   2443      0       stevel }
   2444      0       stevel 
   2445      0       stevel /*
   2446      0       stevel  * If we need to send a T_DISCON_REQ, send one.
   2447      0       stevel  */
   2448      0       stevel static void
   2449      0       stevel connmgr_dis_and_wait(struct cm_xprt *cm_entry)
   2450      0       stevel {
   2451      0       stevel 	ASSERT(MUTEX_HELD(&connmgr_lock));
   2452      0       stevel 	for (;;) {
   2453      0       stevel 		while (cm_entry->x_needdis == TRUE) {
   2454      0       stevel 			RPCLOG(8, "connmgr_dis_and_wait: need "
   2455   6403      gt29601 			    "T_DISCON_REQ for connection 0x%p\n",
   2456   6403      gt29601 			    (void *)cm_entry);
   2457      0       stevel 			cm_entry->x_needdis = FALSE;
   2458      0       stevel 			cm_entry->x_waitdis = TRUE;
   2459      0       stevel 
   2460      0       stevel 			connmgr_snddis(cm_entry);
   2461      0       stevel 
   2462      0       stevel 			mutex_enter(&connmgr_lock);
   2463      0       stevel 		}
   2464      0       stevel 
   2465      0       stevel 		if (cm_entry->x_waitdis == TRUE) {
   2466      0       stevel 			clock_t timout;
   2467      0       stevel 
   2468      0       stevel 			RPCLOG(8, "connmgr_dis_and_wait waiting for "
   2469   6403      gt29601 			    "T_DISCON_REQ's ACK for connection %p\n",
   2470   6403      gt29601 			    (void *)cm_entry);
   2471      0       stevel 
   2472  11066       rafael 			timout = clnt_cots_min_conntout * drv_usectohz(1000000);
   2473      0       stevel 
   2474      0       stevel 			/*
   2475      0       stevel 			 * The TPI spec says that the T_DISCON_REQ
   2476      0       stevel 			 * will get acknowledged, but in practice
   2477      0       stevel 			 * the ACK may never get sent. So don't
   2478      0       stevel 			 * block forever.
   2479      0       stevel 			 */
   2480  11066       rafael 			(void) cv_reltimedwait(&cm_entry->x_dis_cv,
   2481  11066       rafael 			    &connmgr_lock, timout, TR_CLOCK_TICK);
   2482      0       stevel 		}
   2483      0       stevel 		/*
   2484      0       stevel 		 * If we got the ACK, break. If we didn't,
   2485      0       stevel 		 * then send another T_DISCON_REQ.
   2486      0       stevel 		 */
   2487      0       stevel 		if (cm_entry->x_waitdis == FALSE) {
   2488      0       stevel 			break;
   2489      0       stevel 		} else {
   2490      0       stevel 			RPCLOG(8, "connmgr_dis_and_wait: did"
   2491   6403      gt29601 			    "not get T_DISCON_REQ's ACK for "
   2492   6403      gt29601 			    "connection  %p\n", (void *)cm_entry);
   2493      0       stevel 			cm_entry->x_needdis = TRUE;
   2494      0       stevel 		}
   2495      0       stevel 	}
   2496      0       stevel }
   2497      0       stevel 
   2498      0       stevel static void
   2499      0       stevel connmgr_cancelconn(struct cm_xprt *cm_entry)
   2500      0       stevel {
   2501      0       stevel 	/*
   2502      0       stevel 	 * Mark the connection table entry as dead; the next thread that
   2503      0       stevel 	 * goes through connmgr_release() will notice this and deal with it.
   2504      0       stevel 	 */
   2505      0       stevel 	mutex_enter(&connmgr_lock);
   2506      0       stevel 	cm_entry->x_dead = TRUE;
   2507      0       stevel 
   2508      0       stevel 	/*
   2509      0       stevel 	 * Notify any threads waiting for the connection that it isn't
   2510      0       stevel 	 * going to happen.
   2511      0       stevel 	 */
   2512      0       stevel 	cm_entry->x_thread = FALSE;
   2513      0       stevel 	cv_broadcast(&cm_entry->x_conn_cv);
   2514      0       stevel 	mutex_exit(&connmgr_lock);
   2515      0       stevel 
   2516      0       stevel 	connmgr_release(cm_entry);
   2517      0       stevel }
   2518      0       stevel 
   2519      0       stevel static void
   2520      0       stevel connmgr_close(struct cm_xprt *cm_entry)
   2521      0       stevel {
   2522      0       stevel 	mutex_enter(&cm_entry->x_lock);
   2523      0       stevel 	while (cm_entry->x_ref != 0) {
   2524      0       stevel 		/*
   2525      0       stevel 		 * Must be a noninterruptible wait.
   2526      0       stevel 		 */
   2527      0       stevel 		cv_wait(&cm_entry->x_cv, &cm_entry->x_lock);
   2528      0       stevel 	}
   2529      0       stevel 
   2530      0       stevel 	if (cm_entry->x_tiptr != NULL)
   2531      0       stevel 		(void) t_kclose(cm_entry->x_tiptr, 1);
   2532      0       stevel 
   2533      0       stevel 	mutex_exit(&cm_entry->x_lock);
   2534      0       stevel 	if (cm_entry->x_ksp != NULL) {
   2535      0       stevel 		mutex_enter(&connmgr_lock);
   2536      0       stevel 		cm_entry->x_ksp->ks_private = NULL;
   2537      0       stevel 		mutex_exit(&connmgr_lock);
   2538      0       stevel 
   2539      0       stevel 		/*
   2540      0       stevel 		 * Must free the buffer we allocated for the
   2541      0       stevel 		 * server address in the update function
   2542      0       stevel 		 */
   2543      0       stevel 		if (((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
   2544    457          bmc 		    x_server.value.str.addr.ptr != NULL)
   2545      0       stevel 			kmem_free(((struct cm_kstat_xprt *)(cm_entry->x_ksp->
   2546    457          bmc 			    ks_data))->x_server.value.str.addr.ptr,
   2547   6403      gt29601 			    INET6_ADDRSTRLEN);
   2548      0       stevel 		kmem_free(cm_entry->x_ksp->ks_data,
   2549   6403      gt29601 		    cm_entry->x_ksp->ks_data_size);
   2550      0       stevel 		kstat_delete(cm_entry->x_ksp);
   2551      0       stevel 	}
   2552      0       stevel 
   2553      0       stevel 	mutex_destroy(&cm_entry->x_lock);
   2554      0       stevel 	cv_destroy(&cm_entry->x_cv);
   2555      0       stevel 	cv_destroy(&cm_entry->x_conn_cv);
   2556      0       stevel 	cv_destroy(&cm_entry->x_dis_cv);
   2557      0       stevel 
   2558      0       stevel 	if (cm_entry->x_server.buf != NULL)
   2559      0       stevel 		kmem_free(cm_entry->x_server.buf, cm_entry->x_server.maxlen);
   2560      0       stevel 	if (cm_entry->x_src.buf != NULL)
   2561      0       stevel 		kmem_free(cm_entry->x_src.buf, cm_entry->x_src.maxlen);
   2562      0       stevel 	kmem_free(cm_entry, sizeof (struct cm_xprt));
   2563      0       stevel }
   2564      0       stevel 
   2565      0       stevel /*
   2566      0       stevel  * Called by KRPC after sending the call message to release the connection
   2567      0       stevel  * it was using.
   2568      0       stevel  */
   2569      0       stevel static void
   2570      0       stevel connmgr_release(struct cm_xprt *cm_entry)
   2571      0       stevel {
   2572      0       stevel 	mutex_enter(&cm_entry->x_lock);
   2573      0       stevel 	cm_entry->x_ref--;
   2574      0       stevel 	if (cm_entry->x_ref == 0)
   2575      0       stevel 		cv_signal(&cm_entry->x_cv);
   2576      0       stevel 	mutex_exit(&cm_entry->x_lock);
   2577      0       stevel }
   2578      0       stevel 
   2579      0       stevel /*
   2580  10004          dai  * Set TCP receive and xmit buffer size for RPC connections.
   2581  10004          dai  */
   2582  10004          dai static bool_t
   2583  10004          dai connmgr_setbufsz(calllist_t *e, queue_t *wq, cred_t *cr)
   2584  10004          dai {
   2585  10004          dai 	int ok = FALSE;
   2586  10004          dai 	int val;
   2587  10004          dai 
   2588  10004          dai 	if (rpc_default_tcp_bufsz)
   2589  10004          dai 		return (FALSE);
   2590  10004          dai 
   2591  10004          dai 	/*
   2592  10004          dai 	 * Only set new buffer size if it's larger than the system
   2593  10004          dai 	 * default buffer size. If smaller buffer size is needed
   2594  10004          dai 	 * then use /etc/system to set rpc_default_tcp_bufsz to 1.
   2595  10004          dai 	 */
   2596  10004          dai 	ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_RCVBUF, &val, e, cr);
   2597  10004          dai 	if ((ok == TRUE) && (val < rpc_send_bufsz)) {
   2598  10004          dai 		ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_RCVBUF,
   2599  10004          dai 		    rpc_send_bufsz, e, cr);
   2600  10004          dai 		DTRACE_PROBE2(krpc__i__connmgr_rcvbufsz,
   2601  10004          dai 		    int, ok, calllist_t *, e);
   2602  10004          dai 	}
   2603  10004          dai 
   2604  10004          dai 	ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_SNDBUF, &val, e, cr);
   2605  10004          dai 	if ((ok == TRUE) && (val < rpc_recv_bufsz)) {
   2606  10004          dai 		ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_SNDBUF,
   2607  10004          dai 		    rpc_recv_bufsz, e, cr);
   2608  10004          dai 		DTRACE_PROBE2(krpc__i__connmgr_sndbufsz,
   2609  10004          dai 		    int, ok, calllist_t *, e);
   2610  10004          dai 	}
   2611  10004          dai 	return (TRUE);
   2612  10004          dai }
   2613  10004          dai 
   2614  10004          dai /*
   2615      0       stevel  * Given an open stream, connect to the remote.  Returns true if connected,
   2616      0       stevel  * false otherwise.
   2617      0       stevel  */
   2618      0       stevel static bool_t
   2619      0       stevel connmgr_connect(
   2620      0       stevel 	struct cm_xprt		*cm_entry,
   2621      0       stevel 	queue_t			*wq,
   2622      0       stevel 	struct netbuf		*addr,
   2623      0       stevel 	int			addrfmly,
   2624      0       stevel 	calllist_t 		*e,
   2625      0       stevel 	int 			*tidu_ptr,
   2626      0       stevel 	bool_t 			reconnect,
   2627      0       stevel 	const struct timeval 	*waitp,
   2628   8778         Erik 	bool_t 			nosignal,
   2629   8778         Erik 	cred_t			*cr)
   2630      0       stevel {
   2631      0       stevel 	mblk_t *mp;
   2632      0       stevel 	struct T_conn_req *tcr;
   2633      0       stevel 	struct T_info_ack *tinfo;
   2634      0       stevel 	int interrupted, error;
   2635      0       stevel 	int tidu_size, kstat_instance;
   2636      0       stevel 
   2637      0       stevel 	/* if it's a reconnect, flush any lingering data messages */
   2638      0       stevel 	if (reconnect)
   2639      0       stevel 		(void) putctl1(wq, M_FLUSH, FLUSHRW);
   2640      0       stevel 
   2641   8778         Erik 	/*
   2642   8778         Erik 	 * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will
   2643   8778         Erik 	 * appear as -1.
   2644   8778         Erik 	 */
   2645   8778         Erik 	mp = allocb_cred(sizeof (*tcr) + addr->len, cr, NOPID);
   2646      0       stevel 	if (mp == NULL) {
   2647      0       stevel 		/*
   2648      0       stevel 		 * This is unfortunate, but we need to look up the stats for
   2649      0       stevel 		 * this zone to increment the "memory allocation failed"
   2650      0       stevel 		 * counter.  curproc->p_zone is safe since we're initiating a
   2651      0       stevel 		 * connection and not in some strange streams context.
   2652      0       stevel 		 */
   2653      0       stevel 		struct rpcstat *rpcstat;
   2654      0       stevel 
   2655    766     carlsonj 		rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone());
   2656      0       stevel 		ASSERT(rpcstat != NULL);
   2657      0       stevel 
   2658      0       stevel 		RPCLOG0(1, "connmgr_connect: cannot alloc mp for "
   2659      0       stevel 		    "sending conn request\n");
   2660      0       stevel 		COTSRCSTAT_INCR(rpcstat->rpc_cots_client, rcnomem);
   2661      0       stevel 		e->call_status = RPC_SYSTEMERROR;
   2662      0       stevel 		e->call_reason = ENOSR;
   2663      0       stevel 		return (FALSE);
   2664      0       stevel 	}
   2665  10004          dai 
   2666  10004          dai 	/* Set TCP buffer size for RPC connections if needed */
   2667  10004          dai 	if (addrfmly == AF_INET || addrfmly == AF_INET6)
   2668  10004          dai 		(void) connmgr_setbufsz(e, wq, cr);
   2669      0       stevel 
   2670      0       stevel 	mp->b_datap->db_type = M_PROTO;
   2671      0       stevel 	tcr = (struct T_conn_req *)mp->b_rptr;
   2672      0       stevel 	bzero(tcr, sizeof (*tcr));
   2673      0       stevel 	tcr->PRIM_type = T_CONN_REQ;
   2674      0       stevel 	tcr->DEST_length = addr->len;
   2675      0       stevel 	tcr->DEST_offset = sizeof (struct T_conn_req);
   2676      0       stevel 	mp->b_wptr = mp->b_rptr + sizeof (*tcr);
   2677      0       stevel 
   2678      0       stevel 	bcopy(addr->buf, mp->b_wptr, tcr->DEST_length);
   2679      0       stevel 	mp->b_wptr += tcr->DEST_length;
   2680      0       stevel 
   2681      0       stevel 	RPCLOG(8, "connmgr_connect: sending conn request on queue "
   2682      0       stevel 	    "%p", (void *)wq);
   2683      0       stevel 	RPCLOG(8, " call %p\n", (void *)wq);
   2684      0       stevel 	/*
   2685      0       stevel 	 * We use the entry in the handle that is normally used for
   2686      0       stevel 	 * waiting for RPC replies to wait for the connection accept.
   2687      0       stevel 	 */
   2688   8205  Siddheshwar 	if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
   2689   8205  Siddheshwar 		DTRACE_PROBE(krpc__e__connmgr__connect__cantsend);
   2690   8205  Siddheshwar 		freemsg(mp);
   2691   8205  Siddheshwar 		return (FALSE);
   2692   8205  Siddheshwar 	}
   2693      0       stevel 
   2694      0       stevel 	mutex_enter(&clnt_pending_lock);
   2695      0       stevel 
   2696      0       stevel 	/*
   2697      0       stevel 	 * We wait for the transport connection to be made, or an
   2698      0       stevel 	 * indication that it could not be made.
   2699      0       stevel 	 */
   2700      0       stevel 	interrupted = 0;
   2701      0       stevel 
   2702      0       stevel 	/*
   2703      0       stevel 	 * waitforack should have been called with T_OK_ACK, but the
   2704      0       stevel 	 * present implementation needs to be passed T_INFO_ACK to
   2705      0       stevel 	 * work correctly.
   2706      0       stevel 	 */
   2707      0       stevel 	error = waitforack(e, T_INFO_ACK, waitp, nosignal);
   2708      0       stevel 	if (error == EINTR)
   2709      0       stevel 		interrupted = 1;
   2710      0       stevel 	if (zone_status_get(curproc->p_zone) >= ZONE_IS_EMPTY) {
   2711      0       stevel 		/*
   2712      0       stevel 		 * No time to lose; we essentially have been signaled to
   2713      0       stevel 		 * quit.
   2714      0       stevel 		 */
   2715      0       stevel 		interrupted = 1;
   2716      0       stevel 	}
   2717      0       stevel #ifdef RPCDEBUG
   2718      0       stevel 	if (error == ETIME)
   2719      0       stevel 		RPCLOG0(8, "connmgr_connect: giving up "
   2720      0       stevel 		    "on connection attempt; "
   2721      0       stevel 		    "clnt_dispatch notifyconn "
   2722      0       stevel 		    "diagnostic 'no one waiting for "
   2723      0       stevel 		    "connection' should not be "
   2724      0       stevel 		    "unexpected\n");
   2725      0       stevel #endif
   2726      0       stevel 	if (e->call_prev)
   2727      0       stevel 		e->call_prev->call_next = e->call_next;
   2728      0       stevel 	else
   2729      0       stevel 		clnt_pending = e->call_next;
   2730      0       stevel 	if (e->call_next)
   2731      0       stevel 		e->call_next->call_prev = e->call_prev;
   2732      0       stevel 	mutex_exit(&clnt_pending_lock);
   2733      0       stevel 
   2734      0       stevel 	if (e->call_status != RPC_SUCCESS || error != 0) {
   2735      0       stevel 		if (interrupted)
   2736      0       stevel 			e->call_status = RPC_INTR;
   2737      0       stevel 		else if (error == ETIME)
   2738      0       stevel 			e->call_status = RPC_TIMEDOUT;
   2739   9804       Gerald 		else if (error == EPROTO) {
   2740      0       stevel 			e->call_status = RPC_SYSTEMERROR;
   2741   9804       Gerald 			e->call_reason = EPROTO;
   2742   9804       Gerald 		}
   2743      0       stevel 
   2744      0       stevel 		RPCLOG(8, "connmgr_connect: can't connect, status: "
   2745      0       stevel 		    "%s\n", clnt_sperrno(e->call_status));
   2746      0       stevel 
   2747      0       stevel 		if (e->call_reply) {
   2748      0       stevel 			freemsg(e->call_reply);
   2749      0       stevel 			e->call_reply = NULL;
   2750      0       stevel 		}
   2751      0       stevel 
   2752      0       stevel 		return (FALSE);
   2753      0       stevel 	}
   2754      0       stevel 	/*
   2755      0       stevel 	 * The result of the "connection accept" is a T_info_ack
   2756      0       stevel 	 * in the call_reply field.
   2757      0       stevel 	 */
   2758      0       stevel 	ASSERT(e->call_reply != NULL);
   2759      0       stevel 	mp = e->call_reply;
   2760      0       stevel 	e->call_reply = NULL;
   2761      0       stevel 	tinfo = (struct T_info_ack *)mp->b_rptr;
   2762      0       stevel 
   2763      0       stevel 	tidu_size = tinfo->TIDU_size;
   2764      0       stevel 	tidu_size -= (tidu_size % BYTES_PER_XDR_UNIT);
   2765      0       stevel 	if (tidu_size > COTS_DEFAULT_ALLOCSIZE || (tidu_size <= 0))
   2766      0       stevel 		tidu_size = COTS_DEFAULT_ALLOCSIZE;
   2767      0       stevel 	*tidu_ptr = tidu_size;
   2768      0       stevel 
   2769      0       stevel 	freemsg(mp);
   2770      0       stevel 
   2771      0       stevel 	/*
   2772      0       stevel 	 * Set up the pertinent options.  NODELAY is so the transport doesn't
   2773      0       stevel 	 * buffer up RPC messages on either end.  This may not be valid for
   2774      0       stevel 	 * all transports.  Failure to set this option is not cause to
   2775      0       stevel 	 * bail out so we return success anyway.  Note that lack of NODELAY
   2776      0       stevel 	 * or some other way to flush the message on both ends will cause
   2777      0       stevel 	 * lots of retries and terrible performance.
   2778      0       stevel 	 */
   2779      0       stevel 	if (addrfmly == AF_INET || addrfmly == AF_INET6) {
   2780   8778         Erik 		(void) connmgr_setopt(wq, IPPROTO_TCP, TCP_NODELAY, e, cr);
   2781      0       stevel 		if (e->call_status == RPC_XPRTFAILED)
   2782      0       stevel 			return (FALSE);
   2783      0       stevel 	}
   2784      0       stevel 
   2785      0       stevel 	/*
   2786      0       stevel 	 * Since we have a connection, we now need to figure out if
   2787      0       stevel 	 * we need to create a kstat. If x_ksp is not NULL then we
   2788      0       stevel 	 * are reusing a connection and so we do not need to create
   2789      0       stevel 	 * another kstat -- lets just return.
   2790      0       stevel 	 */
   2791      0       stevel 	if (cm_entry->x_ksp != NULL)
   2792      0       stevel 		return (TRUE);
   2793      0       stevel 
   2794      0       stevel 	/*
   2795      0       stevel 	 * We need to increment rpc_kstat_instance atomically to prevent
   2796      0       stevel 	 * two kstats being created with the same instance.
   2797      0       stevel 	 */
   2798      0       stevel 	kstat_instance = atomic_add_32_nv((uint32_t *)&rpc_kstat_instance, 1);
   2799      0       stevel 
   2800      0       stevel 	if ((cm_entry->x_ksp = kstat_create_zone("unix", kstat_instance,
   2801      0       stevel 	    "rpc_cots_connections", "rpc", KSTAT_TYPE_NAMED,
   2802      0       stevel 	    (uint_t)(sizeof (cm_kstat_xprt_t) / sizeof (kstat_named_t)),
   2803      0       stevel 	    KSTAT_FLAG_VIRTUAL, cm_entry->x_zoneid)) == NULL) {
   2804      0       stevel 		return (TRUE);
   2805   6403      gt29601 	}
   2806      0       stevel 
   2807      0       stevel 	cm_entry->x_ksp->ks_lock = &connmgr_lock;
   2808      0       stevel 	cm_entry->x_ksp->ks_private = cm_entry;
   2809      0       stevel 	cm_entry->x_ksp->ks_data_size = ((INET6_ADDRSTRLEN * sizeof (char))
   2810   6403      gt29601 	    + sizeof (cm_kstat_template));
   2811      0       stevel 	cm_entry->x_ksp->ks_data = kmem_alloc(cm_entry->x_ksp->ks_data_size,
   2812   6403      gt29601 	    KM_SLEEP);
   2813      0       stevel 	bcopy(&cm_kstat_template, cm_entry->x_ksp->ks_data,
   2814      0       stevel 	    cm_entry->x_ksp->ks_data_size);
   2815      0       stevel 	((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
   2816   6403      gt29601 	    x_server.value.str.addr.ptr =
   2817   6403      gt29601 	    kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP);
   2818      0       stevel 
   2819      0       stevel 	cm_entry->x_ksp->ks_update = conn_kstat_update;
   2820      0       stevel 	kstat_install(cm_entry->x_ksp);
   2821      0       stevel 	return (TRUE);
   2822      0       stevel }
   2823      0       stevel 
   2824      0       stevel /*
   2825  10004          dai  * Verify that the specified offset falls within the mblk and
   2826  10004          dai  * that the resulting pointer is aligned.
   2827  10004          dai  * Returns NULL if not.
   2828  10004          dai  *
   2829  10004          dai  * code from fs/sockfs/socksubr.c
   2830  10004          dai  */
   2831  10004          dai static void *
   2832  10004          dai connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset,
   2833  10004          dai     t_uscalar_t length, uint_t align_size)
   2834  10004          dai {
   2835  10004          dai 	uintptr_t ptr1, ptr2;
   2836  10004          dai 
   2837  10004          dai 	ASSERT(mp && mp->b_wptr >= mp->b_rptr);
   2838  10004          dai 	ptr1 = (uintptr_t)mp->b_rptr + offset;
   2839  10004          dai 	ptr2 = (uintptr_t)ptr1 + length;
   2840  10004          dai 	if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) {
   2841  10004          dai 		return (NULL);
   2842  10004          dai 	}
   2843  10004          dai 	if ((ptr1 & (align_size - 1)) != 0) {
   2844  10004          dai 		return (NULL);
   2845  10004          dai 	}
   2846  10004          dai 	return ((void *)ptr1);
   2847  10004          dai }
   2848  10004          dai 
   2849  10004          dai static bool_t
   2850  10004          dai connmgr_getopt_int(queue_t *wq, int level, int name, int *val,
   2851  10004          dai     calllist_t *e, cred_t *cr)
   2852  10004          dai {
   2853  10004          dai 	mblk_t *mp;
   2854  10004          dai 	struct opthdr *opt, *opt_res;
   2855  10004          dai 	struct T_optmgmt_req *tor;
   2856  10004          dai 	struct T_optmgmt_ack *opt_ack;
   2857  10004          dai 	struct timeval waitp;
   2858  10004          dai 	int error;
   2859  10004          dai 
   2860  10004          dai 	mp = allocb_cred(sizeof (struct T_optmgmt_req) +
   2861  10004          dai 	    sizeof (struct opthdr) + sizeof (int), cr, NOPID);
   2862  10004          dai 	if (mp == NULL)
   2863  10004          dai 		return (FALSE);
   2864  10004          dai 
   2865  10004          dai 	mp->b_datap->db_type = M_PROTO;
   2866  10004          dai 	tor = (struct T_optmgmt_req *)(mp->b_rptr);
   2867  10004          dai 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
   2868  10004          dai 	tor->MGMT_flags = T_CURRENT;
   2869  10004          dai 	tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
   2870  10004          dai 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
   2871  10004          dai 
   2872  10004          dai 	opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
   2873  10004          dai 	opt->level = level;
   2874  10004          dai 	opt->name = name;
   2875  10004          dai 	opt->len = sizeof (int);
   2876  10004          dai 	mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
   2877  10004          dai 	    sizeof (int);
   2878  10004          dai 
   2879  10004          dai 	/*
   2880  10004          dai 	 * We will use this connection regardless
   2881  10004          dai 	 * of whether or not the option is readable.
   2882  10004          dai 	 */
   2883  10004          dai 	if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
   2884  10004          dai 		DTRACE_PROBE(krpc__e__connmgr__getopt__cantsend);
   2885  10004          dai 		freemsg(mp);
   2886  10004          dai 		return (FALSE);
   2887  10004          dai 	}
   2888  10004          dai 
   2889  10004          dai 	mutex_enter(&clnt_pending_lock);
   2890  10004          dai 
   2891  10004          dai 	waitp.tv_sec = clnt_cots_min_conntout;
   2892  10004          dai 	waitp.tv_usec = 0;
   2893  10004          dai 	error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
   2894  10004          dai 
   2895  10004          dai 	if (e->call_prev)
   2896  10004          dai 		e->call_prev->call_next = e->call_next;
   2897  10004          dai 	else
   2898  10004          dai 		clnt_pending = e->call_next;
   2899  10004          dai 	if (e->call_next)
   2900  10004          dai 		e->call_next->call_prev = e->call_prev;
   2901  10004          dai 	mutex_exit(&clnt_pending_lock);
   2902  10004          dai 
   2903  10004          dai 	/* get reply message */
   2904  10004          dai 	mp = e->call_reply;
   2905  10004          dai 	e->call_reply = NULL;
   2906  10004          dai 
   2907  10004          dai 	if ((!mp) || (e->call_status != RPC_SUCCESS) || (error != 0)) {
   2908  10004          dai 
   2909  10004          dai 		DTRACE_PROBE4(krpc__e__connmgr_getopt, int, name,
   2910  10004          dai 		    int, e->call_status, int, error, mblk_t *, mp);
   2911  10004          dai 
   2912  10004          dai 		if (mp)
   2913  10004          dai 			freemsg(mp);
   2914  10004          dai 		return (FALSE);
   2915  10004          dai 	}
   2916  10004          dai 
   2917  10004          dai 	opt_ack = (struct T_optmgmt_ack *)mp->b_rptr;
   2918  10004          dai 	opt_res = (struct opthdr *)connmgr_opt_getoff(mp, opt_ack->OPT_offset,
   2919  10004          dai 	    opt_ack->OPT_length, __TPI_ALIGN_SIZE);
   2920  10004          dai 
   2921  10004          dai 	if (!opt_res) {
   2922  10004          dai 		DTRACE_PROBE4(krpc__e__connmgr_optres, mblk_t *, mp, int, name,
   2923  10004          dai 		    int, opt_ack->OPT_offset, int, opt_ack->OPT_length);
   2924  10004          dai 		freemsg(mp);
   2925  10004          dai 		return (FALSE);
   2926  10004          dai 	}
   2927  10004          dai 	*val = *(int *)&opt_res[1];
   2928  10004          dai 
   2929  10004          dai 	DTRACE_PROBE2(connmgr_getopt__ok, int, name, int, *val);
   2930  10004          dai 
   2931  10004          dai 	freemsg(mp);
   2932  10004          dai 	return (TRUE);
   2933  10004          dai }
   2934  10004          dai 
   2935  10004          dai /*
   2936      0       stevel  * Called by connmgr_connect to set an option on the new stream.
   2937      0       stevel  */
   2938      0       stevel static bool_t
   2939  10004          dai connmgr_setopt_int(queue_t *wq, int level, int name, int val,
   2940  10004          dai     calllist_t *e, cred_t *cr)
   2941      0       stevel {
   2942      0       stevel 	mblk_t *mp;
   2943      0       stevel 	struct opthdr *opt;
   2944      0       stevel 	struct T_optmgmt_req *tor;
   2945      0       stevel 	struct timeval waitp;
   2946      0       stevel 	int error;
   2947      0       stevel 
   2948   8778         Erik 	mp = allocb_cred(sizeof (struct T_optmgmt_req) +
   2949   8778         Erik 	    sizeof (struct opthdr) + sizeof (int), cr, NOPID);
   2950      0       stevel 	if (mp == NULL) {
   2951      0       stevel 		RPCLOG0(1, "connmgr_setopt: cannot alloc mp for option "
   2952      0       stevel 		    "request\n");
   2953      0       stevel 		return (FALSE);
   2954      0       stevel 	}
   2955      0       stevel 
   2956      0       stevel 	mp->b_datap->db_type = M_PROTO;
   2957      0       stevel 	tor = (struct T_optmgmt_req *)(mp->b_rptr);
   2958      0       stevel 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
   2959      0       stevel 	tor->MGMT_flags = T_NEGOTIATE;
   2960      0       stevel 	tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
   2961      0       stevel 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
   2962      0       stevel 
   2963      0       stevel 	opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
   2964      0       stevel 	opt->level = level;
   2965      0       stevel 	opt->name = name;
   2966      0       stevel 	opt->len = sizeof (int);
   2967  10004          dai 	*(int *)((char *)opt + sizeof (*opt)) = val;
   2968      0       stevel 	mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
   2969      0       stevel 	    sizeof (int);
   2970      0       stevel 
   2971      0       stevel 	/*
   2972      0       stevel 	 * We will use this connection regardless
   2973      0       stevel 	 * of whether or not the option is settable.
   2974      0       stevel 	 */
   2975   8205  Siddheshwar 	if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
   2976   8205  Siddheshwar 		DTRACE_PROBE(krpc__e__connmgr__setopt__cantsend);
   2977   8205  Siddheshwar 		freemsg(mp);
   2978   8205  Siddheshwar 		return (FALSE);
   2979   8205  Siddheshwar 	}
   2980   8205  Siddheshwar 
   2981      0       stevel 	mutex_enter(&clnt_pending_lock);
   2982      0       stevel 
   2983      0       stevel 	waitp.tv_sec = clnt_cots_min_conntout;
   2984      0       stevel 	waitp.tv_usec = 0;
   2985      0       stevel 	error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
   2986      0       stevel 
   2987      0       stevel 	if (e->call_prev)
   2988      0       stevel 		e->call_prev->call_next = e->call_next;
   2989      0       stevel 	else
   2990      0       stevel 		clnt_pending = e->call_next;
   2991      0       stevel 	if (e->call_next)
   2992      0       stevel 		e->call_next->call_prev = e->call_prev;
   2993      0       stevel 	mutex_exit(&clnt_pending_lock);
   2994      0       stevel 
   2995      0       stevel 	if (e->call_reply != NULL) {
   2996      0       stevel 		freemsg(e->call_reply);
   2997      0       stevel 		e->call_reply = NULL;
   2998      0       stevel 	}
   2999      0       stevel 
   3000      0       stevel 	if (e->call_status != RPC_SUCCESS || error != 0) {
   3001      0       stevel 		RPCLOG(1, "connmgr_setopt: can't set option: %d\n", name);
   3002      0       stevel 		return (FALSE);
   3003      0       stevel 	}
   3004      0       stevel 	RPCLOG(8, "connmgr_setopt: successfully set option: %d\n", name);
   3005      0       stevel 	return (TRUE);
   3006  10004          dai }
   3007  10004          dai 
   3008  10004          dai static bool_t
   3009  10004          dai connmgr_setopt(queue_t *wq, int level, int name, calllist_t *e, cred_t *cr)
   3010  10004          dai {
   3011  10004          dai 	return (connmgr_setopt_int(wq, level, name, 1, e, cr));
   3012      0       stevel }
   3013      0       stevel 
   3014      0       stevel #ifdef	DEBUG
   3015      0       stevel 
   3016      0       stevel /*
   3017      0       stevel  * This is a knob to let us force code coverage in allocation failure
   3018      0       stevel  * case.
   3019      0       stevel  */
   3020      0       stevel static int	connmgr_failsnd;
   3021      0       stevel #define	CONN_SND_ALLOC(Size, Pri)	\
   3022      0       stevel 	((connmgr_failsnd-- > 0) ? NULL : allocb(Size, Pri))
   3023      0       stevel 
   3024      0       stevel #else
   3025      0       stevel 
   3026      0       stevel #define	CONN_SND_ALLOC(Size, Pri)	allocb(Size, Pri)
   3027      0       stevel 
   3028      0       stevel #endif
   3029      0       stevel 
   3030      0       stevel /*
   3031      0       stevel  * Sends an orderly release on the specified queue.
   3032      0       stevel  * Entered with connmgr_lock. Exited without connmgr_lock
   3033      0       stevel  */
   3034      0       stevel static void
   3035      0       stevel connmgr_sndrel(struct cm_xprt *cm_entry)
   3036      0       stevel {
   3037      0       stevel 	struct T_ordrel_req *torr;
   3038      0       stevel 	mblk_t *mp;
   3039      0       stevel 	queue_t *q = cm_entry->x_wq;
   3040      0       stevel 	ASSERT(MUTEX_HELD(&connmgr_lock));
   3041      0       stevel 	mp = CONN_SND_ALLOC(sizeof (struct T_ordrel_req), BPRI_LO);
   3042      0       stevel 	if (mp == NULL) {
   3043      0       stevel 		cm_entry->x_needrel = TRUE;
   3044      0       stevel 		mutex_exit(&connmgr_lock);
   3045      0       stevel 		RPCLOG(1, "connmgr_sndrel: cannot alloc mp for sending ordrel "
   3046   6403      gt29601 		    "to queue %p\n", (void *)q);
   3047      0       stevel 		return;
   3048      0       stevel 	}
   3049      0       stevel 	mutex_exit(&connmgr_lock);
   3050      0       stevel 
   3051      0       stevel 	mp->b_datap->db_type = M_PROTO;
   3052      0       stevel 	torr = (struct T_ordrel_req *)(mp->b_rptr);
   3053      0       stevel 	torr->PRIM_type = T_ORDREL_REQ;
   3054      0       stevel 	mp->b_wptr = mp->b_rptr + sizeof (struct T_ordrel_req);
   3055      0       stevel 
   3056      0       stevel 	RPCLOG(8,