17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
52caf0dcrshoaib * Common Development and Distribution License (the "License").
62caf0dcrshoaib * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
212caf0dcrshoaib
227c478bdstevel@tonic-gate/*
23dd49f12Anders Persson * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate#include <sys/types.h>
277c478bdstevel@tonic-gate#include <sys/inttypes.h>
287c478bdstevel@tonic-gate#include <sys/t_lock.h>
297c478bdstevel@tonic-gate#include <sys/param.h>
307c478bdstevel@tonic-gate#include <sys/systm.h>
317c478bdstevel@tonic-gate#include <sys/buf.h>
327c478bdstevel@tonic-gate#include <sys/conf.h>
337c478bdstevel@tonic-gate#include <sys/cred.h>
347c478bdstevel@tonic-gate#include <sys/kmem.h>
357c478bdstevel@tonic-gate#include <sys/sysmacros.h>
367c478bdstevel@tonic-gate#include <sys/vfs.h>
377c478bdstevel@tonic-gate#include <sys/vnode.h>
387c478bdstevel@tonic-gate#include <sys/debug.h>
397c478bdstevel@tonic-gate#include <sys/errno.h>
407c478bdstevel@tonic-gate#include <sys/time.h>
417c478bdstevel@tonic-gate#include <sys/file.h>
427c478bdstevel@tonic-gate#include <sys/user.h>
437c478bdstevel@tonic-gate#include <sys/stream.h>
447c478bdstevel@tonic-gate#include <sys/strsubr.h>
457c478bdstevel@tonic-gate#include <sys/esunddi.h>
467c478bdstevel@tonic-gate#include <sys/flock.h>
477c478bdstevel@tonic-gate#include <sys/modctl.h>
487c478bdstevel@tonic-gate#include <sys/vtrace.h>
497c478bdstevel@tonic-gate#include <sys/strsun.h>
507c478bdstevel@tonic-gate#include <sys/cmn_err.h>
517c478bdstevel@tonic-gate#include <sys/proc.h>
527c478bdstevel@tonic-gate#include <sys/ddi.h>
537c478bdstevel@tonic-gate
547c478bdstevel@tonic-gate#include <sys/suntpi.h>
557c478bdstevel@tonic-gate#include <sys/socket.h>
567c478bdstevel@tonic-gate#include <sys/sockio.h>
577c478bdstevel@tonic-gate#include <sys/socketvar.h>
587c478bdstevel@tonic-gate#include <netinet/in.h>
590f1702cYu Xiangning<Eric.Yu@Sun.COM>#include <inet/common.h>
600f1702cYu Xiangning<Eric.Yu@Sun.COM>#include <inet/proto_set.h>
617c478bdstevel@tonic-gate
627c478bdstevel@tonic-gate#include <sys/tiuser.h>
637c478bdstevel@tonic-gate#define	_SUN_TPI_VERSION	2
647c478bdstevel@tonic-gate#include <sys/tihdr.h>
657c478bdstevel@tonic-gate
667c478bdstevel@tonic-gate#include <c2/audit.h>
677c478bdstevel@tonic-gate
680f1702cYu Xiangning<Eric.Yu@Sun.COM>#include <fs/sockfs/socktpi.h>
690f1702cYu Xiangning<Eric.Yu@Sun.COM>#include <fs/sockfs/socktpi_impl.h>
701716904brutus
717c478bdstevel@tonic-gateint so_default_version = SOV_SOCKSTREAM;
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate#ifdef DEBUG
747c478bdstevel@tonic-gate/* Set sockdebug to print debug messages when SO_DEBUG is set */
757c478bdstevel@tonic-gateint sockdebug = 0;
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gate/* Set sockprinterr to print error messages when SO_DEBUG is set */
787c478bdstevel@tonic-gateint sockprinterr = 0;
797c478bdstevel@tonic-gate
807c478bdstevel@tonic-gate/*
817c478bdstevel@tonic-gate * Set so_default_options to SO_DEBUG is all sockets should be created
827c478bdstevel@tonic-gate * with SO_DEBUG set. This is needed to get debug printouts from the
837c478bdstevel@tonic-gate * socket() call itself.
847c478bdstevel@tonic-gate */
857c478bdstevel@tonic-gateint so_default_options = 0;
867c478bdstevel@tonic-gate#endif /* DEBUG */
877c478bdstevel@tonic-gate
887c478bdstevel@tonic-gate#ifdef SOCK_TEST
897c478bdstevel@tonic-gate/*
907c478bdstevel@tonic-gate * Set to number of ticks to limit cv_waits for code coverage testing.
917c478bdstevel@tonic-gate * Set to 1000 when SO_DEBUG is set to 2.
927c478bdstevel@tonic-gate */
937c478bdstevel@tonic-gateclock_t sock_test_timelimit = 0;
947c478bdstevel@tonic-gate#endif /* SOCK_TEST */
957c478bdstevel@tonic-gate
967c478bdstevel@tonic-gate/*
977c478bdstevel@tonic-gate * For concurrency testing of e.g. opening /dev/ip which does not
987c478bdstevel@tonic-gate * handle T_INFO_REQ messages.
997c478bdstevel@tonic-gate */
1007c478bdstevel@tonic-gateint so_no_tinfo = 0;
1017c478bdstevel@tonic-gate
1027c478bdstevel@tonic-gate/*
1037c478bdstevel@tonic-gate * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider
1047c478bdstevel@tonic-gate * to simply ignore the T_CAPABILITY_REQ.
1057c478bdstevel@tonic-gate */
1067c478bdstevel@tonic-gateclock_t	sock_capability_timeout	= 2;	/* seconds */
1077c478bdstevel@tonic-gate
1087c478bdstevel@tonic-gatestatic int	do_tcapability(struct sonode *so, t_uscalar_t cap_bits1);
1097c478bdstevel@tonic-gatestatic void	so_removehooks(struct sonode *so);
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gatestatic mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp,
1127c478bdstevel@tonic-gate		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1137c478bdstevel@tonic-gate		strsigset_t *allmsgsigs, strpollset_t *pollwakeups);
1147c478bdstevel@tonic-gatestatic mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp,
1157c478bdstevel@tonic-gate		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1167c478bdstevel@tonic-gate		strsigset_t *allmsgsigs, strpollset_t *pollwakeups);
1171716904brutus
1181716904brutus/*
1197c478bdstevel@tonic-gate * Convert a socket to a stream. Invoked when the illusory sockmod
1207c478bdstevel@tonic-gate * is popped from the stream.
1217c478bdstevel@tonic-gate * Change the stream head back to default operation without losing
1227c478bdstevel@tonic-gate * any messages (T_conn_ind's are moved to the stream head queue).
1237c478bdstevel@tonic-gate */
1247c478bdstevel@tonic-gateint
1257c478bdstevel@tonic-gateso_sock2stream(struct sonode *so)
1267c478bdstevel@tonic-gate{
1277c478bdstevel@tonic-gate	struct vnode		*vp = SOTOV(so);
1287c478bdstevel@tonic-gate	queue_t			*rq;
1297c478bdstevel@tonic-gate	mblk_t			*mp;
1307c478bdstevel@tonic-gate	int			error = 0;
1310f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t		*sti = SOTOTPI(so);
1327c478bdstevel@tonic-gate
1330f1702cYu Xiangning<Eric.Yu@Sun.COM>	ASSERT(MUTEX_HELD(&sti->sti_plumb_lock));
1347c478bdstevel@tonic-gate
1357c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
1367c478bdstevel@tonic-gate	so_lock_single(so);
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gate	ASSERT(so->so_version != SOV_STREAM);
1397c478bdstevel@tonic-gate
1400f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_direct) {
141ff550d0masputra		mblk_t **mpp;
142ff550d0masputra		int rval;
1437c478bdstevel@tonic-gate
144ff550d0masputra		/*
145ff550d0masputra		 * Tell the transport below that sockmod is being popped
146ff550d0masputra		 */
1477c478bdstevel@tonic-gate		mutex_exit(&so->so_lock);
148ff550d0masputra		error = strioctl(vp, _SIOCSOCKFALLBACK, 0, 0, K_TO_K, CRED(),
1497c478bdstevel@tonic-gate		    &rval);
1507c478bdstevel@tonic-gate		mutex_enter(&so->so_lock);
1517c478bdstevel@tonic-gate		if (error != 0) {
152ff550d0masputra			dprintso(so, 0, ("so_sock2stream(%p): "
153903a11erh			    "_SIOCSOCKFALLBACK failed\n", (void *)so));
1547c478bdstevel@tonic-gate			goto exit;
1557c478bdstevel@tonic-gate		}
1560f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_direct = 0;
1577c478bdstevel@tonic-gate
1580f1702cYu Xiangning<Eric.Yu@Sun.COM>		for (mpp = &sti->sti_conn_ind_head; (mp = *mpp) != NULL;
1597c478bdstevel@tonic-gate		    mpp = &mp->b_next) {
1607c478bdstevel@tonic-gate			struct T_conn_ind	*conn_ind;
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gate			/*
1637c478bdstevel@tonic-gate			 * strsock_proto() has already verified the length of
1647c478bdstevel@tonic-gate			 * this message block.
1657c478bdstevel@tonic-gate			 */
1667c478bdstevel@tonic-gate			ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind));
1677c478bdstevel@tonic-gate
1687c478bdstevel@tonic-gate			conn_ind = (struct T_conn_ind *)mp->b_rptr;
1697c478bdstevel@tonic-gate			if (conn_ind->OPT_length == 0 &&
1707c478bdstevel@tonic-gate			    conn_ind->OPT_offset == 0)
1717c478bdstevel@tonic-gate				continue;
1727c478bdstevel@tonic-gate
1737c478bdstevel@tonic-gate			if (DB_REF(mp) > 1) {
1747c478bdstevel@tonic-gate				mblk_t	*newmp;
1757c478bdstevel@tonic-gate				size_t	length;
1767c478bdstevel@tonic-gate				cred_t	*cr;
177de8c4a1Erik Nordmark				pid_t	cpid;
178de8c4a1Erik Nordmark				int error;	/* Dummy - error not returned */
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gate				/*
1817c478bdstevel@tonic-gate				 * Copy the message block because it is used
1827c478bdstevel@tonic-gate				 * elsewhere, too.
183de8c4a1Erik Nordmark				 * Can't use copyb since we want to wait
184de8c4a1Erik Nordmark				 * yet allow for EINTR.
1857c478bdstevel@tonic-gate				 */
186de8c4a1Erik Nordmark				/* Round up size for reuse */
187de8c4a1Erik Nordmark				length = MAX(MBLKL(mp), 64);
188de8c4a1Erik Nordmark				cr = msg_getcred(mp, &cpid);
189de8c4a1Erik Nordmark				if (cr != NULL) {
190de8c4a1Erik Nordmark					newmp = allocb_cred_wait(length, 0,
191de8c4a1Erik Nordmark					    &error, cr, cpid);
192de8c4a1Erik Nordmark				} else {
193de8c4a1Erik Nordmark					newmp = allocb_wait(length, 0, 0,
194de8c4a1Erik Nordmark					    &error);
195de8c4a1Erik Nordmark				}
1967c478bdstevel@tonic-gate				if (newmp == NULL) {
1977c478bdstevel@tonic-gate					error = EINTR;
1987c478bdstevel@tonic-gate					goto exit;
1997c478bdstevel@tonic-gate				}
2007c478bdstevel@tonic-gate				bcopy(mp->b_rptr, newmp->b_wptr, length);
2017c478bdstevel@tonic-gate				newmp->b_wptr += length;
2027c478bdstevel@tonic-gate				newmp->b_next = mp->b_next;
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate				/*
2057c478bdstevel@tonic-gate				 * Link the new message block into the queue
2067c478bdstevel@tonic-gate				 * and free the old one.
2077c478bdstevel@tonic-gate				 */
2087c478bdstevel@tonic-gate				*mpp = newmp;
2097c478bdstevel@tonic-gate				mp->b_next = NULL;
2107c478bdstevel@tonic-gate				freemsg(mp);
2117c478bdstevel@tonic-gate
2127c478bdstevel@tonic-gate				mp = newmp;
2137c478bdstevel@tonic-gate				conn_ind = (struct T_conn_ind *)mp->b_rptr;
2147c478bdstevel@tonic-gate			}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate			/*
2177c478bdstevel@tonic-gate			 * Remove options added by TCP for accept fast-path.
2187c478bdstevel@tonic-gate			 */
2197c478bdstevel@tonic-gate			conn_ind->OPT_length = 0;
2207c478bdstevel@tonic-gate			conn_ind->OPT_offset = 0;
2217c478bdstevel@tonic-gate		}
2227c478bdstevel@tonic-gate	}
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	so->so_version = SOV_STREAM;
2250f1702cYu Xiangning<Eric.Yu@Sun.COM>	so->so_proto_handle = NULL;
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate	/*
2287c478bdstevel@tonic-gate	 * Remove the hooks in the stream head to avoid queuing more
2297c478bdstevel@tonic-gate	 * packets in sockfs.
2307c478bdstevel@tonic-gate	 */
2317c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
2327c478bdstevel@tonic-gate	so_removehooks(so);
2337c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
2347c478bdstevel@tonic-gate
2357c478bdstevel@tonic-gate	/*
2367c478bdstevel@tonic-gate	 * Clear any state related to urgent data. Leave any T_EXDATA_IND
2377c478bdstevel@tonic-gate	 * on the queue - the behavior of urgent data after a switch is
2387c478bdstevel@tonic-gate	 * left undefined.
2397c478bdstevel@tonic-gate	 */
2400f1702cYu Xiangning<Eric.Yu@Sun.COM>	so->so_error = sti->sti_delayed_error = 0;
2417c478bdstevel@tonic-gate	freemsg(so->so_oobmsg);
2427c478bdstevel@tonic-gate	so->so_oobmsg = NULL;
2430f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_oobsigcnt = sti->sti_oobcnt = 0;
2447c478bdstevel@tonic-gate
2457c478bdstevel@tonic-gate	so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA|
2460f1702cYu Xiangning<Eric.Yu@Sun.COM>	    SS_SAVEDEOR);
2477c478bdstevel@tonic-gate	ASSERT(so_verify_oobstate(so));
2487c478bdstevel@tonic-gate
2490f1702cYu Xiangning<Eric.Yu@Sun.COM>	freemsg(sti->sti_ack_mp);
2500f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_ack_mp = NULL;
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gate	/*
2530f1702cYu Xiangning<Eric.Yu@Sun.COM>	 * Flush the T_DISCON_IND on sti_discon_ind_mp.
2547c478bdstevel@tonic-gate	 */
2557c478bdstevel@tonic-gate	so_flush_discon_ind(so);
2567c478bdstevel@tonic-gate
2577c478bdstevel@tonic-gate	/*
2587c478bdstevel@tonic-gate	 * Move any queued T_CONN_IND messages to stream head queue.
2597c478bdstevel@tonic-gate	 */
2607c478bdstevel@tonic-gate	rq = RD(strvp2wq(vp));
2610f1702cYu Xiangning<Eric.Yu@Sun.COM>	while ((mp = sti->sti_conn_ind_head) != NULL) {
2620f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_conn_ind_head = mp->b_next;
2637c478bdstevel@tonic-gate		mp->b_next = NULL;
2640f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (sti->sti_conn_ind_head == NULL) {
2650f1702cYu Xiangning<Eric.Yu@Sun.COM>			ASSERT(sti->sti_conn_ind_tail == mp);
2660f1702cYu Xiangning<Eric.Yu@Sun.COM>			sti->sti_conn_ind_tail = NULL;
2677c478bdstevel@tonic-gate		}
2687c478bdstevel@tonic-gate		dprintso(so, 0,
2690f1702cYu Xiangning<Eric.Yu@Sun.COM>		    ("so_sock2stream(%p): moving T_CONN_IND\n", (void *)so));
2707c478bdstevel@tonic-gate
2717c478bdstevel@tonic-gate		/* Drop lock across put() */
2727c478bdstevel@tonic-gate		mutex_exit(&so->so_lock);
2737c478bdstevel@tonic-gate		put(rq, mp);
2747c478bdstevel@tonic-gate		mutex_enter(&so->so_lock);
2757c478bdstevel@tonic-gate	}
2767c478bdstevel@tonic-gate
2777c478bdstevel@tonic-gateexit:
2787c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
2797c478bdstevel@tonic-gate	so_unlock_single(so, SOLOCKED);
2807c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
2817c478bdstevel@tonic-gate	return (error);
2827c478bdstevel@tonic-gate}
2837c478bdstevel@tonic-gate
2847c478bdstevel@tonic-gate/*
2857c478bdstevel@tonic-gate * Covert a stream back to a socket. This is invoked when the illusory
2867c478bdstevel@tonic-gate * sockmod is pushed on a stream (where the stream was "created" by
2877c478bdstevel@tonic-gate * popping the illusory sockmod).
2887c478bdstevel@tonic-gate * This routine can not recreate the socket state (certain aspects of
2897c478bdstevel@tonic-gate * it like urgent data state and the bound/connected addresses for AF_UNIX
2907c478bdstevel@tonic-gate * sockets can not be recreated by asking the transport for information).
2917c478bdstevel@tonic-gate * Thus this routine implicitly assumes that the socket is in an initial
2927c478bdstevel@tonic-gate * state (as if it was just created). It flushes any messages queued on the
2937c478bdstevel@tonic-gate * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages.
2947c478bdstevel@tonic-gate */
2957c478bdstevel@tonic-gatevoid
2967c478bdstevel@tonic-gateso_stream2sock(struct sonode *so)
2977c478bdstevel@tonic-gate{
2987c478bdstevel@tonic-gate	struct vnode *vp = SOTOV(so);
2990f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
3007c478bdstevel@tonic-gate
3010f1702cYu Xiangning<Eric.Yu@Sun.COM>	ASSERT(MUTEX_HELD(&sti->sti_plumb_lock));
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
3047c478bdstevel@tonic-gate	so_lock_single(so);
3057c478bdstevel@tonic-gate	ASSERT(so->so_version == SOV_STREAM);
3067c478bdstevel@tonic-gate	so->so_version = SOV_SOCKSTREAM;
3070f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_pushcnt = 0;
3087c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate	/*
3117c478bdstevel@tonic-gate	 * Set a permenent error to force any thread in sorecvmsg to
3127c478bdstevel@tonic-gate	 * return (and drop SOREADLOCKED). Clear the error once
3137c478bdstevel@tonic-gate	 * we have SOREADLOCKED.
3147c478bdstevel@tonic-gate	 * This makes a read sleeping during the I_PUSH of sockmod return
3157c478bdstevel@tonic-gate	 * EIO.
3167c478bdstevel@tonic-gate	 */
3177c478bdstevel@tonic-gate	strsetrerror(SOTOV(so), EIO, 1, NULL);
3187c478bdstevel@tonic-gate
3197c478bdstevel@tonic-gate	/*
3207c478bdstevel@tonic-gate	 * Get the read lock before flushing data to avoid
3217c478bdstevel@tonic-gate	 * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg.
3227c478bdstevel@tonic-gate	 */
3237c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
3247c478bdstevel@tonic-gate	(void) so_lock_read(so, 0);	/* Set SOREADLOCKED */
3257c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
3267c478bdstevel@tonic-gate
3277c478bdstevel@tonic-gate	strsetrerror(SOTOV(so), 0, 0, NULL);
3287c478bdstevel@tonic-gate	so_installhooks(so);
3297c478bdstevel@tonic-gate
3307c478bdstevel@tonic-gate	/*
3317c478bdstevel@tonic-gate	 * Flush everything on the read queue.
3327c478bdstevel@tonic-gate	 * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND
3337c478bdstevel@tonic-gate	 * remain; those types of messages would confuse sockfs.
3347c478bdstevel@tonic-gate	 */
3357c478bdstevel@tonic-gate	strflushrq(vp, FLUSHALL);
3367c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
3377c478bdstevel@tonic-gate
3387c478bdstevel@tonic-gate	/*
3390f1702cYu Xiangning<Eric.Yu@Sun.COM>	 * Flush the T_DISCON_IND on sti_discon_ind_mp.
3407c478bdstevel@tonic-gate	 */
3417c478bdstevel@tonic-gate	so_flush_discon_ind(so);
3427c478bdstevel@tonic-gate	so_unlock_read(so);	/* Clear SOREADLOCKED */
3437c478bdstevel@tonic-gate
3447c478bdstevel@tonic-gate	so_unlock_single(so, SOLOCKED);
3457c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
3467c478bdstevel@tonic-gate}
3477c478bdstevel@tonic-gate
3487c478bdstevel@tonic-gate/*
3497c478bdstevel@tonic-gate * Install the hooks in the stream head.
3507c478bdstevel@tonic-gate */
3517c478bdstevel@tonic-gatevoid
3527c478bdstevel@tonic-gateso_installhooks(struct sonode *so)
3537c478bdstevel@tonic-gate{
3547c478bdstevel@tonic-gate	struct vnode *vp = SOTOV(so);
3557c478bdstevel@tonic-gate
3567c478bdstevel@tonic-gate	strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA,
3577c478bdstevel@tonic-gate	    strsock_proto, strsock_misc);
3587c478bdstevel@tonic-gate	strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0);
3597c478bdstevel@tonic-gate}
3607c478bdstevel@tonic-gate
3617c478bdstevel@tonic-gate/*
3627c478bdstevel@tonic-gate * Remove the hooks in the stream head.
3637c478bdstevel@tonic-gate */
3647c478bdstevel@tonic-gatestatic void
3657c478bdstevel@tonic-gateso_removehooks(struct sonode *so)
3667c478bdstevel@tonic-gate{
3677c478bdstevel@tonic-gate	struct vnode *vp = SOTOV(so);
3687c478bdstevel@tonic-gate
3697c478bdstevel@tonic-gate	strsetrputhooks(vp, 0, NULL, NULL);
3707c478bdstevel@tonic-gate	strsetwputhooks(vp, 0, STRTIMOUT);
3717c478bdstevel@tonic-gate	/*
3727c478bdstevel@tonic-gate	 * Leave read behavior as it would have been for a normal
3737c478bdstevel@tonic-gate	 * stream i.e. a read of an M_PROTO will fail.
3747c478bdstevel@tonic-gate	 */
3757c478bdstevel@tonic-gate}
3767c478bdstevel@tonic-gate
3770f1702cYu Xiangning<Eric.Yu@Sun.COM>void
3780f1702cYu Xiangning<Eric.Yu@Sun.COM>so_basic_strinit(struct sonode *so)
3797c478bdstevel@tonic-gate{
3807c478bdstevel@tonic-gate	struct vnode *vp = SOTOV(so);
3817c478bdstevel@tonic-gate	struct stdata *stp;
3827c478bdstevel@tonic-gate	mblk_t *mp;
3830f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate	/* Preallocate an unbind_req message */
386de8c4a1Erik Nordmark	mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP, CRED());
3877c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
3880f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_unbind_mp = mp;
3897c478bdstevel@tonic-gate#ifdef DEBUG
3907c478bdstevel@tonic-gate	so->so_options = so_default_options;
3917c478bdstevel@tonic-gate#endif /* DEBUG */
3927c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
3937c478bdstevel@tonic-gate
3947c478bdstevel@tonic-gate	so_installhooks(so);
3957c478bdstevel@tonic-gate
3960f1702cYu Xiangning<Eric.Yu@Sun.COM>	stp = vp->v_stream;
3970f1702cYu Xiangning<Eric.Yu@Sun.COM>	/*
3980f1702cYu Xiangning<Eric.Yu@Sun.COM>	 * Have to keep minpsz at zero in order to allow write/send of zero
3990f1702cYu Xiangning<Eric.Yu@Sun.COM>	 * bytes.
4000f1702cYu Xiangning<Eric.Yu@Sun.COM>	 */
4010f1702cYu Xiangning<Eric.Yu@Sun.COM>	mutex_enter(&stp->sd_lock);
4020f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (stp->sd_qn_minpsz == 1)
4030f1702cYu Xiangning<Eric.Yu@Sun.COM>		stp->sd_qn_minpsz = 0;
4040f1702cYu Xiangning<Eric.Yu@Sun.COM>	mutex_exit(&stp->sd_lock);
4050f1702cYu Xiangning<Eric.Yu@Sun.COM>}
4060f1702cYu Xiangning<Eric.Yu@Sun.COM>
4070f1702cYu Xiangning<Eric.Yu@Sun.COM>/*
4080f1702cYu Xiangning<Eric.Yu@Sun.COM> * Initialize the streams side of a socket including
4090f1702cYu Xiangning<Eric.Yu@Sun.COM> * T_info_req/ack processing. If tso is not NULL its values are used thereby
4100f1702cYu Xiangning<Eric.Yu@Sun.COM> * avoiding the T_INFO_REQ.
4110f1702cYu Xiangning<Eric.Yu@Sun.COM> */
4120f1702cYu Xiangning<Eric.Yu@Sun.COM>int
4130f1702cYu Xiangning<Eric.Yu@Sun.COM>so_strinit(struct sonode *so, struct sonode *tso)
4140f1702cYu Xiangning<Eric.Yu@Sun.COM>{
4150f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
4160f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *tsti;
4170f1702cYu Xiangning<Eric.Yu@Sun.COM>	int error;
4180f1702cYu Xiangning<Eric.Yu@Sun.COM>
4190f1702cYu Xiangning<Eric.Yu@Sun.COM>	so_basic_strinit(so);
4200f1702cYu Xiangning<Eric.Yu@Sun.COM>
4217c478bdstevel@tonic-gate	/*
4227c478bdstevel@tonic-gate	 * The T_CAPABILITY_REQ should be the first message sent down because
4237c478bdstevel@tonic-gate	 * at least TCP has a fast-path for this which avoids timeouts while
4247c478bdstevel@tonic-gate	 * waiting for the T_CAPABILITY_ACK under high system load.
4257c478bdstevel@tonic-gate	 */
4267c478bdstevel@tonic-gate	if (tso == NULL) {
4277c478bdstevel@tonic-gate		error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO);
4287c478bdstevel@tonic-gate		if (error)
4297c478bdstevel@tonic-gate			return (error);
4307c478bdstevel@tonic-gate	} else {
4310f1702cYu Xiangning<Eric.Yu@Sun.COM>		tsti = SOTOTPI(tso);
4320f1702cYu Xiangning<Eric.Yu@Sun.COM>
4337c478bdstevel@tonic-gate		mutex_enter(&so->so_lock);
4340f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_tsdu_size = tsti->sti_tsdu_size;
4350f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_etsdu_size = tsti->sti_etsdu_size;
4360f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_addr_size = tsti->sti_addr_size;
4370f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_opt_size = tsti->sti_opt_size;
4380f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_tidu_size = tsti->sti_tidu_size;
4390f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_serv_type = tsti->sti_serv_type;
4407c478bdstevel@tonic-gate		so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID;
4417c478bdstevel@tonic-gate		mutex_exit(&so->so_lock);
4427c478bdstevel@tonic-gate
4437c478bdstevel@tonic-gate		/* the following do_tcapability may update so->so_mode */
4440f1702cYu Xiangning<Eric.Yu@Sun.COM>		if ((tsti->sti_serv_type != T_CLTS) &&
4450f1702cYu Xiangning<Eric.Yu@Sun.COM>		    (sti->sti_direct == 0)) {
4467c478bdstevel@tonic-gate			error = do_tcapability(so, TC1_ACCEPTOR_ID);
4477c478bdstevel@tonic-gate			if (error)
4487c478bdstevel@tonic-gate				return (error);
4497c478bdstevel@tonic-gate		}
4507c478bdstevel@tonic-gate	}
4517c478bdstevel@tonic-gate	/*
4527c478bdstevel@tonic-gate	 * If the addr_size is 0 we treat it as already bound
4537c478bdstevel@tonic-gate	 * and connected. This is used by the routing socket.
4547c478bdstevel@tonic-gate	 * We set the addr_size to something to allocate a the address
4557c478bdstevel@tonic-gate	 * structures.
4567c478bdstevel@tonic-gate	 */
4570f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_addr_size == 0) {
4587c478bdstevel@tonic-gate		so->so_state |= SS_ISBOUND | SS_ISCONNECTED;
4597c478bdstevel@tonic-gate		/* Address size can vary with address families. */
4607c478bdstevel@tonic-gate		if (so->so_family == AF_INET6)
4610f1702cYu Xiangning<Eric.Yu@Sun.COM>			sti->sti_addr_size =
4627c478bdstevel@tonic-gate			    (t_scalar_t)sizeof (struct sockaddr_in6);
4637c478bdstevel@tonic-gate		else
4640f1702cYu Xiangning<Eric.Yu@Sun.COM>			sti->sti_addr_size =
4657c478bdstevel@tonic-gate			    (t_scalar_t)sizeof (struct sockaddr_in);
4660f1702cYu Xiangning<Eric.Yu@Sun.COM>		ASSERT(sti->sti_unbind_mp);
4677c478bdstevel@tonic-gate	}
4687c478bdstevel@tonic-gate
4690f1702cYu Xiangning<Eric.Yu@Sun.COM>	so_alloc_addr(so, sti->sti_addr_size);
4701716904brutus
4717c478bdstevel@tonic-gate	return (0);
4727c478bdstevel@tonic-gate}
4737c478bdstevel@tonic-gate
4747c478bdstevel@tonic-gatestatic void
4757c478bdstevel@tonic-gatecopy_tinfo(struct sonode *so, struct T_info_ack *tia)
4767c478bdstevel@tonic-gate{
4770f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
4780f1702cYu Xiangning<Eric.Yu@Sun.COM>
4790f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_tsdu_size = tia->TSDU_size;
4800f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_etsdu_size = tia->ETSDU_size;
4810f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_addr_size = tia->ADDR_size;
4820f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_opt_size = tia->OPT_size;
4830f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_tidu_size = tia->TIDU_size;
4840f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_serv_type = tia->SERV_type;
4857c478bdstevel@tonic-gate	switch (tia->CURRENT_state) {
4867c478bdstevel@tonic-gate	case TS_UNBND:
4877c478bdstevel@tonic-gate		break;
4887c478bdstevel@tonic-gate	case TS_IDLE:
4897c478bdstevel@tonic-gate		so->so_state |= SS_ISBOUND;
4900f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_laddr_len = 0;
4910f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_laddr_valid = 0;
4927c478bdstevel@tonic-gate		break;
4937c478bdstevel@tonic-gate	case TS_DATA_XFER:
4947c478bdstevel@tonic-gate		so->so_state |= SS_ISBOUND|SS_ISCONNECTED;
4950f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_laddr_len = 0;
4960f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_faddr_len = 0;
4970f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_laddr_valid = 0;
4980f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_faddr_valid = 0;
4997c478bdstevel@tonic-gate		break;
5007c478bdstevel@tonic-gate	}
5017c478bdstevel@tonic-gate
5027c478bdstevel@tonic-gate	/*
5037c478bdstevel@tonic-gate	 * Heuristics for determining the socket mode flags
5047c478bdstevel@tonic-gate	 * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING,
5057c478bdstevel@tonic-gate	 * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM)
5067c478bdstevel@tonic-gate	 * from the info ack.
5077c478bdstevel@tonic-gate	 */
5080f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_serv_type == T_CLTS) {
5097c478bdstevel@tonic-gate		so->so_mode |= SM_ATOMIC | SM_ADDR;
5107c478bdstevel@tonic-gate	} else {
5117c478bdstevel@tonic-gate		so->so_mode |= SM_CONNREQUIRED;
5120f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (sti->sti_etsdu_size != 0 && sti->sti_etsdu_size != -2)
5137c478bdstevel@tonic-gate			so->so_mode |= SM_EXDATA;
5147c478bdstevel@tonic-gate	}
5157c478bdstevel@tonic-gate	if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) {
5167c478bdstevel@tonic-gate		/* Semantics are to discard tail end of messages */
5177c478bdstevel@tonic-gate		so->so_mode |= SM_ATOMIC;
5187c478bdstevel@tonic-gate	}
5197c478bdstevel@tonic-gate	if (so->so_family == AF_UNIX) {
5207c478bdstevel@tonic-gate		so->so_mode |= SM_FDPASSING | SM_OPTDATA;
5210f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (sti->sti_addr_size == -1) {
5227c478bdstevel@tonic-gate			/* MAXPATHLEN + soun_family + nul termination */
5230f1702cYu Xiangning<Eric.Yu@Sun.COM>			sti->sti_addr_size = (t_scalar_t)(MAXPATHLEN +
524d3e55dcgww			    sizeof (short) + 1);
5257c478bdstevel@tonic-gate		}
5267c478bdstevel@tonic-gate		if (so->so_type == SOCK_STREAM) {
5277c478bdstevel@tonic-gate			/*
5287c478bdstevel@tonic-gate			 * Make it into a byte-stream transport.
5297c478bdstevel@tonic-gate			 * SOCK_SEQPACKET sockets are unchanged.
5307c478bdstevel@tonic-gate			 */
5310f1702cYu Xiangning<Eric.Yu@Sun.COM>			sti->sti_tsdu_size = 0;
5327c478bdstevel@tonic-gate		}
5330f1702cYu Xiangning<Eric.Yu@Sun.COM>	} else if (sti->sti_addr_size == -1) {
5347c478bdstevel@tonic-gate		/*
5357c478bdstevel@tonic-gate		 * Logic extracted from sockmod - have to pick some max address
5367c478bdstevel@tonic-gate		 * length in order to preallocate the addresses.
5377c478bdstevel@tonic-gate		 */
5380f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_addr_size = SOA_DEFSIZE;
5397c478bdstevel@tonic-gate	}
5400f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_tsdu_size == 0)
5417c478bdstevel@tonic-gate		so->so_mode |= SM_BYTESTREAM;
5427c478bdstevel@tonic-gate}
5437c478bdstevel@tonic-gate
5447c478bdstevel@tonic-gatestatic int
5457c478bdstevel@tonic-gatecheck_tinfo(struct sonode *so)
5467c478bdstevel@tonic-gate{
5470f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
5480f1702cYu Xiangning<Eric.Yu@Sun.COM>
5497c478bdstevel@tonic-gate	/* Consistency checks */
5500f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (so->so_type == SOCK_DGRAM && sti->sti_serv_type != T_CLTS) {
5517c478bdstevel@tonic-gate		eprintso(so, ("service type and socket type mismatch\n"));
5527c478bdstevel@tonic-gate		eprintsoline(so, EPROTO);
5537c478bdstevel@tonic-gate		return (EPROTO);
5547c478bdstevel@tonic-gate	}
5550f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (so->so_type == SOCK_STREAM && sti->sti_serv_type == T_CLTS) {
5567c478bdstevel@tonic-gate		eprintso(so, ("service type and socket type mismatch\n"));
5577c478bdstevel@tonic-gate		eprintsoline(so, EPROTO);
5587c478bdstevel@tonic-gate		return (EPROTO);
5597c478bdstevel@tonic-gate	}
5600f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (so->so_type == SOCK_SEQPACKET && sti->sti_serv_type == T_CLTS) {
5617c478bdstevel@tonic-gate		eprintso(so, ("service type and socket type mismatch\n"));
5627c478bdstevel@tonic-gate		eprintsoline(so, EPROTO);
5637c478bdstevel@tonic-gate		return (EPROTO);
5647c478bdstevel@tonic-gate	}
5657c478bdstevel@tonic-gate	if (so->so_family == AF_INET &&
5660f1702cYu Xiangning<Eric.Yu@Sun.COM>	    sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) {
5677c478bdstevel@tonic-gate		eprintso(so,
5687c478bdstevel@tonic-gate		    ("AF_INET must have sockaddr_in address length. Got %d\n",
5690f1702cYu Xiangning<Eric.Yu@Sun.COM>		    sti->sti_addr_size));
5707c478bdstevel@tonic-gate		eprintsoline(so, EMSGSIZE);
5717c478bdstevel@tonic-gate		return (EMSGSIZE);
5727c478bdstevel@tonic-gate	}
5737c478bdstevel@tonic-gate	if (so->so_family == AF_INET6 &&
5740f1702cYu Xiangning<Eric.Yu@Sun.COM>	    sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) {
5757c478bdstevel@tonic-gate		eprintso(so,
5767c478bdstevel@tonic-gate		    ("AF_INET6 must have sockaddr_in6 address length. Got %d\n",
5770f1702cYu Xiangning<Eric.Yu@Sun.COM>		    sti->sti_addr_size));
5787c478bdstevel@tonic-gate		eprintsoline(so, EMSGSIZE);
5797c478bdstevel@tonic-gate		return (EMSGSIZE);
5807c478bdstevel@tonic-gate	}
5817c478bdstevel@tonic-gate
5827c478bdstevel@tonic-gate	dprintso(so, 1, (
5837c478bdstevel@tonic-gate	    "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n",
5840f1702cYu Xiangning<Eric.Yu@Sun.COM>	    sti->sti_serv_type, sti->sti_tsdu_size, sti->sti_etsdu_size,
5850f1702cYu Xiangning<Eric.Yu@Sun.COM>	    sti->sti_addr_size, sti->sti_opt_size,
5860f1702cYu Xiangning<Eric.Yu@Sun.COM>	    sti->sti_tidu_size));
5877c478bdstevel@tonic-gate	dprintso(so, 1, ("tinfo: so_state %s\n",
588d3e55dcgww	    pr_state(so->so_state, so->so_mode)));
5897c478bdstevel@tonic-gate	return (0);
5907c478bdstevel@tonic-gate}
5917c478bdstevel@tonic-gate
5927c478bdstevel@tonic-gate/*
5937c478bdstevel@tonic-gate * Send down T_info_req and wait for the ack.
5947c478bdstevel@tonic-gate * Record interesting T_info_ack values in the sonode.
5957c478bdstevel@tonic-gate */
5967c478bdstevel@tonic-gatestatic int
5977c478bdstevel@tonic-gatedo_tinfo(struct sonode *so)
5987c478bdstevel@tonic-gate{
5997c478bdstevel@tonic-gate	struct T_info_req tir;
6007c478bdstevel@tonic-gate	mblk_t *mp;
6017c478bdstevel@tonic-gate	int error;
6027c478bdstevel@tonic-gate
6037c478bdstevel@tonic-gate	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6047c478bdstevel@tonic-gate
6057c478bdstevel@tonic-gate	if (so_no_tinfo) {
6060f1702cYu Xiangning<Eric.Yu@Sun.COM>		SOTOTPI(so)->sti_addr_size = 0;
6077c478bdstevel@tonic-gate		return (0);
6087c478bdstevel@tonic-gate	}
6097c478bdstevel@tonic-gate
610903a11erh	dprintso(so, 1, ("do_tinfo(%p)\n", (void *)so));
6117c478bdstevel@tonic-gate
6127c478bdstevel@tonic-gate	/* Send T_INFO_REQ */
6137c478bdstevel@tonic-gate	tir.PRIM_type = T_INFO_REQ;
6147c478bdstevel@tonic-gate	mp = soallocproto1(&tir, sizeof (tir),
6157c478bdstevel@tonic-gate	    sizeof (struct T_info_req) + sizeof (struct T_info_ack),
616de8c4a1Erik Nordmark	    _ALLOC_INTR, CRED());
6177c478bdstevel@tonic-gate	if (mp == NULL) {
6187c478bdstevel@tonic-gate		eprintsoline(so, ENOBUFS);
6197c478bdstevel@tonic-gate		return (ENOBUFS);
6207c478bdstevel@tonic-gate	}
6217c478bdstevel@tonic-gate	/* T_INFO_REQ has to be M_PCPROTO */
6227c478bdstevel@tonic-gate	DB_TYPE(mp) = M_PCPROTO;
6237c478bdstevel@tonic-gate
6247c478bdstevel@tonic-gate	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
625d3e55dcgww	    MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
6267c478bdstevel@tonic-gate	if (error) {
6277c478bdstevel@tonic-gate		eprintsoline(so, error);
6287c478bdstevel@tonic-gate		return (error);
6297c478bdstevel@tonic-gate	}
6307c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
6317c478bdstevel@tonic-gate	/* Wait for T_INFO_ACK */
6327c478bdstevel@tonic-gate	if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK,
6337c478bdstevel@tonic-gate	    (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) {
6347c478bdstevel@tonic-gate		mutex_exit(&so->so_lock);
6357c478bdstevel@tonic-gate		eprintsoline(so, error);
6367c478bdstevel@tonic-gate		return (error);
6377c478bdstevel@tonic-gate	}
6387c478bdstevel@tonic-gate
6397c478bdstevel@tonic-gate	ASSERT(mp);
6407c478bdstevel@tonic-gate	copy_tinfo(so, (struct T_info_ack *)mp->b_rptr);
6417c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
6427c478bdstevel@tonic-gate	freemsg(mp);
6437c478bdstevel@tonic-gate	return (check_tinfo(so));
6447c478bdstevel@tonic-gate}
6457c478bdstevel@tonic-gate
6467c478bdstevel@tonic-gate/*
6477c478bdstevel@tonic-gate * Send down T_capability_req and wait for the ack.
6487c478bdstevel@tonic-gate * Record interesting T_capability_ack values in the sonode.
6497c478bdstevel@tonic-gate */
6507c478bdstevel@tonic-gatestatic int
6517c478bdstevel@tonic-gatedo_tcapability(struct sonode *so, t_uscalar_t cap_bits1)
6527c478bdstevel@tonic-gate{
6537c478bdstevel@tonic-gate	struct T_capability_req tcr;
6547c478bdstevel@tonic-gate	struct T_capability_ack *tca;
6557c478bdstevel@tonic-gate	mblk_t *mp;
6567c478bdstevel@tonic-gate	int error;
6570f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
6587c478bdstevel@tonic-gate
6597c478bdstevel@tonic-gate	ASSERT(cap_bits1 != 0);
6607c478bdstevel@tonic-gate	ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0);
6617c478bdstevel@tonic-gate	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6627c478bdstevel@tonic-gate
6630f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_provinfo->tpi_capability == PI_NO)
6647c478bdstevel@tonic-gate		return (do_tinfo(so));
6657c478bdstevel@tonic-gate
6667c478bdstevel@tonic-gate	if (so_no_tinfo) {
6670f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_addr_size = 0;
6687c478bdstevel@tonic-gate		if ((cap_bits1 &= ~TC1_INFO) == 0)
6697c478bdstevel@tonic-gate			return (0);
6707c478bdstevel@tonic-gate	}
6717c478bdstevel@tonic-gate
672903a11erh	dprintso(so, 1, ("do_tcapability(%p)\n", (void *)so));
6737c478bdstevel@tonic-gate
6747c478bdstevel@tonic-gate	/* Send T_CAPABILITY_REQ */
6757c478bdstevel@tonic-gate	tcr.PRIM_type = T_CAPABILITY_REQ;
6767c478bdstevel@tonic-gate	tcr.CAP_bits1 = cap_bits1;
6777c478bdstevel@tonic-gate	mp = soallocproto1(&tcr, sizeof (tcr),
6787c478bdstevel@tonic-gate	    sizeof (struct T_capability_req) + sizeof (struct T_capability_ack),
679de8c4a1Erik Nordmark	    _ALLOC_INTR, CRED());
6807c478bdstevel@tonic-gate	if (mp == NULL) {
6817c478bdstevel@tonic-gate		eprintsoline(so, ENOBUFS);
6827c478bdstevel@tonic-gate		return (ENOBUFS);
6837c478bdstevel@tonic-gate	}
6847c478bdstevel@tonic-gate	/* T_CAPABILITY_REQ should be M_PCPROTO here */
6857c478bdstevel@tonic-gate	DB_TYPE(mp) = M_PCPROTO;
6867c478bdstevel@tonic-gate
6877c478bdstevel@tonic-gate	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
6887c478bdstevel@tonic-gate	    MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
6897c478bdstevel@tonic-gate	if (error) {
6907c478bdstevel@tonic-gate		eprintsoline(so, error);
6917c478bdstevel@tonic-gate		return (error);
6927c478bdstevel@tonic-gate	}
6937c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
6947c478bdstevel@tonic-gate	/* Wait for T_CAPABILITY_ACK */
6957c478bdstevel@tonic-gate	if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK,
6967c478bdstevel@tonic-gate	    (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) {
6977c478bdstevel@tonic-gate		mutex_exit(&so->so_lock);
6980f1702cYu Xiangning<Eric.Yu@Sun.COM>		PI_PROVLOCK(sti->sti_provinfo);
6990f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW)
7000f1702cYu Xiangning<Eric.Yu@Sun.COM>			sti->sti_provinfo->tpi_capability = PI_NO;
7010f1702cYu Xiangning<Eric.Yu@Sun.COM>		PI_PROVUNLOCK(sti->sti_provinfo);
7027c478bdstevel@tonic-gate		ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0);
7037c478bdstevel@tonic-gate		if (cap_bits1 & TC1_INFO) {
7047c478bdstevel@tonic-gate			/*
7057c478bdstevel@tonic-gate			 * If the T_CAPABILITY_REQ timed out and then a
7067c478bdstevel@tonic-gate			 * T_INFO_REQ gets a protocol error, most likely
7077c478bdstevel@tonic-gate			 * the capability was slow (vs. unsupported). Return
7087c478bdstevel@tonic-gate			 * ENOSR for this case as a best guess.
7097c478bdstevel@tonic-gate			 */
7107c478bdstevel@tonic-gate			if (error == ETIME) {
7117c478bdstevel@tonic-gate				return ((error = do_tinfo(so)) == EPROTO ?
7127c478bdstevel@tonic-gate				    ENOSR : error);
7137c478bdstevel@tonic-gate			}
7147c478bdstevel@tonic-gate			return (do_tinfo(so));
7157c478bdstevel@tonic-gate		}
7167c478bdstevel@tonic-gate		return (0);
7177c478bdstevel@tonic-gate	}
7187c478bdstevel@tonic-gate
7197c478bdstevel@tonic-gate	ASSERT(mp);
7207c478bdstevel@tonic-gate	tca = (struct T_capability_ack *)mp->b_rptr;
7217c478bdstevel@tonic-gate
7227c478bdstevel@tonic-gate	ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO));
7230f1702cYu Xiangning<Eric.Yu@Sun.COM>	so_proc_tcapability_ack(so, tca);
7247c478bdstevel@tonic-gate
7257c478bdstevel@tonic-gate	cap_bits1 = tca->CAP_bits1;
7267c478bdstevel@tonic-gate
7277c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
7287c478bdstevel@tonic-gate	freemsg(mp);
7297c478bdstevel@tonic-gate
7307c478bdstevel@tonic-gate	if (cap_bits1 & TC1_INFO)
7317c478bdstevel@tonic-gate		return (check_tinfo(so));
7327c478bdstevel@tonic-gate
7337c478bdstevel@tonic-gate	return (0);
7347c478bdstevel@tonic-gate}
7357c478bdstevel@tonic-gate
7367c478bdstevel@tonic-gate/*
7370f1702cYu Xiangning<Eric.Yu@Sun.COM> * Process a T_CAPABILITY_ACK
7380f1702cYu Xiangning<Eric.Yu@Sun.COM> */
7390f1702cYu Xiangning<Eric.Yu@Sun.COM>void
7400f1702cYu Xiangning<Eric.Yu@Sun.COM>so_proc_tcapability_ack(struct sonode *so, struct T_capability_ack *tca)
7410f1702cYu Xiangning<Eric.Yu@Sun.COM>{
7420f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
7430f1702cYu Xiangning<Eric.Yu@Sun.COM>
7440f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW) {
7450f1702cYu Xiangning<Eric.Yu@Sun.COM>		PI_PROVLOCK(sti->sti_provinfo);
7460f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_provinfo->tpi_capability = PI_YES;
7470f1702cYu Xiangning<Eric.Yu@Sun.COM>		PI_PROVUNLOCK(sti->sti_provinfo);
7480f1702cYu Xiangning<Eric.Yu@Sun.COM>	}
7490f1702cYu Xiangning<Eric.Yu@Sun.COM>
7500f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (tca->CAP_bits1 & TC1_ACCEPTOR_ID) {
7510f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_acceptor_id = tca->ACCEPTOR_id;
7520f1702cYu Xiangning<Eric.Yu@Sun.COM>		so->so_mode |= SM_ACCEPTOR_ID;
7530f1702cYu Xiangning<Eric.Yu@Sun.COM>	}
7540f1702cYu Xiangning<Eric.Yu@Sun.COM>
7550f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (tca->CAP_bits1 & TC1_INFO)
7560f1702cYu Xiangning<Eric.Yu@Sun.COM>		copy_tinfo(so, &tca->INFO_ack);
7570f1702cYu Xiangning<Eric.Yu@Sun.COM>}
7580f1702cYu Xiangning<Eric.Yu@Sun.COM>
7590f1702cYu Xiangning<Eric.Yu@Sun.COM>/*
7600f1702cYu Xiangning<Eric.Yu@Sun.COM> * Retrieve socket error, clear error if not peek.
7617c478bdstevel@tonic-gate */
7627c478bdstevel@tonic-gateint
7630f1702cYu Xiangning<Eric.Yu@Sun.COM>sogeterr(struct sonode *so, boolean_t clear_err)
7647c478bdstevel@tonic-gate{
7657c478bdstevel@tonic-gate	int error;
7667c478bdstevel@tonic-gate
7677c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
7687c478bdstevel@tonic-gate
7697c478bdstevel@tonic-gate	error = so->so_error;
7700f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (clear_err)
7710f1702cYu Xiangning<Eric.Yu@Sun.COM>		so->so_error = 0;
7727c478bdstevel@tonic-gate
7737c478bdstevel@tonic-gate	return (error);
7747c478bdstevel@tonic-gate}
7757c478bdstevel@tonic-gate
7767c478bdstevel@tonic-gate/*
7777c478bdstevel@tonic-gate * This routine is registered with the stream head to retrieve read
7787c478bdstevel@tonic-gate * side errors.
7797c478bdstevel@tonic-gate * It does not clear the socket error for a peeking read side operation.
7807c478bdstevel@tonic-gate * It the error is to be cleared it sets *clearerr.
7817c478bdstevel@tonic-gate */
7827c478bdstevel@tonic-gateint
7837c478bdstevel@tonic-gatesogetrderr(vnode_t *vp, int ispeek, int *clearerr)
7847c478bdstevel@tonic-gate{
7857c478bdstevel@tonic-gate	struct sonode *so = VTOSO(vp);
7867c478bdstevel@tonic-gate	int error;
7877c478bdstevel@tonic-gate
7887c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
7897c478bdstevel@tonic-gate	if (ispeek) {
7907c478bdstevel@tonic-gate		error = so->so_error;
7917c478bdstevel@tonic-gate		*clearerr = 0;
7927c478bdstevel@tonic-gate	} else {
7937c478bdstevel@tonic-gate		error = so->so_error;
7947c478bdstevel@tonic-gate		so->so_error = 0;
7957c478bdstevel@tonic-gate		*clearerr = 1;
7967c478bdstevel@tonic-gate	}
7977c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
7987c478bdstevel@tonic-gate	return (error);
7997c478bdstevel@tonic-gate}
8007c478bdstevel@tonic-gate
8017c478bdstevel@tonic-gate/*
8027c478bdstevel@tonic-gate * This routine is registered with the stream head to retrieve write
8037c478bdstevel@tonic-gate * side errors.
8047c478bdstevel@tonic-gate * It does not clear the socket error for a peeking read side operation.
8057c478bdstevel@tonic-gate * It the error is to be cleared it sets *clearerr.
8067c478bdstevel@tonic-gate */
8077c478bdstevel@tonic-gateint
8087c478bdstevel@tonic-gatesogetwrerr(vnode_t *vp, int ispeek, int *clearerr)
8097c478bdstevel@tonic-gate{
8107c478bdstevel@tonic-gate	struct sonode *so = VTOSO(vp);
8117c478bdstevel@tonic-gate	int error;
8127c478bdstevel@tonic-gate
8137c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
8147c478bdstevel@tonic-gate	if (so->so_state & SS_CANTSENDMORE) {
8157c478bdstevel@tonic-gate		error = EPIPE;
8167c478bdstevel@tonic-gate		*clearerr = 0;
8177c478bdstevel@tonic-gate	} else {
8187c478bdstevel@tonic-gate		error = so->so_error;
8197c478bdstevel@tonic-gate		if (ispeek) {
8207c478bdstevel@tonic-gate			*clearerr = 0;
8217c478bdstevel@tonic-gate		} else {
8227c478bdstevel@tonic-gate			so->so_error = 0;
8237c478bdstevel@tonic-gate			*clearerr = 1;
8247c478bdstevel@tonic-gate		}
8257c478bdstevel@tonic-gate	}
8267c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
8277c478bdstevel@tonic-gate	return (error);
8287c478bdstevel@tonic-gate}
8297c478bdstevel@tonic-gate
8307c478bdstevel@tonic-gate/*
8317c478bdstevel@tonic-gate * Set a nonpersistent read and write error on the socket.
8327c478bdstevel@tonic-gate * Used when there is a T_uderror_ind for a connected socket.
8337c478bdstevel@tonic-gate * The caller also needs to call strsetrerror and strsetwerror
8347c478bdstevel@tonic-gate * after dropping the lock.
8357c478bdstevel@tonic-gate */
8367c478bdstevel@tonic-gatevoid
8377c478bdstevel@tonic-gatesoseterror(struct sonode *so, int error)
8387c478bdstevel@tonic-gate{
8397c478bdstevel@tonic-gate	ASSERT(error != 0);
8407c478bdstevel@tonic-gate
8417c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
8427c478bdstevel@tonic-gate	so->so_error = (ushort_t)error;
8437c478bdstevel@tonic-gate}
8447c478bdstevel@tonic-gate
8457c478bdstevel@tonic-gatevoid
8467c478bdstevel@tonic-gatesoisconnecting(struct sonode *so)
8477c478bdstevel@tonic-gate{
8487c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
8497c478bdstevel@tonic-gate	so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
8507c478bdstevel@tonic-gate	so->so_state |= SS_ISCONNECTING;
8517c478bdstevel@tonic-gate	cv_broadcast(&so->so_state_cv);
8527c478bdstevel@tonic-gate}
8537c478bdstevel@tonic-gate
8547c478bdstevel@tonic-gatevoid
8557c478bdstevel@tonic-gatesoisconnected(struct sonode *so)
8567c478bdstevel@tonic-gate{
8577c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
8587c478bdstevel@tonic-gate	so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
8597c478bdstevel@tonic-gate	so->so_state |= SS_ISCONNECTED;
8607c478bdstevel@tonic-gate	cv_broadcast(&so->so_state_cv);
8617c478bdstevel@tonic-gate}
8627c478bdstevel@tonic-gate
8637c478bdstevel@tonic-gate/*
8647c478bdstevel@tonic-gate * The caller also needs to call strsetrerror, strsetwerror and strseteof.
8657c478bdstevel@tonic-gate */
8667c478bdstevel@tonic-gatevoid
8677c478bdstevel@tonic-gatesoisdisconnected(struct sonode *so, int error)
8687c478bdstevel@tonic-gate{
8697c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
8700f1702cYu Xiangning<Eric.Yu@Sun.COM>	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
8717c478bdstevel@tonic-gate	so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
8727c478bdstevel@tonic-gate	so->so_error = (ushort_t)error;
8737c478bdstevel@tonic-gate	if (so->so_peercred != NULL) {
8747c478bdstevel@tonic-gate		crfree(so->so_peercred);
8757c478bdstevel@tonic-gate		so->so_peercred = NULL;
8767c478bdstevel@tonic-gate	}
8777c478bdstevel@tonic-gate	cv_broadcast(&so->so_state_cv);
8787c478bdstevel@tonic-gate}
8797c478bdstevel@tonic-gate
8807c478bdstevel@tonic-gate/*
8817c478bdstevel@tonic-gate * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes.
8827c478bdstevel@tonic-gate * Does not affect write side.
8837c478bdstevel@tonic-gate * The caller also has to call strsetrerror.
8847c478bdstevel@tonic-gate */
8857c478bdstevel@tonic-gatestatic void
8867c478bdstevel@tonic-gatesobreakconn(struct sonode *so, int error)
8877c478bdstevel@tonic-gate{
8887c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
8897c478bdstevel@tonic-gate	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
8907c478bdstevel@tonic-gate	so->so_error = (ushort_t)error;
8917c478bdstevel@tonic-gate	cv_broadcast(&so->so_state_cv);
8927c478bdstevel@tonic-gate}
8937c478bdstevel@tonic-gate
8947c478bdstevel@tonic-gate/*
8957c478bdstevel@tonic-gate * Can no longer send.
8967c478bdstevel@tonic-gate * Caller must also call strsetwerror.
8977c478bdstevel@tonic-gate *
8987c478bdstevel@tonic-gate * We mark the peer address as no longer valid for getpeername, but
8997c478bdstevel@tonic-gate * leave it around for so_unix_close to notify the peer (that
9007c478bdstevel@tonic-gate * transport has no addressing held at that layer).
9017c478bdstevel@tonic-gate */
9027c478bdstevel@tonic-gatevoid
9037c478bdstevel@tonic-gatesocantsendmore(struct sonode *so)
9047c478bdstevel@tonic-gate{
9057c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
9060f1702cYu Xiangning<Eric.Yu@Sun.COM>	so->so_state |= SS_CANTSENDMORE;
9077c478bdstevel@tonic-gate	cv_broadcast(&so->so_state_cv);
9087c478bdstevel@tonic-gate}
9097c478bdstevel@tonic-gate
9107c478bdstevel@tonic-gate/*
9117c478bdstevel@tonic-gate * The caller must call strseteof(,1) as well as this routine
9127c478bdstevel@tonic-gate * to change the socket state.
9137c478bdstevel@tonic-gate */
9147c478bdstevel@tonic-gatevoid
9157c478bdstevel@tonic-gatesocantrcvmore(struct sonode *so)
9167c478bdstevel@tonic-gate{
9177c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
9187c478bdstevel@tonic-gate	so->so_state |= SS_CANTRCVMORE;
9197c478bdstevel@tonic-gate	cv_broadcast(&so->so_state_cv);
9207c478bdstevel@tonic-gate}
9217c478bdstevel@tonic-gate
9227c478bdstevel@tonic-gate/*
9237c478bdstevel@tonic-gate * The caller has sent down a "request_prim" primitive and wants to wait for
9247c478bdstevel@tonic-gate * an ack ("ack_prim") or an T_ERROR_ACK for it.
9257c478bdstevel@tonic-gate * The specified "ack_prim" can be a T_OK_ACK.
9267c478bdstevel@tonic-gate *
9277c478bdstevel@tonic-gate * Assumes that all the TPI acks are M_PCPROTO messages.
9287c478bdstevel@tonic-gate *
9297c478bdstevel@tonic-gate * Note that the socket is single-threaded (using so_lock_single)
9307c478bdstevel@tonic-gate * for all operations that generate TPI ack messages. Since
9317c478bdstevel@tonic-gate * only TPI ack messages are M_PCPROTO we should never receive
9327c478bdstevel@tonic-gate * anything except either the ack we are expecting or a T_ERROR_ACK
9337c478bdstevel@tonic-gate * for the same primitive.
9347c478bdstevel@tonic-gate */
9357c478bdstevel@tonic-gateint
9367c478bdstevel@tonic-gatesowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim,
9377c478bdstevel@tonic-gate	    t_uscalar_t min_size, mblk_t **mpp, clock_t wait)
9387c478bdstevel@tonic-gate{
9397c478bdstevel@tonic-gate	mblk_t *mp;
9407c478bdstevel@tonic-gate	union T_primitives *tpr;
9417c478bdstevel@tonic-gate	int error;
9427c478bdstevel@tonic-gate
9437c478bdstevel@tonic-gate	dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n",
944903a11erh	    (void *)so, request_prim, ack_prim, min_size, (void *)mpp, wait));
9457c478bdstevel@tonic-gate
9467c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
9477c478bdstevel@tonic-gate
9487c478bdstevel@tonic-gate	error = sowaitack(so, &mp, wait);
9497c478bdstevel@tonic-gate	if (error)
9507c478bdstevel@tonic-gate		return (error);
9517c478bdstevel@tonic-gate
952903a11erh	dprintso(so, 1, ("got msg %p\n", (void *)mp));
9537c478bdstevel@tonic-gate	if (DB_TYPE(mp) != M_PCPROTO ||
9547c478bdstevel@tonic-gate	    MBLKL(mp) < sizeof (tpr->type)) {
9557c478bdstevel@tonic-gate		freemsg(mp);
9567c478bdstevel@tonic-gate		eprintsoline(so, EPROTO);
9577c478bdstevel@tonic-gate		return (EPROTO);
9587c478bdstevel@tonic-gate	}
9597c478bdstevel@tonic-gate	tpr = (union T_primitives *)mp->b_rptr;
9607c478bdstevel@tonic-gate	/*
9617c478bdstevel@tonic-gate	 * Did we get the primitive that we were asking for?
9627c478bdstevel@tonic-gate	 * For T_OK_ACK we also check that it matches the request primitive.
9637c478bdstevel@tonic-gate	 */
9647c478bdstevel@tonic-gate	if (tpr->type == ack_prim &&
9657c478bdstevel@tonic-gate	    (ack_prim != T_OK_ACK ||
9667c478bdstevel@tonic-gate	    tpr->ok_ack.CORRECT_prim == request_prim)) {
9677c478bdstevel@tonic-gate		if (MBLKL(mp) >= (ssize_t)min_size) {
9687c478bdstevel@tonic-gate			/* Found what we are looking for */
9697c478bdstevel@tonic-gate			*mpp = mp;
9707c478bdstevel@tonic-gate			return (0);
9717c478bdstevel@tonic-gate		}
9727c478bdstevel@tonic-gate		/* Too short */
9737c478bdstevel@tonic-gate		freemsg(mp);
9747c478bdstevel@tonic-gate		eprintsoline(so, EPROTO);
9757c478bdstevel@tonic-gate		return (EPROTO);
9767c478bdstevel@tonic-gate	}
9777c478bdstevel@tonic-gate
9787c478bdstevel@tonic-gate	if (tpr->type == T_ERROR_ACK &&
9797c478bdstevel@tonic-gate	    tpr->error_ack.ERROR_prim == request_prim) {
9807c478bdstevel@tonic-gate		/* Error to the primitive we were looking for */
9817c478bdstevel@tonic-gate		if (tpr->error_ack.TLI_error == TSYSERR) {
9827c478bdstevel@tonic-gate			error = tpr->error_ack.UNIX_error;
9837c478bdstevel@tonic-gate		} else {
9840f1702cYu Xiangning<Eric.Yu@Sun.COM>			error = proto_tlitosyserr(tpr->error_ack.TLI_error);
9857c478bdstevel@tonic-gate		}
9867c478bdstevel@tonic-gate		dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n",
9870f1702cYu Xiangning<Eric.Yu@Sun.COM>		    tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error,
9880f1702cYu Xiangning<Eric.Yu@Sun.COM>		    tpr->error_ack.UNIX_error, error));
9897c478bdstevel@tonic-gate		freemsg(mp);
9907c478bdstevel@tonic-gate		return (error);
9917c478bdstevel@tonic-gate	}
9927c478bdstevel@tonic-gate	/*
9937c478bdstevel@tonic-gate	 * Wrong primitive or T_ERROR_ACK for the wrong primitive
9947c478bdstevel@tonic-gate	 */
9957c478bdstevel@tonic-gate#ifdef DEBUG
9967c478bdstevel@tonic-gate	if (tpr->type == T_ERROR_ACK) {
9977c478bdstevel@tonic-gate		dprintso(so, 0, ("error_ack for %d: %d/%d\n",
9980f1702cYu Xiangning<Eric.Yu@Sun.COM>		    tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error,
999d3e55dcgww		    tpr->error_ack.UNIX_error));
10007c478bdstevel@tonic-gate	} else if (tpr->type == T_OK_ACK) {
10017c478bdstevel@tonic-gate		dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n",
10020f1702cYu Xiangning<Eric.Yu@Sun.COM>		    tpr->ok_ack.CORRECT_prim, ack_prim, request_prim));
10037c478bdstevel@tonic-gate	} else {
10047c478bdstevel@tonic-gate		dprintso(so, 0,
1005d3e55dcgww		    ("unexpected primitive %d, expected %d for %d\n",
1006d3e55dcgww		    tpr->type, ack_prim, request_prim));
10077c478bdstevel@tonic-gate	}
10087c478bdstevel@tonic-gate#endif /* DEBUG */
10097c478bdstevel@tonic-gate
10107c478bdstevel@tonic-gate	freemsg(mp);
10117c478bdstevel@tonic-gate	eprintsoline(so, EPROTO);
10127c478bdstevel@tonic-gate	return (EPROTO);
10137c478bdstevel@tonic-gate}
10147c478bdstevel@tonic-gate
10157c478bdstevel@tonic-gate/*
10167c478bdstevel@tonic-gate * Wait for a T_OK_ACK for the specified primitive.
10177c478bdstevel@tonic-gate */
10187c478bdstevel@tonic-gateint
10197c478bdstevel@tonic-gatesowaitokack(struct sonode *so, t_scalar_t request_prim)
10207c478bdstevel@tonic-gate{
10217c478bdstevel@tonic-gate	mblk_t *mp;
10227c478bdstevel@tonic-gate	int error;
10237c478bdstevel@tonic-gate
10247c478bdstevel@tonic-gate	error = sowaitprim(so, request_prim, T_OK_ACK,
10257c478bdstevel@tonic-gate	    (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0);
10267c478bdstevel@tonic-gate	if (error)
10277c478bdstevel@tonic-gate		return (error);
10287c478bdstevel@tonic-gate	freemsg(mp);
10297c478bdstevel@tonic-gate	return (0);
10307c478bdstevel@tonic-gate}
10317c478bdstevel@tonic-gate
10327c478bdstevel@tonic-gate/*
10330f1702cYu Xiangning<Eric.Yu@Sun.COM> * Queue a received TPI ack message on sti_ack_mp.
10347c478bdstevel@tonic-gate */
10357c478bdstevel@tonic-gatevoid
10367c478bdstevel@tonic-gatesoqueueack(struct sonode *so, mblk_t *mp)
10377c478bdstevel@tonic-gate{
10380f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
10390f1702cYu Xiangning<Eric.Yu@Sun.COM>
10407c478bdstevel@tonic-gate	if (DB_TYPE(mp) != M_PCPROTO) {
10412caf0dcrshoaib		zcmn_err(getzoneid(), CE_WARN,
10427c478bdstevel@tonic-gate		    "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n",
10437c478bdstevel@tonic-gate		    *(t_scalar_t *)mp->b_rptr);
10447c478bdstevel@tonic-gate		freemsg(mp);
10457c478bdstevel@tonic-gate		return;
10467c478bdstevel@tonic-gate	}
10477c478bdstevel@tonic-gate
10487c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
10490f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_ack_mp != NULL) {
10500f1702cYu Xiangning<Eric.Yu@Sun.COM>		dprintso(so, 1, ("sti_ack_mp already set\n"));
10510f1702cYu Xiangning<Eric.Yu@Sun.COM>		freemsg(sti->sti_ack_mp);
10520f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_ack_mp = NULL;
10537c478bdstevel@tonic-gate	}
10540f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_ack_mp = mp;
10550f1702cYu Xiangning<Eric.Yu@Sun.COM>	cv_broadcast(&sti->sti_ack_cv);
10567c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
10577c478bdstevel@tonic-gate}
10587c478bdstevel@tonic-gate
10597c478bdstevel@tonic-gate/*
10607c478bdstevel@tonic-gate * Wait for a TPI ack ignoring signals and errors.
10617c478bdstevel@tonic-gate */
10627c478bdstevel@tonic-gateint
10637c478bdstevel@tonic-gatesowaitack(struct sonode *so, mblk_t **mpp, clock_t wait)
10647c478bdstevel@tonic-gate{
10650f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
10660f1702cYu Xiangning<Eric.Yu@Sun.COM>
10677c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
10687c478bdstevel@tonic-gate
10690f1702cYu Xiangning<Eric.Yu@Sun.COM>	while (sti->sti_ack_mp == NULL) {
10707c478bdstevel@tonic-gate#ifdef SOCK_TEST
10717c478bdstevel@tonic-gate		if (wait == 0 && sock_test_timelimit != 0)
10727c478bdstevel@tonic-gate			wait = sock_test_timelimit;
10737c478bdstevel@tonic-gate#endif
10747c478bdstevel@tonic-gate		if (wait != 0) {
10757c478bdstevel@tonic-gate			/*
10767c478bdstevel@tonic-gate			 * Only wait for the time limit.
10777c478bdstevel@tonic-gate			 */
1078d3d5073Rafael Vanoni			if (cv_reltimedwait(&sti->sti_ack_cv, &so->so_lock,
1079d3d5073Rafael Vanoni			    wait, TR_CLOCK_TICK) == -1) {
10807c478bdstevel@tonic-gate				eprintsoline(so, ETIME);
10817c478bdstevel@tonic-gate				return (ETIME);
10827c478bdstevel@tonic-gate			}
10837c478bdstevel@tonic-gate		}
10847c478bdstevel@tonic-gate		else
10850f1702cYu Xiangning<Eric.Yu@Sun.COM>			cv_wait(&sti->sti_ack_cv, &so->so_lock);
10867c478bdstevel@tonic-gate	}
10870f1702cYu Xiangning<Eric.Yu@Sun.COM>	*mpp = sti->sti_ack_mp;
10887c478bdstevel@tonic-gate#ifdef DEBUG
10897c478bdstevel@tonic-gate	{
10907c478bdstevel@tonic-gate		union T_primitives *tpr;
10917c478bdstevel@tonic-gate		mblk_t *mp = *mpp;
10927c478bdstevel@tonic-gate
10937c478bdstevel@tonic-gate		tpr = (union T_primitives *)mp->b_rptr;
10947c478bdstevel@tonic-gate		ASSERT(DB_TYPE(mp) == M_PCPROTO);
10957c478bdstevel@tonic-gate		ASSERT(tpr->type == T_OK_ACK ||
1096d3e55dcgww		    tpr->type == T_ERROR_ACK ||
1097d3e55dcgww		    tpr->type == T_BIND_ACK ||
1098d3e55dcgww		    tpr->type == T_CAPABILITY_ACK ||
1099d3e55dcgww		    tpr->type == T_INFO_ACK ||
1100d3e55dcgww		    tpr->type == T_OPTMGMT_ACK);
11017c478bdstevel@tonic-gate	}
11027c478bdstevel@tonic-gate#endif /* DEBUG */
11030f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_ack_mp = NULL;
11047c478bdstevel@tonic-gate	return (0);
11057c478bdstevel@tonic-gate}
11067c478bdstevel@tonic-gate
11077c478bdstevel@tonic-gate/*
11080f1702cYu Xiangning<Eric.Yu@Sun.COM> * Queue a received T_CONN_IND message on sti_conn_ind_head/tail.
11097c478bdstevel@tonic-gate */
11107c478bdstevel@tonic-gatevoid
11117c478bdstevel@tonic-gatesoqueueconnind(struct sonode *so, mblk_t *mp)
11127c478bdstevel@tonic-gate{
11130f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
11140f1702cYu Xiangning<Eric.Yu@Sun.COM>
11157c478bdstevel@tonic-gate	if (DB_TYPE(mp) != M_PROTO) {
11162caf0dcrshoaib		zcmn_err(getzoneid(), CE_WARN,
11177c478bdstevel@tonic-gate		    "sockfs: received unexpected M_PCPROTO T_CONN_IND\n");
11187c478bdstevel@tonic-gate		freemsg(mp);
11197c478bdstevel@tonic-gate		return;
11207c478bdstevel@tonic-gate	}
11217c478bdstevel@tonic-gate
11227c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
11237c478bdstevel@tonic-gate	ASSERT(mp->b_next == NULL);
11240f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_conn_ind_head == NULL) {
11250f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_conn_ind_head = mp;
11267c478bdstevel@tonic-gate	} else {
11270f1702cYu Xiangning<Eric.Yu@Sun.COM>		ASSERT(sti->sti_conn_ind_tail->b_next == NULL);
11280f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_conn_ind_tail->b_next = mp;
11297c478bdstevel@tonic-gate	}
11300f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_conn_ind_tail = mp;
11317c478bdstevel@tonic-gate	/* Wakeup a single consumer of the T_CONN_IND */
11320f1702cYu Xiangning<Eric.Yu@Sun.COM>	cv_signal(&so->so_acceptq_cv);
11337c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
11347c478bdstevel@tonic-gate}
11357c478bdstevel@tonic-gate
11367c478bdstevel@tonic-gate/*
11377c478bdstevel@tonic-gate * Wait for a T_CONN_IND.
11387c478bdstevel@tonic-gate * Don't wait if nonblocking.
11397c478bdstevel@tonic-gate * Accept signals and socket errors.
11407c478bdstevel@tonic-gate */
11417c478bdstevel@tonic-gateint
11427c478bdstevel@tonic-gatesowaitconnind(struct sonode *so, int fmode, mblk_t **mpp)
11437c478bdstevel@tonic-gate{
11447c478bdstevel@tonic-gate	mblk_t *mp;
11450f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
11467c478bdstevel@tonic-gate	int error = 0;
11477c478bdstevel@tonic-gate
11487c478bdstevel@tonic-gate	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11497c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
11507c478bdstevel@tonic-gatecheck_error:
11517c478bdstevel@tonic-gate	if (so->so_error) {
11520f1702cYu Xiangning<Eric.Yu@Sun.COM>		error = sogeterr(so, B_TRUE);
11537c478bdstevel@tonic-gate		if (error) {
11547c478bdstevel@tonic-gate			mutex_exit(&so->so_lock);
11557c478bdstevel@tonic-gate			return (error);
11567c478bdstevel@tonic-gate		}
11577c478bdstevel@tonic-gate	}
11587c478bdstevel@tonic-gate
11590f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_conn_ind_head == NULL) {
11607c478bdstevel@tonic-gate		if (fmode & (FNDELAY|FNONBLOCK)) {
11617c478bdstevel@tonic-gate			error = EWOULDBLOCK;
11627c478bdstevel@tonic-gate			goto done;
11637c478bdstevel@tonic-gate		}
11640f1702cYu Xiangning<Eric.Yu@Sun.COM>
11650f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (so->so_state & SS_CLOSING) {
11660f1702cYu Xiangning<Eric.Yu@Sun.COM>			error = EINTR;
11670f1702cYu Xiangning<Eric.Yu@Sun.COM>			goto done;
11680f1702cYu Xiangning<Eric.Yu@Sun.COM>		}
11690f1702cYu Xiangning<Eric.Yu@Sun.COM>
11700f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (!cv_wait_sig_swap(&so->so_acceptq_cv, &so->so_lock)) {
11717c478bdstevel@tonic-gate			error = EINTR;
11727c478bdstevel@tonic-gate			goto done;
11737c478bdstevel@tonic-gate		}
11747c478bdstevel@tonic-gate		goto check_error;
11757c478bdstevel@tonic-gate	}
11760f1702cYu Xiangning<Eric.Yu@Sun.COM>	mp = sti->sti_conn_ind_head;
11770f1702cYu Xiangning<Eric.Yu@Sun.COM>	sti->sti_conn_ind_head = mp->b_next;
11787c478bdstevel@tonic-gate	mp->b_next = NULL;
11790f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_conn_ind_head == NULL) {
11800f1702cYu Xiangning<Eric.Yu@Sun.COM>		ASSERT(sti->sti_conn_ind_tail == mp);
11810f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_conn_ind_tail = NULL;
11827c478bdstevel@tonic-gate	}
11837c478bdstevel@tonic-gate	*mpp = mp;
11847c478bdstevel@tonic-gatedone:
11857c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
11867c478bdstevel@tonic-gate	return (error);
11877c478bdstevel@tonic-gate}
11887c478bdstevel@tonic-gate
11897c478bdstevel@tonic-gate/*
11907c478bdstevel@tonic-gate * Flush a T_CONN_IND matching the sequence number from the list.
11917c478bdstevel@tonic-gate * Return zero if found; non-zero otherwise.
11927c478bdstevel@tonic-gate * This is called very infrequently thus it is ok to do a linear search.
11937c478bdstevel@tonic-gate */
11947c478bdstevel@tonic-gateint
11957c478bdstevel@tonic-gatesoflushconnind(struct sonode *so, t_scalar_t seqno)
11967c478bdstevel@tonic-gate{
11977c478bdstevel@tonic-gate	mblk_t *prevmp, *mp;
11987c478bdstevel@tonic-gate	struct T_conn_ind *tci;
11990f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
12007c478bdstevel@tonic-gate
12017c478bdstevel@tonic-gate	mutex_enter(&so->so_lock);
12020f1702cYu Xiangning<Eric.Yu@Sun.COM>	for (prevmp = NULL, mp = sti->sti_conn_ind_head; mp != NULL;
12037c478bdstevel@tonic-gate	    prevmp = mp, mp = mp->b_next) {
12047c478bdstevel@tonic-gate		tci = (struct T_conn_ind *)mp->b_rptr;
12057c478bdstevel@tonic-gate		if (tci->SEQ_number == seqno) {
12067c478bdstevel@tonic-gate			dprintso(so, 1,
1207d3e55dcgww			    ("t_discon_ind: found T_CONN_IND %d\n", seqno));
12087c478bdstevel@tonic-gate			/* Deleting last? */
12090f1702cYu Xiangning<Eric.Yu@Sun.COM>			if (sti->sti_conn_ind_tail == mp) {
12100f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_conn_ind_tail = prevmp;
12117c478bdstevel@tonic-gate			}
12127c478bdstevel@tonic-gate			if (prevmp == NULL) {
12137c478bdstevel@tonic-gate				/* Deleting first */
12140f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_conn_ind_head = mp->b_next;
12157c478bdstevel@tonic-gate			} else {
12167c478bdstevel@tonic-gate				prevmp->b_next = mp->b_next;
12177c478bdstevel@tonic-gate			}
12187c478bdstevel@tonic-gate			mp->b_next = NULL;
12190f1702cYu Xiangning<Eric.Yu@Sun.COM>
12200f1702cYu Xiangning<Eric.Yu@Sun.COM>			ASSERT((sti->sti_conn_ind_head == NULL &&
12210f1702cYu Xiangning<Eric.Yu@Sun.COM>			    sti->sti_conn_ind_tail == NULL) ||
12220f1702cYu Xiangning<Eric.Yu@Sun.COM>			    (sti->sti_conn_ind_head != NULL &&
12230f1702cYu Xiangning<Eric.Yu@Sun.COM>			    sti->sti_conn_ind_tail != NULL));
12240f1702cYu Xiangning<Eric.Yu@Sun.COM>
12257c478bdstevel@tonic-gate			so->so_error = ECONNABORTED;
12267c478bdstevel@tonic-gate			mutex_exit(&so->so_lock);
1227c28749ekais
12287c478bdstevel@tonic-gate			freemsg(mp);
12297c478bdstevel@tonic-gate			return (0);
12307c478bdstevel@tonic-gate		}
12317c478bdstevel@tonic-gate	}
12327c478bdstevel@tonic-gate	mutex_exit(&so->so_lock);
12337c478bdstevel@tonic-gate	dprintso(so, 1,	("t_discon_ind: NOT found T_CONN_IND %d\n", seqno));
12347c478bdstevel@tonic-gate	return (-1);
12357c478bdstevel@tonic-gate}
12367c478bdstevel@tonic-gate
12377c478bdstevel@tonic-gate/*
12387c478bdstevel@tonic-gate * Wait until the socket is connected or there is an error.
12397c478bdstevel@tonic-gate * fmode should contain any nonblocking flags. nosig should be
12407c478bdstevel@tonic-gate * set if the caller does not want the wait to be interrupted by a signal.
12417c478bdstevel@tonic-gate */
12427c478bdstevel@tonic-gateint
12437c478bdstevel@tonic-gatesowaitconnected(struct sonode *so, int fmode, int nosig)
12447c478bdstevel@tonic-gate{
12457c478bdstevel@tonic-gate	int error;
12467c478bdstevel@tonic-gate
12477c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
12487c478bdstevel@tonic-gate
12497c478bdstevel@tonic-gate	while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) ==
1250d3e55dcgww	    SS_ISCONNECTING && so->so_error == 0) {
12517c478bdstevel@tonic-gate
1252903a11erh		dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n",
1253903a11erh		    (void *)so));
12547c478bdstevel@tonic-gate		if (fmode & (FNDELAY|FNONBLOCK))
12557c478bdstevel@tonic-gate			return (EINPROGRESS);
12567c478bdstevel@tonic-gate
12570f1702cYu Xiangning<Eric.Yu@Sun.COM>		if (so->so_state & SS_CLOSING)
12580f1702cYu Xiangning<Eric.Yu@Sun.COM>			return (EINTR);
12590f1702cYu Xiangning<Eric.Yu@Sun.COM>
12607c478bdstevel@tonic-gate		if (nosig)
12617c478bdstevel@tonic-gate			cv_wait(&so->so_state_cv, &so->so_lock);
12627c478bdstevel@tonic-gate		else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) {
12637c478bdstevel@tonic-gate			/*
12647c478bdstevel@tonic-gate			 * Return EINTR and let the application use
12657c478bdstevel@tonic-gate			 * nonblocking techniques for detecting when
12667c478bdstevel@tonic-gate			 * the connection has been established.
12677c478bdstevel@tonic-gate			 */
12687c478bdstevel@tonic-gate			return (EINTR);
12697c478bdstevel@tonic-gate		}
1270903a11erh		dprintso(so, 1, ("awoken on %p\n", (void *)so));
12717c478bdstevel@tonic-gate	}
12727c478bdstevel@tonic-gate
12737c478bdstevel@tonic-gate	if (so->so_error != 0) {
12740f1702cYu Xiangning<Eric.Yu@Sun.COM>		error = sogeterr(so, B_TRUE);
12757c478bdstevel@tonic-gate		ASSERT(error != 0);
12767c478bdstevel@tonic-gate		dprintso(so, 1, ("sowaitconnected: error %d\n", error));
12777c478bdstevel@tonic-gate		return (error);
12787c478bdstevel@tonic-gate	}
12797c478bdstevel@tonic-gate	if (!(so->so_state & SS_ISCONNECTED)) {
12807c478bdstevel@tonic-gate		/*
12817c478bdstevel@tonic-gate		 * Could have received a T_ORDREL_IND or a T_DISCON_IND with
12827c478bdstevel@tonic-gate		 * zero errno. Or another thread could have consumed so_error
12837c478bdstevel@tonic-gate		 * e.g. by calling read.
12847c478bdstevel@tonic-gate		 */
12857c478bdstevel@tonic-gate		error = ECONNREFUSED;
12867c478bdstevel@tonic-gate		dprintso(so, 1, ("sowaitconnected: error %d\n", error));
12877c478bdstevel@tonic-gate		return (error);
12887c478bdstevel@tonic-gate	}
12897c478bdstevel@tonic-gate	return (0);
12907c478bdstevel@tonic-gate}
12917c478bdstevel@tonic-gate
12927c478bdstevel@tonic-gate
12937c478bdstevel@tonic-gate/*
12947c478bdstevel@tonic-gate * Handle the signal generation aspect of urgent data.
12957c478bdstevel@tonic-gate */
12967c478bdstevel@tonic-gatestatic void
12977c478bdstevel@tonic-gateso_oob_sig(struct sonode *so, int extrasig,
12987c478bdstevel@tonic-gate    strsigset_t *signals, strpollset_t *pollwakeups)
12997c478bdstevel@tonic-gate{
13000f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
13010f1702cYu Xiangning<Eric.Yu@Sun.COM>
13027c478bdstevel@tonic-gate	ASSERT(MUTEX_HELD(&so->so_lock));
13037c478bdstevel@tonic-gate
13047c478bdstevel@tonic-gate	ASSERT(so_verify_oobstate(so));
13050f1702cYu Xiangning<Eric.Yu@Sun.COM>	ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt);
13060f1702cYu Xiangning<Eric.Yu@Sun.COM>	if (sti->sti_oobsigcnt > sti->sti_oobcnt) {
13077c478bdstevel@tonic-gate		/*
13087c478bdstevel@tonic-gate		 * Signal has already been generated once for this
13097c478bdstevel@tonic-gate		 * urgent "event". However, since TCP can receive updated
13107c478bdstevel@tonic-gate		 * urgent pointers we still generate a signal.
13117c478bdstevel@tonic-gate		 */
13127c478bdstevel@tonic-gate		ASSERT(so->so_state & SS_OOBPEND);
13137c478bdstevel@tonic-gate		if (extrasig) {
13147c478bdstevel@tonic-gate			*signals |= S_RDBAND;
13157c478bdstevel@tonic-gate			*pollwakeups |= POLLRDBAND;
13167c478bdstevel@tonic-gate		}
13177c478bdstevel@tonic-gate		return;
13187c478bdstevel@tonic-gate	}
13197c478bdstevel@tonic-gate
1320