xref: /illumos-gate/usr/src/uts/common/fs/sockfs/sockstr.c (revision 0f1702c5201310f0529cd5abb77652e5e9b241b6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52caf0dcdSrshoaib  * Common Development and Distribution License (the "License").
62caf0dcdSrshoaib  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
212caf0dcdSrshoaib 
227c478bd9Sstevel@tonic-gate /*
2317169044Sbrutus  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/inttypes.h>
297c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
307c478bd9Sstevel@tonic-gate #include <sys/param.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/buf.h>
337c478bd9Sstevel@tonic-gate #include <sys/conf.h>
347c478bd9Sstevel@tonic-gate #include <sys/cred.h>
357c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
377c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
387c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/time.h>
427c478bd9Sstevel@tonic-gate #include <sys/file.h>
437c478bd9Sstevel@tonic-gate #include <sys/user.h>
447c478bd9Sstevel@tonic-gate #include <sys/stream.h>
457c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
467c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/flock.h>
487c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
497c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
507c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
527c478bd9Sstevel@tonic-gate #include <sys/proc.h>
537c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <sys/suntpi.h>
567c478bd9Sstevel@tonic-gate #include <sys/socket.h>
577c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
587c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
59*0f1702c5SYu Xiangning #include <sys/sodirect.h>
607c478bd9Sstevel@tonic-gate #include <netinet/in.h>
61*0f1702c5SYu Xiangning #include <inet/common.h>
62*0f1702c5SYu Xiangning #include <inet/proto_set.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
657c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION	2
667c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
677c478bd9Sstevel@tonic-gate 
68c28749e9Skais #include <inet/kssl/ksslapi.h>
69c28749e9Skais 
707c478bd9Sstevel@tonic-gate #include <c2/audit.h>
717c478bd9Sstevel@tonic-gate 
72*0f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h>
73*0f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h>
7417169044Sbrutus #include <sys/dcopy.h>
7517169044Sbrutus 
767c478bd9Sstevel@tonic-gate int so_default_version = SOV_SOCKSTREAM;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #ifdef DEBUG
797c478bd9Sstevel@tonic-gate /* Set sockdebug to print debug messages when SO_DEBUG is set */
807c478bd9Sstevel@tonic-gate int sockdebug = 0;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* Set sockprinterr to print error messages when SO_DEBUG is set */
837c478bd9Sstevel@tonic-gate int sockprinterr = 0;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Set so_default_options to SO_DEBUG is all sockets should be created
877c478bd9Sstevel@tonic-gate  * with SO_DEBUG set. This is needed to get debug printouts from the
887c478bd9Sstevel@tonic-gate  * socket() call itself.
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate int so_default_options = 0;
917c478bd9Sstevel@tonic-gate #endif /* DEBUG */
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Set to number of ticks to limit cv_waits for code coverage testing.
967c478bd9Sstevel@tonic-gate  * Set to 1000 when SO_DEBUG is set to 2.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate clock_t sock_test_timelimit = 0;
997c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * For concurrency testing of e.g. opening /dev/ip which does not
1037c478bd9Sstevel@tonic-gate  * handle T_INFO_REQ messages.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate int so_no_tinfo = 0;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider
1097c478bd9Sstevel@tonic-gate  * to simply ignore the T_CAPABILITY_REQ.
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate clock_t	sock_capability_timeout	= 2;	/* seconds */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static int	do_tcapability(struct sonode *so, t_uscalar_t cap_bits1);
1147c478bd9Sstevel@tonic-gate static void	so_removehooks(struct sonode *so);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp,
1177c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1187c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups);
1197c478bd9Sstevel@tonic-gate static mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp,
1207c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1217c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups);
12217169044Sbrutus /*
123*0f1702c5SYu Xiangning  * STREAMS based sodirect put/wakeup functions.
12417169044Sbrutus  */
12517169044Sbrutus static int sodput(sodirect_t *, mblk_t *);
12617169044Sbrutus static void sodwakeup(sodirect_t *);
12717169044Sbrutus 
12817169044Sbrutus /*
12917169044Sbrutus  * Called by sockinit() when sockfs is loaded.
13017169044Sbrutus  */
13117169044Sbrutus int
13217169044Sbrutus sostr_init()
13317169044Sbrutus {
134*0f1702c5SYu Xiangning 	sod_init();
13517169044Sbrutus 	return (0);
13617169044Sbrutus }
13717169044Sbrutus 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Convert a socket to a stream. Invoked when the illusory sockmod
1407c478bd9Sstevel@tonic-gate  * is popped from the stream.
1417c478bd9Sstevel@tonic-gate  * Change the stream head back to default operation without losing
1427c478bd9Sstevel@tonic-gate  * any messages (T_conn_ind's are moved to the stream head queue).
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate int
1457c478bd9Sstevel@tonic-gate so_sock2stream(struct sonode *so)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	struct vnode		*vp = SOTOV(so);
1487c478bd9Sstevel@tonic-gate 	queue_t			*rq;
1497c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
1507c478bd9Sstevel@tonic-gate 	int			error = 0;
151*0f1702c5SYu Xiangning 	sotpi_info_t		*sti = SOTOTPI(so);
1527c478bd9Sstevel@tonic-gate 
153*0f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&sti->sti_plumb_lock));
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1567c478bd9Sstevel@tonic-gate 	so_lock_single(so);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	ASSERT(so->so_version != SOV_STREAM);
1597c478bd9Sstevel@tonic-gate 
160*0f1702c5SYu Xiangning 	if (sti->sti_direct) {
161ff550d0eSmasputra 		mblk_t **mpp;
162ff550d0eSmasputra 		int rval;
1637c478bd9Sstevel@tonic-gate 
164ff550d0eSmasputra 		/*
165ff550d0eSmasputra 		 * Tell the transport below that sockmod is being popped
166ff550d0eSmasputra 		 */
1677c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
168ff550d0eSmasputra 		error = strioctl(vp, _SIOCSOCKFALLBACK, 0, 0, K_TO_K, CRED(),
1697c478bd9Sstevel@tonic-gate 		    &rval);
1707c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
1717c478bd9Sstevel@tonic-gate 		if (error != 0) {
172ff550d0eSmasputra 			dprintso(so, 0, ("so_sock2stream(%p): "
173903a11ebSrh 			    "_SIOCSOCKFALLBACK failed\n", (void *)so));
1747c478bd9Sstevel@tonic-gate 			goto exit;
1757c478bd9Sstevel@tonic-gate 		}
176*0f1702c5SYu Xiangning 		sti->sti_direct = 0;
1777c478bd9Sstevel@tonic-gate 
178*0f1702c5SYu Xiangning 		for (mpp = &sti->sti_conn_ind_head; (mp = *mpp) != NULL;
1797c478bd9Sstevel@tonic-gate 		    mpp = &mp->b_next) {
1807c478bd9Sstevel@tonic-gate 			struct T_conn_ind	*conn_ind;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 			/*
1837c478bd9Sstevel@tonic-gate 			 * strsock_proto() has already verified the length of
1847c478bd9Sstevel@tonic-gate 			 * this message block.
1857c478bd9Sstevel@tonic-gate 			 */
1867c478bd9Sstevel@tonic-gate 			ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind));
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 			conn_ind = (struct T_conn_ind *)mp->b_rptr;
1897c478bd9Sstevel@tonic-gate 			if (conn_ind->OPT_length == 0 &&
1907c478bd9Sstevel@tonic-gate 			    conn_ind->OPT_offset == 0)
1917c478bd9Sstevel@tonic-gate 				continue;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 			if (DB_REF(mp) > 1) {
1947c478bd9Sstevel@tonic-gate 				mblk_t	*newmp;
1957c478bd9Sstevel@tonic-gate 				size_t	length;
1967c478bd9Sstevel@tonic-gate 				cred_t	*cr;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 				/*
1997c478bd9Sstevel@tonic-gate 				 * Copy the message block because it is used
2007c478bd9Sstevel@tonic-gate 				 * elsewhere, too.
2017c478bd9Sstevel@tonic-gate 				 */
2027c478bd9Sstevel@tonic-gate 				length = MBLKL(mp);
2037c478bd9Sstevel@tonic-gate 				newmp = soallocproto(length, _ALLOC_INTR);
2047c478bd9Sstevel@tonic-gate 				if (newmp == NULL) {
2057c478bd9Sstevel@tonic-gate 					error = EINTR;
2067c478bd9Sstevel@tonic-gate 					goto exit;
2077c478bd9Sstevel@tonic-gate 				}
2087c478bd9Sstevel@tonic-gate 				bcopy(mp->b_rptr, newmp->b_wptr, length);
2097c478bd9Sstevel@tonic-gate 				newmp->b_wptr += length;
2107c478bd9Sstevel@tonic-gate 				newmp->b_next = mp->b_next;
2117c478bd9Sstevel@tonic-gate 				cr = DB_CRED(mp);
2127c478bd9Sstevel@tonic-gate 				if (cr != NULL)
2137c478bd9Sstevel@tonic-gate 					mblk_setcred(newmp, cr);
2147c478bd9Sstevel@tonic-gate 				DB_CPID(newmp) = DB_CPID(mp);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 				/*
2177c478bd9Sstevel@tonic-gate 				 * Link the new message block into the queue
2187c478bd9Sstevel@tonic-gate 				 * and free the old one.
2197c478bd9Sstevel@tonic-gate 				 */
2207c478bd9Sstevel@tonic-gate 				*mpp = newmp;
2217c478bd9Sstevel@tonic-gate 				mp->b_next = NULL;
2227c478bd9Sstevel@tonic-gate 				freemsg(mp);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 				mp = newmp;
2257c478bd9Sstevel@tonic-gate 				conn_ind = (struct T_conn_ind *)mp->b_rptr;
2267c478bd9Sstevel@tonic-gate 			}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 			/*
2297c478bd9Sstevel@tonic-gate 			 * Remove options added by TCP for accept fast-path.
2307c478bd9Sstevel@tonic-gate 			 */
2317c478bd9Sstevel@tonic-gate 			conn_ind->OPT_length = 0;
2327c478bd9Sstevel@tonic-gate 			conn_ind->OPT_offset = 0;
2337c478bd9Sstevel@tonic-gate 		}
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	so->so_version = SOV_STREAM;
237*0f1702c5SYu Xiangning 	so->so_proto_handle = NULL;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/*
2407c478bd9Sstevel@tonic-gate 	 * Remove the hooks in the stream head to avoid queuing more
2417c478bd9Sstevel@tonic-gate 	 * packets in sockfs.
2427c478bd9Sstevel@tonic-gate 	 */
2437c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
2447c478bd9Sstevel@tonic-gate 	so_removehooks(so);
2457c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/*
2487c478bd9Sstevel@tonic-gate 	 * Clear any state related to urgent data. Leave any T_EXDATA_IND
2497c478bd9Sstevel@tonic-gate 	 * on the queue - the behavior of urgent data after a switch is
2507c478bd9Sstevel@tonic-gate 	 * left undefined.
2517c478bd9Sstevel@tonic-gate 	 */
252*0f1702c5SYu Xiangning 	so->so_error = sti->sti_delayed_error = 0;
2537c478bd9Sstevel@tonic-gate 	freemsg(so->so_oobmsg);
2547c478bd9Sstevel@tonic-gate 	so->so_oobmsg = NULL;
255*0f1702c5SYu Xiangning 	sti->sti_oobsigcnt = sti->sti_oobcnt = 0;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA|
258*0f1702c5SYu Xiangning 	    SS_SAVEDEOR);
2597c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
2607c478bd9Sstevel@tonic-gate 
261*0f1702c5SYu Xiangning 	freemsg(sti->sti_ack_mp);
262*0f1702c5SYu Xiangning 	sti->sti_ack_mp = NULL;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
265*0f1702c5SYu Xiangning 	 * Flush the T_DISCON_IND on sti_discon_ind_mp.
2667c478bd9Sstevel@tonic-gate 	 */
2677c478bd9Sstevel@tonic-gate 	so_flush_discon_ind(so);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/*
2707c478bd9Sstevel@tonic-gate 	 * Move any queued T_CONN_IND messages to stream head queue.
2717c478bd9Sstevel@tonic-gate 	 */
2727c478bd9Sstevel@tonic-gate 	rq = RD(strvp2wq(vp));
273*0f1702c5SYu Xiangning 	while ((mp = sti->sti_conn_ind_head) != NULL) {
274*0f1702c5SYu Xiangning 		sti->sti_conn_ind_head = mp->b_next;
2757c478bd9Sstevel@tonic-gate 		mp->b_next = NULL;
276*0f1702c5SYu Xiangning 		if (sti->sti_conn_ind_head == NULL) {
277*0f1702c5SYu Xiangning 			ASSERT(sti->sti_conn_ind_tail == mp);
278*0f1702c5SYu Xiangning 			sti->sti_conn_ind_tail = NULL;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
281*0f1702c5SYu Xiangning 		    ("so_sock2stream(%p): moving T_CONN_IND\n", (void *)so));
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		/* Drop lock across put() */
2847c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2857c478bd9Sstevel@tonic-gate 		put(rq, mp);
2867c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate exit:
2907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
2917c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
2927c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
2937c478bd9Sstevel@tonic-gate 	return (error);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * Covert a stream back to a socket. This is invoked when the illusory
2987c478bd9Sstevel@tonic-gate  * sockmod is pushed on a stream (where the stream was "created" by
2997c478bd9Sstevel@tonic-gate  * popping the illusory sockmod).
3007c478bd9Sstevel@tonic-gate  * This routine can not recreate the socket state (certain aspects of
3017c478bd9Sstevel@tonic-gate  * it like urgent data state and the bound/connected addresses for AF_UNIX
3027c478bd9Sstevel@tonic-gate  * sockets can not be recreated by asking the transport for information).
3037c478bd9Sstevel@tonic-gate  * Thus this routine implicitly assumes that the socket is in an initial
3047c478bd9Sstevel@tonic-gate  * state (as if it was just created). It flushes any messages queued on the
3057c478bd9Sstevel@tonic-gate  * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate void
3087c478bd9Sstevel@tonic-gate so_stream2sock(struct sonode *so)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
311*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
3127c478bd9Sstevel@tonic-gate 
313*0f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&sti->sti_plumb_lock));
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
3167c478bd9Sstevel@tonic-gate 	so_lock_single(so);
3177c478bd9Sstevel@tonic-gate 	ASSERT(so->so_version == SOV_STREAM);
3187c478bd9Sstevel@tonic-gate 	so->so_version = SOV_SOCKSTREAM;
319*0f1702c5SYu Xiangning 	sti->sti_pushcnt = 0;
3207c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/*
3237c478bd9Sstevel@tonic-gate 	 * Set a permenent error to force any thread in sorecvmsg to
3247c478bd9Sstevel@tonic-gate 	 * return (and drop SOREADLOCKED). Clear the error once
3257c478bd9Sstevel@tonic-gate 	 * we have SOREADLOCKED.
3267c478bd9Sstevel@tonic-gate 	 * This makes a read sleeping during the I_PUSH of sockmod return
3277c478bd9Sstevel@tonic-gate 	 * EIO.
3287c478bd9Sstevel@tonic-gate 	 */
3297c478bd9Sstevel@tonic-gate 	strsetrerror(SOTOV(so), EIO, 1, NULL);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/*
3327c478bd9Sstevel@tonic-gate 	 * Get the read lock before flushing data to avoid
3337c478bd9Sstevel@tonic-gate 	 * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg.
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
3367c478bd9Sstevel@tonic-gate 	(void) so_lock_read(so, 0);	/* Set SOREADLOCKED */
3377c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	strsetrerror(SOTOV(so), 0, 0, NULL);
3407c478bd9Sstevel@tonic-gate 	so_installhooks(so);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * Flush everything on the read queue.
3447c478bd9Sstevel@tonic-gate 	 * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND
3457c478bd9Sstevel@tonic-gate 	 * remain; those types of messages would confuse sockfs.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	strflushrq(vp, FLUSHALL);
3487c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/*
351*0f1702c5SYu Xiangning 	 * Flush the T_DISCON_IND on sti_discon_ind_mp.
3527c478bd9Sstevel@tonic-gate 	 */
3537c478bd9Sstevel@tonic-gate 	so_flush_discon_ind(so);
3547c478bd9Sstevel@tonic-gate 	so_unlock_read(so);	/* Clear SOREADLOCKED */
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
3577c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * Install the hooks in the stream head.
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate void
3647c478bd9Sstevel@tonic-gate so_installhooks(struct sonode *so)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA,
3697c478bd9Sstevel@tonic-gate 	    strsock_proto, strsock_misc);
3707c478bd9Sstevel@tonic-gate 	strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate /*
3747c478bd9Sstevel@tonic-gate  * Remove the hooks in the stream head.
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate static void
3777c478bd9Sstevel@tonic-gate so_removehooks(struct sonode *so)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	strsetrputhooks(vp, 0, NULL, NULL);
3827c478bd9Sstevel@tonic-gate 	strsetwputhooks(vp, 0, STRTIMOUT);
3837c478bd9Sstevel@tonic-gate 	/*
3847c478bd9Sstevel@tonic-gate 	 * Leave read behavior as it would have been for a normal
3857c478bd9Sstevel@tonic-gate 	 * stream i.e. a read of an M_PROTO will fail.
3867c478bd9Sstevel@tonic-gate 	 */
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
389*0f1702c5SYu Xiangning void
390*0f1702c5SYu Xiangning so_basic_strinit(struct sonode *so)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
3937c478bd9Sstevel@tonic-gate 	struct stdata *stp;
3947c478bd9Sstevel@tonic-gate 	mblk_t *mp;
395*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* Preallocate an unbind_req message */
3987c478bd9Sstevel@tonic-gate 	mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP);
3997c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
400*0f1702c5SYu Xiangning 	sti->sti_unbind_mp = mp;
4017c478bd9Sstevel@tonic-gate #ifdef DEBUG
4027c478bd9Sstevel@tonic-gate 	so->so_options = so_default_options;
4037c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4047c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	so_installhooks(so);
4077c478bd9Sstevel@tonic-gate 
408*0f1702c5SYu Xiangning 	stp = vp->v_stream;
409*0f1702c5SYu Xiangning 	/*
410*0f1702c5SYu Xiangning 	 * Have to keep minpsz at zero in order to allow write/send of zero
411*0f1702c5SYu Xiangning 	 * bytes.
412*0f1702c5SYu Xiangning 	 */
413*0f1702c5SYu Xiangning 	mutex_enter(&stp->sd_lock);
414*0f1702c5SYu Xiangning 	if (stp->sd_qn_minpsz == 1)
415*0f1702c5SYu Xiangning 		stp->sd_qn_minpsz = 0;
416*0f1702c5SYu Xiangning 	mutex_exit(&stp->sd_lock);
417*0f1702c5SYu Xiangning 
418*0f1702c5SYu Xiangning 	/*
419*0f1702c5SYu Xiangning 	 * If sodirect capable allocate and initialize sodirect_t.
420*0f1702c5SYu Xiangning 	 * Note, SS_SODIRECT is set in socktpi_open().
421*0f1702c5SYu Xiangning 	 */
422*0f1702c5SYu Xiangning 	if ((so->so_state & SS_SODIRECT) &&
423*0f1702c5SYu Xiangning 	    !(so->so_state & SS_FALLBACK_PENDING)) {
424*0f1702c5SYu Xiangning 		sod_sock_init(so, stp, sodput, sodwakeup, &stp->sd_lock);
425*0f1702c5SYu Xiangning 	}
426*0f1702c5SYu Xiangning }
427*0f1702c5SYu Xiangning 
428*0f1702c5SYu Xiangning /*
429*0f1702c5SYu Xiangning  * Initialize the streams side of a socket including
430*0f1702c5SYu Xiangning  * T_info_req/ack processing. If tso is not NULL its values are used thereby
431*0f1702c5SYu Xiangning  * avoiding the T_INFO_REQ.
432*0f1702c5SYu Xiangning  */
433*0f1702c5SYu Xiangning int
434*0f1702c5SYu Xiangning so_strinit(struct sonode *so, struct sonode *tso)
435*0f1702c5SYu Xiangning {
436*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
437*0f1702c5SYu Xiangning 	sotpi_info_t *tsti;
438*0f1702c5SYu Xiangning 	int error;
439*0f1702c5SYu Xiangning 
440*0f1702c5SYu Xiangning 	so_basic_strinit(so);
441*0f1702c5SYu Xiangning 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * The T_CAPABILITY_REQ should be the first message sent down because
4447c478bd9Sstevel@tonic-gate 	 * at least TCP has a fast-path for this which avoids timeouts while
4457c478bd9Sstevel@tonic-gate 	 * waiting for the T_CAPABILITY_ACK under high system load.
4467c478bd9Sstevel@tonic-gate 	 */
4477c478bd9Sstevel@tonic-gate 	if (tso == NULL) {
4487c478bd9Sstevel@tonic-gate 		error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO);
4497c478bd9Sstevel@tonic-gate 		if (error)
4507c478bd9Sstevel@tonic-gate 			return (error);
4517c478bd9Sstevel@tonic-gate 	} else {
452*0f1702c5SYu Xiangning 		tsti = SOTOTPI(tso);
453*0f1702c5SYu Xiangning 
4547c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
455*0f1702c5SYu Xiangning 		sti->sti_tsdu_size = tsti->sti_tsdu_size;
456*0f1702c5SYu Xiangning 		sti->sti_etsdu_size = tsti->sti_etsdu_size;
457*0f1702c5SYu Xiangning 		sti->sti_addr_size = tsti->sti_addr_size;
458*0f1702c5SYu Xiangning 		sti->sti_opt_size = tsti->sti_opt_size;
459*0f1702c5SYu Xiangning 		sti->sti_tidu_size = tsti->sti_tidu_size;
460*0f1702c5SYu Xiangning 		sti->sti_serv_type = tsti->sti_serv_type;
4617c478bd9Sstevel@tonic-gate 		so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID;
4627c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 		/* the following do_tcapability may update so->so_mode */
465*0f1702c5SYu Xiangning 		if ((tsti->sti_serv_type != T_CLTS) &&
466*0f1702c5SYu Xiangning 		    (sti->sti_direct == 0)) {
4677c478bd9Sstevel@tonic-gate 			error = do_tcapability(so, TC1_ACCEPTOR_ID);
4687c478bd9Sstevel@tonic-gate 			if (error)
4697c478bd9Sstevel@tonic-gate 				return (error);
4707c478bd9Sstevel@tonic-gate 		}
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * If the addr_size is 0 we treat it as already bound
4747c478bd9Sstevel@tonic-gate 	 * and connected. This is used by the routing socket.
4757c478bd9Sstevel@tonic-gate 	 * We set the addr_size to something to allocate a the address
4767c478bd9Sstevel@tonic-gate 	 * structures.
4777c478bd9Sstevel@tonic-gate 	 */
478*0f1702c5SYu Xiangning 	if (sti->sti_addr_size == 0) {
4797c478bd9Sstevel@tonic-gate 		so->so_state |= SS_ISBOUND | SS_ISCONNECTED;
4807c478bd9Sstevel@tonic-gate 		/* Address size can vary with address families. */
4817c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_INET6)
482*0f1702c5SYu Xiangning 			sti->sti_addr_size =
4837c478bd9Sstevel@tonic-gate 			    (t_scalar_t)sizeof (struct sockaddr_in6);
4847c478bd9Sstevel@tonic-gate 		else
485*0f1702c5SYu Xiangning 			sti->sti_addr_size =
4867c478bd9Sstevel@tonic-gate 			    (t_scalar_t)sizeof (struct sockaddr_in);
487*0f1702c5SYu Xiangning 		ASSERT(sti->sti_unbind_mp);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
490*0f1702c5SYu Xiangning 	so_alloc_addr(so, sti->sti_addr_size);
49117169044Sbrutus 
4927c478bd9Sstevel@tonic-gate 	return (0);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate static void
4967c478bd9Sstevel@tonic-gate copy_tinfo(struct sonode *so, struct T_info_ack *tia)
4977c478bd9Sstevel@tonic-gate {
498*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
499*0f1702c5SYu Xiangning 
500*0f1702c5SYu Xiangning 	sti->sti_tsdu_size = tia->TSDU_size;
501*0f1702c5SYu Xiangning 	sti->sti_etsdu_size = tia->ETSDU_size;
502*0f1702c5SYu Xiangning 	sti->sti_addr_size = tia->ADDR_size;
503*0f1702c5SYu Xiangning 	sti->sti_opt_size = tia->OPT_size;
504*0f1702c5SYu Xiangning 	sti->sti_tidu_size = tia->TIDU_size;
505*0f1702c5SYu Xiangning 	sti->sti_serv_type = tia->SERV_type;
5067c478bd9Sstevel@tonic-gate 	switch (tia->CURRENT_state) {
5077c478bd9Sstevel@tonic-gate 	case TS_UNBND:
5087c478bd9Sstevel@tonic-gate 		break;
5097c478bd9Sstevel@tonic-gate 	case TS_IDLE:
5107c478bd9Sstevel@tonic-gate 		so->so_state |= SS_ISBOUND;
511*0f1702c5SYu Xiangning 		sti->sti_laddr_len = 0;
512*0f1702c5SYu Xiangning 		sti->sti_laddr_valid = 0;
5137c478bd9Sstevel@tonic-gate 		break;
5147c478bd9Sstevel@tonic-gate 	case TS_DATA_XFER:
5157c478bd9Sstevel@tonic-gate 		so->so_state |= SS_ISBOUND|SS_ISCONNECTED;
516*0f1702c5SYu Xiangning 		sti->sti_laddr_len = 0;
517*0f1702c5SYu Xiangning 		sti->sti_faddr_len = 0;
518*0f1702c5SYu Xiangning 		sti->sti_laddr_valid = 0;
519*0f1702c5SYu Xiangning 		sti->sti_faddr_valid = 0;
5207c478bd9Sstevel@tonic-gate 		break;
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * Heuristics for determining the socket mode flags
5257c478bd9Sstevel@tonic-gate 	 * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING,
5267c478bd9Sstevel@tonic-gate 	 * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM)
5277c478bd9Sstevel@tonic-gate 	 * from the info ack.
5287c478bd9Sstevel@tonic-gate 	 */
529*0f1702c5SYu Xiangning 	if (sti->sti_serv_type == T_CLTS) {
5307c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_ATOMIC | SM_ADDR;
5317c478bd9Sstevel@tonic-gate 	} else {
5327c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_CONNREQUIRED;
533*0f1702c5SYu Xiangning 		if (sti->sti_etsdu_size != 0 && sti->sti_etsdu_size != -2)
5347c478bd9Sstevel@tonic-gate 			so->so_mode |= SM_EXDATA;
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 	if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) {
5377c478bd9Sstevel@tonic-gate 		/* Semantics are to discard tail end of messages */
5387c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_ATOMIC;
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_UNIX) {
5417c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_FDPASSING | SM_OPTDATA;
542*0f1702c5SYu Xiangning 		if (sti->sti_addr_size == -1) {
5437c478bd9Sstevel@tonic-gate 			/* MAXPATHLEN + soun_family + nul termination */
544*0f1702c5SYu Xiangning 			sti->sti_addr_size = (t_scalar_t)(MAXPATHLEN +
545d3e55dcdSgww 			    sizeof (short) + 1);
5467c478bd9Sstevel@tonic-gate 		}
5477c478bd9Sstevel@tonic-gate 		if (so->so_type == SOCK_STREAM) {
5487c478bd9Sstevel@tonic-gate 			/*
5497c478bd9Sstevel@tonic-gate 			 * Make it into a byte-stream transport.
5507c478bd9Sstevel@tonic-gate 			 * SOCK_SEQPACKET sockets are unchanged.
5517c478bd9Sstevel@tonic-gate 			 */
552*0f1702c5SYu Xiangning 			sti->sti_tsdu_size = 0;
5537c478bd9Sstevel@tonic-gate 		}
554*0f1702c5SYu Xiangning 	} else if (sti->sti_addr_size == -1) {
5557c478bd9Sstevel@tonic-gate 		/*
5567c478bd9Sstevel@tonic-gate 		 * Logic extracted from sockmod - have to pick some max address
5577c478bd9Sstevel@tonic-gate 		 * length in order to preallocate the addresses.
5587c478bd9Sstevel@tonic-gate 		 */
559*0f1702c5SYu Xiangning 		sti->sti_addr_size = SOA_DEFSIZE;
5607c478bd9Sstevel@tonic-gate 	}
561*0f1702c5SYu Xiangning 	if (sti->sti_tsdu_size == 0)
5627c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_BYTESTREAM;
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate static int
5667c478bd9Sstevel@tonic-gate check_tinfo(struct sonode *so)
5677c478bd9Sstevel@tonic-gate {
568*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
569*0f1702c5SYu Xiangning 
5707c478bd9Sstevel@tonic-gate 	/* Consistency checks */
571*0f1702c5SYu Xiangning 	if (so->so_type == SOCK_DGRAM && sti->sti_serv_type != T_CLTS) {
5727c478bd9Sstevel@tonic-gate 		eprintso(so, ("service type and socket type mismatch\n"));
5737c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
5747c478bd9Sstevel@tonic-gate 		return (EPROTO);
5757c478bd9Sstevel@tonic-gate 	}
576*0f1702c5SYu Xiangning 	if (so->so_type == SOCK_STREAM && sti->sti_serv_type == T_CLTS) {
5777c478bd9Sstevel@tonic-gate 		eprintso(so, ("service type and socket type mismatch\n"));
5787c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
5797c478bd9Sstevel@tonic-gate 		return (EPROTO);
5807c478bd9Sstevel@tonic-gate 	}
581*0f1702c5SYu Xiangning 	if (so->so_type == SOCK_SEQPACKET && sti->sti_serv_type == T_CLTS) {
5827c478bd9Sstevel@tonic-gate 		eprintso(so, ("service type and socket type mismatch\n"));
5837c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
5847c478bd9Sstevel@tonic-gate 		return (EPROTO);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_INET &&
587*0f1702c5SYu Xiangning 	    sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) {
5887c478bd9Sstevel@tonic-gate 		eprintso(so,
5897c478bd9Sstevel@tonic-gate 		    ("AF_INET must have sockaddr_in address length. Got %d\n",
590*0f1702c5SYu Xiangning 		    sti->sti_addr_size));
5917c478bd9Sstevel@tonic-gate 		eprintsoline(so, EMSGSIZE);
5927c478bd9Sstevel@tonic-gate 		return (EMSGSIZE);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_INET6 &&
595*0f1702c5SYu Xiangning 	    sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) {
5967c478bd9Sstevel@tonic-gate 		eprintso(so,
5977c478bd9Sstevel@tonic-gate 		    ("AF_INET6 must have sockaddr_in6 address length. Got %d\n",
598*0f1702c5SYu Xiangning 		    sti->sti_addr_size));
5997c478bd9Sstevel@tonic-gate 		eprintsoline(so, EMSGSIZE);
6007c478bd9Sstevel@tonic-gate 		return (EMSGSIZE);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	dprintso(so, 1, (
6047c478bd9Sstevel@tonic-gate 	    "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n",
605*0f1702c5SYu Xiangning 	    sti->sti_serv_type, sti->sti_tsdu_size, sti->sti_etsdu_size,
606*0f1702c5SYu Xiangning 	    sti->sti_addr_size, sti->sti_opt_size,
607*0f1702c5SYu Xiangning 	    sti->sti_tidu_size));
6087c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("tinfo: so_state %s\n",
609d3e55dcdSgww 	    pr_state(so->so_state, so->so_mode)));
6107c478bd9Sstevel@tonic-gate 	return (0);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate /*
6147c478bd9Sstevel@tonic-gate  * Send down T_info_req and wait for the ack.
6157c478bd9Sstevel@tonic-gate  * Record interesting T_info_ack values in the sonode.
6167c478bd9Sstevel@tonic-gate  */
6177c478bd9Sstevel@tonic-gate static int
6187c478bd9Sstevel@tonic-gate do_tinfo(struct sonode *so)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate 	struct T_info_req tir;
6217c478bd9Sstevel@tonic-gate 	mblk_t *mp;
6227c478bd9Sstevel@tonic-gate 	int error;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (so_no_tinfo) {
627*0f1702c5SYu Xiangning 		SOTOTPI(so)->sti_addr_size = 0;
6287c478bd9Sstevel@tonic-gate 		return (0);
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
631903a11ebSrh 	dprintso(so, 1, ("do_tinfo(%p)\n", (void *)so));
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	/* Send T_INFO_REQ */
6347c478bd9Sstevel@tonic-gate 	tir.PRIM_type = T_INFO_REQ;
6357c478bd9Sstevel@tonic-gate 	mp = soallocproto1(&tir, sizeof (tir),
6367c478bd9Sstevel@tonic-gate 	    sizeof (struct T_info_req) + sizeof (struct T_info_ack),
6377c478bd9Sstevel@tonic-gate 	    _ALLOC_INTR);
6387c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
6397c478bd9Sstevel@tonic-gate 		eprintsoline(so, ENOBUFS);
6407c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	/* T_INFO_REQ has to be M_PCPROTO */
6437c478bd9Sstevel@tonic-gate 	DB_TYPE(mp) = M_PCPROTO;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
646d3e55dcdSgww 	    MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
6477c478bd9Sstevel@tonic-gate 	if (error) {
6487c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
6497c478bd9Sstevel@tonic-gate 		return (error);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
6527c478bd9Sstevel@tonic-gate 	/* Wait for T_INFO_ACK */
6537c478bd9Sstevel@tonic-gate 	if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK,
6547c478bd9Sstevel@tonic-gate 	    (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) {
6557c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
6567c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
6577c478bd9Sstevel@tonic-gate 		return (error);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	ASSERT(mp);
6617c478bd9Sstevel@tonic-gate 	copy_tinfo(so, (struct T_info_ack *)mp->b_rptr);
6627c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
6637c478bd9Sstevel@tonic-gate 	freemsg(mp);
6647c478bd9Sstevel@tonic-gate 	return (check_tinfo(so));
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate /*
6687c478bd9Sstevel@tonic-gate  * Send down T_capability_req and wait for the ack.
6697c478bd9Sstevel@tonic-gate  * Record interesting T_capability_ack values in the sonode.
6707c478bd9Sstevel@tonic-gate  */
6717c478bd9Sstevel@tonic-gate static int
6727c478bd9Sstevel@tonic-gate do_tcapability(struct sonode *so, t_uscalar_t cap_bits1)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate 	struct T_capability_req tcr;
6757c478bd9Sstevel@tonic-gate 	struct T_capability_ack *tca;
6767c478bd9Sstevel@tonic-gate 	mblk_t *mp;
6777c478bd9Sstevel@tonic-gate 	int error;
678*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	ASSERT(cap_bits1 != 0);
6817c478bd9Sstevel@tonic-gate 	ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0);
6827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6837c478bd9Sstevel@tonic-gate 
684*0f1702c5SYu Xiangning 	if (sti->sti_provinfo->tpi_capability == PI_NO)
6857c478bd9Sstevel@tonic-gate 		return (do_tinfo(so));
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (so_no_tinfo) {
688*0f1702c5SYu Xiangning 		sti->sti_addr_size = 0;
6897c478bd9Sstevel@tonic-gate 		if ((cap_bits1 &= ~TC1_INFO) == 0)
6907c478bd9Sstevel@tonic-gate 			return (0);
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
693903a11ebSrh 	dprintso(so, 1, ("do_tcapability(%p)\n", (void *)so));
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/* Send T_CAPABILITY_REQ */
6967c478bd9Sstevel@tonic-gate 	tcr.PRIM_type = T_CAPABILITY_REQ;
6977c478bd9Sstevel@tonic-gate 	tcr.CAP_bits1 = cap_bits1;
6987c478bd9Sstevel@tonic-gate 	mp = soallocproto1(&tcr, sizeof (tcr),
6997c478bd9Sstevel@tonic-gate 	    sizeof (struct T_capability_req) + sizeof (struct T_capability_ack),
7007c478bd9Sstevel@tonic-gate 	    _ALLOC_INTR);
7017c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
7027c478bd9Sstevel@tonic-gate 		eprintsoline(so, ENOBUFS);
7037c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 	/* T_CAPABILITY_REQ should be M_PCPROTO here */
7067c478bd9Sstevel@tonic-gate 	DB_TYPE(mp) = M_PCPROTO;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
7097c478bd9Sstevel@tonic-gate 	    MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
7107c478bd9Sstevel@tonic-gate 	if (error) {
7117c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
7127c478bd9Sstevel@tonic-gate 		return (error);
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
7157c478bd9Sstevel@tonic-gate 	/* Wait for T_CAPABILITY_ACK */
7167c478bd9Sstevel@tonic-gate 	if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK,
7177c478bd9Sstevel@tonic-gate 	    (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) {
7187c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
719*0f1702c5SYu Xiangning 		PI_PROVLOCK(sti->sti_provinfo);
720*0f1702c5SYu Xiangning 		if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW)
721*0f1702c5SYu Xiangning 			sti->sti_provinfo->tpi_capability = PI_NO;
722*0f1702c5SYu Xiangning 		PI_PROVUNLOCK(sti->sti_provinfo);
7237c478bd9Sstevel@tonic-gate 		ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0);
7247c478bd9Sstevel@tonic-gate 		if (cap_bits1 & TC1_INFO) {
7257c478bd9Sstevel@tonic-gate 			/*
7267c478bd9Sstevel@tonic-gate 			 * If the T_CAPABILITY_REQ timed out and then a
7277c478bd9Sstevel@tonic-gate 			 * T_INFO_REQ gets a protocol error, most likely
7287c478bd9Sstevel@tonic-gate 			 * the capability was slow (vs. unsupported). Return
7297c478bd9Sstevel@tonic-gate 			 * ENOSR for this case as a best guess.
7307c478bd9Sstevel@tonic-gate 			 */
7317c478bd9Sstevel@tonic-gate 			if (error == ETIME) {
7327c478bd9Sstevel@tonic-gate 				return ((error = do_tinfo(so)) == EPROTO ?
7337c478bd9Sstevel@tonic-gate 				    ENOSR : error);
7347c478bd9Sstevel@tonic-gate 			}
7357c478bd9Sstevel@tonic-gate 			return (do_tinfo(so));
7367c478bd9Sstevel@tonic-gate 		}
7377c478bd9Sstevel@tonic-gate 		return (0);
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	ASSERT(mp);
7417c478bd9Sstevel@tonic-gate 	tca = (struct T_capability_ack *)mp->b_rptr;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO));
744*0f1702c5SYu Xiangning 	so_proc_tcapability_ack(so, tca);
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	cap_bits1 = tca->CAP_bits1;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
7497c478bd9Sstevel@tonic-gate 	freemsg(mp);
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	if (cap_bits1 & TC1_INFO)
7527c478bd9Sstevel@tonic-gate 		return (check_tinfo(so));
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	return (0);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate /*
758*0f1702c5SYu Xiangning  * Process a T_CAPABILITY_ACK
759*0f1702c5SYu Xiangning  */
760*0f1702c5SYu Xiangning void
761*0f1702c5SYu Xiangning so_proc_tcapability_ack(struct sonode *so, struct T_capability_ack *tca)
762*0f1702c5SYu Xiangning {
763*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
764*0f1702c5SYu Xiangning 
765*0f1702c5SYu Xiangning 	if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW) {
766*0f1702c5SYu Xiangning 		PI_PROVLOCK(sti->sti_provinfo);
767*0f1702c5SYu Xiangning 		sti->sti_provinfo->tpi_capability = PI_YES;
768*0f1702c5SYu Xiangning 		PI_PROVUNLOCK(sti->sti_provinfo);
769*0f1702c5SYu Xiangning 	}
770*0f1702c5SYu Xiangning 
771*0f1702c5SYu Xiangning 	if (tca->CAP_bits1 & TC1_ACCEPTOR_ID) {
772*0f1702c5SYu Xiangning 		sti->sti_acceptor_id = tca->ACCEPTOR_id;
773*0f1702c5SYu Xiangning 		so->so_mode |= SM_ACCEPTOR_ID;
774*0f1702c5SYu Xiangning 	}
775*0f1702c5SYu Xiangning 
776*0f1702c5SYu Xiangning 	if (tca->CAP_bits1 & TC1_INFO)
777*0f1702c5SYu Xiangning 		copy_tinfo(so, &tca->INFO_ack);
778*0f1702c5SYu Xiangning }
779*0f1702c5SYu Xiangning 
780*0f1702c5SYu Xiangning /*
781*0f1702c5SYu Xiangning  * Retrieve socket error, clear error if not peek.
7827c478bd9Sstevel@tonic-gate  */
7837c478bd9Sstevel@tonic-gate int
784*0f1702c5SYu Xiangning sogeterr(struct sonode *so, boolean_t clear_err)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	int error;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	error = so->so_error;
791*0f1702c5SYu Xiangning 	if (clear_err)
792*0f1702c5SYu Xiangning 		so->so_error = 0;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	return (error);
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate /*
7987c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to retrieve read
7997c478bd9Sstevel@tonic-gate  * side errors.
8007c478bd9Sstevel@tonic-gate  * It does not clear the socket error for a peeking read side operation.
8017c478bd9Sstevel@tonic-gate  * It the error is to be cleared it sets *clearerr.
8027c478bd9Sstevel@tonic-gate  */
8037c478bd9Sstevel@tonic-gate int
8047c478bd9Sstevel@tonic-gate sogetrderr(vnode_t *vp, int ispeek, int *clearerr)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate 	struct sonode *so = VTOSO(vp);
8077c478bd9Sstevel@tonic-gate 	int error;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
8107c478bd9Sstevel@tonic-gate 	if (ispeek) {
8117c478bd9Sstevel@tonic-gate 		error = so->so_error;
8127c478bd9Sstevel@tonic-gate 		*clearerr = 0;
8137c478bd9Sstevel@tonic-gate 	} else {
8147c478bd9Sstevel@tonic-gate 		error = so->so_error;
8157c478bd9Sstevel@tonic-gate 		so->so_error = 0;
8167c478bd9Sstevel@tonic-gate 		*clearerr = 1;
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
8197c478bd9Sstevel@tonic-gate 	return (error);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to retrieve write
8247c478bd9Sstevel@tonic-gate  * side errors.
8257c478bd9Sstevel@tonic-gate  * It does not clear the socket error for a peeking read side operation.
8267c478bd9Sstevel@tonic-gate  * It the error is to be cleared it sets *clearerr.
8277c478bd9Sstevel@tonic-gate  */
8287c478bd9Sstevel@tonic-gate int
8297c478bd9Sstevel@tonic-gate sogetwrerr(vnode_t *vp, int ispeek, int *clearerr)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	struct sonode *so = VTOSO(vp);
8327c478bd9Sstevel@tonic-gate 	int error;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
8357c478bd9Sstevel@tonic-gate 	if (so->so_state & SS_CANTSENDMORE) {
8367c478bd9Sstevel@tonic-gate 		error = EPIPE;
8377c478bd9Sstevel@tonic-gate 		*clearerr = 0;
8387c478bd9Sstevel@tonic-gate 	} else {
8397c478bd9Sstevel@tonic-gate 		error = so->so_error;
8407c478bd9Sstevel@tonic-gate 		if (ispeek) {
8417c478bd9Sstevel@tonic-gate 			*clearerr = 0;
8427c478bd9Sstevel@tonic-gate 		} else {
8437c478bd9Sstevel@tonic-gate 			so->so_error = 0;
8447c478bd9Sstevel@tonic-gate 			*clearerr = 1;
8457c478bd9Sstevel@tonic-gate 		}
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
8487c478bd9Sstevel@tonic-gate 	return (error);
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate  * Set a nonpersistent read and write error on the socket.
8537c478bd9Sstevel@tonic-gate  * Used when there is a T_uderror_ind for a connected socket.
8547c478bd9Sstevel@tonic-gate  * The caller also needs to call strsetrerror and strsetwerror
8557c478bd9Sstevel@tonic-gate  * after dropping the lock.
8567c478bd9Sstevel@tonic-gate  */
8577c478bd9Sstevel@tonic-gate void
8587c478bd9Sstevel@tonic-gate soseterror(struct sonode *so, int error)
8597c478bd9Sstevel@tonic-gate {
8607c478bd9Sstevel@tonic-gate 	ASSERT(error != 0);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
8637c478bd9Sstevel@tonic-gate 	so->so_error = (ushort_t)error;
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate void
8677c478bd9Sstevel@tonic-gate soisconnecting(struct sonode *so)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
8707c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
8717c478bd9Sstevel@tonic-gate 	so->so_state |= SS_ISCONNECTING;
8727c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate void
8767c478bd9Sstevel@tonic-gate soisconnected(struct sonode *so)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
8797c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
8807c478bd9Sstevel@tonic-gate 	so->so_state |= SS_ISCONNECTED;
8817c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * The caller also needs to call strsetrerror, strsetwerror and strseteof.
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate void
8887c478bd9Sstevel@tonic-gate soisdisconnected(struct sonode *so, int error)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
891*0f1702c5SYu Xiangning 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
8927c478bd9Sstevel@tonic-gate 	so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
8937c478bd9Sstevel@tonic-gate 	so->so_error = (ushort_t)error;
8947c478bd9Sstevel@tonic-gate 	if (so->so_peercred != NULL) {
8957c478bd9Sstevel@tonic-gate 		crfree(so->so_peercred);
8967c478bd9Sstevel@tonic-gate 		so->so_peercred = NULL;
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate /*
9027c478bd9Sstevel@tonic-gate  * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes.
9037c478bd9Sstevel@tonic-gate  * Does not affect write side.
9047c478bd9Sstevel@tonic-gate  * The caller also has to call strsetrerror.
9057c478bd9Sstevel@tonic-gate  */
9067c478bd9Sstevel@tonic-gate static void
9077c478bd9Sstevel@tonic-gate sobreakconn(struct sonode *so, int error)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
9107c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
9117c478bd9Sstevel@tonic-gate 	so->so_error = (ushort_t)error;
9127c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate /*
9167c478bd9Sstevel@tonic-gate  * Can no longer send.
9177c478bd9Sstevel@tonic-gate  * Caller must also call strsetwerror.
9187c478bd9Sstevel@tonic-gate  *
9197c478bd9Sstevel@tonic-gate  * We mark the peer address as no longer valid for getpeername, but
9207c478bd9Sstevel@tonic-gate  * leave it around for so_unix_close to notify the peer (that
9217c478bd9Sstevel@tonic-gate  * transport has no addressing held at that layer).
9227c478bd9Sstevel@tonic-gate  */
9237c478bd9Sstevel@tonic-gate void
9247c478bd9Sstevel@tonic-gate socantsendmore(struct sonode *so)
9257c478bd9Sstevel@tonic-gate {
9267c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
927*0f1702c5SYu Xiangning 	so->so_state |= SS_CANTSENDMORE;
9287c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate /*
9327c478bd9Sstevel@tonic-gate  * The caller must call strseteof(,1) as well as this routine
9337c478bd9Sstevel@tonic-gate  * to change the socket state.
9347c478bd9Sstevel@tonic-gate  */
9357c478bd9Sstevel@tonic-gate void
9367c478bd9Sstevel@tonic-gate socantrcvmore(struct sonode *so)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
9397c478bd9Sstevel@tonic-gate 	so->so_state |= SS_CANTRCVMORE;
9407c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate  * The caller has sent down a "request_prim" primitive and wants to wait for
9457c478bd9Sstevel@tonic-gate  * an ack ("ack_prim") or an T_ERROR_ACK for it.
9467c478bd9Sstevel@tonic-gate  * The specified "ack_prim" can be a T_OK_ACK.
9477c478bd9Sstevel@tonic-gate  *
9487c478bd9Sstevel@tonic-gate  * Assumes that all the TPI acks are M_PCPROTO messages.
9497c478bd9Sstevel@tonic-gate  *
9507c478bd9Sstevel@tonic-gate  * Note that the socket is single-threaded (using so_lock_single)
9517c478bd9Sstevel@tonic-gate  * for all operations that generate TPI ack messages. Since
9527c478bd9Sstevel@tonic-gate  * only TPI ack messages are M_PCPROTO we should never receive
9537c478bd9Sstevel@tonic-gate  * anything except either the ack we are expecting or a T_ERROR_ACK
9547c478bd9Sstevel@tonic-gate  * for the same primitive.
9557c478bd9Sstevel@tonic-gate  */
9567c478bd9Sstevel@tonic-gate int
9577c478bd9Sstevel@tonic-gate sowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim,
9587c478bd9Sstevel@tonic-gate 	    t_uscalar_t min_size, mblk_t **mpp, clock_t wait)
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate 	mblk_t *mp;
9617c478bd9Sstevel@tonic-gate 	union T_primitives *tpr;
9627c478bd9Sstevel@tonic-gate 	int error;
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n",
965903a11ebSrh 	    (void *)so, request_prim, ack_prim, min_size, (void *)mpp, wait));
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	error = sowaitack(so, &mp, wait);
9707c478bd9Sstevel@tonic-gate 	if (error)
9717c478bd9Sstevel@tonic-gate 		return (error);
9727c478bd9Sstevel@tonic-gate 
973903a11ebSrh 	dprintso(so, 1, ("got msg %p\n", (void *)mp));
9747c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_PCPROTO ||
9757c478bd9Sstevel@tonic-gate 	    MBLKL(mp) < sizeof (tpr->type)) {
9767c478bd9Sstevel@tonic-gate 		freemsg(mp);
9777c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
9787c478bd9Sstevel@tonic-gate 		return (EPROTO);
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 	tpr = (union T_primitives *)mp->b_rptr;
9817c478bd9Sstevel@tonic-gate 	/*
9827c478bd9Sstevel@tonic-gate 	 * Did we get the primitive that we were asking for?
9837c478bd9Sstevel@tonic-gate 	 * For T_OK_ACK we also check that it matches the request primitive.
9847c478bd9Sstevel@tonic-gate 	 */
9857c478bd9Sstevel@tonic-gate 	if (tpr->type == ack_prim &&
9867c478bd9Sstevel@tonic-gate 	    (ack_prim != T_OK_ACK ||
9877c478bd9Sstevel@tonic-gate 	    tpr->ok_ack.CORRECT_prim == request_prim)) {
9887c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) >= (ssize_t)min_size) {
9897c478bd9Sstevel@tonic-gate 			/* Found what we are looking for */
9907c478bd9Sstevel@tonic-gate 			*mpp = mp;
9917c478bd9Sstevel@tonic-gate 			return (0);
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 		/* Too short */
9947c478bd9Sstevel@tonic-gate 		freemsg(mp);
9957c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
9967c478bd9Sstevel@tonic-gate 		return (EPROTO);
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	if (tpr->type == T_ERROR_ACK &&
10007c478bd9Sstevel@tonic-gate 	    tpr->error_ack.ERROR_prim == request_prim) {
10017c478bd9Sstevel@tonic-gate 		/* Error to the primitive we were looking for */
10027c478bd9Sstevel@tonic-gate 		if (tpr->error_ack.TLI_error == TSYSERR) {
10037c478bd9Sstevel@tonic-gate 			error = tpr->error_ack.UNIX_error;
10047c478bd9Sstevel@tonic-gate 		} else {
1005*0f1702c5SYu Xiangning 			error = proto_tlitosyserr(tpr->error_ack.TLI_error);
10067c478bd9Sstevel@tonic-gate 		}
10077c478bd9Sstevel@tonic-gate 		dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n",
1008*0f1702c5SYu Xiangning 		    tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error,
1009*0f1702c5SYu Xiangning 		    tpr->error_ack.UNIX_error, error));
10107c478bd9Sstevel@tonic-gate 		freemsg(mp);
10117c478bd9Sstevel@tonic-gate 		return (error);
10127c478bd9Sstevel@tonic-gate 	}
10137c478bd9Sstevel@tonic-gate 	/*
10147c478bd9Sstevel@tonic-gate 	 * Wrong primitive or T_ERROR_ACK for the wrong primitive
10157c478bd9Sstevel@tonic-gate 	 */
10167c478bd9Sstevel@tonic-gate #ifdef DEBUG
10177c478bd9Sstevel@tonic-gate 	if (tpr->type == T_ERROR_ACK) {
10187c478bd9Sstevel@tonic-gate 		dprintso(so, 0, ("error_ack for %d: %d/%d\n",
1019*0f1702c5SYu Xiangning 		    tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error,
1020d3e55dcdSgww 		    tpr->error_ack.UNIX_error));
10217c478bd9Sstevel@tonic-gate 	} else if (tpr->type == T_OK_ACK) {
10227c478bd9Sstevel@tonic-gate 		dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n",
1023*0f1702c5SYu Xiangning 		    tpr->ok_ack.CORRECT_prim, ack_prim, request_prim));
10247c478bd9Sstevel@tonic-gate 	} else {
10257c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
1026d3e55dcdSgww 		    ("unexpected primitive %d, expected %d for %d\n",
1027d3e55dcdSgww 		    tpr->type, ack_prim, request_prim));
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate #endif /* DEBUG */
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	freemsg(mp);
10327c478bd9Sstevel@tonic-gate 	eprintsoline(so, EPROTO);
10337c478bd9Sstevel@tonic-gate 	return (EPROTO);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * Wait for a T_OK_ACK for the specified primitive.
10387c478bd9Sstevel@tonic-gate  */
10397c478bd9Sstevel@tonic-gate int
10407c478bd9Sstevel@tonic-gate sowaitokack(struct sonode *so, t_scalar_t request_prim)
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate 	mblk_t *mp;
10437c478bd9Sstevel@tonic-gate 	int error;
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	error = sowaitprim(so, request_prim, T_OK_ACK,
10467c478bd9Sstevel@tonic-gate 	    (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0);
10477c478bd9Sstevel@tonic-gate 	if (error)
10487c478bd9Sstevel@tonic-gate 		return (error);
10497c478bd9Sstevel@tonic-gate 	freemsg(mp);
10507c478bd9Sstevel@tonic-gate 	return (0);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate /*
1054*0f1702c5SYu Xiangning  * Queue a received TPI ack message on sti_ack_mp.
10557c478bd9Sstevel@tonic-gate  */
10567c478bd9Sstevel@tonic-gate void
10577c478bd9Sstevel@tonic-gate soqueueack(struct sonode *so, mblk_t *mp)
10587c478bd9Sstevel@tonic-gate {
1059*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1060*0f1702c5SYu Xiangning 
10617c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_PCPROTO) {
10622caf0dcdSrshoaib 		zcmn_err(getzoneid(), CE_WARN,
10637c478bd9Sstevel@tonic-gate 		    "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n",
10647c478bd9Sstevel@tonic-gate 		    *(t_scalar_t *)mp->b_rptr);
10657c478bd9Sstevel@tonic-gate 		freemsg(mp);
10667c478bd9Sstevel@tonic-gate 		return;
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1070*0f1702c5SYu Xiangning 	if (sti->sti_ack_mp != NULL) {
1071*0f1702c5SYu Xiangning 		dprintso(so, 1, ("sti_ack_mp already set\n"));
1072*0f1702c5SYu Xiangning 		freemsg(sti->sti_ack_mp);
1073*0f1702c5SYu Xiangning 		sti->sti_ack_mp = NULL;
10747c478bd9Sstevel@tonic-gate 	}
1075*0f1702c5SYu Xiangning 	sti->sti_ack_mp = mp;
1076*0f1702c5SYu Xiangning 	cv_broadcast(&sti->sti_ack_cv);
10777c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate  * Wait for a TPI ack ignoring signals and errors.
10827c478bd9Sstevel@tonic-gate  */
10837c478bd9Sstevel@tonic-gate int
10847c478bd9Sstevel@tonic-gate sowaitack(struct sonode *so, mblk_t **mpp, clock_t wait)
10857c478bd9Sstevel@tonic-gate {
1086*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1087*0f1702c5SYu Xiangning 
10887c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
10897c478bd9Sstevel@tonic-gate 
1090*0f1702c5SYu Xiangning 	while (sti->sti_ack_mp == NULL) {
10917c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST
10927c478bd9Sstevel@tonic-gate 		if (wait == 0 && sock_test_timelimit != 0)
10937c478bd9Sstevel@tonic-gate 			wait = sock_test_timelimit;
10947c478bd9Sstevel@tonic-gate #endif
10957c478bd9Sstevel@tonic-gate 		if (wait != 0) {
10967c478bd9Sstevel@tonic-gate 			/*
10977c478bd9Sstevel@tonic-gate 			 * Only wait for the time limit.
10987c478bd9Sstevel@tonic-gate 			 */
10997c478bd9Sstevel@tonic-gate 			clock_t now;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 			time_to_wait(&now, wait);
1102*0f1702c5SYu Xiangning 			if (cv_timedwait(&sti->sti_ack_cv, &so->so_lock,
11037c478bd9Sstevel@tonic-gate 			    now) == -1) {
11047c478bd9Sstevel@tonic-gate 				eprintsoline(so, ETIME);
11057c478bd9Sstevel@tonic-gate 				return (ETIME);
11067c478bd9Sstevel@tonic-gate 			}
11077c478bd9Sstevel@tonic-gate 		}
11087c478bd9Sstevel@tonic-gate 		else
1109*0f1702c5SYu Xiangning 			cv_wait(&sti->sti_ack_cv, &so->so_lock);
11107c478bd9Sstevel@tonic-gate 	}
1111*0f1702c5SYu Xiangning 	*mpp = sti->sti_ack_mp;
11127c478bd9Sstevel@tonic-gate #ifdef DEBUG
11137c478bd9Sstevel@tonic-gate 	{
11147c478bd9Sstevel@tonic-gate 		union T_primitives *tpr;
11157c478bd9Sstevel@tonic-gate 		mblk_t *mp = *mpp;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 		tpr = (union T_primitives *)mp->b_rptr;
11187c478bd9Sstevel@tonic-gate 		ASSERT(DB_TYPE(mp) == M_PCPROTO);
11197c478bd9Sstevel@tonic-gate 		ASSERT(tpr->type == T_OK_ACK ||
1120d3e55dcdSgww 		    tpr->type == T_ERROR_ACK ||
1121d3e55dcdSgww 		    tpr->type == T_BIND_ACK ||
1122d3e55dcdSgww 		    tpr->type == T_CAPABILITY_ACK ||
1123d3e55dcdSgww 		    tpr->type == T_INFO_ACK ||
1124d3e55dcdSgww 		    tpr->type == T_OPTMGMT_ACK);
11257c478bd9Sstevel@tonic-gate 	}
11267c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1127*0f1702c5SYu Xiangning 	sti->sti_ack_mp = NULL;
11287c478bd9Sstevel@tonic-gate 	return (0);
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate /*
1132*0f1702c5SYu Xiangning  * Queue a received T_CONN_IND message on sti_conn_ind_head/tail.
11337c478bd9Sstevel@tonic-gate  */
11347c478bd9Sstevel@tonic-gate void
11357c478bd9Sstevel@tonic-gate soqueueconnind(struct sonode *so, mblk_t *mp)
11367c478bd9Sstevel@tonic-gate {
1137*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1138*0f1702c5SYu Xiangning 
11397c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_PROTO) {
11402caf0dcdSrshoaib 		zcmn_err(getzoneid(), CE_WARN,
11417c478bd9Sstevel@tonic-gate 		    "sockfs: received unexpected M_PCPROTO T_CONN_IND\n");
11427c478bd9Sstevel@tonic-gate 		freemsg(mp);
11437c478bd9Sstevel@tonic-gate 		return;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
11477c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_next == NULL);
1148*0f1702c5SYu Xiangning 	if (sti->sti_conn_ind_head == NULL) {
1149*0f1702c5SYu Xiangning 		sti->sti_conn_ind_head = mp;
11507c478bd9Sstevel@tonic-gate 	} else {
1151*0f1702c5SYu Xiangning 		ASSERT(sti->sti_conn_ind_tail->b_next == NULL);
1152*0f1702c5SYu Xiangning 		sti->sti_conn_ind_tail->b_next = mp;
11537c478bd9Sstevel@tonic-gate 	}
1154*0f1702c5SYu Xiangning 	sti->sti_conn_ind_tail = mp;
11557c478bd9Sstevel@tonic-gate 	/* Wakeup a single consumer of the T_CONN_IND */
1156*0f1702c5SYu Xiangning 	cv_signal(&so->so_acceptq_cv);
11577c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate  * Wait for a T_CONN_IND.
11627c478bd9Sstevel@tonic-gate  * Don't wait if nonblocking.
11637c478bd9Sstevel@tonic-gate  * Accept signals and socket errors.
11647c478bd9Sstevel@tonic-gate  */
11657c478bd9Sstevel@tonic-gate int
11667c478bd9Sstevel@tonic-gate sowaitconnind(struct sonode *so, int fmode, mblk_t **mpp)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1169*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
11707c478bd9Sstevel@tonic-gate 	int error = 0;
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11737c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
11747c478bd9Sstevel@tonic-gate check_error:
11757c478bd9Sstevel@tonic-gate 	if (so->so_error) {
1176*0f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
11777c478bd9Sstevel@tonic-gate 		if (error) {
11787c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
11797c478bd9Sstevel@tonic-gate 			return (error);
11807c478bd9Sstevel@tonic-gate 		}
11817c478bd9Sstevel@tonic-gate 	}
11827c478bd9Sstevel@tonic-gate 
1183*0f1702c5SYu Xiangning 	if (sti->sti_conn_ind_head == NULL) {
11847c478bd9Sstevel@tonic-gate 		if (fmode & (FNDELAY|FNONBLOCK)) {
11857c478bd9Sstevel@tonic-gate 			error = EWOULDBLOCK;
11867c478bd9Sstevel@tonic-gate 			goto done;
11877c478bd9Sstevel@tonic-gate 		}
1188*0f1702c5SYu Xiangning 
1189*0f1702c5SYu Xiangning 		if (so->so_state & SS_CLOSING) {
1190*0f1702c5SYu Xiangning 			error = EINTR;
1191*0f1702c5SYu Xiangning 			goto done;
1192*0f1702c5SYu Xiangning 		}
1193*0f1702c5SYu Xiangning 
1194*0f1702c5SYu Xiangning 		if (!cv_wait_sig_swap(&so->so_acceptq_cv, &so->so_lock)) {
11957c478bd9Sstevel@tonic-gate 			error = EINTR;
11967c478bd9Sstevel@tonic-gate 			goto done;
11977c478bd9Sstevel@tonic-gate 		}
11987c478bd9Sstevel@tonic-gate 		goto check_error;
11997c478bd9Sstevel@tonic-gate 	}
1200*0f1702c5SYu Xiangning 	mp = sti->sti_conn_ind_head;
1201*0f1702c5SYu Xiangning 	sti->sti_conn_ind_head = mp->b_next;
12027c478bd9Sstevel@tonic-gate 	mp->b_next = NULL;
1203*0f1702c5SYu Xiangning 	if (sti->sti_conn_ind_head == NULL) {
1204*0f1702c5SYu Xiangning 		ASSERT(sti->sti_conn_ind_tail == mp);
1205*0f1702c5SYu Xiangning 		sti->sti_conn_ind_tail = NULL;
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 	*mpp = mp;
12087c478bd9Sstevel@tonic-gate done:
12097c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
12107c478bd9Sstevel@tonic-gate 	return (error);
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate /*
12147c478bd9Sstevel@tonic-gate  * Flush a T_CONN_IND matching the sequence number from the list.
12157c478bd9Sstevel@tonic-gate  * Return zero if found; non-zero otherwise.
12167c478bd9Sstevel@tonic-gate  * This is called very infrequently thus it is ok to do a linear search.
12177c478bd9Sstevel@tonic-gate  */
12187c478bd9Sstevel@tonic-gate int
12197c478bd9Sstevel@tonic-gate soflushconnind(struct sonode *so, t_scalar_t seqno)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate 	mblk_t *prevmp, *mp;
12227c478bd9Sstevel@tonic-gate 	struct T_conn_ind *tci;
1223*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1226*0f1702c5SYu Xiangning 	for (prevmp = NULL, mp = sti->sti_conn_ind_head; mp != NULL;
12277c478bd9Sstevel@tonic-gate 	    prevmp = mp, mp = mp->b_next) {
12287c478bd9Sstevel@tonic-gate 		tci = (struct T_conn_ind *)mp->b_rptr;
12297c478bd9Sstevel@tonic-gate 		if (tci->SEQ_number == seqno) {
12307c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
1231d3e55dcdSgww 			    ("t_discon_ind: found T_CONN_IND %d\n", seqno));
12327c478bd9Sstevel@tonic-gate 			/* Deleting last? */
1233*0f1702c5SYu Xiangning 			if (sti->sti_conn_ind_tail == mp) {
1234*0f1702c5SYu Xiangning 				sti->sti_conn_ind_tail = prevmp;
12357c478bd9Sstevel@tonic-gate 			}
12367c478bd9Sstevel@tonic-gate 			if (prevmp == NULL) {
12377c478bd9Sstevel@tonic-gate 				/* Deleting first */
1238*0f1702c5SYu Xiangning 				sti->sti_conn_ind_head = mp->b_next;
12397c478bd9Sstevel@tonic-gate 			} else {
12407c478bd9Sstevel@tonic-gate 				prevmp->b_next = mp->b_next;
12417c478bd9Sstevel@tonic-gate 			}
12427c478bd9Sstevel@tonic-gate 			mp->b_next = NULL;
1243*0f1702c5SYu Xiangning 
1244*0f1702c5SYu Xiangning 			ASSERT((sti->sti_conn_ind_head == NULL &&
1245*0f1702c5SYu Xiangning 			    sti->sti_conn_ind_tail == NULL) ||
1246*0f1702c5SYu Xiangning 			    (sti->sti_conn_ind_head != NULL &&
1247*0f1702c5SYu Xiangning 			    sti->sti_conn_ind_tail != NULL));
1248*0f1702c5SYu Xiangning 
12497c478bd9Sstevel@tonic-gate 			so->so_error = ECONNABORTED;
12507c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
1251c28749e9Skais 
1252c28749e9Skais 			/*
1253c28749e9Skais 			 * T_KSSL_PROXY_CONN_IND may carry a handle for
1254c28749e9Skais 			 * an SSL context, and needs to be released.
1255c28749e9Skais 			 */
1256c28749e9Skais 			if ((tci->PRIM_type == T_SSL_PROXY_CONN_IND) &&
1257c28749e9Skais 			    (mp->b_cont != NULL)) {
1258c28749e9Skais 				kssl_ctx_t kssl_ctx;
1259c28749e9Skais 
1260c28749e9Skais 				ASSERT(MBLKL(mp->b_cont) ==
1261c28749e9Skais 				    sizeof (kssl_ctx_t));
1262c28749e9Skais 				kssl_ctx = *((kssl_ctx_t *)mp->b_cont->b_rptr);
1263c28749e9Skais 				kssl_release_ctx(kssl_ctx);
1264c28749e9Skais 			}
12657c478bd9Sstevel@tonic-gate 			freemsg(mp);
12667c478bd9Sstevel@tonic-gate 			return (0);
12677c478bd9Sstevel@tonic-gate 		}
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
12707c478bd9Sstevel@tonic-gate 	dprintso(so, 1,	("t_discon_ind: NOT found T_CONN_IND %d\n", seqno));
12717c478bd9Sstevel@tonic-gate 	return (-1);
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate /*
12757c478bd9Sstevel@tonic-gate  * Wait until the socket is connected or there is an error.
12767c478bd9Sstevel@tonic-gate  * fmode should contain any nonblocking flags. nosig should be
12777c478bd9Sstevel@tonic-gate  * set if the caller does not want the wait to be interrupted by a signal.
12787c478bd9Sstevel@tonic-gate  */
12797c478bd9Sstevel@tonic-gate int
12807c478bd9Sstevel@tonic-gate sowaitconnected(struct sonode *so, int fmode, int nosig)
12817c478bd9Sstevel@tonic-gate {
12827c478bd9Sstevel@tonic-gate 	int error;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) ==
1287d3e55dcdSgww 	    SS_ISCONNECTING && so->so_error == 0) {
12887c478bd9Sstevel@tonic-gate 
1289903a11ebSrh 		dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n",
1290903a11ebSrh 		    (void *)so));
12917c478bd9Sstevel@tonic-gate 		if (fmode & (FNDELAY|FNONBLOCK))
12927c478bd9Sstevel@tonic-gate 			return (EINPROGRESS);
12937c478bd9Sstevel@tonic-gate 
1294*0f1702c5SYu Xiangning 		if (so->so_state & SS_CLOSING)
1295*0f1702c5SYu Xiangning 			return (EINTR);
1296*0f1702c5SYu Xiangning 
12977c478bd9Sstevel@tonic-gate 		if (nosig)
12987c478bd9Sstevel@tonic-gate 			cv_wait(&so->so_state_cv, &so->so_lock);
12997c478bd9Sstevel@tonic-gate 		else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) {
13007c478bd9Sstevel@tonic-gate 			/*
13017c478bd9Sstevel@tonic-gate 			 * Return EINTR and let the application use
13027c478bd9Sstevel@tonic-gate 			 * nonblocking techniques for detecting when
13037c478bd9Sstevel@tonic-gate 			 * the connection has been established.
13047c478bd9Sstevel@tonic-gate 			 */
13057c478bd9Sstevel@tonic-gate 			return (EINTR);
13067c478bd9Sstevel@tonic-gate 		}
1307903a11ebSrh 		dprintso(so, 1, ("awoken on %p\n", (void *)so));
13087c478bd9Sstevel@tonic-gate 	}
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	if (so->so_error != 0) {
1311*0f1702c5SYu Xiangning 		error = sogeterr(so, B_TRUE);
13127c478bd9Sstevel@tonic-gate 		ASSERT(error != 0);
13137c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("sowaitconnected: error %d\n", error));
13147c478bd9Sstevel@tonic-gate 		return (error);
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 	if (!(so->so_state & SS_ISCONNECTED)) {
13177c478bd9Sstevel@tonic-gate 		/*
13187c478bd9Sstevel@tonic-gate 		 * Could have received a T_ORDREL_IND or a T_DISCON_IND with
13197c478bd9Sstevel@tonic-gate 		 * zero errno. Or another thread could have consumed so_error
13207c478bd9Sstevel@tonic-gate 		 * e.g. by calling read.
13217c478bd9Sstevel@tonic-gate 		 */
13227c478bd9Sstevel@tonic-gate 		error = ECONNREFUSED;
13237c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("sowaitconnected: error %d\n", error));
13247c478bd9Sstevel@tonic-gate 		return (error);
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 	return (0);
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate /*
13317c478bd9Sstevel@tonic-gate  * Handle the signal generation aspect of urgent data.
13327c478bd9Sstevel@tonic-gate  */
13337c478bd9Sstevel@tonic-gate static void
13347c478bd9Sstevel@tonic-gate so_oob_sig(struct sonode *so, int extrasig,
13357c478bd9Sstevel@tonic-gate     strsigset_t *signals, strpollset_t *pollwakeups)
13367c478bd9Sstevel@tonic-gate {
1337*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1338*0f1702c5SYu Xiangning 
13397c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1342*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt);
1343*0f1702c5SYu Xiangning 	if (sti->sti_oobsigcnt > sti->sti_oobcnt) {
13447c478bd9Sstevel@tonic-gate 		/*
13457c478bd9Sstevel@tonic-gate 		 * Signal has already been generated once for this
13467c478bd9Sstevel@tonic-gate 		 * urgent "event". However, since TCP can receive updated
13477c478bd9Sstevel@tonic-gate 		 * urgent pointers we still generate a signal.
13487c478bd9Sstevel@tonic-gate 		 */
13497c478bd9Sstevel@tonic-gate 		ASSERT(so->so_state & SS_OOBPEND);
13507c478bd9Sstevel@tonic-gate 		if (extrasig) {
13517c478bd9Sstevel@tonic-gate 			*signals |= S_RDBAND;
13527c478bd9Sstevel@tonic-gate 			*pollwakeups |= POLLRDBAND;
13537c478bd9Sstevel@tonic-gate 		}
13547c478bd9Sstevel@tonic-gate 		return;
13557c478bd9Sstevel@tonic-gate 	}
13567c478bd9Sstevel@tonic-gate 
1357*0f1702c5SYu Xiangning 	sti->sti_oobsigcnt++;
1358*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobsigcnt > 0);	/* Wraparound */
1359*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobsigcnt > sti->sti_oobcnt);
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	/*
13627c478bd9Sstevel@tonic-gate 	 * Record (for select/poll) that urgent data is pending.
13637c478bd9Sstevel@tonic-gate 	 */
13647c478bd9Sstevel@tonic-gate 	so->so_state |= SS_OOBPEND;
13657c478bd9Sstevel@tonic-gate 	/*
13667c478bd9Sstevel@tonic-gate 	 * New urgent data on the way so forget about any old
13677c478bd9Sstevel@tonic-gate 	 * urgent data.
13687c478bd9Sstevel@tonic-gate 	 */
13697c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA);
13707c478bd9Sstevel@tonic-gate 	if (so->so_oobmsg != NULL) {
13717c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("sock: discarding old oob\n"));
13727c478bd9Sstevel@tonic-gate 		freemsg(so->so_oobmsg);
13737c478bd9Sstevel@tonic-gate 		so->so_oobmsg = NULL;
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 	*signals |= S_RDBAND;
13767c478bd9Sstevel@tonic-gate 	*pollwakeups |= POLLRDBAND;
13777c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate /*
13817c478bd9Sstevel@tonic-gate  * Handle the processing of the T_EXDATA_IND with urgent data.
13827c478bd9Sstevel@tonic-gate  * Returns the T_EXDATA_IND if it should be queued on the read queue.
13837c478bd9Sstevel@tonic-gate  */
13847c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
13857c478bd9Sstevel@tonic-gate static mblk_t *
13867c478bd9Sstevel@tonic-gate so_oob_exdata(struct sonode *so, mblk_t *mp,
13877c478bd9Sstevel@tonic-gate 	strsigset_t *signals, strpollset_t *pollwakeups)
13887c478bd9Sstevel@tonic-gate {
1389*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1390*0f1702c5SYu Xiangning 
13917c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
13947c478bd9Sstevel@tonic-gate 
1395*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobsigcnt > sti->sti_oobcnt);
13967c478bd9Sstevel@tonic-gate 
1397*0f1702c5SYu Xiangning 	sti->sti_oobcnt++;
1398*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobcnt > 0);	/* wraparound? */
1399*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt);
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	/*
14027c478bd9Sstevel@tonic-gate 	 * Set MSGMARK for SIOCATMARK.
14037c478bd9Sstevel@tonic-gate 	 */
14047c478bd9Sstevel@tonic-gate 	mp->b_flag |= MSGMARK;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
14077c478bd9Sstevel@tonic-gate 	return (mp);
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate /*
14117c478bd9Sstevel@tonic-gate  * Handle the processing of the actual urgent data.
14127c478bd9Sstevel@tonic-gate  * Returns the data mblk if it should be queued on the read queue.
14137c478bd9Sstevel@tonic-gate  */
14147c478bd9Sstevel@tonic-gate static mblk_t *
14157c478bd9Sstevel@tonic-gate so_oob_data(struct sonode *so, mblk_t *mp,
14167c478bd9Sstevel@tonic-gate 	strsigset_t *signals, strpollset_t *pollwakeups)
14177c478bd9Sstevel@tonic-gate {
1418*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1419*0f1702c5SYu Xiangning 
14207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
14237c478bd9Sstevel@tonic-gate 
1424*0f1702c5SYu Xiangning 	ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt);
14257c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
14267c478bd9Sstevel@tonic-gate 	/*
14277c478bd9Sstevel@tonic-gate 	 * For OOBINLINE we keep the data in the T_EXDATA_IND.
14287c478bd9Sstevel@tonic-gate 	 * Otherwise we store it in so_oobmsg.
14297c478bd9Sstevel@tonic-gate 	 */
14307c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobmsg == NULL);
14317c478bd9Sstevel@tonic-gate 	if (so->so_options & SO_OOBINLINE) {
14327c478bd9Sstevel@tonic-gate 		*pollwakeups |= POLLIN | POLLRDNORM | POLLRDBAND;
14337c478bd9Sstevel@tonic-gate 		*signals |= S_INPUT | S_RDNORM;
14347c478bd9Sstevel@tonic-gate 	} else {
14357c478bd9Sstevel@tonic-gate 		*pollwakeups |= POLLRDBAND;
14367c478bd9Sstevel@tonic-gate 		so->so_state |= SS_HAVEOOBDATA;
14377c478bd9Sstevel@tonic-gate 		so->so_oobmsg = mp;
14387c478bd9Sstevel@tonic-gate 		mp = NULL;
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
14417c478bd9Sstevel@tonic-gate 	return (mp);
14427c478bd9Sstevel@tonic-gate }
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate /*
14457c478bd9Sstevel@tonic-gate  * Caller must hold the mutex.
14467c478bd9Sstevel@tonic-gate  * For delayed processing, save the T_DISCON_IND received
1447*0f1702c5SYu Xiangning  * from below on sti_discon_ind_mp.
14487c478bd9Sstevel@tonic-gate  * When the message is processed the framework will call:
14497c478bd9Sstevel@tonic-gate  *      (*func)(so, mp);
14507c478bd9Sstevel@tonic-gate  */
14517c478bd9Sstevel@tonic-gate static void
14527c478bd9Sstevel@tonic-gate so_save_discon_ind(struct sonode *so,
14537c478bd9Sstevel@tonic-gate 	mblk_t *mp,
14547c478bd9Sstevel@tonic-gate 	void (*func)(struct sonode *so, mblk_t *))
14557c478bd9Sstevel@tonic-gate {
1456*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
1457*0f1702c5SYu Xiangning 
14587c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	/*
14617c478bd9Sstevel@tonic-gate 	 * Discard new T_DISCON_IND if we have already received another.
1462*0f1702c5SYu Xiangning 	 * Currently the earlier message can either be on sti_discon_ind_mp
14637c478bd9Sstevel@tonic-gate 	 * or being processed.
14647c478bd9Sstevel@tonic-gate 	 */
1465*0f1702c5SYu Xiangning 	if (sti->sti_discon_ind_mp != NULL || (so->so_flag & SOASYNC_UNBIND)) {
14662caf0dcdSrshoaib 		zcmn_err(getzoneid(), CE_WARN,
14677c478bd9Sstevel@tonic-gate 		    "sockfs: received unexpected additional T_DISCON_IND\n");
14687c478bd9Sstevel@tonic-gate 		freemsg(mp);
14697c478bd9Sstevel@tonic-gate 		return;
14707c478bd9Sstevel@tonic-gate 	}
14717c478bd9Sstevel@tonic-gate 	mp->b_prev = (mblk_t *)func;
14727c478bd9Sstevel@tonic-gate 	mp->b_next = NULL;
1473*0f1702c5SYu Xiangning 	sti->sti_discon_ind_mp = mp;
14747c478bd9Sstevel@tonic-gate }
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate /*
14777c478bd9Sstevel@tonic-gate  * Caller must hold the mutex and make sure that either SOLOCKED
14787c478bd9Sstevel@tonic-gate  * or SOASYNC_UNBIND is set. Called from so_unlock_single().
1479*0f1702c5SYu Xiangning  * Perform delayed processing of T_DISCON_IND message on sti_discon_ind_mp.
14807c478bd9Sstevel@tonic-gate  * Need to ensure that strsock_proto() will not end up sleeping for
14817c478bd9Sstevel@tonic-gate  * SOASYNC_UNBIND, while executing this function.
14827c478bd9Sstevel@tonic-gate  */
14837c478bd9Sstevel@tonic-gate void
14847c478bd9Sstevel@tonic-gate so_drain_discon_ind(struct sonode *so)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	mblk_t	*bp;
14877c478bd9Sstevel@tonic-gate 	void (*func)(struct sonode *so, mblk_t *);
1488*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
14917c478bd9Sstevel@tonic-gate 	ASSERT(so->so_flag & (SOLOCKED|SOASYNC_UNBIND));
14927c478bd9Sstevel@tonic-gate 
1493*0f1702c5SYu Xiangning 	/* Process T_DISCON_IND on sti_discon_ind_mp */
1494*0f1702c5SYu Xiangning 	if ((bp = sti->sti_discon_ind_mp) != NULL) {
1495*0f1702c5SYu Xiangning 		sti->sti_discon_ind_mp = NULL;
14967c478bd9Sstevel@tonic-gate 		func = (void (*)())bp->b_prev;
14977c478bd9Sstevel@tonic-gate 		bp->b_prev = NULL;
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 		/*
15007c478bd9Sstevel@tonic-gate 		 * This (*func) is supposed to generate a message downstream
15017c478bd9Sstevel@tonic-gate 		 * and we need to have a flag set until the corresponding
15027c478bd9Sstevel@tonic-gate 		 * upstream message reaches stream head.
15037c478bd9Sstevel@tonic-gate 		 * When processing T_DISCON_IND in strsock_discon_ind
15047c478bd9Sstevel@tonic-gate 		 * we hold SOASYN_UNBIND when sending T_UNBIND_REQ down and
15057c478bd9Sstevel@tonic-gate 		 * drop the flag after we get the ACK in strsock_proto.
15067c478bd9Sstevel@tonic-gate 		 */
15077c478bd9Sstevel@tonic-gate 		(void) (*func)(so, bp);
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate }
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate /*
15127c478bd9Sstevel@tonic-gate  * Caller must hold the mutex.
1513*0f1702c5SYu Xiangning  * Remove the T_DISCON_IND on sti_discon_ind_mp.
15147c478bd9Sstevel@tonic-gate  */
15157c478bd9Sstevel@tonic-gate void
15167c478bd9Sstevel@tonic-gate so_flush_discon_ind(struct sonode *so)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	mblk_t	*bp;
1519*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	/*
1524*0f1702c5SYu Xiangning 	 * Remove T_DISCON_IND mblk at sti_discon_ind_mp.
15257c478bd9Sstevel@tonic-gate 	 */
1526*0f1702c5SYu Xiangning 	if ((bp = sti->sti_discon_ind_mp) != NULL) {
1527*0f1702c5SYu Xiangning 		sti->sti_discon_ind_mp = NULL;
15287c478bd9Sstevel@tonic-gate 		bp->b_prev = NULL;
15297c478bd9Sstevel@tonic-gate 		freemsg(bp);
15307c478bd9Sstevel@tonic-gate 	}
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate  * Caller must hold the mutex.
15357c478bd9Sstevel@tonic-gate  *
15367c478bd9Sstevel@tonic-gate  * This function is used to process the T_DISCON_IND message. It does
15377c478bd9Sstevel@tonic-gate  * immediate processing when called from strsock_proto and delayed
1538*0f1702c5SYu Xiangning  * processing of discon_ind saved on sti_discon_ind_mp when called from
15397c478bd9Sstevel@tonic-gate  * so_drain_discon_ind. When a T_DISCON_IND message is saved in
1540*0f1702c5SYu Xiangning  * sti_discon_ind_mp for delayed processing, this function is registered
15417c478bd9Sstevel@tonic-gate  * as the callback function to process the message.
15427c478bd9Sstevel@tonic-gate  *
15437c478bd9Sstevel@tonic-gate  * SOASYNC_UNBIND should be held in this function, during the non-blocking
15447c478bd9Sstevel@tonic-gate  * unbind operation, and should be released only after we receive the ACK
15457c478bd9Sstevel@tonic-gate  * in strsock_proto, for the T_UNBIND_REQ sent here. Since SOLOCKED is not set,
15467c478bd9Sstevel@tonic-gate  * no TPI messages would be sent down at this time. This is to prevent M_FLUSH
15477c478bd9Sstevel@tonic-gate  * sent from either this function or tcp_unbind(), flushing away any TPI
15487c478bd9Sstevel@tonic-gate  * message that is being sent down and stays in a lower module's queue.
15497c478bd9Sstevel@tonic-gate  *
15507c478bd9Sstevel@tonic-gate  * This function drops so_lock and grabs it again.
15517c478bd9Sstevel@tonic-gate  */
15527c478bd9Sstevel@tonic-gate static void
15537c478bd9Sstevel@tonic-gate strsock_discon_ind(struct sonode *so, mblk_t *discon_mp)
15547c478bd9Sstevel@tonic-gate {
15557c478bd9Sstevel@tonic-gate 	struct vnode *vp;
15567c478bd9Sstevel@tonic-gate 	struct stdata *stp;
15577c478bd9Sstevel@tonic-gate 	union T_primitives *tpr;
15587c478bd9Sstevel@tonic-gate 	struct T_unbind_req *ubr;
15597c478bd9Sstevel@tonic-gate 	mblk_t *mp;
15607c478bd9Sstevel@tonic-gate 	int error;
1561*0f1702c5SYu Xiangning 	sotpi_info_t *sti = SOTOTPI(so);
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
15647c478bd9Sstevel@tonic-gate 	ASSERT(discon_mp);
15657c478bd9Sstevel@tonic-gate 	ASSERT(discon_mp->b_rptr);
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	tpr = (union T_primitives *)discon_mp->b_rptr;
15687c478bd9Sstevel@tonic-gate 	ASSERT(tpr->type == T_DISCON_IND);
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	vp = SOTOV(so);
15717c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
15727c478bd9Sstevel@tonic-gate 	ASSERT(stp);
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	/*
15757c478bd9Sstevel@tonic-gate 	 * Not a listener
15767c478bd9Sstevel@tonic-gate 	 */
15777c478bd9Sstevel@tonic-gate 	ASSERT((so->so_state & SS_ACCEPTCONN) == 0);
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	/*
15807c478bd9Sstevel@tonic-gate 	 * This assumes that the name space for DISCON_reason
15817c478bd9Sstevel@tonic-gate 	 * is the errno name space.
15827c478bd9Sstevel@tonic-gate 	 */
15837c478bd9Sstevel@tonic-gate 	soisdisconnected(so, tpr->discon_ind.DISCON_reason);
1584*0f1702c5SYu Xiangning 	sti->sti_laddr_valid = 0;
1585*0f1702c5SYu Xiangning 	sti->sti_faddr_valid = 0;
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	/*
15887c478bd9Sstevel@tonic-gate 	 * Unbind with the transport without blocking.
15897c478bd9Sstevel@tonic-gate 	 * If we've already received a T_DISCON_IND do not unbind.
15907c478bd9Sstevel@tonic-gate 	 *
15917c478bd9Sstevel@tonic-gate 	 * If there is no preallocated unbind message, we have already
15927c478bd9Sstevel@tonic-gate 	 * unbound with the transport
15937c478bd9Sstevel@tonic-gate 	 *
15947c478bd9Sstevel@tonic-gate 	 * If the socket is not bound, no need to unbind.
15957c478bd9Sstevel@tonic-gate 	 */
1596*0f1702c5SYu Xiangning 	mp = sti->sti_unbind_mp;
15977c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
15987c478bd9Sstevel@tonic-gate 		ASSERT(!(so->so_state & SS_ISBOUND));
15997c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
16007c478bd9Sstevel@tonic-gate 	} else if (!(so->so_state & SS_ISBOUND))  {
16017c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
16027c478bd9Sstevel@tonic-gate 	} else {
1603*0f1702c5SYu Xiangning 		sti->sti_unbind_mp = NULL;
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 		/*
16067c478bd9Sstevel@tonic-gate 		 * Is another T_DISCON_IND being processed.
16077c478bd9Sstevel@tonic-gate 		 */
16087c478bd9Sstevel@tonic-gate 		ASSERT((so->so_flag & SOASYNC_UNBIND) == 0);
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 		/*
16117c478bd9Sstevel@tonic-gate 		 * Make strsock_proto ignore T_OK_ACK and T_ERROR_ACK for
16127c478bd9Sstevel@tonic-gate 		 * this unbind. Set SOASYNC_UNBIND. This should be cleared
16137c478bd9Sstevel@tonic-gate 		 * only after we receive the ACK in strsock_proto.
16147c478bd9Sstevel@tonic-gate 		 */
16157c478bd9Sstevel@tonic-gate 		so->so_flag |= SOASYNC_UNBIND;
16167c478bd9Sstevel@tonic-gate 		ASSERT(!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)));
1617*0f1702c5SYu Xiangning 		so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN);
1618*0f1702c5SYu Xiangning 		sti->sti_laddr_valid = 0;
16197c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 		/*
16227c478bd9Sstevel@tonic-gate 		 * Send down T_UNBIND_REQ ignoring flow control.
16237c478bd9Sstevel@tonic-gate 		 * XXX Assumes that MSG_IGNFLOW implies that this thread
16247c478bd9Sstevel@tonic-gate 		 * does not run service procedures.
16257c478bd9Sstevel@tonic-gate 		 */
16267c478bd9Sstevel@tonic-gate 		ASSERT(DB_TYPE(mp) == M_PROTO);
16277c478bd9Sstevel@tonic-gate 		ubr = (struct T_unbind_req *)mp->b_rptr;
16287c478bd9Sstevel@tonic-gate 		mp->b_wptr += sizeof (*ubr);
16297c478bd9Sstevel@tonic-gate 		ubr->PRIM_type = T_UNBIND_REQ;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		/*
16327c478bd9Sstevel@tonic-gate 		 * Flush the read and write side (except stream head read queue)
16337c478bd9Sstevel@tonic-gate 		 * and send down T_UNBIND_REQ.
16347c478bd9Sstevel@tonic-gate 		 */
16357c478bd9Sstevel@tonic-gate 		(void) putnextctl1(strvp2wq(SOTOV(so)), M_FLUSH, FLUSHRW);
16367c478bd9Sstevel@tonic-gate 		error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
1637d3e55dcdSgww 		    MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0);
16387c478bd9Sstevel@tonic-gate 		/* LINTED - warning: statement has no consequent: if */
16397c478bd9Sstevel@tonic-gate 		if (error) {
16407c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 	}
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	if (tpr->discon_ind.DISCON_reason != 0)
16457c478bd9Sstevel@tonic-gate 		strsetrerror(SOTOV(so), 0, 0, sogetrderr);
16467c478bd9Sstevel@tonic-gate 	strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
16477c478bd9Sstevel@tonic-gate 	strseteof(SOTOV(so), 1);
16487c478bd9Sstevel@tonic-gate 	/*
16497c478bd9Sstevel@tonic-gate 	 * strseteof takes care of read side wakeups,
16507c478bd9Sstevel@tonic-gate 	 * pollwakeups, and signals.
16517c478bd9Sstevel@tonic-gate 	 */
16527c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("T_DISCON_IND: error %d\n", so->so_error));
16537c478bd9Sstevel@tonic-gate 	freemsg(discon_mp);
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	pollwakeup(&stp->sd_pollist, POLLOUT);
16577c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	/*
16607c478bd9Sstevel@tonic-gate 	 * Wake sleeping write
16617c478bd9Sstevel@tonic-gate 	 */
16627c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & WSLEEP) {
16637c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
16647c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_wrq->q_wait);
16657c478bd9Sstevel@tonic-gate 	}
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	/*
16687c478bd9Sstevel@tonic-gate 	 * strsendsig can handle multiple signals with a
16697c478bd9Sstevel@tonic-gate 	 * single call.  Send SIGPOLL for S_OUTPUT event.
16707c478bd9Sstevel@tonic-gate 	 */
16717c478bd9Sstevel@tonic-gate 	if (stp->sd_sigflags & S_OUTPUT)
16727c478bd9Sstevel@tonic-gate 		strsendsig(stp->sd_siglist, S_OUTPUT, 0, 0);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
16757c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate /*
16797c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to receive M_PROTO
16807c478bd9Sstevel@tonic-gate  * and M_PCPROTO messages.
16817c478bd9Sstevel@tonic-gate  *
16827c478bd9Sstevel@tonic-gate  * Returns NULL if the message was consumed.
16837c478bd9Sstevel@tonic-gate  * Returns an mblk to make that mblk be processed (and queued) by the stream
16847c478bd9Sstevel@tonic-gate  * head.
16857c478bd9Sstevel@tonic-gate  *
16867c478bd9Sstevel@tonic-gate  * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and
16877c478bd9Sstevel@tonic-gate  * *pollwakeups) for the stream head to take action on. Note that since
16887c478bd9Sstevel@tonic-gate  * sockets always deliver SIGIO for every new piece of data this routine
16897c478bd9Sstevel@tonic-gate  * never sets *firstmsgsigs; any signals are returned in *allmsgsigs.
16907c478bd9Sstevel@tonic-gate  *
16917c478bd9Sstevel@tonic-gate  * This routine handles all data related TPI messages independent of
16927c478bd9Sstevel@tonic-gate  * the type of the socket i.e. it doesn't care if T_UNITDATA_IND message
16937c478bd9Sstevel@tonic-gate  * arrive on a SOCK_STREAM.
16947c478bd9Sstevel@tonic-gate  */
16957c478bd9Sstevel@tonic-gate static mblk_t *
16967c478bd9Sstevel@tonic-gate strsock_proto(vnode_t *vp, mblk_t *mp,
16977c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
16987c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
16997c478bd9Sstevel@tonic-gate {
17007c478bd9Sstevel@tonic-gate 	union T_primitives *tpr;
17017c478bd9Sstevel@tonic-gate 	struct sonode *so;
1702*0f1702c5SYu Xiangning 	sotpi_info_t *sti;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	so = VTOSO(vp);
1705*0f1702c5SYu Xiangning 	sti = SOTOTPI(so);
17067c478bd9Sstevel@tonic-gate 
1707903a11ebSrh 	dprintso(so, 1, ("strsock_proto(%p, %p)\n", (void *)vp, (void *)mp));
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	/* Set default return values */
17107c478bd9Sstevel@tonic-gate 	*firstmsgsigs = *wakeups = *allmsgsigs = *pollwakeups = 0;
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_PROTO ||
17137c478bd9Sstevel@tonic-gate 	    DB_TYPE(mp) == M_PCPROTO);
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (tpr->type)) {
17167c478bd9Sstevel@tonic-gate 		/* The message is too short to even contain the primitive */
17172caf0dcdSrshoaib 		zcmn_err(getzoneid(), CE_WARN,
17187c478bd9Sstevel@tonic-gate 		    "sockfs: Too short TPI message received. Len = %ld\n",
17197c478bd9Sstevel@tonic-gate 		    (ptrdiff_t)(MBLKL(mp)));
17207c478bd9Sstevel@tonic-gate 		freemsg(mp);
17217c478bd9Sstevel@tonic-gate 		return (NULL);
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 	if (!__TPI_PRIM_ISALIGNED(mp->b_rptr)) {
17247c478bd9Sstevel@tonic-gate 		/* The read pointer is not aligned correctly for TPI */
17252caf0dcdSrshoaib 		zcmn_err(getzoneid(), CE_WARN,
17267c478bd9Sstevel@tonic-gate 		    "sockfs: Unaligned TPI message received. rptr = %p\n",
17277c478bd9Sstevel@tonic-gate 		    (void *)mp->b_rptr);
17287c478bd9Sstevel@tonic-gate 		freemsg(mp);
17297c478bd9Sstevel@tonic-gate 		return (NULL);
17307c478bd9Sstevel@tonic-gate 	}
17317c478bd9Sstevel@tonic-gate 	tpr = (union T_primitives *)mp->b_rptr;
17327c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("strsock_proto: primitive %d\n", tpr->type));
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	switch (tpr->type) {
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	case T_DATA_IND:
17377c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_data_ind)) {
17382caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
17397c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_DATA_IND. Len = %ld\n",
17407c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
17417c478bd9Sstevel@tonic-gate 			freemsg(mp);
17427c478bd9Sstevel@tonic-gate 			return (NULL);
17437c478bd9Sstevel@tonic-gate 		}
17447c478bd9Sstevel@tonic-gate 		/*
17457c478bd9Sstevel@tonic-gate 		 * Ignore zero-length T_DATA_IND messages. These might be
17467c478bd9Sstevel@tonic-gate 		 * generated by some transports.
17477c478bd9Sstevel@tonic-gate 		 * This is needed to prevent read (which skips the M_PROTO
17487c478bd9Sstevel@tonic-gate 		 * part) to unexpectedly return 0 (or return EWOULDBLOCK
17497c478bd9Sstevel@tonic-gate 		 * on a non-blocking socket after select/poll has indicated
17507c478bd9Sstevel@tonic-gate 		 * that data is available).
17517c478bd9Sstevel@tonic-gate 		 */
17527c478bd9Sstevel@tonic-gate 		if (msgdsize(mp->b_cont) == 0) {
17537c478bd9Sstevel@tonic-gate 			dprintso(so, 0,
17547c478bd9Sstevel@tonic-gate 			    ("strsock_proto: zero length T_DATA_IND\n"));
17557c478bd9Sstevel@tonic-gate 			freemsg(mp);
17567c478bd9Sstevel@tonic-gate 			return (NULL);
17577c478bd9Sstevel@tonic-gate 		}
17587c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
17597c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
17607c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
17617c478bd9Sstevel@tonic-gate 		return (mp);
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 	case T_UNITDATA_IND: {
17647c478bd9Sstevel@tonic-gate 		struct T_unitdata_ind	*tudi = &tpr->unitdata_ind;
17657c478bd9Sstevel@tonic-gate 		void			*addr;
17667c478bd9Sstevel@tonic-gate 		t_uscalar_t		addrlen;
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_unitdata_ind)) {
17692caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
17707c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_UNITDATA_IND. Len = %ld\n",
17717c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
17727c478bd9Sstevel@tonic-gate 			freemsg(mp);
17737c478bd9Sstevel@tonic-gate 			return (NULL);
17747c478bd9Sstevel@tonic-gate 		}
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 		/* Is this is not a connected datagram socket? */
17777c478bd9Sstevel@tonic-gate 		if ((so->so_mode & SM_CONNREQUIRED) ||
17787c478bd9Sstevel@tonic-gate 		    !(so->so_state & SS_ISCONNECTED)) {
17797c478bd9Sstevel@tonic-gate 			/*
17807c478bd9Sstevel@tonic-gate 			 * Not a connected datagram socket. Look for
17817c478bd9Sstevel@tonic-gate 			 * the SO_UNIX_CLOSE option. If such an option is found
17827c478bd9Sstevel@tonic-gate 			 * discard the message (since it has no meaning
17837c478bd9Sstevel@tonic-gate 			 * unless connected).
17847c478bd9Sstevel@tonic-gate 			 */
17857c478bd9Sstevel@tonic-gate 			if (so->so_family == AF_UNIX && msgdsize(mp) == 0 &&
17867c478bd9Sstevel@tonic-gate 			    tudi->OPT_length != 0) {
17877c478bd9Sstevel@tonic-gate 				void *opt;
17887c478bd9Sstevel@tonic-gate 				t_uscalar_t optlen = tudi->OPT_length;
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 				opt = sogetoff(mp, tudi->OPT_offset,
1791d3e55dcdSgww 				    optlen, __TPI_ALIGN_SIZE);
17927c478bd9Sstevel@tonic-gate 				if (opt == NULL) {
17937c478bd9Sstevel@tonic-gate 					/* The len/off falls outside mp */
17947c478bd9Sstevel@tonic-gate 					freemsg(mp);
17957c478bd9Sstevel@tonic-gate 					mutex_enter(&so->so_lock);
17967c478bd9Sstevel@tonic-gate 					soseterror(so, EPROTO);
17977c478bd9Sstevel@tonic-gate 					mutex_exit(&so->so_lock);
17982caf0dcdSrshoaib 					zcmn_err(getzoneid(), CE_WARN,
17997c478bd9Sstevel@tonic-gate 					    "sockfs: T_unidata_ind with "
18007c478bd9Sstevel@tonic-gate 					    "invalid optlen/offset %u/%d\n",
18017c478bd9Sstevel@tonic-gate 					    optlen, tudi->OPT_offset);
18027c478bd9Sstevel@tonic-gate 					return (NULL);
18037c478bd9Sstevel@tonic-gate 				}
18047c478bd9Sstevel@tonic-gate 				if (so_getopt_unix_close(opt, optlen)) {
18057c478bd9Sstevel@tonic-gate 					freemsg(mp);
18067c478bd9Sstevel@tonic-gate 					return (NULL);
18077c478bd9Sstevel@tonic-gate 				}
18087c478bd9Sstevel@tonic-gate 			}
18097c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_INPUT | S_RDNORM;
18107c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM;
18117c478bd9Sstevel@tonic-gate 			*wakeups = RSLEEP;
18127c478bd9Sstevel@tonic-gate 			if (audit_active)
18137c478bd9Sstevel@tonic-gate 				audit_sock(T_UNITDATA_IND, strvp2wq(vp),
1814d3e55dcdSgww 				    mp, 0);
18157c478bd9Sstevel@tonic-gate 			return (mp);
18167c478bd9Sstevel@tonic-gate 		}
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		/*
18197c478bd9Sstevel@tonic-gate 		 * A connect datagram socket. For AF_INET{,6} we verify that
18207c478bd9Sstevel@tonic-gate 		 * the source address matches the "connected to" address.
18217c478bd9Sstevel@tonic-gate 		 * The semantics of AF_UNIX sockets is to not verify
18227c478bd9Sstevel@tonic-gate 		 * the source address.
18237c478bd9Sstevel@tonic-gate 		 * Note that this source address verification is transport
18247c478bd9Sstevel@tonic-gate 		 * specific. Thus the real fix would be to extent TPI
18257c478bd9Sstevel@tonic-gate 		 * to allow T_CONN_REQ messages to be send to connectionless
18267c478bd9Sstevel@tonic-gate 		 * transport providers and always let the transport provider
18277c478bd9Sstevel@tonic-gate 		 * do whatever filtering is needed.
18287c478bd9Sstevel@tonic-gate 		 *
18297c478bd9Sstevel@tonic-gate 		 * The verification/filtering semantics for transports
18307c478bd9Sstevel@tonic-gate 		 * other than AF_INET and AF_UNIX are unknown. The choice
18317c478bd9Sstevel@tonic-gate 		 * would be to either filter using bcmp or let all messages
18327c478bd9Sstevel@tonic-gate 		 * get through. This code does not filter other address
18337c478bd9Sstevel@tonic-gate 		 * families since this at least allows the application to
18347c478bd9Sstevel@tonic-gate 		 * work around any missing filtering.
18357c478bd9Sstevel@tonic-gate 		 *
18367c478bd9Sstevel@tonic-gate 		 * XXX Should we move filtering to UDP/ICMP???
18377c478bd9Sstevel@tonic-gate 		 * That would require passing e.g. a T_DISCON_REQ to UDP
18387c478bd9Sstevel@tonic-gate 		 * when the socket becomes unconnected.
18397c478bd9Sstevel@tonic-gate 		 */
18407c478bd9Sstevel@tonic-gate 		addrlen = tudi->SRC_length;
18417c478bd9Sstevel@tonic-gate 		/*
18427c478bd9Sstevel@tonic-gate 		 * The alignment restriction is really to strict but
18437c478bd9Sstevel@tonic-gate 		 * we want enough alignment to inspect the fields of
18447c478bd9Sstevel@tonic-gate 		 * a sockaddr_in.
18457c478bd9Sstevel@tonic-gate 		 */
18467c478bd9Sstevel@tonic-gate 		addr = sogetoff(mp, tudi->SRC_offset, addrlen,
1847d3e55dcdSgww 		    __TPI_ALIGN_SIZE);
18487c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
18497c478bd9Sstevel@tonic-gate 			freemsg(mp);
18507c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
18517c478bd9Sstevel@tonic-gate 			soseterror(so, EPROTO);
18527c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
18532caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
18547c478bd9Sstevel@tonic-gate 			    "sockfs: T_unidata_ind with invalid "
18557c478bd9Sstevel@tonic-gate 			    "addrlen/offset %u/%d\n",
18567c478bd9Sstevel@tonic-gate 			    addrlen, tudi->SRC_offset);
18577c478bd9Sstevel@tonic-gate 			return (NULL);
18587c478bd9Sstevel@tonic-gate 		}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_INET) {
18617c478bd9Sstevel@tonic-gate 			/*
18627c478bd9Sstevel@tonic-gate 			 * For AF_INET we allow wildcarding both sin_addr
18637c478bd9Sstevel@tonic-gate 			 * and sin_port.
18647c478bd9Sstevel@tonic-gate 			 */
18657c478bd9Sstevel@tonic-gate 			struct sockaddr_in *faddr, *sin;
18667c478bd9Sstevel@tonic-gate 
1867*0f1702c5SYu Xiangning 			/* Prevent sti_faddr_sa from changing while accessed */
18687c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
1869*0f1702c5SYu Xiangning 			ASSERT(sti->sti_faddr_len ==
1870d3e55dcdSgww 			    (socklen_t)sizeof (struct sockaddr_in));
1871*0f1702c5SYu Xiangning 			faddr = (struct sockaddr_in *)sti->sti_faddr_sa;
18727c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)addr;
18737c478bd9Sstevel@tonic-gate 			if (addrlen !=
1874d3e55dcdSgww 			    (t_uscalar_t)sizeof (struct sockaddr_in) ||
18757c478bd9Sstevel@tonic-gate 			    (sin->sin_addr.s_addr != faddr->sin_addr.s_addr &&
18767c478bd9Sstevel@tonic-gate 			    faddr->sin_addr.s_addr != INADDR_ANY) ||
18777c478bd9Sstevel@tonic-gate 			    (so->so_type != SOCK_RAW &&
18787c478bd9Sstevel@tonic-gate 			    sin->sin_port != faddr->sin_port &&
18797c478bd9Sstevel@tonic-gate 			    faddr->sin_port != 0)) {
18807c478bd9Sstevel@tonic-gate #ifdef DEBUG
18817c478bd9Sstevel@tonic-gate 				dprintso(so, 0,
1882d3e55dcdSgww 				    ("sockfs: T_UNITDATA_IND mismatch: %s",
1883d3e55dcdSgww 				    pr_addr(so->so_family,
1884*0f1702c5SYu Xiangning 				    (struct sockaddr *)addr, addrlen)));
18857c478bd9Sstevel@tonic-gate 				dprintso(so, 0, (" - %s\n",
1886*0f1702c5SYu Xiangning 				    pr_addr(so->so_family, sti->sti_faddr_sa,
1887*0f1702c5SYu Xiangning 				    (t_uscalar_t)sti->sti_faddr_len)));
18887c478bd9Sstevel@tonic-gate #endif /* DEBUG */
18897c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
18907c478bd9Sstevel@tonic-gate 				freemsg(mp);
18917c478bd9Sstevel@tonic-gate 				return (NULL);
18927c478bd9Sstevel@tonic-gate 			}
18937c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
18947c478bd9Sstevel@tonic-gate 		} else if (so->so_family == AF_INET6) {
18957c478bd9Sstevel@tonic-gate 			/*
18967c478bd9Sstevel@tonic-gate 			 * For AF_INET6 we allow wildcarding both sin6_addr
18977c478bd9Sstevel@tonic-gate 			 * and sin6_port.
18987c478bd9Sstevel@tonic-gate 			 */
18997c478bd9Sstevel@tonic-gate 			struct sockaddr_in6 *faddr6, *sin6;
19007c478bd9Sstevel@tonic-gate 			static struct in6_addr zeroes; /* inits to all zeros */
19017c478bd9Sstevel@tonic-gate 
1902*0f1702c5SYu Xiangning 			/* Prevent sti_faddr_sa from changing while accessed */
19037c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
1904*0f1702c5SYu Xiangning 			ASSERT(sti->sti_faddr_len ==
19057c478bd9Sstevel@tonic-gate 			    (socklen_t)sizeof (struct sockaddr_in6));
1906*0f1702c5SYu Xiangning 			faddr6 = (struct sockaddr_in6 *)sti->sti_faddr_sa;
19077c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addr;
19087c478bd9Sstevel@tonic-gate 			/* XXX could we get a mapped address ::ffff:0.0.0.0 ? */
19097c478bd9Sstevel@tonic-gate 			if (addrlen !=
19107c478bd9Sstevel@tonic-gate 			    (t_uscalar_t)sizeof (struct sockaddr_in6) ||
19117c478bd9Sstevel@tonic-gate 			    (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
1912d3e55dcdSgww 			    &faddr6->sin6_addr) &&
19137c478bd9Sstevel@tonic-gate 			    !IN6_ARE_ADDR_EQUAL(&faddr6->sin6_addr, &zeroes)) ||
19147c478bd9Sstevel@tonic-gate 			    (so->so_type != SOCK_RAW &&
19157c478bd9Sstevel@tonic-gate 			    sin6->sin6_port != faddr6->sin6_port &&
19167c478bd9Sstevel@tonic-gate 			    faddr6->sin6_port != 0)) {
19177c478bd9Sstevel@tonic-gate #ifdef DEBUG
19187c478bd9Sstevel@tonic-gate 				dprintso(so, 0,
19197c478bd9Sstevel@tonic-gate 				    ("sockfs: T_UNITDATA_IND mismatch: %s",
1920d3e55dcdSgww 				    pr_addr(so->so_family,
1921*0f1702c5SYu Xiangning 				    (struct sockaddr *)addr, addrlen)));
19227c478bd9Sstevel@tonic-gate 				dprintso(so, 0, (" - %s\n",
1923*0f1702c5SYu Xiangning 				    pr_addr(so->so_family, sti->sti_faddr_sa,
1924*0f1702c5SYu Xiangning 				    (t_uscalar_t)sti->sti_faddr_len)));
19257c478bd9Sstevel@tonic-gate #endif /* DEBUG */
19267c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
19277c478bd9Sstevel@tonic-gate 				freemsg(mp);
19287c478bd9Sstevel@tonic-gate 				return (NULL);
19297c478bd9Sstevel@tonic-gate 			}
19307c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
19317c478bd9Sstevel@tonic-gate 		} else if (so->so_family == AF_UNIX &&
19327c478bd9Sstevel@tonic-gate 		    msgdsize(mp->b_cont) == 0 &&
19337c478bd9Sstevel@tonic-gate 		    tudi->OPT_length != 0) {
19347c478bd9Sstevel@tonic-gate 			/*
19357c478bd9Sstevel@tonic-gate 			 * Attempt to extract AF_UNIX
19367c478bd9Sstevel@tonic-gate 			 * SO_UNIX_CLOSE indication from options.
19377c478bd9Sstevel@tonic-gate 			 */
19387c478bd9Sstevel@tonic-gate 			void *opt;
19397c478bd9Sstevel@tonic-gate 			t_uscalar_t optlen = tudi->OPT_length;
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 			opt = sogetoff(mp, tudi->OPT_offset,
1942d3e55dcdSgww 			    optlen, __TPI_ALIGN_SIZE);
19437c478bd9Sstevel@tonic-gate 			if (opt == NULL) {
19447c478bd9Sstevel@tonic-gate 				/* The len/off falls outside mp */
19457c478bd9Sstevel@tonic-gate 				freemsg(mp);
19467c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
19477c478bd9Sstevel@tonic-gate 				soseterror(so, EPROTO);
19487c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
19492caf0dcdSrshoaib 				zcmn_err(getzoneid(), CE_WARN,
19507c478bd9Sstevel@tonic-gate 				    "sockfs: T_unidata_ind with invalid "
19517c478bd9Sstevel@tonic-gate 				    "optlen/offset %u/%d\n",
19527c478bd9Sstevel@tonic-gate 				    optlen, tudi->OPT_offset);
19537c478bd9Sstevel@tonic-gate 				return (NULL);
19547c478bd9Sstevel@tonic-gate 			}
19557c478bd9Sstevel@tonic-gate 			/*
19567c478bd9Sstevel@tonic-gate 			 * If we received a unix close indication mark the
19577c478bd9Sstevel@tonic-gate 			 * socket and discard this message.
19587c478bd9Sstevel@tonic-gate 			 */
19597c478bd9Sstevel@tonic-gate 			if (so_getopt_unix_close(opt, optlen)) {
19607c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
19617c478bd9Sstevel@tonic-gate 				sobreakconn(so, ECONNRESET);
19627c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
19637c478bd9Sstevel@tonic-gate 				strsetrerror(SOTOV(so), 0, 0, sogetrderr);
19647c478bd9Sstevel@tonic-gate 				freemsg(mp);
19657c478bd9Sstevel@tonic-gate 				*pollwakeups = POLLIN | POLLRDNORM;
19667c478bd9Sstevel@tonic-gate 				*allmsgsigs = S_INPUT | S_RDNORM;
19677c478bd9Sstevel@tonic-gate 				*wakeups = RSLEEP;
19687c478bd9Sstevel@tonic-gate 				return (NULL);
19697c478bd9Sstevel@tonic-gate 			}
19707c478bd9Sstevel@tonic-gate 		}
19717c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
19727c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
19737c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
19747c478bd9Sstevel@tonic-gate 		return (mp);
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	case T_OPTDATA_IND: {
19787c478bd9Sstevel@tonic-gate 		struct T_optdata_ind	*tdi = &tpr->optdata_ind;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_optdata_ind)) {
19812caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
19827c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_OPTDATA_IND. Len = %ld\n",
19837c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
19847c478bd9Sstevel@tonic-gate 			freemsg(mp);
19857c478bd9Sstevel@tonic-gate 			return (NULL);
19867c478bd9Sstevel@tonic-gate 		}
19877c478bd9Sstevel@tonic-gate 		/*
19887c478bd9Sstevel@tonic-gate 		 * Allow zero-length messages carrying options.
19897c478bd9Sstevel@tonic-gate 		 * This is used when carrying the SO_UNIX_CLOSE option.
19907c478bd9Sstevel@tonic-gate 		 */
19917c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_UNIX && msgdsize(mp->b_cont) == 0 &&
19927c478bd9Sstevel@tonic-gate 		    tdi->OPT_length != 0) {
19937c478bd9Sstevel@tonic-gate 			/*
19947c478bd9Sstevel@tonic-gate 			 * Attempt to extract AF_UNIX close indication
19957c478bd9Sstevel@tonic-gate 			 * from the options. Ignore any other options -
19967c478bd9Sstevel@tonic-gate 			 * those are handled once the message is removed
19977c478bd9Sstevel@tonic-gate 			 * from the queue.
19987c478bd9Sstevel@tonic-gate 			 * The close indication message should not carry data.
19997c478bd9Sstevel@tonic-gate 			 */
20007c478bd9Sstevel@tonic-gate 			void *opt;
20017c478bd9Sstevel@tonic-gate 			t_uscalar_t optlen = tdi->OPT_length;
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 			opt = sogetoff(mp, tdi->OPT_offset,
2004d3e55dcdSgww 			    optlen, __TPI_ALIGN_SIZE);
20057c478bd9Sstevel@tonic-gate 			if (opt == NULL) {
20067c478bd9Sstevel@tonic-gate 				/* The len/off falls outside mp */
20077c478bd9Sstevel@tonic-gate 				freemsg(mp);
20087c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
20097c478bd9Sstevel@tonic-gate 				soseterror(so, EPROTO);
20107c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
20112caf0dcdSrshoaib 				zcmn_err(getzoneid(), CE_WARN,
20127c478bd9Sstevel@tonic-gate 				    "sockfs: T_optdata_ind with invalid "
20137c478bd9Sstevel@tonic-gate 				    "optlen/offset %u/%d\n",
20147c478bd9Sstevel@tonic-gate 				    optlen, tdi->OPT_offset);
20157c478bd9Sstevel@tonic-gate 				return (NULL);
20167c478bd9Sstevel@tonic-gate 			}
20177c478bd9Sstevel@tonic-gate 			/*
20187c478bd9Sstevel@tonic-gate 			 * If we received a close indication mark the
20197c478bd9Sstevel@tonic-gate 			 * socket and discard this message.
20207c478bd9Sstevel@tonic-gate 			 */
20217c478bd9Sstevel@tonic-gate 			if (so_getopt_unix_close(opt, optlen)) {
20227c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
20237c478bd9Sstevel@tonic-gate 				socantsendmore(so);
2024*0f1702c5SYu Xiangning 				sti->sti_faddr_valid = 0;
20257c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
20267c478bd9Sstevel@tonic-gate 				strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
20277c478bd9Sstevel@tonic-gate 				freemsg(mp);
20287c478bd9Sstevel@tonic-gate 				return (NULL);
20297c478bd9Sstevel@tonic-gate 			}
20307c478bd9Sstevel@tonic-gate 		}
20317c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
20327c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
20337c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
20347c478bd9Sstevel@tonic-gate 		return (mp);
20357c478bd9Sstevel@tonic-gate 	}
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	case T_EXDATA_IND: {
20387c478bd9Sstevel@tonic-gate 		mblk_t		*mctl, *mdata;
2039e63f9565Sss 		mblk_t *lbp;
2040e63f9565Sss 		union T_primitives *tprp;
2041e63f9565Sss 		struct stdata   *stp;
2042e63f9565Sss 		queue_t *qp;
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_exdata_ind)) {
20452caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
20467c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_EXDATA_IND. Len = %ld\n",
20477c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
20487c478bd9Sstevel@tonic-gate 			freemsg(mp);
20497c478bd9Sstevel@tonic-gate 			return (NULL);
20507c478bd9Sstevel@tonic-gate 		}
20517c478bd9Sstevel@tonic-gate 		/*
20527c478bd9Sstevel@tonic-gate 		 * Ignore zero-length T_EXDATA_IND messages. These might be
20537c478bd9Sstevel@tonic-gate 		 * generated by some transports.
20547c478bd9Sstevel@tonic-gate 		 *
20557c478bd9Sstevel@tonic-gate 		 * This is needed to prevent read (which skips the M_PROTO
20567c478bd9Sstevel@tonic-gate 		 * part) to unexpectedly return 0 (or return EWOULDBLOCK
20577c478bd9Sstevel@tonic-gate 		 * on a non-blocking socket after select/poll has indicated
20587c478bd9Sstevel@tonic-gate 		 * that data is available).
20597c478bd9Sstevel@tonic-gate 		 */
20607c478bd9Sstevel@tonic-gate 		dprintso(so, 1,
2061d3e55dcdSgww 		    ("T_EXDATA_IND(%p): counts %d/%d state %s\n",
2062*0f1702c5SYu Xiangning 		    (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt,
2063d3e55dcdSgww 		    pr_state(so->so_state, so->so_mode)));
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 		if (msgdsize(mp->b_cont) == 0) {
20667c478bd9Sstevel@tonic-gate 			dprintso(so, 0,
2067d3e55dcdSgww 			    ("strsock_proto: zero length T_EXDATA_IND\n"));
20687c478bd9Sstevel@tonic-gate 			freemsg(mp);
20697c478bd9Sstevel@tonic-gate 			return (NULL);
20707c478bd9Sstevel@tonic-gate 		}
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 		/*
20737c478bd9Sstevel@tonic-gate 		 * Split into the T_EXDATA_IND and the M_DATA part.
20747c478bd9Sstevel@tonic-gate 		 * We process these three pieces separately:
20757c478bd9Sstevel@tonic-gate 		 *	signal generation
20767c478bd9Sstevel@tonic-gate 		 *	handling T_EXDATA_IND
20777c478bd9Sstevel@tonic-gate 		 *	handling M_DATA component
20787c478bd9Sstevel@tonic-gate 		 */
20797c478bd9Sstevel@tonic-gate 		mctl = mp;
20807c478bd9Sstevel@tonic-gate 		mdata = mctl->b_cont;
20817c478bd9Sstevel@tonic-gate 		mctl->b_cont = NULL;
20827c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
20837c478bd9Sstevel@tonic-gate 		so_oob_sig(so, 0, allmsgsigs, pollwakeups);
20847c478bd9Sstevel@tonic-gate 		mctl = so_oob_exdata(so, mctl, allmsgsigs, pollwakeups);
20857c478bd9Sstevel@tonic-gate 		mdata = so_oob_data(so, mdata, allmsgsigs, pollwakeups);
20867c478bd9Sstevel@tonic-gate 
2087e63f9565Sss 		stp = vp->v_stream;
2088e63f9565Sss 		ASSERT(stp != NULL);
2089e63f9565Sss 		qp = _RD(stp->sd_wrq);
2090e63f9565Sss 
2091e63f9565Sss 		mutex_enter(QLOCK(qp));
2092e63f9565Sss 		lbp = qp->q_last;
2093e63f9565Sss 
2094e63f9565Sss 		/*
2095e63f9565Sss 		 * We want to avoid queueing up a string of T_EXDATA_IND
2096e63f9565Sss 		 * messages with no intervening data messages at the stream
2097e63f9565Sss 		 * head. These messages contribute to the total message
2098e63f9565Sss 		 * count. Eventually this can lead to STREAMS flow contol
2099e63f9565Sss 		 * and also cause TCP to advertise a zero window condition
2100e63f9565Sss 		 * to the peer. This can happen in the degenerate case where
2101e63f9565Sss 		 * the sender and receiver exchange only OOB data. The sender
2102e63f9565Sss 		 * only sends messages with MSG_OOB flag and the receiver
2103e63f9565Sss 		 * receives only MSG_OOB messages and does not use SO_OOBINLINE.
2104e63f9565Sss 		 * An example of this scenario has been reported in applications
2105e63f9565Sss 		 * that use OOB data to exchange heart beats. Flow control
2106e63f9565Sss 		 * relief will never happen if the application only reads OOB
2107e63f9565Sss 		 * data which is done directly by sorecvoob() and the
2108e63f9565Sss 		 * T_EXDATA_IND messages at the streamhead won't be consumed.
2109e63f9565Sss 		 * Note that there is no correctness issue in compressing the
2110e63f9565Sss 		 * string of T_EXDATA_IND messages into a single T_EXDATA_IND
2111e63f9565Sss 		 * message. A single read that does not specify MSG_OOB will
2112e63f9565Sss 		 * read across all the marks in a loop in sotpi_recvmsg().
2113e63f9565Sss 		 * Each mark is individually distinguishable only if the
2114e63f9565Sss 		 * T_EXDATA_IND messages are separated by data messages.
2115e63f9565Sss 		 */
2116e63f9565Sss 		if ((qp->q_first != NULL) && (DB_TYPE(lbp) == M_PROTO)) {
2117e63f9565Sss 			tprp = (union T_primitives *)lbp->b_rptr;
2118e63f9565Sss 			if ((tprp->type == T_EXDATA_IND) &&
2119e63f9565Sss 			    !(so->so_options & SO_OOBINLINE)) {
2120e63f9565Sss 
2121e63f9565Sss 				/*
2122e63f9565Sss 				 * free the new M_PROTO message
2123e63f9565Sss 				 */
2124e63f9565Sss 				freemsg(mctl);
2125e63f9565Sss 
2126e63f9565Sss 				/*
2127e63f9565Sss 				 * adjust the OOB count and OOB	signal count
2128e63f9565Sss 				 * just incremented for the new OOB data.
2129e63f9565Sss 				 */
2130*0f1702c5SYu Xiangning 				sti->sti_oobcnt--;
2131*0f1702c5SYu Xiangning 				sti->sti_oobsigcnt--;
2132e63f9565Sss 				mutex_exit(QLOCK(qp));
2133e63f9565Sss 				mutex_exit(&so->so_lock);
2134e63f9565Sss 				return (NULL);
2135e63f9565Sss 			}
2136e63f9565Sss 		}
2137e63f9565Sss 		mutex_exit(QLOCK(qp));
2138e63f9565Sss 
21397c478bd9Sstevel@tonic-gate 		/*
21407c478bd9Sstevel@tonic-gate 		 * Pass the T_EXDATA_IND and the M_DATA back separately
21417c478bd9Sstevel@tonic-gate 		 * by using b_next linkage. (The stream head will queue any
21427c478bd9Sstevel@tonic-gate 		 * b_next linked messages separately.) This is needed
21437c478bd9Sstevel@tonic-gate 		 * since MSGMARK applies to the last by of the message
21447c478bd9Sstevel@tonic-gate 		 * hence we can not have any M_DATA component attached
21457c478bd9Sstevel@tonic-gate 		 * to the marked T_EXDATA_IND. Note that the stream head
21467c478bd9Sstevel@tonic-gate 		 * will not consolidate M_DATA messages onto an MSGMARK'ed
21477c478bd9Sstevel@tonic-gate 		 * message in order to preserve the constraint that
21487c478bd9Sstevel@tonic-gate 		 * the T_EXDATA_IND always is a separate message.
21497c478bd9Sstevel@tonic-gate 		 */
21507c478bd9Sstevel@tonic-gate 		ASSERT(mctl != NULL);
21517c478bd9Sstevel@tonic-gate 		mctl->b_next = mdata;
21527c478bd9Sstevel@tonic-gate 		mp = mctl;
21537c478bd9Sstevel@tonic-gate #ifdef DEBUG
21547c478bd9Sstevel@tonic-gate 		if (mdata == NULL) {
21557c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2156d3e55dcdSgww 			    ("after outofline T_EXDATA_IND(%p): "
2157d3e55dcdSgww 			    "counts %d/%d  poll 0x%x sig 0x%x state %s\n",
2158*0f1702c5SYu Xiangning 			    (void *)vp, sti->sti_oobsigcnt,
2159*0f1702c5SYu Xiangning 			    sti->sti_oobcnt, *pollwakeups, *allmsgsigs,
2160d3e55dcdSgww 			    pr_state(so->so_state, so->so_mode)));
21617c478bd9Sstevel@tonic-gate 		} else {
21627c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2163d3e55dcdSgww 			    ("after inline T_EXDATA_IND(%p): "
2164d3e55dcdSgww 			    "counts %d/%d  poll 0x%x sig 0x%x state %s\n",
2165*0f1702c5SYu Xiangning 			    (void *)vp, sti->sti_oobsigcnt,
2166*0f1702c5SYu Xiangning 			    sti->sti_oobcnt, *pollwakeups, *allmsgsigs,
2167d3e55dcdSgww 			    pr_state(so->so_state, so->so_mode)));
21687c478bd9Sstevel@tonic-gate 		}
21697c478bd9Sstevel@tonic-gate #endif /* DEBUG */
21707c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
21717c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
21727c478bd9Sstevel@tonic-gate 		return (mp);
21737c478bd9Sstevel@tonic-gate 	}
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	case T_CONN_CON: {
21767c478bd9Sstevel@tonic-gate 		struct T_conn_con	*conn_con;
21777c478bd9Sstevel@tonic-gate 		void			*addr;
21787c478bd9Sstevel@tonic-gate 		t_uscalar_t		addrlen;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 		/*
21817c478bd9Sstevel@tonic-gate 		 * Verify the state, update the state to ISCONNECTED,
21827c478bd9Sstevel@tonic-gate 		 * record the potentially new address in the message,
21837c478bd9Sstevel@tonic-gate 		 * and drop the message.
21847c478bd9Sstevel@tonic-gate 		 */
21857c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_conn_con)) {
21862caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
21877c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_CONN_CON. Len = %ld\n",
21887c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
21897c478bd9Sstevel@tonic-gate 			freemsg(mp);
21907c478bd9Sstevel@tonic-gate 			return (NULL);
21917c478bd9Sstevel@tonic-gate 		}
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
21947c478bd9Sstevel@tonic-gate 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) !=
21957c478bd9Sstevel@tonic-gate 		    SS_ISCONNECTING) {
21967c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
21977c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2198d3e55dcdSgww 			    ("T_CONN_CON: state %x\n", so->so_state));
21997c478bd9Sstevel@tonic-gate 			freemsg(mp);
22007c478bd9Sstevel@tonic-gate 			return (NULL);
22017c478bd9Sstevel@tonic-gate 		}
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 		conn_con = &tpr->conn_con;
22047c478bd9Sstevel@tonic-gate 		addrlen = conn_con->RES_length;
22057c478bd9Sstevel@tonic-gate 		/*
22067c478bd9Sstevel@tonic-gate 		 * Allow the address to be of different size than sent down
22077c478bd9Sstevel@tonic-gate 		 * in the T_CONN_REQ as long as it doesn't exceed the maxlen.
22087c478bd9Sstevel@tonic-gate 		 * For AF_UNIX require the identical length.
22097c478bd9Sstevel@tonic-gate 		 */
22107c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_UNIX ?
2211*0f1702c5SYu Xiangning 		    addrlen != (t_uscalar_t)sizeof (sti->sti_ux_laddr) :
2212*0f1702c5SYu Xiangning 		    addrlen > (t_uscalar_t)sti->sti_faddr_maxlen) {
22132caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
22147c478bd9Sstevel@tonic-gate 			    "sockfs: T_conn_con with different "
22157c478bd9Sstevel@tonic-gate 			    "length %u/%d\n",
22167c478bd9Sstevel@tonic-gate 			    addrlen, conn_con->RES_length);
22177c478bd9Sstevel@tonic-gate 			soisdisconnected(so, EPROTO);
2218*0f1702c5SYu Xiangning 			sti->sti_laddr_valid = 0;
2219*0f1702c5SYu Xiangning 			sti->sti_faddr_valid = 0;
22207c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
22217c478bd9Sstevel@tonic-gate 			strsetrerror(SOTOV(so), 0, 0, sogetrderr);
22227c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
22237c478bd9Sstevel@tonic-gate 			strseteof(SOTOV(so), 1);
22247c478bd9Sstevel@tonic-gate 			freemsg(mp);
22257c478bd9Sstevel@tonic-gate 			/*
22267c478bd9Sstevel@tonic-gate 			 * strseteof takes care of read side wakeups,
22277c478bd9Sstevel@tonic-gate 			 * pollwakeups, and signals.
22287c478bd9Sstevel@tonic-gate 			 */
22297c478bd9Sstevel@tonic-gate 			*wakeups = WSLEEP;
22307c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_OUTPUT;
22317c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLOUT;
22327c478bd9Sstevel@tonic-gate 			return (NULL);
22337c478bd9Sstevel@tonic-gate 		}
22347c478bd9Sstevel@tonic-gate 		addr = sogetoff(mp, conn_con->RES_offset, addrlen, 1);
22357c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
22362caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
22377c478bd9Sstevel@tonic-gate 			    "sockfs: T_conn_con with invalid "
22387c478bd9Sstevel@tonic-gate 			    "addrlen/offset %u/%d\n",
22397c478bd9Sstevel@tonic-gate 			    addrlen, conn_con->RES_offset);
22407c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
22417c478bd9Sstevel@tonic-gate 			strsetrerror(SOTOV(so), 0, 0, sogetrderr);
22427c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
22437c478bd9Sstevel@tonic-gate 			strseteof(SOTOV(so), 1);
22447c478bd9Sstevel@tonic-gate 			freemsg(mp);
22457c478bd9Sstevel@tonic-gate 			/*
22467c478bd9Sstevel@tonic-gate 			 * strseteof takes care of read side wakeups,
22477c478bd9Sstevel@tonic-gate 			 * pollwakeups, and signals.
22487c478bd9Sstevel@tonic-gate 			 */
22497c478bd9Sstevel@tonic-gate 			*wakeups = WSLEEP;
22507c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_OUTPUT;
22517c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLOUT;
22527c478bd9Sstevel@tonic-gate 			return (NULL);
22537c478bd9Sstevel@tonic-gate 		}
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 		/*
22567c478bd9Sstevel@tonic-gate 		 * Save for getpeername.
22577c478bd9Sstevel@tonic-gate 		 */
22587c478bd9Sstevel@tonic-gate 		if (so->so_family != AF_UNIX) {
2259*0f1702c5SYu Xiangning 			sti->sti_faddr_len = (socklen_t)addrlen;
2260*0f1702c5SYu Xiangning 			ASSERT(sti->sti_faddr_len <= sti->sti_faddr_maxlen);
2261*0f1702c5SYu Xiangning 			bcopy(addr, sti->sti_faddr_sa, addrlen);
2262*0f1702c5SYu Xiangning 			sti->sti_faddr_valid = 1;
22637c478bd9Sstevel@tonic-gate 		}
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 		if (so->so_peercred != NULL)
22667c478bd9Sstevel@tonic-gate 			crfree(so->so_peercred);
22677c478bd9Sstevel@tonic-gate 		so->so_peercred = DB_CRED(mp);
22687c478bd9Sstevel@tonic-gate 		so->so_cpid = DB_CPID(mp);
22697c478bd9Sstevel@tonic-gate 		if (so->so_peercred != NULL)
22707c478bd9Sstevel@tonic-gate 			crhold(so->so_peercred);
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 		/* Wakeup anybody sleeping in sowaitconnected */
22737c478bd9Sstevel@tonic-gate 		soisconnected(so);
22747c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 		/*
22777c478bd9Sstevel@tonic-gate 		 * The socket is now available for sending data.
22787c478bd9Sstevel@tonic-gate 		 */
22797c478bd9Sstevel@tonic-gate 		*wakeups = WSLEEP;
22807c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_OUTPUT;
22817c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLOUT;
22827c478bd9Sstevel@tonic-gate 		freemsg(mp);
22837c478bd9Sstevel@tonic-gate 		return (NULL);
22847c478bd9Sstevel@tonic-gate 	}
22857c478bd9Sstevel@tonic-gate 
2286c28749e9Skais 	/*
2287c28749e9Skais 	 * Extra processing in case of an SSL proxy, before queuing or
2288c28749e9Skais 	 * forwarding to the fallback endpoint
2289c28749e9Skais 	 */
2290c28749e9Skais 	case T_SSL_PROXY_CONN_IND:
22917c478bd9Sstevel@tonic-gate 	case T_CONN_IND:
22927c478bd9Sstevel@tonic-gate 		/*
22937c478bd9Sstevel@tonic-gate 		 * Verify the min size and queue the message on
2294*0f1702c5SYu Xiangning 		 * the sti_conn_ind_head/tail list.
22957c478bd9Sstevel@tonic-gate 		 */
22967c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_conn_ind)) {
22972caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
22987c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_CONN_IND. Len = %ld\n",
22997c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
23007c478bd9Sstevel@tonic-gate 			freemsg(mp);
23017c478bd9Sstevel@tonic-gate 			return (NULL);
23027c478bd9Sstevel@tonic-gate 		}
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 		if (audit_active)
23057c478bd9Sstevel@tonic-gate 			audit_sock(T_CONN_IND, strvp2wq(vp), mp, 0);
23067c478bd9Sstevel@tonic-gate 		if (!(so->so_state & SS_ACCEPTCONN)) {
23072caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
23087c478bd9Sstevel@tonic-gate 			    "sockfs: T_conn_ind on non-listening socket\n");
23097c478bd9Sstevel@tonic-gate 			freemsg(mp);
23107c478bd9Sstevel@tonic-gate 			return (NULL);
23117c478bd9Sstevel@tonic-gate 		}
2312c28749e9Skais 
2313c28749e9Skais 		if (tpr->type == T_SSL_PROXY_CONN_IND && mp->b_cont == NULL) {
2314c28749e9Skais 			/* No context: need to fall back */
2315c28749e9Skais 			struct sonode *fbso;
2316c28749e9Skais 			stdata_t *fbstp;
2317c28749e9Skais 
2318c28749e9Skais 			tpr->type = T_CONN_IND;
2319c28749e9Skais 
2320*0f1702c5SYu Xiangning 			fbso = kssl_find_fallback(sti->sti_kssl_ent);
2321c28749e9Skais 
2322c28749e9Skais 			/*
2323c28749e9Skais 			 * No fallback: the remote will timeout and
2324c28749e9Skais 			 * disconnect.
2325c28749e9Skais 			 */
2326c28749e9Skais 			if (fbso == NULL) {
2327c28749e9Skais 				freemsg(mp);
2328c28749e9Skais 				return (NULL);
2329c28749e9Skais 			}
2330c28749e9Skais 			fbstp = SOTOV(fbso)->v_stream;
2331c28749e9Skais 			qreply(fbstp->sd_wrq->q_next, mp);
2332c28749e9Skais 			return (NULL);
2333c28749e9Skais 		}
23347c478bd9Sstevel@tonic-gate 		soqueueconnind(so, mp);
23357c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
23367c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
23377c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
23387c478bd9Sstevel@tonic-gate 		return (NULL);
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	case T_ORDREL_IND:
23417c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_ordrel_ind)) {
23422caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
23437c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_ORDREL_IND. Len = %ld\n",
23447c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
23457c478bd9Sstevel@tonic-gate 			freemsg(mp);
23467c478bd9Sstevel@tonic-gate 			return (NULL);
23477c478bd9Sstevel@tonic-gate 		}
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 		/*
23507c478bd9Sstevel@tonic-gate 		 * Some providers send this when not fully connected.
23517c478bd9Sstevel@tonic-gate 		 * SunLink X.25 needs to retrieve disconnect reason after
23527c478bd9Sstevel@tonic-gate 		 * disconnect for compatibility. It uses T_ORDREL_IND
23537c478bd9Sstevel@tonic-gate 		 * instead of T_DISCON_IND so that it may use the
23547c478bd9Sstevel@tonic-gate 		 * endpoint after a connect failure to retrieve the
23557c478bd9Sstevel@tonic-gate 		 * reason using an ioctl. Thus we explicitly clear
23567c478bd9Sstevel@tonic-gate 		 * SS_ISCONNECTING here for SunLink X.25.
23577c478bd9Sstevel@tonic-gate 		 * This is a needed TPI violation.
23587c478bd9Sstevel@tonic-gate 		 */
23597c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
23607c478bd9Sstevel@tonic-gate 		so->so_state &= ~SS_ISCONNECTING;
23617c478bd9Sstevel@tonic-gate 		socantrcvmore(so);
23627c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
23637c478bd9Sstevel@tonic-gate 		strseteof(SOTOV(so), 1);
23647c478bd9Sstevel@tonic-gate 		/*
23657c478bd9Sstevel@tonic-gate 		 * strseteof takes care of read side wakeups,
23667c478bd9Sstevel@tonic-gate 		 * pollwakeups, and signals.
23677c478bd9Sstevel@tonic-gate 		 */
23687c478bd9Sstevel@tonic-gate 		freemsg(mp);
23697c478bd9Sstevel@tonic-gate 		return (NULL);
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	case T_DISCON_IND:
23727c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_discon_ind)) {
23732caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
23747c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_DISCON_IND. Len = %ld\n",
23757c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
23767c478bd9Sstevel@tonic-gate 			freemsg(mp);
23777c478bd9Sstevel@tonic-gate 			return (NULL);
23787c478bd9Sstevel@tonic-gate 		}
23797c478bd9Sstevel@tonic-gate 		if (so->so_state & SS_ACCEPTCONN) {
23807c478bd9Sstevel@tonic-gate 			/*
23817c478bd9Sstevel@tonic-gate 			 * This is a listener. Look for a queued T_CONN_IND
23827c478bd9Sstevel@tonic-gate 			 * with a matching sequence number and remove it
23837c478bd9Sstevel@tonic-gate 			 * from the list.
23847c478bd9Sstevel@tonic-gate 			 * It is normal to not find the sequence number since
23857c478bd9Sstevel@tonic-gate 			 * the soaccept might have already dequeued it
23867c478bd9Sstevel@tonic-gate 			 * (in which case the T_CONN_RES will fail with
23877c478bd9Sstevel@tonic-gate 			 * TBADSEQ).
23887c478bd9Sstevel@tonic-gate 			 */
23897c478bd9Sstevel@tonic-gate 			(void) soflushconnind(so, tpr->discon_ind.SEQ_number);
23907c478bd9Sstevel@tonic-gate 			freemsg(mp);
23917c478bd9Sstevel@tonic-gate 			return (0);
23927c478bd9Sstevel@tonic-gate 		}
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 		/*
23957c478bd9Sstevel@tonic-gate 		 * Not a listener
23967c478bd9Sstevel@tonic-gate 		 *
23977c478bd9Sstevel@tonic-gate 		 * If SS_CANTRCVMORE for AF_UNIX ignore the discon_reason.
23987c478bd9Sstevel@tonic-gate 		 * Such a discon_ind appears when the peer has first done
23997c478bd9Sstevel@tonic-gate 		 * a shutdown() followed by a close() in which case we just
24007c478bd9Sstevel@tonic-gate 		 * want to record socantsendmore.
24017c478bd9Sstevel@tonic-gate 		 * In this case sockfs first receives a T_ORDREL_IND followed
24027c478bd9Sstevel@tonic-gate 		 * by a T_DISCON_IND.
24037c478bd9Sstevel@tonic-gate 		 * Note that for other transports (e.g. TCP) we need to handle
24047c478bd9Sstevel@tonic-gate 		 * the discon_ind in this case since it signals an error.
24057c478bd9Sstevel@tonic-gate 		 */
24067c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
24077c478bd9Sstevel@tonic-gate 		if ((so->so_state & SS_CANTRCVMORE) &&
24087c478bd9Sstevel@tonic-gate 		    (so->so_family == AF_UNIX)) {
24097c478bd9Sstevel@tonic-gate 			socantsendmore(so);
2410*0f1702c5SYu Xiangning 			sti->sti_faddr_valid = 0;
24117c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
24127c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
24137c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2414d3e55dcdSgww 			    ("T_DISCON_IND: error %d\n", so->so_error));
24157c478bd9Sstevel@tonic-gate 			freemsg(mp);
24167c478bd9Sstevel@tonic-gate 			/*
24177c478bd9Sstevel@tonic-gate 			 * Set these variables for caller to process them.
24187c478bd9Sstevel@tonic-gate 			 * For the else part where T_DISCON_IND is processed,
24197c478bd9Sstevel@tonic-gate 			 * this will be done in the function being called
24207c478bd9Sstevel@tonic-gate 			 * (strsock_discon_ind())
24217c478bd9Sstevel@tonic-gate 			 */
24227c478bd9Sstevel@tonic-gate 			*wakeups = WSLEEP;
24237c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_OUTPUT;
24247c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLOUT;
24257c478bd9Sstevel@tonic-gate 		} else if (so->so_flag & (SOASYNC_UNBIND | SOLOCKED)) {
24267c478bd9Sstevel@tonic-gate 			/*
24277c478bd9Sstevel@tonic-gate 			 * Deferred processing of T_DISCON_IND
24287c478bd9Sstevel@tonic-gate 			 */
24297c478bd9Sstevel@tonic-gate 			so_save_discon_ind(so, mp, strsock_discon_ind);
24307c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
24317c478bd9Sstevel@tonic-gate 		} else {
24327c478bd9Sstevel@tonic-gate 			/*
24337c478bd9Sstevel@tonic-gate 			 * Process T_DISCON_IND now
24347c478bd9Sstevel@tonic-gate 			 */
24357c478bd9Sstevel@tonic-gate 			(void) strsock_discon_ind(so, mp);
24367c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
24377c478bd9Sstevel@tonic-gate 		}
24387c478bd9Sstevel@tonic-gate 		return (NULL);
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	case T_UDERROR_IND: {
24417c478bd9Sstevel@tonic-gate 		struct T_uderror_ind	*tudi = &tpr->uderror_ind;
24427c478bd9Sstevel@tonic-gate 		void			*addr;
24437c478bd9Sstevel@tonic-gate 		t_uscalar_t		addrlen;
24447c478bd9Sstevel@tonic-gate 		int			error;
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
2447d3e55dcdSgww 		    ("T_UDERROR_IND: error %d\n", tudi->ERROR_type));
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_uderror_ind)) {
24502caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
24517c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_UDERROR_IND. Len = %ld\n",
24527c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
24537c478bd9Sstevel@tonic-gate 			freemsg(mp);
24547c478bd9Sstevel@tonic-gate 			return (NULL);
24557c478bd9Sstevel@tonic-gate 		}
24567c478bd9Sstevel@tonic-gate 		/* Ignore on connection-oriented transports */
24577c478bd9Sstevel@tonic-gate 		if (so->so_mode & SM_CONNREQUIRED) {
24587c478bd9Sstevel@tonic-gate 			freemsg(mp);
24597c478bd9Sstevel@tonic-gate 			eprintsoline(so, 0);
24602caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
24617c478bd9Sstevel@tonic-gate 			    "sockfs: T_uderror_ind on connection-oriented "
24627c478bd9Sstevel@tonic-gate 			    "transport\n");
24637c478bd9Sstevel@tonic-gate 			return (NULL);
24647c478bd9Sstevel@tonic-gate 		}
24657c478bd9Sstevel@tonic-gate 		addrlen = tudi->DEST_length;
24667c478bd9Sstevel@tonic-gate 		addr = sogetoff(mp, tudi->DEST_offset, addrlen, 1);
24677c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
24682caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
24697c478bd9Sstevel@tonic-gate 			    "sockfs: T_uderror_ind with invalid "
24707c478bd9Sstevel@tonic-gate 			    "addrlen/offset %u/%d\n",
24717c478bd9Sstevel@tonic-gate 			    addrlen, tudi->DEST_offset);
24727c478bd9Sstevel@tonic-gate 			freemsg(mp);
24737c478bd9Sstevel@tonic-gate 			return (NULL);
24747c478bd9Sstevel@tonic-gate 		}
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 		/* Verify source address for connected socket. */
24777c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
24787c478bd9Sstevel@tonic-gate 		if (so->so_state & SS_ISCONNECTED) {
24797c478bd9Sstevel@tonic-gate 			void *faddr;
24807c478bd9Sstevel@tonic-gate 			t_uscalar_t faddr_len;
24817c478bd9Sstevel@tonic-gate 			boolean_t match = B_FALSE;
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 			switch (so->so_family) {
24847c478bd9Sstevel@tonic-gate 			case AF_INET: {
24857c478bd9Sstevel@tonic-gate 				/* Compare just IP address and port */
24867c478bd9Sstevel@tonic-gate 				struct sockaddr_in *sin1, *sin2;
24877c478bd9Sstevel@tonic-gate 
2488*0f1702c5SYu Xiangning 				sin1 = (struct sockaddr_in *)sti->sti_faddr_sa;
24897c478bd9Sstevel@tonic-gate 				sin2 = (struct sockaddr_in *)addr;
24907c478bd9Sstevel@tonic-gate 				if (addrlen == sizeof (struct sockaddr_in) &&
24917c478bd9Sstevel@tonic-gate 				    sin1->sin_port == sin2->sin_port &&
24927c478bd9Sstevel@tonic-gate 				    sin1->sin_addr.s_addr ==
24937c478bd9Sstevel@tonic-gate 				    sin2->sin_addr.s_addr)
24947c478bd9Sstevel@tonic-gate 					match = B_TRUE;
24957c478bd9Sstevel@tonic-gate 				break;
24967c478bd9Sstevel@tonic-gate 			}
24977c478bd9Sstevel@tonic-gate 			case AF_INET6: {
24987c478bd9Sstevel@tonic-gate 				/* Compare just IP address and port. Not flow */
24997c478bd9Sstevel@tonic-gate 				struct sockaddr_in6 *sin1, *sin2;
25007c478bd9Sstevel@tonic-gate 
2501*0f1702c5SYu Xiangning 				sin1 = (struct sockaddr_in6 *)sti->sti_faddr_sa;
25027c478bd9Sstevel@tonic-gate 				sin2 = (struct sockaddr_in6 *)addr;
25037c478bd9Sstevel@tonic-gate 				if (addrlen == sizeof (struct sockaddr_in6) &&
25047c478bd9Sstevel@tonic-gate 				    sin1->sin6_port == sin2->sin6_port &&
25057c478bd9Sstevel@tonic-gate 				    IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr,
2506d3e55dcdSgww 				    &sin2->sin6_addr))
25077c478bd9Sstevel@tonic-gate 					match = B_TRUE;
25087c478bd9Sstevel@tonic-gate 				break;
25097c478bd9Sstevel@tonic-gate 			}
25107c478bd9Sstevel@tonic-gate 			case AF_UNIX:
2511*0f1702c5SYu Xiangning 				faddr = &sti->sti_ux_faddr;
25127c478bd9Sstevel@tonic-gate 				faddr_len =
2513*0f1702c5SYu Xiangning 				    (t_uscalar_t)sizeof (sti->sti_ux_faddr);
25147c478bd9Sstevel@tonic-gate 				if (faddr_len == addrlen &&
25157c478bd9Sstevel@tonic-gate 				    bcmp(addr, faddr, addrlen) == 0)
25167c478bd9Sstevel@tonic-gate 					match = B_TRUE;
25177c478bd9Sstevel@tonic-gate 				break;
25187c478bd9Sstevel@tonic-gate 			default:
2519*0f1702c5SYu Xiangning 				faddr = sti->sti_faddr_sa;
2520*0f1702c5SYu Xiangning 				faddr_len = (t_uscalar_t)sti->sti_faddr_len;
25217c478bd9Sstevel@tonic-gate 				if (faddr_len == addrlen &&
25227c478bd9Sstevel@tonic-gate 				    bcmp(addr, faddr, addrlen) == 0)
25237c478bd9Sstevel@tonic-gate 					match = B_TRUE;
25247c478bd9Sstevel@tonic-gate 				break;
25257c478bd9Sstevel@tonic-gate 			}
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 			if (!match) {
25287c478bd9Sstevel@tonic-gate #ifdef DEBUG
25297c478bd9Sstevel@tonic-gate 				dprintso(so, 0,
2530d3e55dcdSgww 				    ("sockfs: T_UDERR_IND mismatch: %s - ",
2531d3e55dcdSgww 				    pr_addr(so->so_family,
2532*0f1702c5SYu Xiangning 				    (struct sockaddr *)addr, addrlen)));
25337c478bd9Sstevel@tonic-gate 				dprintso(so, 0, ("%s\n",
2534*0f1702c5SYu Xiangning 				    pr_addr(so->so_family, sti->sti_faddr_sa,
2535*0f1702c5SYu Xiangning 				    sti->sti_faddr_len)));
25367c478bd9Sstevel@tonic-gate #endif /* DEBUG */
25377c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
25387c478bd9Sstevel@tonic-gate 				freemsg(mp);
25397c478bd9Sstevel@tonic-gate 				return (NULL);
25407c478bd9Sstevel@tonic-gate 			}
25417c478bd9Sstevel@tonic-gate 			/*
25427c478bd9Sstevel@tonic-gate 			 * Make the write error nonpersistent. If the error
25437c478bd9Sstevel@tonic-gate 			 * is zero we use ECONNRESET.
25447c478bd9Sstevel@tonic-gate 			 * This assumes that the name space for ERROR_type
25457c478bd9Sstevel@tonic-gate 			 * is the errno name space.
25467c478bd9Sstevel@tonic-gate 			 */
25477c478bd9Sstevel@tonic-gate 			if (tudi->ERROR_type != 0)
25487c478bd9Sstevel@tonic-gate 				error = tudi->ERROR_type;
25497c478bd9Sstevel@tonic-gate 			else
25507c478bd9Sstevel@tonic-gate 				error = ECONNRESET;
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 			soseterror(so, error);
25537c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
25547c478bd9Sstevel@tonic-gate 			strsetrerror(SOTOV(so), 0, 0, sogetrderr);
25557c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
25567c478bd9Sstevel@tonic-gate 			*wakeups = RSLEEP | WSLEEP;
25577c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_INPUT | S_RDNORM | S_OUTPUT;
25587c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM | POLLOUT;
25597c478bd9Sstevel@tonic-gate 			freemsg(mp);
25607c478bd9Sstevel@tonic-gate 			return (NULL);
25617c478bd9Sstevel@tonic-gate 		}
25627c478bd9Sstevel@tonic-gate 		/*
25637c478bd9Sstevel@tonic-gate 		 * If the application asked for delayed errors
2564*0f1702c5SYu Xiangning 		 * record the T_UDERROR_IND sti_eaddr_mp and the reason in
2565*0f1702c5SYu Xiangning 		 * sti_delayed_error for delayed error posting. If the reason
25667c478bd9Sstevel@tonic-gate 		 * is zero use ECONNRESET.
25677c478bd9Sstevel@tonic-gate 		 * Note that delayed error indications do not make sense for
25687c478bd9Sstevel@tonic-gate 		 * AF_UNIX sockets since sendto checks that the destination
25697c478bd9Sstevel@tonic-gate 		 * address is valid at the time of the sendto.
25707c478bd9Sstevel@tonic-gate 		 */
25717c478bd9Sstevel@tonic-gate 		if (!(so->so_options & SO_DGRAM_ERRIND)) {
25727c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
25737c478bd9Sstevel@tonic-gate 			freemsg(mp);
25747c478bd9Sstevel@tonic-gate 			return (NULL);
25757c478bd9Sstevel@tonic-gate 		}
2576*0f1702c5SYu Xiangning 		if (sti->sti_eaddr_mp != NULL)
2577*0f1702c5SYu Xiangning 			freemsg(sti->sti_eaddr_mp);
25787c478bd9Sstevel@tonic-gate 
2579*0f1702c5SYu Xiangning 		sti->sti_eaddr_mp = mp;
25807c478bd9Sstevel@tonic-gate 		if (tudi->ERROR_type != 0)
25817c478bd9Sstevel@tonic-gate 			error = tudi->ERROR_type;
25827c478bd9Sstevel@tonic-gate 		else
25837c478bd9Sstevel@tonic-gate 			error = ECONNRESET;
2584*0f1702c5SYu Xiangning 		sti->sti_delayed_error = (ushort_t)error;
25857c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
25867c478bd9Sstevel@tonic-gate 		return (NULL);
25877c478bd9Sstevel@tonic-gate 	}
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	case T_ERROR_ACK:
25907c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
2591d3e55dcdSgww 		    ("strsock_proto: T_ERROR_ACK for %d, error %d/%d\n",
2592d3e55dcdSgww 		    tpr->error_ack.ERROR_prim,
2593d3e55dcdSgww 		    tpr->error_ack.TLI_error,
2594d3e55dcdSgww 		    tpr->error_ack.UNIX_error));
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_error_ack)) {
25972caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
25987c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_ERROR_ACK. Len = %ld\n",
25997c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
26007c478bd9Sstevel@tonic-gate 			freemsg(mp);
26017c478bd9Sstevel@tonic-gate 			return (NULL);
26027c478bd9Sstevel@tonic-gate 		}
26037c478bd9Sstevel@tonic-gate 		/*
26047c478bd9Sstevel@tonic-gate 		 * Check if we were waiting for the async message
26057c478bd9Sstevel@tonic-gate 		 */
26067c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
26077c478bd9Sstevel@tonic-gate 		if ((so->so_flag & SOASYNC_UNBIND) &&
26087c478bd9Sstevel@tonic-gate 		    tpr->error_ack.ERROR_prim == T_UNBIND_REQ) {
26097c478bd9Sstevel@tonic-gate 			so_unlock_single(so, SOASYNC_UNBIND);
26107c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
26117c478bd9Sstevel@tonic-gate 			freemsg(mp);
26127c478bd9Sstevel@tonic-gate 			return (NULL);
26137c478bd9Sstevel@tonic-gate 		}
26147c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
26157c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
26167c478bd9Sstevel@tonic-gate 		return (NULL);
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	case T_OK_ACK:
26197c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_ok_ack)) {
26202caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
26217c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_OK_ACK. Len = %ld\n",
26227c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
26237c478bd9Sstevel@tonic-gate 			freemsg(mp);
26247c478bd9Sstevel@tonic-gate 			return (NULL);
26257c478bd9Sstevel@tonic-gate 		}
26267c478bd9Sstevel@tonic-gate 		/*
26277c478bd9Sstevel@tonic-gate 		 * Check if we were waiting for the async message
26287c478bd9Sstevel@tonic-gate 		 */
26297c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
26307c478bd9Sstevel@tonic-gate 		if ((so->so_flag & SOASYNC_UNBIND) &&
26317c478bd9Sstevel@tonic-gate 		    tpr->ok_ack.CORRECT_prim == T_UNBIND_REQ) {
26327c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2633d3e55dcdSgww 			    ("strsock_proto: T_OK_ACK async unbind\n"));
26347c478bd9Sstevel@tonic-gate 			so_unlock_single(so, SOASYNC_UNBIND);
26357c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
26367c478bd9Sstevel@tonic-gate 			freemsg(mp);
26377c478bd9Sstevel@tonic-gate 			return (NULL);
26387c478bd9Sstevel@tonic-gate 		}
26397c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
26407c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
26417c478bd9Sstevel@tonic-gate 		return (NULL);
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 	case T_INFO_ACK:
26447c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_info_ack)) {
26452caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
26467c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_INFO_ACK. Len = %ld\n",
26477c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
26487c478bd9Sstevel@tonic-gate 			freemsg(mp);
26497c478bd9Sstevel@tonic-gate 			return (NULL);
26507c478bd9Sstevel@tonic-gate 		}
26517c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
26527c478bd9Sstevel@tonic-gate 		return (NULL);
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	case T_CAPABILITY_ACK:
26557c478bd9Sstevel@tonic-gate 		/*
26567c478bd9Sstevel@tonic-gate 		 * A T_capability_ack need only be large enough to hold
26577c478bd9Sstevel@tonic-gate 		 * the PRIM_type and CAP_bits1 fields; checking for anything
26587c478bd9Sstevel@tonic-gate 		 * larger might reject a correct response from an older
26597c478bd9Sstevel@tonic-gate 		 * provider.
26607c478bd9Sstevel@tonic-gate 		 */
26617c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < 2 * sizeof (t_uscalar_t)) {
26622caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
26637c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_CAPABILITY_ACK. Len = %ld\n",
26647c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
26657c478bd9Sstevel@tonic-gate 			freemsg(mp);
26667c478bd9Sstevel@tonic-gate 			return (NULL);
26677c478bd9Sstevel@tonic-gate 		}
26687c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
26697c478bd9Sstevel@tonic-gate 		return (NULL);
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 	case T_BIND_ACK:
26727c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_bind_ack)) {
26732caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
26747c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_BIND_ACK. Len = %ld\n",
26757c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
26767c478bd9Sstevel@tonic-gate 			freemsg(mp);
26777c478bd9Sstevel@tonic-gate 			return (NULL);
26787c478bd9Sstevel@tonic-gate 		}
26797c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
26807c478bd9Sstevel@tonic-gate 		return (NULL);
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 	case T_OPTMGMT_ACK:
26837c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_optmgmt_ack)) {
26842caf0dcdSrshoaib 			zcmn_err(getzoneid(), CE_WARN,
26857c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_OPTMGMT_ACK. Len = %ld\n",
26867c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
26877c478bd9Sstevel@tonic-gate 			freemsg(mp);
26887c478bd9Sstevel@tonic-gate 			return (NULL);
26897c478bd9Sstevel@tonic-gate 		}
26907c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
26917c478bd9Sstevel@tonic-gate 		return (NULL);
26927c478bd9Sstevel@tonic-gate 	default:
26937c478bd9Sstevel@tonic-gate #ifdef DEBUG
26942caf0dcdSrshoaib 		zcmn_err(getzoneid(), CE_WARN,
2695d3e55dcdSgww 		    "sockfs: unknown TPI primitive %d received\n",
2696d3e55dcdSgww 		    tpr->type);
26977c478bd9Sstevel@tonic-gate #endif /* DEBUG */
26987c478bd9Sstevel@tonic-gate 		freemsg(mp);
26997c478bd9Sstevel@tonic-gate 		return (NULL);
27007c478bd9Sstevel@tonic-gate 	}
27017c478bd9Sstevel@tonic-gate }
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate /*
27047c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to receive other
27057c478bd9Sstevel@tonic-gate  * (non-data, and non-proto) messages.
27067c478bd9Sstevel@tonic-gate  *
27077c478bd9Sstevel@tonic-gate  * Returns NULL if the message was consumed.
27087c478bd9Sstevel@tonic-gate  * Returns an mblk to make that mblk be processed by the stream head.
27097c478bd9Sstevel@tonic-gate  *
27107c478bd9Sstevel@tonic-gate  * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and
27117c478bd9Sstevel@tonic-gate  * *pollwakeups) for the stream head to take action on.
27127c478bd9Sstevel@tonic-gate  */
27137c478bd9Sstevel@tonic-gate static mblk_t *
27147c478bd9Sstevel@tonic-gate strsock_misc(vnode_t *vp, mblk_t *mp,
27157c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
27167c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
27177c478bd9Sstevel@tonic-gate {
27187c478bd9Sstevel@tonic-gate 	struct sonode *so;
2719*0f1702c5SYu Xiangning 	sotpi_info_t *sti;
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate 	so = VTOSO(vp);
2722*0f1702c5SYu Xiangning 	sti = SOTOTPI(so);
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("strsock_misc(%p, %p, 0x%x)\n",
2725903a11ebSrh 	    (void *)vp, (void *)mp, DB_TYPE(mp)));
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	/* Set default return values */
27287c478bd9Sstevel@tonic-gate 	*wakeups = *allmsgsigs = *firstmsgsigs = *pollwakeups = 0;
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
27317c478bd9Sstevel@tonic-gate 	case M_PCSIG:
27327c478bd9Sstevel@tonic-gate 		/*
27337c478bd9Sstevel@tonic-gate 		 * This assumes that an M_PCSIG for the urgent data arrives
27347c478bd9Sstevel@tonic-gate 		 * before the corresponding T_EXDATA_IND.
27357c478bd9Sstevel@tonic-gate 		 *
27367c478bd9Sstevel@tonic-gate 		 * Note: Just like in SunOS 4.X and 4.4BSD a poll will be
27377c478bd9Sstevel@tonic-gate 		 * awoken before the urgent data shows up.
27387c478bd9Sstevel@tonic-gate 		 * For OOBINLINE this can result in select returning
27397c478bd9Sstevel@tonic-gate 		 * only exceptions as opposed to except|read.
27407c478bd9Sstevel@tonic-gate 		 */
27417c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr == SIGURG) {
27427c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
27437c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2744d3e55dcdSgww 			    ("SIGURG(%p): counts %d/%d state %s\n",
2745*0f1702c5SYu Xiangning 			    (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt,
2746d3e55dcdSgww 			    pr_state(so->so_state, so->so_mode)));
27477c478bd9Sstevel@tonic-gate 			so_oob_sig(so, 1, allmsgsigs, pollwakeups);
27487c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2749d3e55dcdSgww 			    ("after SIGURG(%p): counts %d/%d "
2750d3e55dcdSgww 			    " poll 0x%x sig 0x%x state %s\n",
2751*0f1702c5SYu Xiangning 			    (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt,
2752*0f1702c5SYu Xiangning 			    *pollwakeups, *allmsgsigs,
2753d3e55dcdSgww 			    pr_state(so->so_state, so->so_mode)));
27547c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
27557c478bd9Sstevel@tonic-gate 		}
27567c478bd9Sstevel@tonic-gate 		freemsg(mp);
27577c478bd9Sstevel@tonic-gate 		return (NULL);
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	case M_SIG:
27607c478bd9Sstevel@tonic-gate 	case M_HANGUP:
27617c478bd9Sstevel@tonic-gate 	case M_UNHANGUP:
27627c478bd9Sstevel@tonic-gate 	case M_ERROR:
27637c478bd9Sstevel@tonic-gate 		/* M_ERRORs etc are ignored */
27647c478bd9Sstevel@tonic-gate 		freemsg(mp);
27657c478bd9Sstevel@tonic-gate 		return (NULL);
27667c478bd9Sstevel@tonic-gate 
27677c478bd9Sstevel@tonic-gate 	case M_FLUSH:
27687c478bd9Sstevel@tonic-gate 		/*
27697c478bd9Sstevel@tonic-gate 		 * Do not flush read queue. If the M_FLUSH
27707c478bd9Sstevel@tonic-gate 		 * arrives because of an impending T_discon_ind
27717c478bd9Sstevel@tonic-gate 		 * we still have to keep any queued data - this is part of
27727c478bd9Sstevel@tonic-gate 		 * socket semantics.
27737c478bd9Sstevel@tonic-gate 		 */
27747c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
27757c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHR;
27767c478bd9Sstevel@tonic-gate 			return (mp);
27777c478bd9Sstevel@tonic-gate 		}
27787c478bd9Sstevel@tonic-gate 		freemsg(mp);
27797c478bd9Sstevel@tonic-gate 		return (NULL);
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	default:
27827c478bd9Sstevel@tonic-gate 		return (mp);
27837c478bd9Sstevel@tonic-gate 	}
27847c478bd9Sstevel@tonic-gate }
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate /* Register to receive signals for certain events */
27887c478bd9Sstevel@tonic-gate int
27897c478bd9Sstevel@tonic-gate so_set_asyncsigs(vnode_t *vp, pid_t pgrp, int events, int mode, cred_t *cr)
27907c478bd9Sstevel@tonic-gate {
27917c478bd9Sstevel@tonic-gate 	struct strsigset ss;
27927c478bd9Sstevel@tonic-gate 	int32_t rval;
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 	/*
27957c478bd9Sstevel@tonic-gate 	 * Note that SOLOCKED will be set except for the call from soaccept().
27967c478bd9Sstevel@tonic-gate 	 */
27977c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&VTOSO(vp)->so_lock));
27987c478bd9Sstevel@tonic-gate 	ss.ss_pid = pgrp;
27997c478bd9Sstevel@tonic-gate 	ss.ss_events = events;
28007c478bd9Sstevel@tonic-gate 	return (strioctl(vp, I_ESETSIG, (intptr_t)&ss, mode, K_TO_K, cr,
28017c478bd9Sstevel@tonic-gate 	    &rval));
28027c478bd9Sstevel@tonic-gate }
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate /* Register for events matching the SS_ASYNC flag */
28067c478bd9Sstevel@tonic-gate int
28077c478bd9Sstevel@tonic-gate so_set_events(struct sonode *so, vnode_t *vp, cred_t *cr)
28087c478bd9Sstevel@tonic-gate {
28097c478bd9Sstevel@tonic-gate 	int events = so->so_state & SS_ASYNC ?
28107c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT :
28117c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG;
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	return (so_set_asyncsigs(vp, so->so_pgrp, events, 0, cr));
28147c478bd9Sstevel@tonic-gate }
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate /* Change the SS_ASYNC flag, and update signal delivery if needed */
28187c478bd9Sstevel@tonic-gate int
28197c478bd9Sstevel@tonic-gate so_flip_async(struct sonode *so, vnode_t *vp, int mode, cred_t *cr)
28207c478bd9Sstevel@tonic-gate {
28217c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&so->so_lock));
28227c478bd9Sstevel@tonic-gate 	if (so->so_pgrp != 0) {
28237c478bd9Sstevel@tonic-gate 		int error;
28247c478bd9Sstevel@tonic-gate 		int events = so->so_state & SS_ASYNC ?		/* Old flag */
28257c478bd9Sstevel@tonic-gate 		    S_RDBAND | S_BANDURG :			/* New sigs */
28267c478bd9Sstevel@tonic-gate 		    S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT;
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 		so_lock_single(so);
28297c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 		error = so_set_asyncsigs(vp, so->so_pgrp, events, mode, cr);
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
28347c478bd9Sstevel@tonic-gate 		so_unlock_single(so, SOLOCKED);
28357c478bd9Sstevel@tonic-gate 		if (error)
28367c478bd9Sstevel@tonic-gate 			return (error);
28377c478bd9Sstevel@tonic-gate 	}
28387c478bd9Sstevel@tonic-gate 	so->so_state ^= SS_ASYNC;
28397c478bd9Sstevel@tonic-gate 	return (0);
28407c478bd9Sstevel@tonic-gate }
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate /*
28437c478bd9Sstevel@tonic-gate  * Set new pid/pgrp for SIGPOLL (or SIGIO for FIOASYNC mode), replacing
28447c478bd9Sstevel@tonic-gate  * any existing one.  If passed zero, just clear the existing one.
28457c478bd9Sstevel@tonic-gate  */
28467c478bd9Sstevel@tonic-gate int
28477c478bd9Sstevel@tonic-gate so_set_siggrp(struct sonode *so, vnode_t *vp, pid_t pgrp, int mode, cred_t *cr)
28487c478bd9Sstevel@tonic-gate {
28497c478bd9Sstevel@tonic-gate 	int events = so->so_state & SS_ASYNC ?
28507c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT :
28517c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG;
28527c478bd9Sstevel@tonic-gate 	int error;
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&so->so_lock));
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 	/*
28577c478bd9Sstevel@tonic-gate 	 * Change socket process (group).
28587c478bd9Sstevel@tonic-gate 	 *
28597c478bd9Sstevel@tonic-gate 	 * strioctl (via so_set_asyncsigs) will perform permission check and
28607c478bd9Sstevel@tonic-gate 	 * also keep a PID_HOLD to prevent the pid from being reused.
28617c478bd9Sstevel@tonic-gate 	 */
28627c478bd9Sstevel@tonic-gate 	so_lock_single(so);
28637c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
28647c478bd9Sstevel@tonic-gate 
28657c478bd9Sstevel@tonic-gate 	if (pgrp != 0) {
28667c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("setown: adding pgrp %d ev 0x%x\n",
28677c478bd9Sstevel@tonic-gate 		    pgrp, events));
28687c478bd9Sstevel@tonic-gate 		error = so_set_asyncsigs(vp, pgrp, events, mode, cr);
28697c478bd9Sstevel@tonic-gate 		if (error != 0) {
28707c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
28717c478bd9Sstevel@tonic-gate 			goto bad;
28727c478bd9Sstevel@tonic-gate 		}
28737c478bd9Sstevel@tonic-gate 	}
28747c478bd9Sstevel@tonic-gate 	/* Remove the previously registered process/group */
28757c478bd9Sstevel@tonic-gate 	if (so->so_pgrp != 0) {
28767c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("setown: removing pgrp %d\n", so->so_pgrp));
28777c478bd9Sstevel@tonic-gate 		error = so_set_asyncsigs(vp, so->so_pgrp, 0, mode, cr);
28787c478bd9Sstevel@tonic-gate 		if (error != 0) {
28797c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
28807c478bd9Sstevel@tonic-gate 			error = 0;
28817c478bd9Sstevel@tonic-gate 		}
28827c478bd9Sstevel@tonic-gate 	}
28837c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
28847c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
28857c478bd9Sstevel@tonic-gate 	so->so_pgrp = pgrp;
28867c478bd9Sstevel@tonic-gate 	return (0);
28877c478bd9Sstevel@tonic-gate bad:
28887c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
28897c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
28907c478bd9Sstevel@tonic-gate 	return (error);
28917c478bd9Sstevel@tonic-gate }
28927c478bd9Sstevel@tonic-gate 
2893*0f1702c5SYu Xiangning /*
2894*0f1702c5SYu Xiangning  * Wrapper for getmsg. If the socket has been converted to a stream
2895*0f1702c5SYu Xiangning  * pass the request to the stream head.
2896*0f1702c5SYu Xiangning  */
2897*0f1702c5SYu Xiangning int
2898*0f1702c5SYu Xiangning sock_getmsg(
2899*0f1702c5SYu Xiangning 	struct vnode *vp,
2900*0f1702c5SYu Xiangning 	struct strbuf *mctl,
2901*0f1702c5SYu Xiangning 	struct strbuf *mdata,
2902*0f1702c5SYu Xiangning 	uchar_t *prip,
2903*0f1702c5SYu Xiangning 	int *flagsp,
2904*0f1702c5SYu Xiangning 	int fmode,
2905*0f1702c5SYu Xiangning 	rval_t *rvp
2906*0f1702c5SYu Xiangning )
2907*0f1702c5SYu Xiangning {
2908*0f1702c5SYu Xiangning 	struct sonode *so;
2909*0f1702c5SYu Xiangning 
2910*0f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
2911*0f1702c5SYu Xiangning 	/*
2912*0f1702c5SYu Xiangning 	 * Use the stream head to find the real socket vnode.
2913*0f1702c5SYu Xiangning 	 * This is needed when namefs sits above sockfs.  Some
2914*0f1702c5SYu Xiangning 	 * sockets (like SCTP) are not streams.
2915*0f1702c5SYu Xiangning 	 */
2916*0f1702c5SYu Xiangning 	if (!vp->v_stream) {
2917*0f1702c5SYu Xiangning 		return (ENOSTR);
2918*0f1702c5SYu Xiangning 	}
2919*0f1702c5SYu Xiangning 	ASSERT(vp->v_stream->sd_vnode);
2920*0f1702c5SYu Xiangning 	vp = vp->v_stream->sd_vnode;
2921*0f1702c5SYu Xiangning 	ASSERT(vn_matchops(vp, socket_vnodeops));
2922*0f1702c5SYu Xiangning 	so = VTOSO(vp);
29237c478bd9Sstevel@tonic-gate 
2924*0f1702c5SYu Xiangning 	dprintso(so, 1, ("sock_getmsg(%p) %s\n",
2925*0f1702c5SYu Xiangning 	    (void *)so, pr_state(so->so_state, so->so_mode)));
2926*0f1702c5SYu Xiangning 
2927*0f1702c5SYu Xiangning 	if (so->so_version == SOV_STREAM) {
2928*0f1702c5SYu Xiangning 		/* The imaginary "sockmod" has been popped - act as a stream */
2929*0f1702c5SYu Xiangning 		return (strgetmsg(vp, mctl, mdata, prip, flagsp, fmode, rvp));
2930*0f1702c5SYu Xiangning 	}
2931*0f1702c5SYu Xiangning 	eprintsoline(so, ENOSTR);
2932*0f1702c5SYu Xiangning 	return (ENOSTR);
2933*0f1702c5SYu Xiangning }
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate /*
2936*0f1702c5SYu Xiangning  * Wrapper for putmsg. If the socket has been converted to a stream
2937*0f1702c5SYu Xiangning  * pass the request to the stream head.
2938*0f1702c5SYu Xiangning  *
2939*0f1702c5SYu Xiangning  * Note that a while a regular socket (SOV_SOCKSTREAM) does support the
2940*0f1702c5SYu Xiangning  * streams ioctl set it does not support putmsg and getmsg.
2941*0f1702c5SYu Xiangning  * Allowing putmsg would prevent sockfs from tracking the state of
2942*0f1702c5SYu Xiangning  * the socket/transport and would also invalidate the locking in sockfs.
29437c478bd9Sstevel@tonic-gate  */
2944*0f1702c5SYu Xiangning int
2945*0f1702c5SYu Xiangning sock_putmsg(
2946*0f1702c5SYu Xiangning 	struct vnode *vp,
2947*0f1702c5SYu Xiangning 	struct strbuf *mctl,
2948*0f1702c5SYu Xiangning 	struct strbuf *mdata,
2949*0f1702c5SYu Xiangning 	uchar_t pri,
2950*0f1702c5SYu Xiangning 	int flag,
2951*0f1702c5SYu Xiangning 	int fmode
2952*0f1702c5SYu Xiangning )
2953*0f1702c5SYu Xiangning {
2954*0f1702c5SYu Xiangning 	struct sonode *so;
29557c478bd9Sstevel@tonic-gate 
2956*0f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
2957*0f1702c5SYu Xiangning 	/*
2958*0f1702c5SYu Xiangning 	 * Use the stream head to find the real socket vnode.
2959*0f1702c5SYu Xiangning 	 * This is needed when namefs sits above sockfs.
2960*0f1702c5SYu Xiangning 	 */
2961*0f1702c5SYu Xiangning 	if (!vp->v_stream) {
2962*0f1702c5SYu Xiangning 		return (ENOSTR);
2963*0f1702c5SYu Xiangning 	}
2964*0f1702c5SYu Xiangning 	ASSERT(vp->v_stream->sd_vnode);
2965*0f1702c5SYu Xiangning 	vp = vp->v_stream->sd_vnode;
2966*0f1702c5SYu Xiangning 	ASSERT(vn_matchops(vp, socket_vnodeops));
2967*0f1702c5SYu Xiangning 	so = VTOSO(vp);
2968*0f1702c5SYu Xiangning 
2969*0f1702c5SYu Xiangning 	dprintso(so, 1, ("sock_putmsg(%p) %s\n",
2970*0f1702c5SYu Xiangning 	    (void *)so, pr_state(so->so_state, so->so_mode)));
2971*0f1702c5SYu Xiangning 
2972*0f1702c5SYu Xiangning 	if (so->so_version == SOV_STREAM) {
2973*0f1702c5SYu Xiangning 		/* The imaginary "sockmod" has been popped - act as a stream */
2974*0f1702c5SYu Xiangning 		return (strputmsg(vp, mctl, mdata, pri, flag, fmode));
2975*0f1702c5SYu Xiangning 	}
2976*0f1702c5SYu Xiangning 	eprintsoline(so, ENOSTR);
2977*0f1702c5SYu Xiangning 	return (ENOSTR);
2978*0f1702c5SYu Xiangning }
2979*0f1702c5SYu Xiangning 
2980*0f1702c5SYu Xiangning /*
2981*0f1702c5SYu Xiangning  * Special function called only from f_getfl().
2982*0f1702c5SYu Xiangning  * Returns FASYNC if the SS_ASYNC flag is set on a socket, else 0.
2983*0f1702c5SYu Xiangning  * No locks are acquired here, so it is safe to use while uf_lock is held.
2984*0f1702c5SYu Xiangning  * This exists solely for BSD fcntl() FASYNC compatibility.
2985*0f1702c5SYu Xiangning  */
2986*0f1702c5SYu Xiangning int
2987*0f1702c5SYu Xiangning sock_getfasync(vnode_t *vp)
29887c478bd9Sstevel@tonic-gate {
2989*0f1702c5SYu Xiangning 	struct sonode *so;
2990*0f1702c5SYu Xiangning 
2991*0f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
2992*0f1702c5SYu Xiangning 	/*
2993*0f1702c5SYu Xiangning 	 * For stream model, v_stream is used; For non-stream, v_stream always
2994*0f1702c5SYu Xiangning 	 * equals NULL
2995*0f1702c5SYu Xiangning 	 */
2996*0f1702c5SYu Xiangning 	if (vp->v_stream != NULL)
2997*0f1702c5SYu Xiangning 		so = VTOSO(vp->v_stream->sd_vnode);
29987c478bd9Sstevel@tonic-gate 	else
2999*0f1702c5SYu Xiangning 		so = VTOSO(vp);
3000*0f1702c5SYu Xiangning 
3001*0f1702c5SYu Xiangning 	if (so->so_version == SOV_STREAM || !(so->so_state & SS_ASYNC))
3002*0f1702c5SYu Xiangning 		return (0);
3003*0f1702c5SYu Xiangning 
3004*0f1702c5SYu Xiangning 	return (FASYNC);
30057c478bd9Sstevel@tonic-gate }
300617169044Sbrutus 
300717169044Sbrutus /*
300817169044Sbrutus  * Sockfs sodirect STREAMS read put procedure. Called from sodirect enable
300917169044Sbrutus  * transport driver/module with an mblk_t chain.
301017169044Sbrutus  *
301117169044Sbrutus  * Note, we in-line putq() for the fast-path cases of q is empty, q_last and
301217169044Sbrutus  * bp are of type M_DATA. All other cases we call putq().
301317169044Sbrutus  *
301417169044Sbrutus  * On success a zero will be return, else an errno will be returned.
301517169044Sbrutus  */
301617169044Sbrutus int
301717169044Sbrutus sodput(sodirect_t *sodp, mblk_t *bp)
301817169044Sbrutus {
301917169044Sbrutus 	queue_t		*q = sodp->sod_q;
302017169044Sbrutus 	struct stdata	*stp = (struct stdata *)q->q_ptr;
302117169044Sbrutus 	mblk_t		*nbp;
302217169044Sbrutus 	mblk_t		*last = q->q_last;
302317169044Sbrutus 	int		bytecnt = 0;
302417169044Sbrutus 	int		mblkcnt = 0;
302517169044Sbrutus 
302617169044Sbrutus 
302796e0e3daSYu Xiangning 	ASSERT(MUTEX_HELD(sodp->sod_lockp));
302817169044Sbrutus 
302917169044Sbrutus 	if (stp->sd_flag == STREOF) {
303096e0e3daSYu Xiangning 		do {
303196e0e3daSYu Xiangning 			if ((nbp = bp->b_next) != NULL)
303296e0e3daSYu Xiangning 				bp->b_next = NULL;
303396e0e3daSYu Xiangning 			freemsg(bp);
303496e0e3daSYu Xiangning 		} while ((bp = nbp) != NULL);
303596e0e3daSYu Xiangning 
303696e0e3daSYu Xiangning 		return (0);
303717169044Sbrutus 	}
303817169044Sbrutus 
303996e0e3daSYu Xiangning 	mutex_enter(QLOCK(q));
304017169044Sbrutus 	if (q->q_first == NULL) {
304117169044Sbrutus 		/* Q empty, really fast fast-path */
304217169044Sbrutus 		bp->b_prev = NULL;
304317169044Sbrutus 		bp->b_next = NULL;
304417169044Sbrutus 		q->q_first = bp;
304517169044Sbrutus 		q->q_last = bp;
304617169044Sbrutus 
304717169044Sbrutus 	} else if (last->b_datap->db_type == M_DATA &&
304817169044Sbrutus 	    bp->b_datap->db_type == M_DATA) {
304917169044Sbrutus 		/*
305017169044Sbrutus 		 * Last mblk_t chain and bp are both type M_DATA so
305117169044Sbrutus 		 * in-line putq() here, if the DBLK_UIOA state match
305217169044Sbrutus 		 * add bp to the end of the current last chain, else
305317169044Sbrutus 		 * start a new last chain with bp.
305417169044Sbrutus 		 */
305517169044Sbrutus 		if ((last->b_datap->db_flags & DBLK_UIOA) ==
305617169044Sbrutus 		    (bp->b_datap->db_flags & DBLK_UIOA)) {
305717169044Sbrutus 			/* Added to end */
305817169044Sbrutus 			while ((nbp = last->b_cont) != NULL)
305917169044Sbrutus 				last = nbp;
306017169044Sbrutus 			last->b_cont = bp;
306117169044Sbrutus 		} else {
306217169044Sbrutus 			/* New last */
306396e0e3daSYu Xiangning 			ASSERT((bp->b_datap->db_flags & DBLK_UIOA) == 0 ||
306496e0e3daSYu Xiangning 			    msgdsize(bp) == sodp->sod_uioa.uioa_mbytes);
306517169044Sbrutus 			last->b_next = bp;
306617169044Sbrutus 			bp->b_next = NULL;
306717169044Sbrutus 			bp->b_prev = last;
306817169044Sbrutus 			q->q_last = bp;
306917169044Sbrutus 		}
307017169044Sbrutus 	} else {
307117169044Sbrutus 		/*
307217169044Sbrutus 		 * Can't use q_last so just call putq().
307317169044Sbrutus 		 */
307496e0e3daSYu Xiangning 		mutex_exit(QLOCK(q));
307596e0e3daSYu Xiangning 
307696e0e3daSYu Xiangning 		ASSERT((bp->b_datap->db_flags & DBLK_UIOA) == 0 ||
307796e0e3daSYu Xiangning 		    msgdsize(bp) == sodp->sod_uioa.uioa_mbytes);
307817169044Sbrutus 		(void) putq(q, bp);
307917169044Sbrutus 		return (0);
308017169044Sbrutus 	}
308117169044Sbrutus 
308217169044Sbrutus 	/* Count bytes and mblk_t's */
308317169044Sbrutus 	do {
308417169044Sbrutus 		bytecnt += MBLKL(bp);
308517169044Sbrutus 		mblkcnt++;
308617169044Sbrutus 	} while ((bp = bp->b_cont) != NULL);
308717169044Sbrutus 	q->q_count += bytecnt;
308817169044Sbrutus 	q->q_mblkcnt += mblkcnt;
308917169044Sbrutus 
309017169044Sbrutus 	/* Check for QFULL */
309117169044Sbrutus 	if (q->q_count >= q->q_hiwat + sodp->sod_want ||
309217169044Sbrutus 	    q->q_mblkcnt >= q->q_hiwat) {
309317169044Sbrutus 		q->q_flag |= QFULL;
309417169044Sbrutus 	}
309517169044Sbrutus 
309696e0e3daSYu Xiangning 	mutex_exit(QLOCK(q));
309717169044Sbrutus 	return (0);
309817169044Sbrutus }
309917169044Sbrutus 
310017169044Sbrutus /*
310117169044Sbrutus  * Sockfs sodirect read wakeup. Called from a sodirect enabled transport
310217169044Sbrutus  * driver/module to indicate that read-side data is available.
310317169044Sbrutus  *
310417169044Sbrutus  * On return the sodirect_t.lock mutex will be exited so this must be the
310517169044Sbrutus  * last sodirect_t call to guarantee atomic access of *sodp.
310617169044Sbrutus  */
310717169044Sbrutus void
310817169044Sbrutus sodwakeup(sodirect_t *sodp)
310917169044Sbrutus {
311017169044Sbrutus 	queue_t		*q = sodp->sod_q;
311117169044Sbrutus 	struct stdata	*stp = (struct stdata *)q->q_ptr;
311217169044Sbrutus 
311396e0e3daSYu Xiangning 	ASSERT(MUTEX_HELD(sodp->sod_lockp));
311417169044Sbrutus 
311517169044Sbrutus 	if (stp->sd_flag & RSLEEP) {
311617169044Sbrutus 		stp->sd_flag &= ~RSLEEP;
311717169044Sbrutus 		cv_broadcast(&q->q_wait);
311817169044Sbrutus 	}
311917169044Sbrutus 
312017169044Sbrutus 	if (stp->sd_rput_opt & SR_POLLIN) {
312117169044Sbrutus 		stp->sd_rput_opt &= ~SR_POLLIN;
312296e0e3daSYu Xiangning 		mutex_exit(sodp->sod_lockp);
312317169044Sbrutus 		pollwakeup(&stp->sd_pollist, POLLIN | POLLRDNORM);
312417169044Sbrutus 	} else
312596e0e3daSYu Xiangning 		mutex_exit(sodp->sod_lockp);
312617169044Sbrutus }
3127