xref: /illumos-gate/usr/src/uts/common/fs/sockfs/sockstr.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/inttypes.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/flock.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/kmem_impl.h>
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #include <sys/suntpi.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
62*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
65*7c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION	2
66*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #include <c2/audit.h>
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate int so_default_version = SOV_SOCKSTREAM;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
73*7c478bd9Sstevel@tonic-gate /* Set sockdebug to print debug messages when SO_DEBUG is set */
74*7c478bd9Sstevel@tonic-gate int sockdebug = 0;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /* Set sockprinterr to print error messages when SO_DEBUG is set */
77*7c478bd9Sstevel@tonic-gate int sockprinterr = 0;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate /*
80*7c478bd9Sstevel@tonic-gate  * Set so_default_options to SO_DEBUG is all sockets should be created
81*7c478bd9Sstevel@tonic-gate  * with SO_DEBUG set. This is needed to get debug printouts from the
82*7c478bd9Sstevel@tonic-gate  * socket() call itself.
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate int so_default_options = 0;
85*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST
88*7c478bd9Sstevel@tonic-gate /*
89*7c478bd9Sstevel@tonic-gate  * Set to number of ticks to limit cv_waits for code coverage testing.
90*7c478bd9Sstevel@tonic-gate  * Set to 1000 when SO_DEBUG is set to 2.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate clock_t sock_test_timelimit = 0;
93*7c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /*
96*7c478bd9Sstevel@tonic-gate  * For concurrency testing of e.g. opening /dev/ip which does not
97*7c478bd9Sstevel@tonic-gate  * handle T_INFO_REQ messages.
98*7c478bd9Sstevel@tonic-gate  */
99*7c478bd9Sstevel@tonic-gate int so_no_tinfo = 0;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate /*
102*7c478bd9Sstevel@tonic-gate  * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider
103*7c478bd9Sstevel@tonic-gate  * to simply ignore the T_CAPABILITY_REQ.
104*7c478bd9Sstevel@tonic-gate  */
105*7c478bd9Sstevel@tonic-gate clock_t	sock_capability_timeout	= 2;	/* seconds */
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate static int	do_tcapability(struct sonode *so, t_uscalar_t cap_bits1);
108*7c478bd9Sstevel@tonic-gate static void	so_removehooks(struct sonode *so);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate static mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp,
111*7c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
112*7c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups);
113*7c478bd9Sstevel@tonic-gate static mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp,
114*7c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
115*7c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups);
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static int tlitosyserr(int terr);
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /*
120*7c478bd9Sstevel@tonic-gate  * Convert a socket to a stream. Invoked when the illusory sockmod
121*7c478bd9Sstevel@tonic-gate  * is popped from the stream.
122*7c478bd9Sstevel@tonic-gate  * Change the stream head back to default operation without losing
123*7c478bd9Sstevel@tonic-gate  * any messages (T_conn_ind's are moved to the stream head queue).
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate int
126*7c478bd9Sstevel@tonic-gate so_sock2stream(struct sonode *so)
127*7c478bd9Sstevel@tonic-gate {
128*7c478bd9Sstevel@tonic-gate 	struct vnode		*vp = SOTOV(so);
129*7c478bd9Sstevel@tonic-gate 	queue_t			*rq;
130*7c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
131*7c478bd9Sstevel@tonic-gate 	int			error = 0;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_plumb_lock));
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
136*7c478bd9Sstevel@tonic-gate 	so_lock_single(so);
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_version != SOV_STREAM);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	/* tell the transport below that sockmod is being popped */
141*7c478bd9Sstevel@tonic-gate 	if ((so->so_state & SS_TCP_FAST_ACCEPT) != 0) {
142*7c478bd9Sstevel@tonic-gate 		int	rval;
143*7c478bd9Sstevel@tonic-gate 		mblk_t	**mpp;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
146*7c478bd9Sstevel@tonic-gate 		error = strioctl(vp, SIOCPOPSOCKFS, NULL, 0, K_TO_K, CRED(),
147*7c478bd9Sstevel@tonic-gate 		    &rval);
148*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
149*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
150*7c478bd9Sstevel@tonic-gate 			dprintso(so, 0,
151*7c478bd9Sstevel@tonic-gate 			    ("so_sock2stream(%p): SIOCPOPSOCKFS failed\n", so));
152*7c478bd9Sstevel@tonic-gate 			goto exit;
153*7c478bd9Sstevel@tonic-gate 		}
154*7c478bd9Sstevel@tonic-gate 		so->so_state &= ~SS_TCP_FAST_ACCEPT;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 		for (mpp = &so->so_conn_ind_head; (mp = *mpp) != NULL;
157*7c478bd9Sstevel@tonic-gate 		    mpp = &mp->b_next) {
158*7c478bd9Sstevel@tonic-gate 			struct T_conn_ind	*conn_ind;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 			/*
161*7c478bd9Sstevel@tonic-gate 			 * strsock_proto() has already verified the length of
162*7c478bd9Sstevel@tonic-gate 			 * this message block.
163*7c478bd9Sstevel@tonic-gate 			 */
164*7c478bd9Sstevel@tonic-gate 			ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind));
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 			conn_ind = (struct T_conn_ind *)mp->b_rptr;
167*7c478bd9Sstevel@tonic-gate 			if (conn_ind->OPT_length == 0 &&
168*7c478bd9Sstevel@tonic-gate 			    conn_ind->OPT_offset == 0)
169*7c478bd9Sstevel@tonic-gate 				continue;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 			if (DB_REF(mp) > 1) {
172*7c478bd9Sstevel@tonic-gate 				mblk_t	*newmp;
173*7c478bd9Sstevel@tonic-gate 				size_t	length;
174*7c478bd9Sstevel@tonic-gate 				cred_t	*cr;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 				/*
177*7c478bd9Sstevel@tonic-gate 				 * Copy the message block because it is used
178*7c478bd9Sstevel@tonic-gate 				 * elsewhere, too.
179*7c478bd9Sstevel@tonic-gate 				 */
180*7c478bd9Sstevel@tonic-gate 				length = MBLKL(mp);
181*7c478bd9Sstevel@tonic-gate 				newmp = soallocproto(length, _ALLOC_INTR);
182*7c478bd9Sstevel@tonic-gate 				if (newmp == NULL) {
183*7c478bd9Sstevel@tonic-gate 					error = EINTR;
184*7c478bd9Sstevel@tonic-gate 					goto exit;
185*7c478bd9Sstevel@tonic-gate 				}
186*7c478bd9Sstevel@tonic-gate 				bcopy(mp->b_rptr, newmp->b_wptr, length);
187*7c478bd9Sstevel@tonic-gate 				newmp->b_wptr += length;
188*7c478bd9Sstevel@tonic-gate 				newmp->b_next = mp->b_next;
189*7c478bd9Sstevel@tonic-gate 				cr = DB_CRED(mp);
190*7c478bd9Sstevel@tonic-gate 				if (cr != NULL)
191*7c478bd9Sstevel@tonic-gate 					mblk_setcred(newmp, cr);
192*7c478bd9Sstevel@tonic-gate 				DB_CPID(newmp) = DB_CPID(mp);
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 				/*
195*7c478bd9Sstevel@tonic-gate 				 * Link the new message block into the queue
196*7c478bd9Sstevel@tonic-gate 				 * and free the old one.
197*7c478bd9Sstevel@tonic-gate 				 */
198*7c478bd9Sstevel@tonic-gate 				*mpp = newmp;
199*7c478bd9Sstevel@tonic-gate 				mp->b_next = NULL;
200*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 				mp = newmp;
203*7c478bd9Sstevel@tonic-gate 				conn_ind = (struct T_conn_ind *)mp->b_rptr;
204*7c478bd9Sstevel@tonic-gate 			}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 			/*
207*7c478bd9Sstevel@tonic-gate 			 * Remove options added by TCP for accept fast-path.
208*7c478bd9Sstevel@tonic-gate 			 */
209*7c478bd9Sstevel@tonic-gate 			conn_ind->OPT_length = 0;
210*7c478bd9Sstevel@tonic-gate 			conn_ind->OPT_offset = 0;
211*7c478bd9Sstevel@tonic-gate 		}
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	so->so_version = SOV_STREAM;
215*7c478bd9Sstevel@tonic-gate 	so->so_priv = NULL;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	/*
218*7c478bd9Sstevel@tonic-gate 	 * Remove the hooks in the stream head to avoid queuing more
219*7c478bd9Sstevel@tonic-gate 	 * packets in sockfs.
220*7c478bd9Sstevel@tonic-gate 	 */
221*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
222*7c478bd9Sstevel@tonic-gate 	so_removehooks(so);
223*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	/*
226*7c478bd9Sstevel@tonic-gate 	 * Clear any state related to urgent data. Leave any T_EXDATA_IND
227*7c478bd9Sstevel@tonic-gate 	 * on the queue - the behavior of urgent data after a switch is
228*7c478bd9Sstevel@tonic-gate 	 * left undefined.
229*7c478bd9Sstevel@tonic-gate 	 */
230*7c478bd9Sstevel@tonic-gate 	so->so_error = so->so_delayed_error = 0;
231*7c478bd9Sstevel@tonic-gate 	freemsg(so->so_oobmsg);
232*7c478bd9Sstevel@tonic-gate 	so->so_oobmsg = NULL;
233*7c478bd9Sstevel@tonic-gate 	so->so_oobsigcnt = so->so_oobcnt = 0;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA|
236*7c478bd9Sstevel@tonic-gate 	    SS_HASCONNIND|SS_SAVEDEOR);
237*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	freemsg(so->so_ack_mp);
240*7c478bd9Sstevel@tonic-gate 	so->so_ack_mp = NULL;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	/*
243*7c478bd9Sstevel@tonic-gate 	 * Flush the T_DISCON_IND on so_discon_ind_mp.
244*7c478bd9Sstevel@tonic-gate 	 */
245*7c478bd9Sstevel@tonic-gate 	so_flush_discon_ind(so);
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	/*
248*7c478bd9Sstevel@tonic-gate 	 * Move any queued T_CONN_IND messages to stream head queue.
249*7c478bd9Sstevel@tonic-gate 	 */
250*7c478bd9Sstevel@tonic-gate 	rq = RD(strvp2wq(vp));
251*7c478bd9Sstevel@tonic-gate 	while ((mp = so->so_conn_ind_head) != NULL) {
252*7c478bd9Sstevel@tonic-gate 		so->so_conn_ind_head = mp->b_next;
253*7c478bd9Sstevel@tonic-gate 		mp->b_next = NULL;
254*7c478bd9Sstevel@tonic-gate 		if (so->so_conn_ind_head == NULL) {
255*7c478bd9Sstevel@tonic-gate 			ASSERT(so->so_conn_ind_tail == mp);
256*7c478bd9Sstevel@tonic-gate 			so->so_conn_ind_tail = NULL;
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
259*7c478bd9Sstevel@tonic-gate 			("so_sock2stream(%p): moving T_CONN_IND\n",
260*7c478bd9Sstevel@tonic-gate 			so));
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 		/* Drop lock across put() */
263*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
264*7c478bd9Sstevel@tonic-gate 		put(rq, mp);
265*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
266*7c478bd9Sstevel@tonic-gate 	}
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate exit:
269*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
270*7c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
271*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
272*7c478bd9Sstevel@tonic-gate 	return (error);
273*7c478bd9Sstevel@tonic-gate }
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate /*
276*7c478bd9Sstevel@tonic-gate  * Covert a stream back to a socket. This is invoked when the illusory
277*7c478bd9Sstevel@tonic-gate  * sockmod is pushed on a stream (where the stream was "created" by
278*7c478bd9Sstevel@tonic-gate  * popping the illusory sockmod).
279*7c478bd9Sstevel@tonic-gate  * This routine can not recreate the socket state (certain aspects of
280*7c478bd9Sstevel@tonic-gate  * it like urgent data state and the bound/connected addresses for AF_UNIX
281*7c478bd9Sstevel@tonic-gate  * sockets can not be recreated by asking the transport for information).
282*7c478bd9Sstevel@tonic-gate  * Thus this routine implicitly assumes that the socket is in an initial
283*7c478bd9Sstevel@tonic-gate  * state (as if it was just created). It flushes any messages queued on the
284*7c478bd9Sstevel@tonic-gate  * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages.
285*7c478bd9Sstevel@tonic-gate  */
286*7c478bd9Sstevel@tonic-gate void
287*7c478bd9Sstevel@tonic-gate so_stream2sock(struct sonode *so)
288*7c478bd9Sstevel@tonic-gate {
289*7c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_plumb_lock));
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
294*7c478bd9Sstevel@tonic-gate 	so_lock_single(so);
295*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_version == SOV_STREAM);
296*7c478bd9Sstevel@tonic-gate 	so->so_version = SOV_SOCKSTREAM;
297*7c478bd9Sstevel@tonic-gate 	so->so_pushcnt = 0;
298*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	/*
301*7c478bd9Sstevel@tonic-gate 	 * Set a permenent error to force any thread in sorecvmsg to
302*7c478bd9Sstevel@tonic-gate 	 * return (and drop SOREADLOCKED). Clear the error once
303*7c478bd9Sstevel@tonic-gate 	 * we have SOREADLOCKED.
304*7c478bd9Sstevel@tonic-gate 	 * This makes a read sleeping during the I_PUSH of sockmod return
305*7c478bd9Sstevel@tonic-gate 	 * EIO.
306*7c478bd9Sstevel@tonic-gate 	 */
307*7c478bd9Sstevel@tonic-gate 	strsetrerror(SOTOV(so), EIO, 1, NULL);
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	/*
310*7c478bd9Sstevel@tonic-gate 	 * Get the read lock before flushing data to avoid
311*7c478bd9Sstevel@tonic-gate 	 * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg.
312*7c478bd9Sstevel@tonic-gate 	 */
313*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
314*7c478bd9Sstevel@tonic-gate 	(void) so_lock_read(so, 0);	/* Set SOREADLOCKED */
315*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	strsetrerror(SOTOV(so), 0, 0, NULL);
318*7c478bd9Sstevel@tonic-gate 	so_installhooks(so);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/*
321*7c478bd9Sstevel@tonic-gate 	 * Flush everything on the read queue.
322*7c478bd9Sstevel@tonic-gate 	 * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND
323*7c478bd9Sstevel@tonic-gate 	 * remain; those types of messages would confuse sockfs.
324*7c478bd9Sstevel@tonic-gate 	 */
325*7c478bd9Sstevel@tonic-gate 	strflushrq(vp, FLUSHALL);
326*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	/*
329*7c478bd9Sstevel@tonic-gate 	 * Flush the T_DISCON_IND on so_discon_ind_mp.
330*7c478bd9Sstevel@tonic-gate 	 */
331*7c478bd9Sstevel@tonic-gate 	so_flush_discon_ind(so);
332*7c478bd9Sstevel@tonic-gate 	so_unlock_read(so);	/* Clear SOREADLOCKED */
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
335*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate /*
339*7c478bd9Sstevel@tonic-gate  * Install the hooks in the stream head.
340*7c478bd9Sstevel@tonic-gate  */
341*7c478bd9Sstevel@tonic-gate void
342*7c478bd9Sstevel@tonic-gate so_installhooks(struct sonode *so)
343*7c478bd9Sstevel@tonic-gate {
344*7c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA,
347*7c478bd9Sstevel@tonic-gate 	    strsock_proto, strsock_misc);
348*7c478bd9Sstevel@tonic-gate 	strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0);
349*7c478bd9Sstevel@tonic-gate }
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate /*
352*7c478bd9Sstevel@tonic-gate  * Remove the hooks in the stream head.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate static void
355*7c478bd9Sstevel@tonic-gate so_removehooks(struct sonode *so)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	strsetrputhooks(vp, 0, NULL, NULL);
360*7c478bd9Sstevel@tonic-gate 	strsetwputhooks(vp, 0, STRTIMOUT);
361*7c478bd9Sstevel@tonic-gate 	/*
362*7c478bd9Sstevel@tonic-gate 	 * Leave read behavior as it would have been for a normal
363*7c478bd9Sstevel@tonic-gate 	 * stream i.e. a read of an M_PROTO will fail.
364*7c478bd9Sstevel@tonic-gate 	 */
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * Initialize the streams side of a socket including
369*7c478bd9Sstevel@tonic-gate  * T_info_req/ack processing. If tso is not NULL its values are used thereby
370*7c478bd9Sstevel@tonic-gate  * avoiding the T_INFO_REQ.
371*7c478bd9Sstevel@tonic-gate  */
372*7c478bd9Sstevel@tonic-gate int
373*7c478bd9Sstevel@tonic-gate so_strinit(struct sonode *so, struct sonode *tso)
374*7c478bd9Sstevel@tonic-gate {
375*7c478bd9Sstevel@tonic-gate 	struct vnode *vp = SOTOV(so);
376*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
377*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
378*7c478bd9Sstevel@tonic-gate 	int error;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("so_strinit(%p)\n", so));
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	/* Preallocate an unbind_req message */
383*7c478bd9Sstevel@tonic-gate 	mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP);
384*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
385*7c478bd9Sstevel@tonic-gate 	so->so_unbind_mp = mp;
386*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
387*7c478bd9Sstevel@tonic-gate 	so->so_options = so_default_options;
388*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
389*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	so_installhooks(so);
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	/*
394*7c478bd9Sstevel@tonic-gate 	 * The T_CAPABILITY_REQ should be the first message sent down because
395*7c478bd9Sstevel@tonic-gate 	 * at least TCP has a fast-path for this which avoids timeouts while
396*7c478bd9Sstevel@tonic-gate 	 * waiting for the T_CAPABILITY_ACK under high system load.
397*7c478bd9Sstevel@tonic-gate 	 */
398*7c478bd9Sstevel@tonic-gate 	if (tso == NULL) {
399*7c478bd9Sstevel@tonic-gate 		error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO);
400*7c478bd9Sstevel@tonic-gate 		if (error)
401*7c478bd9Sstevel@tonic-gate 			return (error);
402*7c478bd9Sstevel@tonic-gate 	} else {
403*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
404*7c478bd9Sstevel@tonic-gate 		so->so_tsdu_size = tso->so_tsdu_size;
405*7c478bd9Sstevel@tonic-gate 		so->so_etsdu_size = tso->so_etsdu_size;
406*7c478bd9Sstevel@tonic-gate 		so->so_addr_size = tso->so_addr_size;
407*7c478bd9Sstevel@tonic-gate 		so->so_opt_size = tso->so_opt_size;
408*7c478bd9Sstevel@tonic-gate 		so->so_tidu_size = tso->so_tidu_size;
409*7c478bd9Sstevel@tonic-gate 		so->so_serv_type = tso->so_serv_type;
410*7c478bd9Sstevel@tonic-gate 		so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID;
411*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 		/* the following do_tcapability may update so->so_mode */
414*7c478bd9Sstevel@tonic-gate 		if ((tso->so_serv_type != T_CLTS) &&
415*7c478bd9Sstevel@tonic-gate 		    ((so->so_state & SS_TCP_FAST_ACCEPT) == 0)) {
416*7c478bd9Sstevel@tonic-gate 			error = do_tcapability(so, TC1_ACCEPTOR_ID);
417*7c478bd9Sstevel@tonic-gate 			if (error)
418*7c478bd9Sstevel@tonic-gate 				return (error);
419*7c478bd9Sstevel@tonic-gate 		}
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 	/*
422*7c478bd9Sstevel@tonic-gate 	 * If the addr_size is 0 we treat it as already bound
423*7c478bd9Sstevel@tonic-gate 	 * and connected. This is used by the routing socket.
424*7c478bd9Sstevel@tonic-gate 	 * We set the addr_size to something to allocate a the address
425*7c478bd9Sstevel@tonic-gate 	 * structures.
426*7c478bd9Sstevel@tonic-gate 	 */
427*7c478bd9Sstevel@tonic-gate 	if (so->so_addr_size == 0) {
428*7c478bd9Sstevel@tonic-gate 		so->so_state |= SS_ISBOUND | SS_ISCONNECTED;
429*7c478bd9Sstevel@tonic-gate 		/* Address size can vary with address families. */
430*7c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_INET6)
431*7c478bd9Sstevel@tonic-gate 			so->so_addr_size =
432*7c478bd9Sstevel@tonic-gate 			    (t_scalar_t)sizeof (struct sockaddr_in6);
433*7c478bd9Sstevel@tonic-gate 		else
434*7c478bd9Sstevel@tonic-gate 			so->so_addr_size =
435*7c478bd9Sstevel@tonic-gate 			    (t_scalar_t)sizeof (struct sockaddr_in);
436*7c478bd9Sstevel@tonic-gate 		ASSERT(so->so_unbind_mp);
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 	/*
439*7c478bd9Sstevel@tonic-gate 	 * Allocate the addresses.
440*7c478bd9Sstevel@tonic-gate 	 */
441*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_laddr_sa == NULL && so->so_faddr_sa == NULL);
442*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_laddr_len == 0 && so->so_faddr_len == 0);
443*7c478bd9Sstevel@tonic-gate 	so->so_laddr_maxlen = so->so_faddr_maxlen =
444*7c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(so->so_addr_size, KMEM_ALIGN);
445*7c478bd9Sstevel@tonic-gate 	so->so_laddr_sa = kmem_alloc(so->so_laddr_maxlen * 2, KM_SLEEP);
446*7c478bd9Sstevel@tonic-gate 	so->so_faddr_sa = (struct sockaddr *)((caddr_t)so->so_laddr_sa
447*7c478bd9Sstevel@tonic-gate 		    + so->so_laddr_maxlen);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_UNIX) {
450*7c478bd9Sstevel@tonic-gate 		/*
451*7c478bd9Sstevel@tonic-gate 		 * Initialize AF_UNIX related fields.
452*7c478bd9Sstevel@tonic-gate 		 */
453*7c478bd9Sstevel@tonic-gate 		bzero(&so->so_ux_laddr, sizeof (so->so_ux_laddr));
454*7c478bd9Sstevel@tonic-gate 		bzero(&so->so_ux_faddr, sizeof (so->so_ux_faddr));
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
458*7c478bd9Sstevel@tonic-gate 	/*
459*7c478bd9Sstevel@tonic-gate 	 * Have to keep minpsz at zero in order to allow write/send of zero
460*7c478bd9Sstevel@tonic-gate 	 * bytes.
461*7c478bd9Sstevel@tonic-gate 	 */
462*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
463*7c478bd9Sstevel@tonic-gate 	if (stp->sd_qn_minpsz == 1)
464*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_minpsz = 0;
465*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	return (0);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate static void
471*7c478bd9Sstevel@tonic-gate copy_tinfo(struct sonode *so, struct T_info_ack *tia)
472*7c478bd9Sstevel@tonic-gate {
473*7c478bd9Sstevel@tonic-gate 	so->so_tsdu_size = tia->TSDU_size;
474*7c478bd9Sstevel@tonic-gate 	so->so_etsdu_size = tia->ETSDU_size;
475*7c478bd9Sstevel@tonic-gate 	so->so_addr_size = tia->ADDR_size;
476*7c478bd9Sstevel@tonic-gate 	so->so_opt_size = tia->OPT_size;
477*7c478bd9Sstevel@tonic-gate 	so->so_tidu_size = tia->TIDU_size;
478*7c478bd9Sstevel@tonic-gate 	so->so_serv_type = tia->SERV_type;
479*7c478bd9Sstevel@tonic-gate 	switch (tia->CURRENT_state) {
480*7c478bd9Sstevel@tonic-gate 	case TS_UNBND:
481*7c478bd9Sstevel@tonic-gate 		break;
482*7c478bd9Sstevel@tonic-gate 	case TS_IDLE:
483*7c478bd9Sstevel@tonic-gate 		so->so_state |= SS_ISBOUND;
484*7c478bd9Sstevel@tonic-gate 		so->so_laddr_len = 0;
485*7c478bd9Sstevel@tonic-gate 		so->so_state &= ~SS_LADDR_VALID;
486*7c478bd9Sstevel@tonic-gate 		break;
487*7c478bd9Sstevel@tonic-gate 	case TS_DATA_XFER:
488*7c478bd9Sstevel@tonic-gate 		so->so_state |= SS_ISBOUND|SS_ISCONNECTED;
489*7c478bd9Sstevel@tonic-gate 		so->so_laddr_len = 0;
490*7c478bd9Sstevel@tonic-gate 		so->so_faddr_len = 0;
491*7c478bd9Sstevel@tonic-gate 		so->so_state &= ~(SS_LADDR_VALID | SS_FADDR_VALID);
492*7c478bd9Sstevel@tonic-gate 		break;
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	/*
496*7c478bd9Sstevel@tonic-gate 	 * Heuristics for determining the socket mode flags
497*7c478bd9Sstevel@tonic-gate 	 * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING,
498*7c478bd9Sstevel@tonic-gate 	 * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM)
499*7c478bd9Sstevel@tonic-gate 	 * from the info ack.
500*7c478bd9Sstevel@tonic-gate 	 */
501*7c478bd9Sstevel@tonic-gate 	if (so->so_serv_type == T_CLTS) {
502*7c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_ATOMIC | SM_ADDR;
503*7c478bd9Sstevel@tonic-gate 	} else {
504*7c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_CONNREQUIRED;
505*7c478bd9Sstevel@tonic-gate 		if (so->so_etsdu_size != 0 && so->so_etsdu_size != -2)
506*7c478bd9Sstevel@tonic-gate 			so->so_mode |= SM_EXDATA;
507*7c478bd9Sstevel@tonic-gate 	}
508*7c478bd9Sstevel@tonic-gate 	if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) {
509*7c478bd9Sstevel@tonic-gate 		/* Semantics are to discard tail end of messages */
510*7c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_ATOMIC;
511*7c478bd9Sstevel@tonic-gate 	}
512*7c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_UNIX) {
513*7c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_FDPASSING | SM_OPTDATA;
514*7c478bd9Sstevel@tonic-gate 		if (so->so_addr_size == -1) {
515*7c478bd9Sstevel@tonic-gate 			/* MAXPATHLEN + soun_family + nul termination */
516*7c478bd9Sstevel@tonic-gate 			so->so_addr_size = (t_scalar_t)(MAXPATHLEN +
517*7c478bd9Sstevel@tonic-gate 				sizeof (short) + 1);
518*7c478bd9Sstevel@tonic-gate 		}
519*7c478bd9Sstevel@tonic-gate 		if (so->so_type == SOCK_STREAM) {
520*7c478bd9Sstevel@tonic-gate 			/*
521*7c478bd9Sstevel@tonic-gate 			 * Make it into a byte-stream transport.
522*7c478bd9Sstevel@tonic-gate 			 * SOCK_SEQPACKET sockets are unchanged.
523*7c478bd9Sstevel@tonic-gate 			 */
524*7c478bd9Sstevel@tonic-gate 			so->so_tsdu_size = 0;
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 	} else if (so->so_addr_size == -1) {
527*7c478bd9Sstevel@tonic-gate 		/*
528*7c478bd9Sstevel@tonic-gate 		 * Logic extracted from sockmod - have to pick some max address
529*7c478bd9Sstevel@tonic-gate 		 * length in order to preallocate the addresses.
530*7c478bd9Sstevel@tonic-gate 		 */
531*7c478bd9Sstevel@tonic-gate 		so->so_addr_size = SOA_DEFSIZE;
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 	if (so->so_tsdu_size == 0)
534*7c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_BYTESTREAM;
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate static int
538*7c478bd9Sstevel@tonic-gate check_tinfo(struct sonode *so)
539*7c478bd9Sstevel@tonic-gate {
540*7c478bd9Sstevel@tonic-gate 	/* Consistency checks */
541*7c478bd9Sstevel@tonic-gate 	if (so->so_type == SOCK_DGRAM && so->so_serv_type != T_CLTS) {
542*7c478bd9Sstevel@tonic-gate 		eprintso(so, ("service type and socket type mismatch\n"));
543*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
544*7c478bd9Sstevel@tonic-gate 		return (EPROTO);
545*7c478bd9Sstevel@tonic-gate 	}
546*7c478bd9Sstevel@tonic-gate 	if (so->so_type == SOCK_STREAM && so->so_serv_type == T_CLTS) {
547*7c478bd9Sstevel@tonic-gate 		eprintso(so, ("service type and socket type mismatch\n"));
548*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
549*7c478bd9Sstevel@tonic-gate 		return (EPROTO);
550*7c478bd9Sstevel@tonic-gate 	}
551*7c478bd9Sstevel@tonic-gate 	if (so->so_type == SOCK_SEQPACKET && so->so_serv_type == T_CLTS) {
552*7c478bd9Sstevel@tonic-gate 		eprintso(so, ("service type and socket type mismatch\n"));
553*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
554*7c478bd9Sstevel@tonic-gate 		return (EPROTO);
555*7c478bd9Sstevel@tonic-gate 	}
556*7c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_INET &&
557*7c478bd9Sstevel@tonic-gate 	    so->so_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) {
558*7c478bd9Sstevel@tonic-gate 		eprintso(so,
559*7c478bd9Sstevel@tonic-gate 		    ("AF_INET must have sockaddr_in address length. Got %d\n",
560*7c478bd9Sstevel@tonic-gate 		    so->so_addr_size));
561*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EMSGSIZE);
562*7c478bd9Sstevel@tonic-gate 		return (EMSGSIZE);
563*7c478bd9Sstevel@tonic-gate 	}
564*7c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_INET6 &&
565*7c478bd9Sstevel@tonic-gate 	    so->so_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) {
566*7c478bd9Sstevel@tonic-gate 		eprintso(so,
567*7c478bd9Sstevel@tonic-gate 		    ("AF_INET6 must have sockaddr_in6 address length. Got %d\n",
568*7c478bd9Sstevel@tonic-gate 		    so->so_addr_size));
569*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EMSGSIZE);
570*7c478bd9Sstevel@tonic-gate 		return (EMSGSIZE);
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, (
574*7c478bd9Sstevel@tonic-gate 	    "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n",
575*7c478bd9Sstevel@tonic-gate 	    so->so_serv_type, so->so_tsdu_size, so->so_etsdu_size,
576*7c478bd9Sstevel@tonic-gate 	    so->so_addr_size, so->so_opt_size,
577*7c478bd9Sstevel@tonic-gate 	    so->so_tidu_size));
578*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("tinfo: so_state %s\n",
579*7c478bd9Sstevel@tonic-gate 			pr_state(so->so_state, so->so_mode)));
580*7c478bd9Sstevel@tonic-gate 	return (0);
581*7c478bd9Sstevel@tonic-gate }
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate /*
584*7c478bd9Sstevel@tonic-gate  * Send down T_info_req and wait for the ack.
585*7c478bd9Sstevel@tonic-gate  * Record interesting T_info_ack values in the sonode.
586*7c478bd9Sstevel@tonic-gate  */
587*7c478bd9Sstevel@tonic-gate static int
588*7c478bd9Sstevel@tonic-gate do_tinfo(struct sonode *so)
589*7c478bd9Sstevel@tonic-gate {
590*7c478bd9Sstevel@tonic-gate 	struct T_info_req tir;
591*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
592*7c478bd9Sstevel@tonic-gate 	int error;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	if (so_no_tinfo) {
597*7c478bd9Sstevel@tonic-gate 		so->so_addr_size = 0;
598*7c478bd9Sstevel@tonic-gate 		return (0);
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("do_tinfo(%p)\n", so));
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	/* Send T_INFO_REQ */
604*7c478bd9Sstevel@tonic-gate 	tir.PRIM_type = T_INFO_REQ;
605*7c478bd9Sstevel@tonic-gate 	mp = soallocproto1(&tir, sizeof (tir),
606*7c478bd9Sstevel@tonic-gate 	    sizeof (struct T_info_req) + sizeof (struct T_info_ack),
607*7c478bd9Sstevel@tonic-gate 	    _ALLOC_INTR);
608*7c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
609*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, ENOBUFS);
610*7c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 	/* T_INFO_REQ has to be M_PCPROTO */
613*7c478bd9Sstevel@tonic-gate 	DB_TYPE(mp) = M_PCPROTO;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
616*7c478bd9Sstevel@tonic-gate 			MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
617*7c478bd9Sstevel@tonic-gate 	if (error) {
618*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
619*7c478bd9Sstevel@tonic-gate 		return (error);
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
622*7c478bd9Sstevel@tonic-gate 	/* Wait for T_INFO_ACK */
623*7c478bd9Sstevel@tonic-gate 	if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK,
624*7c478bd9Sstevel@tonic-gate 	    (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) {
625*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
626*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
627*7c478bd9Sstevel@tonic-gate 		return (error);
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	ASSERT(mp);
631*7c478bd9Sstevel@tonic-gate 	copy_tinfo(so, (struct T_info_ack *)mp->b_rptr);
632*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
633*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
634*7c478bd9Sstevel@tonic-gate 	return (check_tinfo(so));
635*7c478bd9Sstevel@tonic-gate }
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate /*
638*7c478bd9Sstevel@tonic-gate  * Send down T_capability_req and wait for the ack.
639*7c478bd9Sstevel@tonic-gate  * Record interesting T_capability_ack values in the sonode.
640*7c478bd9Sstevel@tonic-gate  */
641*7c478bd9Sstevel@tonic-gate static int
642*7c478bd9Sstevel@tonic-gate do_tcapability(struct sonode *so, t_uscalar_t cap_bits1)
643*7c478bd9Sstevel@tonic-gate {
644*7c478bd9Sstevel@tonic-gate 	struct T_capability_req tcr;
645*7c478bd9Sstevel@tonic-gate 	struct T_capability_ack *tca;
646*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
647*7c478bd9Sstevel@tonic-gate 	int error;
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	ASSERT(cap_bits1 != 0);
650*7c478bd9Sstevel@tonic-gate 	ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0);
651*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	if (so->so_provinfo->tpi_capability == PI_NO)
654*7c478bd9Sstevel@tonic-gate 		return (do_tinfo(so));
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	if (so_no_tinfo) {
657*7c478bd9Sstevel@tonic-gate 		so->so_addr_size = 0;
658*7c478bd9Sstevel@tonic-gate 		if ((cap_bits1 &= ~TC1_INFO) == 0)
659*7c478bd9Sstevel@tonic-gate 			return (0);
660*7c478bd9Sstevel@tonic-gate 	}
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("do_tcapability(%p)\n", so));
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	/* Send T_CAPABILITY_REQ */
665*7c478bd9Sstevel@tonic-gate 	tcr.PRIM_type = T_CAPABILITY_REQ;
666*7c478bd9Sstevel@tonic-gate 	tcr.CAP_bits1 = cap_bits1;
667*7c478bd9Sstevel@tonic-gate 	mp = soallocproto1(&tcr, sizeof (tcr),
668*7c478bd9Sstevel@tonic-gate 	    sizeof (struct T_capability_req) + sizeof (struct T_capability_ack),
669*7c478bd9Sstevel@tonic-gate 	    _ALLOC_INTR);
670*7c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
671*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, ENOBUFS);
672*7c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
673*7c478bd9Sstevel@tonic-gate 	}
674*7c478bd9Sstevel@tonic-gate 	/* T_CAPABILITY_REQ should be M_PCPROTO here */
675*7c478bd9Sstevel@tonic-gate 	DB_TYPE(mp) = M_PCPROTO;
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
678*7c478bd9Sstevel@tonic-gate 	    MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0);
679*7c478bd9Sstevel@tonic-gate 	if (error) {
680*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
681*7c478bd9Sstevel@tonic-gate 		return (error);
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
684*7c478bd9Sstevel@tonic-gate 	/* Wait for T_CAPABILITY_ACK */
685*7c478bd9Sstevel@tonic-gate 	if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK,
686*7c478bd9Sstevel@tonic-gate 	    (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) {
687*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
688*7c478bd9Sstevel@tonic-gate 		PI_PROVLOCK(so->so_provinfo);
689*7c478bd9Sstevel@tonic-gate 		if (so->so_provinfo->tpi_capability == PI_DONTKNOW)
690*7c478bd9Sstevel@tonic-gate 			so->so_provinfo->tpi_capability = PI_NO;
691*7c478bd9Sstevel@tonic-gate 		PI_PROVUNLOCK(so->so_provinfo);
692*7c478bd9Sstevel@tonic-gate 		ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0);
693*7c478bd9Sstevel@tonic-gate 		if (cap_bits1 & TC1_INFO) {
694*7c478bd9Sstevel@tonic-gate 			/*
695*7c478bd9Sstevel@tonic-gate 			 * If the T_CAPABILITY_REQ timed out and then a
696*7c478bd9Sstevel@tonic-gate 			 * T_INFO_REQ gets a protocol error, most likely
697*7c478bd9Sstevel@tonic-gate 			 * the capability was slow (vs. unsupported). Return
698*7c478bd9Sstevel@tonic-gate 			 * ENOSR for this case as a best guess.
699*7c478bd9Sstevel@tonic-gate 			 */
700*7c478bd9Sstevel@tonic-gate 			if (error == ETIME) {
701*7c478bd9Sstevel@tonic-gate 				return ((error = do_tinfo(so)) == EPROTO ?
702*7c478bd9Sstevel@tonic-gate 				    ENOSR : error);
703*7c478bd9Sstevel@tonic-gate 			}
704*7c478bd9Sstevel@tonic-gate 			return (do_tinfo(so));
705*7c478bd9Sstevel@tonic-gate 		}
706*7c478bd9Sstevel@tonic-gate 		return (0);
707*7c478bd9Sstevel@tonic-gate 	}
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	if (so->so_provinfo->tpi_capability == PI_DONTKNOW) {
710*7c478bd9Sstevel@tonic-gate 		PI_PROVLOCK(so->so_provinfo);
711*7c478bd9Sstevel@tonic-gate 		so->so_provinfo->tpi_capability = PI_YES;
712*7c478bd9Sstevel@tonic-gate 		PI_PROVUNLOCK(so->so_provinfo);
713*7c478bd9Sstevel@tonic-gate 	}
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	ASSERT(mp);
716*7c478bd9Sstevel@tonic-gate 	tca = (struct T_capability_ack *)mp->b_rptr;
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO));
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	cap_bits1 = tca->CAP_bits1;
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	if (cap_bits1 & TC1_ACCEPTOR_ID) {
723*7c478bd9Sstevel@tonic-gate 		so->so_acceptor_id = tca->ACCEPTOR_id;
724*7c478bd9Sstevel@tonic-gate 		so->so_mode |= SM_ACCEPTOR_ID;
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	if (cap_bits1 & TC1_INFO)
728*7c478bd9Sstevel@tonic-gate 		copy_tinfo(so, &tca->INFO_ack);
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
731*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if (cap_bits1 & TC1_INFO)
734*7c478bd9Sstevel@tonic-gate 		return (check_tinfo(so));
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	return (0);
737*7c478bd9Sstevel@tonic-gate }
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate /*
740*7c478bd9Sstevel@tonic-gate  * Retrieve and clear the socket error.
741*7c478bd9Sstevel@tonic-gate  */
742*7c478bd9Sstevel@tonic-gate int
743*7c478bd9Sstevel@tonic-gate sogeterr(struct sonode *so)
744*7c478bd9Sstevel@tonic-gate {
745*7c478bd9Sstevel@tonic-gate 	int error;
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	error = so->so_error;
750*7c478bd9Sstevel@tonic-gate 	so->so_error = 0;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	return (error);
753*7c478bd9Sstevel@tonic-gate }
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate /*
756*7c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to retrieve read
757*7c478bd9Sstevel@tonic-gate  * side errors.
758*7c478bd9Sstevel@tonic-gate  * It does not clear the socket error for a peeking read side operation.
759*7c478bd9Sstevel@tonic-gate  * It the error is to be cleared it sets *clearerr.
760*7c478bd9Sstevel@tonic-gate  */
761*7c478bd9Sstevel@tonic-gate int
762*7c478bd9Sstevel@tonic-gate sogetrderr(vnode_t *vp, int ispeek, int *clearerr)
763*7c478bd9Sstevel@tonic-gate {
764*7c478bd9Sstevel@tonic-gate 	struct sonode *so = VTOSO(vp);
765*7c478bd9Sstevel@tonic-gate 	int error;
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
768*7c478bd9Sstevel@tonic-gate 	if (ispeek) {
769*7c478bd9Sstevel@tonic-gate 		error = so->so_error;
770*7c478bd9Sstevel@tonic-gate 		*clearerr = 0;
771*7c478bd9Sstevel@tonic-gate 	} else {
772*7c478bd9Sstevel@tonic-gate 		error = so->so_error;
773*7c478bd9Sstevel@tonic-gate 		so->so_error = 0;
774*7c478bd9Sstevel@tonic-gate 		*clearerr = 1;
775*7c478bd9Sstevel@tonic-gate 	}
776*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
777*7c478bd9Sstevel@tonic-gate 	return (error);
778*7c478bd9Sstevel@tonic-gate }
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate /*
781*7c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to retrieve write
782*7c478bd9Sstevel@tonic-gate  * side errors.
783*7c478bd9Sstevel@tonic-gate  * It does not clear the socket error for a peeking read side operation.
784*7c478bd9Sstevel@tonic-gate  * It the error is to be cleared it sets *clearerr.
785*7c478bd9Sstevel@tonic-gate  */
786*7c478bd9Sstevel@tonic-gate int
787*7c478bd9Sstevel@tonic-gate sogetwrerr(vnode_t *vp, int ispeek, int *clearerr)
788*7c478bd9Sstevel@tonic-gate {
789*7c478bd9Sstevel@tonic-gate 	struct sonode *so = VTOSO(vp);
790*7c478bd9Sstevel@tonic-gate 	int error;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
793*7c478bd9Sstevel@tonic-gate 	if (so->so_state & SS_CANTSENDMORE) {
794*7c478bd9Sstevel@tonic-gate 		error = EPIPE;
795*7c478bd9Sstevel@tonic-gate 		*clearerr = 0;
796*7c478bd9Sstevel@tonic-gate 	} else {
797*7c478bd9Sstevel@tonic-gate 		error = so->so_error;
798*7c478bd9Sstevel@tonic-gate 		if (ispeek) {
799*7c478bd9Sstevel@tonic-gate 			*clearerr = 0;
800*7c478bd9Sstevel@tonic-gate 		} else {
801*7c478bd9Sstevel@tonic-gate 			so->so_error = 0;
802*7c478bd9Sstevel@tonic-gate 			*clearerr = 1;
803*7c478bd9Sstevel@tonic-gate 		}
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
806*7c478bd9Sstevel@tonic-gate 	return (error);
807*7c478bd9Sstevel@tonic-gate }
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate /*
810*7c478bd9Sstevel@tonic-gate  * Set a nonpersistent read and write error on the socket.
811*7c478bd9Sstevel@tonic-gate  * Used when there is a T_uderror_ind for a connected socket.
812*7c478bd9Sstevel@tonic-gate  * The caller also needs to call strsetrerror and strsetwerror
813*7c478bd9Sstevel@tonic-gate  * after dropping the lock.
814*7c478bd9Sstevel@tonic-gate  */
815*7c478bd9Sstevel@tonic-gate void
816*7c478bd9Sstevel@tonic-gate soseterror(struct sonode *so, int error)
817*7c478bd9Sstevel@tonic-gate {
818*7c478bd9Sstevel@tonic-gate 	ASSERT(error != 0);
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
821*7c478bd9Sstevel@tonic-gate 	so->so_error = (ushort_t)error;
822*7c478bd9Sstevel@tonic-gate }
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate void
825*7c478bd9Sstevel@tonic-gate soisconnecting(struct sonode *so)
826*7c478bd9Sstevel@tonic-gate {
827*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
828*7c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
829*7c478bd9Sstevel@tonic-gate 	so->so_state |= SS_ISCONNECTING;
830*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
831*7c478bd9Sstevel@tonic-gate }
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate void
834*7c478bd9Sstevel@tonic-gate soisconnected(struct sonode *so)
835*7c478bd9Sstevel@tonic-gate {
836*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
837*7c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
838*7c478bd9Sstevel@tonic-gate 	so->so_state |= SS_ISCONNECTED;
839*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
840*7c478bd9Sstevel@tonic-gate }
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate /*
843*7c478bd9Sstevel@tonic-gate  * The caller also needs to call strsetrerror, strsetwerror and strseteof.
844*7c478bd9Sstevel@tonic-gate  */
845*7c478bd9Sstevel@tonic-gate void
846*7c478bd9Sstevel@tonic-gate soisdisconnected(struct sonode *so, int error)
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
849*7c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING|
850*7c478bd9Sstevel@tonic-gate 	    SS_LADDR_VALID|SS_FADDR_VALID);
851*7c478bd9Sstevel@tonic-gate 	so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
852*7c478bd9Sstevel@tonic-gate 	so->so_error = (ushort_t)error;
853*7c478bd9Sstevel@tonic-gate 	if (so->so_peercred != NULL) {
854*7c478bd9Sstevel@tonic-gate 		crfree(so->so_peercred);
855*7c478bd9Sstevel@tonic-gate 		so->so_peercred = NULL;
856*7c478bd9Sstevel@tonic-gate 	}
857*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
858*7c478bd9Sstevel@tonic-gate }
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate /*
861*7c478bd9Sstevel@tonic-gate  * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes.
862*7c478bd9Sstevel@tonic-gate  * Does not affect write side.
863*7c478bd9Sstevel@tonic-gate  * The caller also has to call strsetrerror.
864*7c478bd9Sstevel@tonic-gate  */
865*7c478bd9Sstevel@tonic-gate static void
866*7c478bd9Sstevel@tonic-gate sobreakconn(struct sonode *so, int error)
867*7c478bd9Sstevel@tonic-gate {
868*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
869*7c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
870*7c478bd9Sstevel@tonic-gate 	so->so_error = (ushort_t)error;
871*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate /*
875*7c478bd9Sstevel@tonic-gate  * Can no longer send.
876*7c478bd9Sstevel@tonic-gate  * Caller must also call strsetwerror.
877*7c478bd9Sstevel@tonic-gate  *
878*7c478bd9Sstevel@tonic-gate  * We mark the peer address as no longer valid for getpeername, but
879*7c478bd9Sstevel@tonic-gate  * leave it around for so_unix_close to notify the peer (that
880*7c478bd9Sstevel@tonic-gate  * transport has no addressing held at that layer).
881*7c478bd9Sstevel@tonic-gate  */
882*7c478bd9Sstevel@tonic-gate void
883*7c478bd9Sstevel@tonic-gate socantsendmore(struct sonode *so)
884*7c478bd9Sstevel@tonic-gate {
885*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
886*7c478bd9Sstevel@tonic-gate 	so->so_state = so->so_state & ~SS_FADDR_VALID | SS_CANTSENDMORE;
887*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
888*7c478bd9Sstevel@tonic-gate }
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate /*
891*7c478bd9Sstevel@tonic-gate  * The caller must call strseteof(,1) as well as this routine
892*7c478bd9Sstevel@tonic-gate  * to change the socket state.
893*7c478bd9Sstevel@tonic-gate  */
894*7c478bd9Sstevel@tonic-gate void
895*7c478bd9Sstevel@tonic-gate socantrcvmore(struct sonode *so)
896*7c478bd9Sstevel@tonic-gate {
897*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
898*7c478bd9Sstevel@tonic-gate 	so->so_state |= SS_CANTRCVMORE;
899*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_state_cv);
900*7c478bd9Sstevel@tonic-gate }
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate /*
903*7c478bd9Sstevel@tonic-gate  * The caller has sent down a "request_prim" primitive and wants to wait for
904*7c478bd9Sstevel@tonic-gate  * an ack ("ack_prim") or an T_ERROR_ACK for it.
905*7c478bd9Sstevel@tonic-gate  * The specified "ack_prim" can be a T_OK_ACK.
906*7c478bd9Sstevel@tonic-gate  *
907*7c478bd9Sstevel@tonic-gate  * Assumes that all the TPI acks are M_PCPROTO messages.
908*7c478bd9Sstevel@tonic-gate  *
909*7c478bd9Sstevel@tonic-gate  * Note that the socket is single-threaded (using so_lock_single)
910*7c478bd9Sstevel@tonic-gate  * for all operations that generate TPI ack messages. Since
911*7c478bd9Sstevel@tonic-gate  * only TPI ack messages are M_PCPROTO we should never receive
912*7c478bd9Sstevel@tonic-gate  * anything except either the ack we are expecting or a T_ERROR_ACK
913*7c478bd9Sstevel@tonic-gate  * for the same primitive.
914*7c478bd9Sstevel@tonic-gate  */
915*7c478bd9Sstevel@tonic-gate int
916*7c478bd9Sstevel@tonic-gate sowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim,
917*7c478bd9Sstevel@tonic-gate 	    t_uscalar_t min_size, mblk_t **mpp, clock_t wait)
918*7c478bd9Sstevel@tonic-gate {
919*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
920*7c478bd9Sstevel@tonic-gate 	union T_primitives *tpr;
921*7c478bd9Sstevel@tonic-gate 	int error;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n",
924*7c478bd9Sstevel@tonic-gate 		so, request_prim, ack_prim, min_size, mpp, wait));
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	error = sowaitack(so, &mp, wait);
929*7c478bd9Sstevel@tonic-gate 	if (error)
930*7c478bd9Sstevel@tonic-gate 		return (error);
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("got msg %p\n", mp));
933*7c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_PCPROTO ||
934*7c478bd9Sstevel@tonic-gate 	    MBLKL(mp) < sizeof (tpr->type)) {
935*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
936*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
937*7c478bd9Sstevel@tonic-gate 		return (EPROTO);
938*7c478bd9Sstevel@tonic-gate 	}
939*7c478bd9Sstevel@tonic-gate 	tpr = (union T_primitives *)mp->b_rptr;
940*7c478bd9Sstevel@tonic-gate 	/*
941*7c478bd9Sstevel@tonic-gate 	 * Did we get the primitive that we were asking for?
942*7c478bd9Sstevel@tonic-gate 	 * For T_OK_ACK we also check that it matches the request primitive.
943*7c478bd9Sstevel@tonic-gate 	 */
944*7c478bd9Sstevel@tonic-gate 	if (tpr->type == ack_prim &&
945*7c478bd9Sstevel@tonic-gate 	    (ack_prim != T_OK_ACK ||
946*7c478bd9Sstevel@tonic-gate 	    tpr->ok_ack.CORRECT_prim == request_prim)) {
947*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) >= (ssize_t)min_size) {
948*7c478bd9Sstevel@tonic-gate 			/* Found what we are looking for */
949*7c478bd9Sstevel@tonic-gate 			*mpp = mp;
950*7c478bd9Sstevel@tonic-gate 			return (0);
951*7c478bd9Sstevel@tonic-gate 		}
952*7c478bd9Sstevel@tonic-gate 		/* Too short */
953*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
954*7c478bd9Sstevel@tonic-gate 		eprintsoline(so, EPROTO);
955*7c478bd9Sstevel@tonic-gate 		return (EPROTO);
956*7c478bd9Sstevel@tonic-gate 	}
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if (tpr->type == T_ERROR_ACK &&
959*7c478bd9Sstevel@tonic-gate 	    tpr->error_ack.ERROR_prim == request_prim) {
960*7c478bd9Sstevel@tonic-gate 		/* Error to the primitive we were looking for */
961*7c478bd9Sstevel@tonic-gate 		if (tpr->error_ack.TLI_error == TSYSERR) {
962*7c478bd9Sstevel@tonic-gate 			error = tpr->error_ack.UNIX_error;
963*7c478bd9Sstevel@tonic-gate 		} else {
964*7c478bd9Sstevel@tonic-gate 			error = tlitosyserr(tpr->error_ack.TLI_error);
965*7c478bd9Sstevel@tonic-gate 		}
966*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n",
967*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.ERROR_prim,
968*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.TLI_error,
969*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.UNIX_error,
970*7c478bd9Sstevel@tonic-gate 			error));
971*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
972*7c478bd9Sstevel@tonic-gate 		return (error);
973*7c478bd9Sstevel@tonic-gate 	}
974*7c478bd9Sstevel@tonic-gate 	/*
975*7c478bd9Sstevel@tonic-gate 	 * Wrong primitive or T_ERROR_ACK for the wrong primitive
976*7c478bd9Sstevel@tonic-gate 	 */
977*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
978*7c478bd9Sstevel@tonic-gate 	if (tpr->type == T_ERROR_ACK) {
979*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0, ("error_ack for %d: %d/%d\n",
980*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.ERROR_prim,
981*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.TLI_error,
982*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.UNIX_error));
983*7c478bd9Sstevel@tonic-gate 	} else if (tpr->type == T_OK_ACK) {
984*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n",
985*7c478bd9Sstevel@tonic-gate 			tpr->ok_ack.CORRECT_prim,
986*7c478bd9Sstevel@tonic-gate 			ack_prim, request_prim));
987*7c478bd9Sstevel@tonic-gate 	} else {
988*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
989*7c478bd9Sstevel@tonic-gate 			("unexpected primitive %d, expected %d for %d\n",
990*7c478bd9Sstevel@tonic-gate 			tpr->type, ack_prim, request_prim));
991*7c478bd9Sstevel@tonic-gate 	}
992*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
995*7c478bd9Sstevel@tonic-gate 	eprintsoline(so, EPROTO);
996*7c478bd9Sstevel@tonic-gate 	return (EPROTO);
997*7c478bd9Sstevel@tonic-gate }
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate /*
1000*7c478bd9Sstevel@tonic-gate  * Wait for a T_OK_ACK for the specified primitive.
1001*7c478bd9Sstevel@tonic-gate  */
1002*7c478bd9Sstevel@tonic-gate int
1003*7c478bd9Sstevel@tonic-gate sowaitokack(struct sonode *so, t_scalar_t request_prim)
1004*7c478bd9Sstevel@tonic-gate {
1005*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1006*7c478bd9Sstevel@tonic-gate 	int error;
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	error = sowaitprim(so, request_prim, T_OK_ACK,
1009*7c478bd9Sstevel@tonic-gate 	    (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0);
1010*7c478bd9Sstevel@tonic-gate 	if (error)
1011*7c478bd9Sstevel@tonic-gate 		return (error);
1012*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
1013*7c478bd9Sstevel@tonic-gate 	return (0);
1014*7c478bd9Sstevel@tonic-gate }
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate /*
1017*7c478bd9Sstevel@tonic-gate  * Queue a received TPI ack message on so_ack_mp.
1018*7c478bd9Sstevel@tonic-gate  */
1019*7c478bd9Sstevel@tonic-gate void
1020*7c478bd9Sstevel@tonic-gate soqueueack(struct sonode *so, mblk_t *mp)
1021*7c478bd9Sstevel@tonic-gate {
1022*7c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_PCPROTO) {
1023*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1024*7c478bd9Sstevel@tonic-gate 		    "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n",
1025*7c478bd9Sstevel@tonic-gate 		    *(t_scalar_t *)mp->b_rptr);
1026*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1027*7c478bd9Sstevel@tonic-gate 		return;
1028*7c478bd9Sstevel@tonic-gate 	}
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1031*7c478bd9Sstevel@tonic-gate 	if (so->so_ack_mp != NULL) {
1032*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("so_ack_mp already set\n"));
1033*7c478bd9Sstevel@tonic-gate 		freemsg(so->so_ack_mp);
1034*7c478bd9Sstevel@tonic-gate 		so->so_ack_mp = NULL;
1035*7c478bd9Sstevel@tonic-gate 	}
1036*7c478bd9Sstevel@tonic-gate 	so->so_ack_mp = mp;
1037*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&so->so_ack_cv);
1038*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
1039*7c478bd9Sstevel@tonic-gate }
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate /*
1042*7c478bd9Sstevel@tonic-gate  * Wait for a TPI ack ignoring signals and errors.
1043*7c478bd9Sstevel@tonic-gate  */
1044*7c478bd9Sstevel@tonic-gate int
1045*7c478bd9Sstevel@tonic-gate sowaitack(struct sonode *so, mblk_t **mpp, clock_t wait)
1046*7c478bd9Sstevel@tonic-gate {
1047*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	while (so->so_ack_mp == NULL) {
1050*7c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST
1051*7c478bd9Sstevel@tonic-gate 		if (wait == 0 && sock_test_timelimit != 0)
1052*7c478bd9Sstevel@tonic-gate 			wait = sock_test_timelimit;
1053*7c478bd9Sstevel@tonic-gate #endif
1054*7c478bd9Sstevel@tonic-gate 		if (wait != 0) {
1055*7c478bd9Sstevel@tonic-gate 			/*
1056*7c478bd9Sstevel@tonic-gate 			 * Only wait for the time limit.
1057*7c478bd9Sstevel@tonic-gate 			 */
1058*7c478bd9Sstevel@tonic-gate 			clock_t now;
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 			time_to_wait(&now, wait);
1061*7c478bd9Sstevel@tonic-gate 			if (cv_timedwait(&so->so_ack_cv, &so->so_lock,
1062*7c478bd9Sstevel@tonic-gate 			    now) == -1) {
1063*7c478bd9Sstevel@tonic-gate 				eprintsoline(so, ETIME);
1064*7c478bd9Sstevel@tonic-gate 				return (ETIME);
1065*7c478bd9Sstevel@tonic-gate 			}
1066*7c478bd9Sstevel@tonic-gate 		}
1067*7c478bd9Sstevel@tonic-gate 		else
1068*7c478bd9Sstevel@tonic-gate 			cv_wait(&so->so_ack_cv, &so->so_lock);
1069*7c478bd9Sstevel@tonic-gate 	}
1070*7c478bd9Sstevel@tonic-gate 	*mpp = so->so_ack_mp;
1071*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1072*7c478bd9Sstevel@tonic-gate 	{
1073*7c478bd9Sstevel@tonic-gate 		union T_primitives *tpr;
1074*7c478bd9Sstevel@tonic-gate 		mblk_t *mp = *mpp;
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 		tpr = (union T_primitives *)mp->b_rptr;
1077*7c478bd9Sstevel@tonic-gate 		ASSERT(DB_TYPE(mp) == M_PCPROTO);
1078*7c478bd9Sstevel@tonic-gate 		ASSERT(tpr->type == T_OK_ACK ||
1079*7c478bd9Sstevel@tonic-gate 			tpr->type == T_ERROR_ACK ||
1080*7c478bd9Sstevel@tonic-gate 			tpr->type == T_BIND_ACK ||
1081*7c478bd9Sstevel@tonic-gate 			tpr->type == T_CAPABILITY_ACK ||
1082*7c478bd9Sstevel@tonic-gate 			tpr->type == T_INFO_ACK ||
1083*7c478bd9Sstevel@tonic-gate 			tpr->type == T_OPTMGMT_ACK);
1084*7c478bd9Sstevel@tonic-gate 	}
1085*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1086*7c478bd9Sstevel@tonic-gate 	so->so_ack_mp = NULL;
1087*7c478bd9Sstevel@tonic-gate 	return (0);
1088*7c478bd9Sstevel@tonic-gate }
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate /*
1091*7c478bd9Sstevel@tonic-gate  * Queue a received T_CONN_IND message on so_conn_ind_head/tail.
1092*7c478bd9Sstevel@tonic-gate  */
1093*7c478bd9Sstevel@tonic-gate void
1094*7c478bd9Sstevel@tonic-gate soqueueconnind(struct sonode *so, mblk_t *mp)
1095*7c478bd9Sstevel@tonic-gate {
1096*7c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_PROTO) {
1097*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1098*7c478bd9Sstevel@tonic-gate 		    "sockfs: received unexpected M_PCPROTO T_CONN_IND\n");
1099*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1100*7c478bd9Sstevel@tonic-gate 		return;
1101*7c478bd9Sstevel@tonic-gate 	}
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1104*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_next == NULL);
1105*7c478bd9Sstevel@tonic-gate 	if (so->so_conn_ind_head == NULL) {
1106*7c478bd9Sstevel@tonic-gate 		so->so_conn_ind_head = mp;
1107*7c478bd9Sstevel@tonic-gate 		so->so_state |= SS_HASCONNIND;
1108*7c478bd9Sstevel@tonic-gate 	} else {
1109*7c478bd9Sstevel@tonic-gate 		ASSERT(so->so_state & SS_HASCONNIND);
1110*7c478bd9Sstevel@tonic-gate 		ASSERT(so->so_conn_ind_tail->b_next == NULL);
1111*7c478bd9Sstevel@tonic-gate 		so->so_conn_ind_tail->b_next = mp;
1112*7c478bd9Sstevel@tonic-gate 	}
1113*7c478bd9Sstevel@tonic-gate 	so->so_conn_ind_tail = mp;
1114*7c478bd9Sstevel@tonic-gate 	/* Wakeup a single consumer of the T_CONN_IND */
1115*7c478bd9Sstevel@tonic-gate 	cv_signal(&so->so_connind_cv);
1116*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
1117*7c478bd9Sstevel@tonic-gate }
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate /*
1120*7c478bd9Sstevel@tonic-gate  * Wait for a T_CONN_IND.
1121*7c478bd9Sstevel@tonic-gate  * Don't wait if nonblocking.
1122*7c478bd9Sstevel@tonic-gate  * Accept signals and socket errors.
1123*7c478bd9Sstevel@tonic-gate  */
1124*7c478bd9Sstevel@tonic-gate int
1125*7c478bd9Sstevel@tonic-gate sowaitconnind(struct sonode *so, int fmode, mblk_t **mpp)
1126*7c478bd9Sstevel@tonic-gate {
1127*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1128*7c478bd9Sstevel@tonic-gate 	int error = 0;
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
1131*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1132*7c478bd9Sstevel@tonic-gate check_error:
1133*7c478bd9Sstevel@tonic-gate 	if (so->so_error) {
1134*7c478bd9Sstevel@tonic-gate 		error = sogeterr(so);
1135*7c478bd9Sstevel@tonic-gate 		if (error) {
1136*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
1137*7c478bd9Sstevel@tonic-gate 			return (error);
1138*7c478bd9Sstevel@tonic-gate 		}
1139*7c478bd9Sstevel@tonic-gate 	}
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 	if (so->so_conn_ind_head == NULL) {
1142*7c478bd9Sstevel@tonic-gate 		if (fmode & (FNDELAY|FNONBLOCK)) {
1143*7c478bd9Sstevel@tonic-gate 			error = EWOULDBLOCK;
1144*7c478bd9Sstevel@tonic-gate 			goto done;
1145*7c478bd9Sstevel@tonic-gate 		}
1146*7c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig_swap(&so->so_connind_cv, &so->so_lock)) {
1147*7c478bd9Sstevel@tonic-gate 			error = EINTR;
1148*7c478bd9Sstevel@tonic-gate 			goto done;
1149*7c478bd9Sstevel@tonic-gate 		}
1150*7c478bd9Sstevel@tonic-gate 		goto check_error;
1151*7c478bd9Sstevel@tonic-gate 	}
1152*7c478bd9Sstevel@tonic-gate 	mp = so->so_conn_ind_head;
1153*7c478bd9Sstevel@tonic-gate 	so->so_conn_ind_head = mp->b_next;
1154*7c478bd9Sstevel@tonic-gate 	mp->b_next = NULL;
1155*7c478bd9Sstevel@tonic-gate 	if (so->so_conn_ind_head == NULL) {
1156*7c478bd9Sstevel@tonic-gate 		ASSERT(so->so_conn_ind_tail == mp);
1157*7c478bd9Sstevel@tonic-gate 		so->so_conn_ind_tail = NULL;
1158*7c478bd9Sstevel@tonic-gate 		so->so_state &= ~SS_HASCONNIND;
1159*7c478bd9Sstevel@tonic-gate 	}
1160*7c478bd9Sstevel@tonic-gate 	*mpp = mp;
1161*7c478bd9Sstevel@tonic-gate done:
1162*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
1163*7c478bd9Sstevel@tonic-gate 	return (error);
1164*7c478bd9Sstevel@tonic-gate }
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate /*
1167*7c478bd9Sstevel@tonic-gate  * Flush a T_CONN_IND matching the sequence number from the list.
1168*7c478bd9Sstevel@tonic-gate  * Return zero if found; non-zero otherwise.
1169*7c478bd9Sstevel@tonic-gate  * This is called very infrequently thus it is ok to do a linear search.
1170*7c478bd9Sstevel@tonic-gate  */
1171*7c478bd9Sstevel@tonic-gate int
1172*7c478bd9Sstevel@tonic-gate soflushconnind(struct sonode *so, t_scalar_t seqno)
1173*7c478bd9Sstevel@tonic-gate {
1174*7c478bd9Sstevel@tonic-gate 	mblk_t *prevmp, *mp;
1175*7c478bd9Sstevel@tonic-gate 	struct T_conn_ind *tci;
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1178*7c478bd9Sstevel@tonic-gate 	for (prevmp = NULL, mp = so->so_conn_ind_head; mp != NULL;
1179*7c478bd9Sstevel@tonic-gate 	    prevmp = mp, mp = mp->b_next) {
1180*7c478bd9Sstevel@tonic-gate 		tci = (struct T_conn_ind *)mp->b_rptr;
1181*7c478bd9Sstevel@tonic-gate 		if (tci->SEQ_number == seqno) {
1182*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
1183*7c478bd9Sstevel@tonic-gate 				("t_discon_ind: found T_CONN_IND %d\n", seqno));
1184*7c478bd9Sstevel@tonic-gate 			/* Deleting last? */
1185*7c478bd9Sstevel@tonic-gate 			if (so->so_conn_ind_tail == mp) {
1186*7c478bd9Sstevel@tonic-gate 				so->so_conn_ind_tail = prevmp;
1187*7c478bd9Sstevel@tonic-gate 			}
1188*7c478bd9Sstevel@tonic-gate 			if (prevmp == NULL) {
1189*7c478bd9Sstevel@tonic-gate 				/* Deleting first */
1190*7c478bd9Sstevel@tonic-gate 				so->so_conn_ind_head = mp->b_next;
1191*7c478bd9Sstevel@tonic-gate 			} else {
1192*7c478bd9Sstevel@tonic-gate 				prevmp->b_next = mp->b_next;
1193*7c478bd9Sstevel@tonic-gate 			}
1194*7c478bd9Sstevel@tonic-gate 			mp->b_next = NULL;
1195*7c478bd9Sstevel@tonic-gate 			if (so->so_conn_ind_head == NULL) {
1196*7c478bd9Sstevel@tonic-gate 				ASSERT(so->so_conn_ind_tail == NULL);
1197*7c478bd9Sstevel@tonic-gate 				so->so_state &= ~SS_HASCONNIND;
1198*7c478bd9Sstevel@tonic-gate 			} else {
1199*7c478bd9Sstevel@tonic-gate 				ASSERT(so->so_conn_ind_tail != NULL);
1200*7c478bd9Sstevel@tonic-gate 			}
1201*7c478bd9Sstevel@tonic-gate 			so->so_error = ECONNABORTED;
1202*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
1203*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1204*7c478bd9Sstevel@tonic-gate 			return (0);
1205*7c478bd9Sstevel@tonic-gate 		}
1206*7c478bd9Sstevel@tonic-gate 	}
1207*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
1208*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1,	("t_discon_ind: NOT found T_CONN_IND %d\n", seqno));
1209*7c478bd9Sstevel@tonic-gate 	return (-1);
1210*7c478bd9Sstevel@tonic-gate }
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate /*
1213*7c478bd9Sstevel@tonic-gate  * Wait until the socket is connected or there is an error.
1214*7c478bd9Sstevel@tonic-gate  * fmode should contain any nonblocking flags. nosig should be
1215*7c478bd9Sstevel@tonic-gate  * set if the caller does not want the wait to be interrupted by a signal.
1216*7c478bd9Sstevel@tonic-gate  */
1217*7c478bd9Sstevel@tonic-gate int
1218*7c478bd9Sstevel@tonic-gate sowaitconnected(struct sonode *so, int fmode, int nosig)
1219*7c478bd9Sstevel@tonic-gate {
1220*7c478bd9Sstevel@tonic-gate 	int error;
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) ==
1225*7c478bd9Sstevel@tonic-gate 		SS_ISCONNECTING && so->so_error == 0) {
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n", so));
1228*7c478bd9Sstevel@tonic-gate 		if (fmode & (FNDELAY|FNONBLOCK))
1229*7c478bd9Sstevel@tonic-gate 			return (EINPROGRESS);
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 		if (nosig)
1232*7c478bd9Sstevel@tonic-gate 			cv_wait(&so->so_state_cv, &so->so_lock);
1233*7c478bd9Sstevel@tonic-gate 		else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) {
1234*7c478bd9Sstevel@tonic-gate 			/*
1235*7c478bd9Sstevel@tonic-gate 			 * Return EINTR and let the application use
1236*7c478bd9Sstevel@tonic-gate 			 * nonblocking techniques for detecting when
1237*7c478bd9Sstevel@tonic-gate 			 * the connection has been established.
1238*7c478bd9Sstevel@tonic-gate 			 */
1239*7c478bd9Sstevel@tonic-gate 			return (EINTR);
1240*7c478bd9Sstevel@tonic-gate 		}
1241*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("awoken on %p\n", so));
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	if (so->so_error != 0) {
1245*7c478bd9Sstevel@tonic-gate 		error = sogeterr(so);
1246*7c478bd9Sstevel@tonic-gate 		ASSERT(error != 0);
1247*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("sowaitconnected: error %d\n", error));
1248*7c478bd9Sstevel@tonic-gate 		return (error);
1249*7c478bd9Sstevel@tonic-gate 	}
1250*7c478bd9Sstevel@tonic-gate 	if (!(so->so_state & SS_ISCONNECTED)) {
1251*7c478bd9Sstevel@tonic-gate 		/*
1252*7c478bd9Sstevel@tonic-gate 		 * Could have received a T_ORDREL_IND or a T_DISCON_IND with
1253*7c478bd9Sstevel@tonic-gate 		 * zero errno. Or another thread could have consumed so_error
1254*7c478bd9Sstevel@tonic-gate 		 * e.g. by calling read.
1255*7c478bd9Sstevel@tonic-gate 		 */
1256*7c478bd9Sstevel@tonic-gate 		error = ECONNREFUSED;
1257*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("sowaitconnected: error %d\n", error));
1258*7c478bd9Sstevel@tonic-gate 		return (error);
1259*7c478bd9Sstevel@tonic-gate 	}
1260*7c478bd9Sstevel@tonic-gate 	return (0);
1261*7c478bd9Sstevel@tonic-gate }
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate /*
1265*7c478bd9Sstevel@tonic-gate  * Handle the signal generation aspect of urgent data.
1266*7c478bd9Sstevel@tonic-gate  */
1267*7c478bd9Sstevel@tonic-gate static void
1268*7c478bd9Sstevel@tonic-gate so_oob_sig(struct sonode *so, int extrasig,
1269*7c478bd9Sstevel@tonic-gate     strsigset_t *signals, strpollset_t *pollwakeups)
1270*7c478bd9Sstevel@tonic-gate {
1271*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1274*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobsigcnt >= so->so_oobcnt);
1275*7c478bd9Sstevel@tonic-gate 	if (so->so_oobsigcnt > so->so_oobcnt) {
1276*7c478bd9Sstevel@tonic-gate 		/*
1277*7c478bd9Sstevel@tonic-gate 		 * Signal has already been generated once for this
1278*7c478bd9Sstevel@tonic-gate 		 * urgent "event". However, since TCP can receive updated
1279*7c478bd9Sstevel@tonic-gate 		 * urgent pointers we still generate a signal.
1280*7c478bd9Sstevel@tonic-gate 		 */
1281*7c478bd9Sstevel@tonic-gate 		ASSERT(so->so_state & SS_OOBPEND);
1282*7c478bd9Sstevel@tonic-gate 		if (extrasig) {
1283*7c478bd9Sstevel@tonic-gate 			*signals |= S_RDBAND;
1284*7c478bd9Sstevel@tonic-gate 			*pollwakeups |= POLLRDBAND;
1285*7c478bd9Sstevel@tonic-gate 		}
1286*7c478bd9Sstevel@tonic-gate 		return;
1287*7c478bd9Sstevel@tonic-gate 	}
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 	so->so_oobsigcnt++;
1290*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobsigcnt > 0);	/* Wraparound */
1291*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobsigcnt > so->so_oobcnt);
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 	/*
1294*7c478bd9Sstevel@tonic-gate 	 * Record (for select/poll) that urgent data is pending.
1295*7c478bd9Sstevel@tonic-gate 	 */
1296*7c478bd9Sstevel@tonic-gate 	so->so_state |= SS_OOBPEND;
1297*7c478bd9Sstevel@tonic-gate 	/*
1298*7c478bd9Sstevel@tonic-gate 	 * New urgent data on the way so forget about any old
1299*7c478bd9Sstevel@tonic-gate 	 * urgent data.
1300*7c478bd9Sstevel@tonic-gate 	 */
1301*7c478bd9Sstevel@tonic-gate 	so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA);
1302*7c478bd9Sstevel@tonic-gate 	if (so->so_oobmsg != NULL) {
1303*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("sock: discarding old oob\n"));
1304*7c478bd9Sstevel@tonic-gate 		freemsg(so->so_oobmsg);
1305*7c478bd9Sstevel@tonic-gate 		so->so_oobmsg = NULL;
1306*7c478bd9Sstevel@tonic-gate 	}
1307*7c478bd9Sstevel@tonic-gate 	*signals |= S_RDBAND;
1308*7c478bd9Sstevel@tonic-gate 	*pollwakeups |= POLLRDBAND;
1309*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1310*7c478bd9Sstevel@tonic-gate }
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate /*
1313*7c478bd9Sstevel@tonic-gate  * Handle the processing of the T_EXDATA_IND with urgent data.
1314*7c478bd9Sstevel@tonic-gate  * Returns the T_EXDATA_IND if it should be queued on the read queue.
1315*7c478bd9Sstevel@tonic-gate  */
1316*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
1317*7c478bd9Sstevel@tonic-gate static mblk_t *
1318*7c478bd9Sstevel@tonic-gate so_oob_exdata(struct sonode *so, mblk_t *mp,
1319*7c478bd9Sstevel@tonic-gate 	strsigset_t *signals, strpollset_t *pollwakeups)
1320*7c478bd9Sstevel@tonic-gate {
1321*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobsigcnt > so->so_oobcnt);
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate 	so->so_oobcnt++;
1328*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobcnt > 0);	/* wraparound? */
1329*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobsigcnt >= so->so_oobcnt);
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 	/*
1332*7c478bd9Sstevel@tonic-gate 	 * Set MSGMARK for SIOCATMARK.
1333*7c478bd9Sstevel@tonic-gate 	 */
1334*7c478bd9Sstevel@tonic-gate 	mp->b_flag |= MSGMARK;
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1337*7c478bd9Sstevel@tonic-gate 	return (mp);
1338*7c478bd9Sstevel@tonic-gate }
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate /*
1341*7c478bd9Sstevel@tonic-gate  * Handle the processing of the actual urgent data.
1342*7c478bd9Sstevel@tonic-gate  * Returns the data mblk if it should be queued on the read queue.
1343*7c478bd9Sstevel@tonic-gate  */
1344*7c478bd9Sstevel@tonic-gate static mblk_t *
1345*7c478bd9Sstevel@tonic-gate so_oob_data(struct sonode *so, mblk_t *mp,
1346*7c478bd9Sstevel@tonic-gate 	strsigset_t *signals, strpollset_t *pollwakeups)
1347*7c478bd9Sstevel@tonic-gate {
1348*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobsigcnt >= so->so_oobcnt);
1353*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1354*7c478bd9Sstevel@tonic-gate 	/*
1355*7c478bd9Sstevel@tonic-gate 	 * For OOBINLINE we keep the data in the T_EXDATA_IND.
1356*7c478bd9Sstevel@tonic-gate 	 * Otherwise we store it in so_oobmsg.
1357*7c478bd9Sstevel@tonic-gate 	 */
1358*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_oobmsg == NULL);
1359*7c478bd9Sstevel@tonic-gate 	if (so->so_options & SO_OOBINLINE) {
1360*7c478bd9Sstevel@tonic-gate 		*pollwakeups |= POLLIN | POLLRDNORM | POLLRDBAND;
1361*7c478bd9Sstevel@tonic-gate 		*signals |= S_INPUT | S_RDNORM;
1362*7c478bd9Sstevel@tonic-gate 	} else {
1363*7c478bd9Sstevel@tonic-gate 		*pollwakeups |= POLLRDBAND;
1364*7c478bd9Sstevel@tonic-gate 		so->so_state |= SS_HAVEOOBDATA;
1365*7c478bd9Sstevel@tonic-gate 		so->so_oobmsg = mp;
1366*7c478bd9Sstevel@tonic-gate 		mp = NULL;
1367*7c478bd9Sstevel@tonic-gate 	}
1368*7c478bd9Sstevel@tonic-gate 	ASSERT(so_verify_oobstate(so));
1369*7c478bd9Sstevel@tonic-gate 	return (mp);
1370*7c478bd9Sstevel@tonic-gate }
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate /*
1373*7c478bd9Sstevel@tonic-gate  * Caller must hold the mutex.
1374*7c478bd9Sstevel@tonic-gate  * For delayed processing, save the T_DISCON_IND received
1375*7c478bd9Sstevel@tonic-gate  * from below on so_discon_ind_mp.
1376*7c478bd9Sstevel@tonic-gate  * When the message is processed the framework will call:
1377*7c478bd9Sstevel@tonic-gate  *      (*func)(so, mp);
1378*7c478bd9Sstevel@tonic-gate  */
1379*7c478bd9Sstevel@tonic-gate static void
1380*7c478bd9Sstevel@tonic-gate so_save_discon_ind(struct sonode *so,
1381*7c478bd9Sstevel@tonic-gate 	mblk_t *mp,
1382*7c478bd9Sstevel@tonic-gate 	void (*func)(struct sonode *so, mblk_t *))
1383*7c478bd9Sstevel@tonic-gate {
1384*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1385*7c478bd9Sstevel@tonic-gate 
1386*7c478bd9Sstevel@tonic-gate 	/*
1387*7c478bd9Sstevel@tonic-gate 	 * Discard new T_DISCON_IND if we have already received another.
1388*7c478bd9Sstevel@tonic-gate 	 * Currently the earlier message can either be on so_discon_ind_mp
1389*7c478bd9Sstevel@tonic-gate 	 * or being processed.
1390*7c478bd9Sstevel@tonic-gate 	 */
1391*7c478bd9Sstevel@tonic-gate 	if (so->so_discon_ind_mp != NULL || (so->so_flag & SOASYNC_UNBIND)) {
1392*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1393*7c478bd9Sstevel@tonic-gate 		    "sockfs: received unexpected additional T_DISCON_IND\n");
1394*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1395*7c478bd9Sstevel@tonic-gate 		return;
1396*7c478bd9Sstevel@tonic-gate 	}
1397*7c478bd9Sstevel@tonic-gate 	mp->b_prev = (mblk_t *)func;
1398*7c478bd9Sstevel@tonic-gate 	mp->b_next = NULL;
1399*7c478bd9Sstevel@tonic-gate 	so->so_discon_ind_mp = mp;
1400*7c478bd9Sstevel@tonic-gate }
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate /*
1403*7c478bd9Sstevel@tonic-gate  * Caller must hold the mutex and make sure that either SOLOCKED
1404*7c478bd9Sstevel@tonic-gate  * or SOASYNC_UNBIND is set. Called from so_unlock_single().
1405*7c478bd9Sstevel@tonic-gate  * Perform delayed processing of T_DISCON_IND message on so_discon_ind_mp.
1406*7c478bd9Sstevel@tonic-gate  * Need to ensure that strsock_proto() will not end up sleeping for
1407*7c478bd9Sstevel@tonic-gate  * SOASYNC_UNBIND, while executing this function.
1408*7c478bd9Sstevel@tonic-gate  */
1409*7c478bd9Sstevel@tonic-gate void
1410*7c478bd9Sstevel@tonic-gate so_drain_discon_ind(struct sonode *so)
1411*7c478bd9Sstevel@tonic-gate {
1412*7c478bd9Sstevel@tonic-gate 	mblk_t	*bp;
1413*7c478bd9Sstevel@tonic-gate 	void (*func)(struct sonode *so, mblk_t *);
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1416*7c478bd9Sstevel@tonic-gate 	ASSERT(so->so_flag & (SOLOCKED|SOASYNC_UNBIND));
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 	/* Process T_DISCON_IND on so_discon_ind_mp */
1419*7c478bd9Sstevel@tonic-gate 	if ((bp = so->so_discon_ind_mp) != NULL) {
1420*7c478bd9Sstevel@tonic-gate 		so->so_discon_ind_mp = NULL;
1421*7c478bd9Sstevel@tonic-gate 		func = (void (*)())bp->b_prev;
1422*7c478bd9Sstevel@tonic-gate 		bp->b_prev = NULL;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 		/*
1425*7c478bd9Sstevel@tonic-gate 		 * This (*func) is supposed to generate a message downstream
1426*7c478bd9Sstevel@tonic-gate 		 * and we need to have a flag set until the corresponding
1427*7c478bd9Sstevel@tonic-gate 		 * upstream message reaches stream head.
1428*7c478bd9Sstevel@tonic-gate 		 * When processing T_DISCON_IND in strsock_discon_ind
1429*7c478bd9Sstevel@tonic-gate 		 * we hold SOASYN_UNBIND when sending T_UNBIND_REQ down and
1430*7c478bd9Sstevel@tonic-gate 		 * drop the flag after we get the ACK in strsock_proto.
1431*7c478bd9Sstevel@tonic-gate 		 */
1432*7c478bd9Sstevel@tonic-gate 		(void) (*func)(so, bp);
1433*7c478bd9Sstevel@tonic-gate 	}
1434*7c478bd9Sstevel@tonic-gate }
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate /*
1437*7c478bd9Sstevel@tonic-gate  * Caller must hold the mutex.
1438*7c478bd9Sstevel@tonic-gate  * Remove the T_DISCON_IND on so_discon_ind_mp.
1439*7c478bd9Sstevel@tonic-gate  */
1440*7c478bd9Sstevel@tonic-gate void
1441*7c478bd9Sstevel@tonic-gate so_flush_discon_ind(struct sonode *so)
1442*7c478bd9Sstevel@tonic-gate {
1443*7c478bd9Sstevel@tonic-gate 	mblk_t	*bp;
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	/*
1448*7c478bd9Sstevel@tonic-gate 	 * Remove T_DISCON_IND mblk at so_discon_ind_mp.
1449*7c478bd9Sstevel@tonic-gate 	 */
1450*7c478bd9Sstevel@tonic-gate 	if ((bp = so->so_discon_ind_mp) != NULL) {
1451*7c478bd9Sstevel@tonic-gate 		so->so_discon_ind_mp = NULL;
1452*7c478bd9Sstevel@tonic-gate 		bp->b_prev = NULL;
1453*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
1454*7c478bd9Sstevel@tonic-gate 	}
1455*7c478bd9Sstevel@tonic-gate }
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate /*
1458*7c478bd9Sstevel@tonic-gate  * Caller must hold the mutex.
1459*7c478bd9Sstevel@tonic-gate  *
1460*7c478bd9Sstevel@tonic-gate  * This function is used to process the T_DISCON_IND message. It does
1461*7c478bd9Sstevel@tonic-gate  * immediate processing when called from strsock_proto and delayed
1462*7c478bd9Sstevel@tonic-gate  * processing of discon_ind saved on so_discon_ind_mp when called from
1463*7c478bd9Sstevel@tonic-gate  * so_drain_discon_ind. When a T_DISCON_IND message is saved in
1464*7c478bd9Sstevel@tonic-gate  * so_discon_ind_mp for delayed processing, this function is registered
1465*7c478bd9Sstevel@tonic-gate  * as the callback function to process the message.
1466*7c478bd9Sstevel@tonic-gate  *
1467*7c478bd9Sstevel@tonic-gate  * SOASYNC_UNBIND should be held in this function, during the non-blocking
1468*7c478bd9Sstevel@tonic-gate  * unbind operation, and should be released only after we receive the ACK
1469*7c478bd9Sstevel@tonic-gate  * in strsock_proto, for the T_UNBIND_REQ sent here. Since SOLOCKED is not set,
1470*7c478bd9Sstevel@tonic-gate  * no TPI messages would be sent down at this time. This is to prevent M_FLUSH
1471*7c478bd9Sstevel@tonic-gate  * sent from either this function or tcp_unbind(), flushing away any TPI
1472*7c478bd9Sstevel@tonic-gate  * message that is being sent down and stays in a lower module's queue.
1473*7c478bd9Sstevel@tonic-gate  *
1474*7c478bd9Sstevel@tonic-gate  * This function drops so_lock and grabs it again.
1475*7c478bd9Sstevel@tonic-gate  */
1476*7c478bd9Sstevel@tonic-gate static void
1477*7c478bd9Sstevel@tonic-gate strsock_discon_ind(struct sonode *so, mblk_t *discon_mp)
1478*7c478bd9Sstevel@tonic-gate {
1479*7c478bd9Sstevel@tonic-gate 	struct vnode *vp;
1480*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
1481*7c478bd9Sstevel@tonic-gate 	union T_primitives *tpr;
1482*7c478bd9Sstevel@tonic-gate 	struct T_unbind_req *ubr;
1483*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1484*7c478bd9Sstevel@tonic-gate 	int error;
1485*7c478bd9Sstevel@tonic-gate 
1486*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&so->so_lock));
1487*7c478bd9Sstevel@tonic-gate 	ASSERT(discon_mp);
1488*7c478bd9Sstevel@tonic-gate 	ASSERT(discon_mp->b_rptr);
1489*7c478bd9Sstevel@tonic-gate 
1490*7c478bd9Sstevel@tonic-gate 	tpr = (union T_primitives *)discon_mp->b_rptr;
1491*7c478bd9Sstevel@tonic-gate 	ASSERT(tpr->type == T_DISCON_IND);
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate 	vp = SOTOV(so);
1494*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
1495*7c478bd9Sstevel@tonic-gate 	ASSERT(stp);
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate 	/*
1498*7c478bd9Sstevel@tonic-gate 	 * Not a listener
1499*7c478bd9Sstevel@tonic-gate 	 */
1500*7c478bd9Sstevel@tonic-gate 	ASSERT((so->so_state & SS_ACCEPTCONN) == 0);
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	/*
1503*7c478bd9Sstevel@tonic-gate 	 * This assumes that the name space for DISCON_reason
1504*7c478bd9Sstevel@tonic-gate 	 * is the errno name space.
1505*7c478bd9Sstevel@tonic-gate 	 */
1506*7c478bd9Sstevel@tonic-gate 	soisdisconnected(so, tpr->discon_ind.DISCON_reason);
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 	/*
1509*7c478bd9Sstevel@tonic-gate 	 * Unbind with the transport without blocking.
1510*7c478bd9Sstevel@tonic-gate 	 * If we've already received a T_DISCON_IND do not unbind.
1511*7c478bd9Sstevel@tonic-gate 	 *
1512*7c478bd9Sstevel@tonic-gate 	 * If there is no preallocated unbind message, we have already
1513*7c478bd9Sstevel@tonic-gate 	 * unbound with the transport
1514*7c478bd9Sstevel@tonic-gate 	 *
1515*7c478bd9Sstevel@tonic-gate 	 * If the socket is not bound, no need to unbind.
1516*7c478bd9Sstevel@tonic-gate 	 */
1517*7c478bd9Sstevel@tonic-gate 	mp = so->so_unbind_mp;
1518*7c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
1519*7c478bd9Sstevel@tonic-gate 		ASSERT(!(so->so_state & SS_ISBOUND));
1520*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
1521*7c478bd9Sstevel@tonic-gate 	} else if (!(so->so_state & SS_ISBOUND))  {
1522*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
1523*7c478bd9Sstevel@tonic-gate 	} else {
1524*7c478bd9Sstevel@tonic-gate 		so->so_unbind_mp = NULL;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 		/*
1527*7c478bd9Sstevel@tonic-gate 		 * Is another T_DISCON_IND being processed.
1528*7c478bd9Sstevel@tonic-gate 		 */
1529*7c478bd9Sstevel@tonic-gate 		ASSERT((so->so_flag & SOASYNC_UNBIND) == 0);
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 		/*
1532*7c478bd9Sstevel@tonic-gate 		 * Make strsock_proto ignore T_OK_ACK and T_ERROR_ACK for
1533*7c478bd9Sstevel@tonic-gate 		 * this unbind. Set SOASYNC_UNBIND. This should be cleared
1534*7c478bd9Sstevel@tonic-gate 		 * only after we receive the ACK in strsock_proto.
1535*7c478bd9Sstevel@tonic-gate 		 */
1536*7c478bd9Sstevel@tonic-gate 		so->so_flag |= SOASYNC_UNBIND;
1537*7c478bd9Sstevel@tonic-gate 		ASSERT(!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)));
1538*7c478bd9Sstevel@tonic-gate 		so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN|SS_LADDR_VALID);
1539*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 		/*
1542*7c478bd9Sstevel@tonic-gate 		 * Send down T_UNBIND_REQ ignoring flow control.
1543*7c478bd9Sstevel@tonic-gate 		 * XXX Assumes that MSG_IGNFLOW implies that this thread
1544*7c478bd9Sstevel@tonic-gate 		 * does not run service procedures.
1545*7c478bd9Sstevel@tonic-gate 		 */
1546*7c478bd9Sstevel@tonic-gate 		ASSERT(DB_TYPE(mp) == M_PROTO);
1547*7c478bd9Sstevel@tonic-gate 		ubr = (struct T_unbind_req *)mp->b_rptr;
1548*7c478bd9Sstevel@tonic-gate 		mp->b_wptr += sizeof (*ubr);
1549*7c478bd9Sstevel@tonic-gate 		ubr->PRIM_type = T_UNBIND_REQ;
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 		/*
1552*7c478bd9Sstevel@tonic-gate 		 * Flush the read and write side (except stream head read queue)
1553*7c478bd9Sstevel@tonic-gate 		 * and send down T_UNBIND_REQ.
1554*7c478bd9Sstevel@tonic-gate 		 */
1555*7c478bd9Sstevel@tonic-gate 		(void) putnextctl1(strvp2wq(SOTOV(so)), M_FLUSH, FLUSHRW);
1556*7c478bd9Sstevel@tonic-gate 		error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0,
1557*7c478bd9Sstevel@tonic-gate 			MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0);
1558*7c478bd9Sstevel@tonic-gate 		/* LINTED - warning: statement has no consequent: if */
1559*7c478bd9Sstevel@tonic-gate 		if (error) {
1560*7c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
1561*7c478bd9Sstevel@tonic-gate 		}
1562*7c478bd9Sstevel@tonic-gate 	}
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate 	if (tpr->discon_ind.DISCON_reason != 0)
1565*7c478bd9Sstevel@tonic-gate 		strsetrerror(SOTOV(so), 0, 0, sogetrderr);
1566*7c478bd9Sstevel@tonic-gate 	strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
1567*7c478bd9Sstevel@tonic-gate 	strseteof(SOTOV(so), 1);
1568*7c478bd9Sstevel@tonic-gate 	/*
1569*7c478bd9Sstevel@tonic-gate 	 * strseteof takes care of read side wakeups,
1570*7c478bd9Sstevel@tonic-gate 	 * pollwakeups, and signals.
1571*7c478bd9Sstevel@tonic-gate 	 */
1572*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("T_DISCON_IND: error %d\n", so->so_error));
1573*7c478bd9Sstevel@tonic-gate 	freemsg(discon_mp);
1574*7c478bd9Sstevel@tonic-gate 
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate 	pollwakeup(&stp->sd_pollist, POLLOUT);
1577*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
1578*7c478bd9Sstevel@tonic-gate 
1579*7c478bd9Sstevel@tonic-gate 	/*
1580*7c478bd9Sstevel@tonic-gate 	 * Wake sleeping write
1581*7c478bd9Sstevel@tonic-gate 	 */
1582*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & WSLEEP) {
1583*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
1584*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_wrq->q_wait);
1585*7c478bd9Sstevel@tonic-gate 	}
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate 	/*
1588*7c478bd9Sstevel@tonic-gate 	 * strsendsig can handle multiple signals with a
1589*7c478bd9Sstevel@tonic-gate 	 * single call.  Send SIGPOLL for S_OUTPUT event.
1590*7c478bd9Sstevel@tonic-gate 	 */
1591*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sigflags & S_OUTPUT)
1592*7c478bd9Sstevel@tonic-gate 		strsendsig(stp->sd_siglist, S_OUTPUT, 0, 0);
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
1595*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
1596*7c478bd9Sstevel@tonic-gate }
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate /*
1599*7c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to receive M_PROTO
1600*7c478bd9Sstevel@tonic-gate  * and M_PCPROTO messages.
1601*7c478bd9Sstevel@tonic-gate  *
1602*7c478bd9Sstevel@tonic-gate  * Returns NULL if the message was consumed.
1603*7c478bd9Sstevel@tonic-gate  * Returns an mblk to make that mblk be processed (and queued) by the stream
1604*7c478bd9Sstevel@tonic-gate  * head.
1605*7c478bd9Sstevel@tonic-gate  *
1606*7c478bd9Sstevel@tonic-gate  * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and
1607*7c478bd9Sstevel@tonic-gate  * *pollwakeups) for the stream head to take action on. Note that since
1608*7c478bd9Sstevel@tonic-gate  * sockets always deliver SIGIO for every new piece of data this routine
1609*7c478bd9Sstevel@tonic-gate  * never sets *firstmsgsigs; any signals are returned in *allmsgsigs.
1610*7c478bd9Sstevel@tonic-gate  *
1611*7c478bd9Sstevel@tonic-gate  * This routine handles all data related TPI messages independent of
1612*7c478bd9Sstevel@tonic-gate  * the type of the socket i.e. it doesn't care if T_UNITDATA_IND message
1613*7c478bd9Sstevel@tonic-gate  * arrive on a SOCK_STREAM.
1614*7c478bd9Sstevel@tonic-gate  */
1615*7c478bd9Sstevel@tonic-gate static mblk_t *
1616*7c478bd9Sstevel@tonic-gate strsock_proto(vnode_t *vp, mblk_t *mp,
1617*7c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1618*7c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
1619*7c478bd9Sstevel@tonic-gate {
1620*7c478bd9Sstevel@tonic-gate 	union T_primitives *tpr;
1621*7c478bd9Sstevel@tonic-gate 	struct sonode *so;
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 	so = VTOSO(vp);
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("strsock_proto(%p, %p)\n", vp, mp));
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 	/* Set default return values */
1628*7c478bd9Sstevel@tonic-gate 	*firstmsgsigs = *wakeups = *allmsgsigs = *pollwakeups = 0;
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_PROTO ||
1631*7c478bd9Sstevel@tonic-gate 	    DB_TYPE(mp) == M_PCPROTO);
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (tpr->type)) {
1634*7c478bd9Sstevel@tonic-gate 		/* The message is too short to even contain the primitive */
1635*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1636*7c478bd9Sstevel@tonic-gate 		    "sockfs: Too short TPI message received. Len = %ld\n",
1637*7c478bd9Sstevel@tonic-gate 		    (ptrdiff_t)(MBLKL(mp)));
1638*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1639*7c478bd9Sstevel@tonic-gate 		return (NULL);
1640*7c478bd9Sstevel@tonic-gate 	}
1641*7c478bd9Sstevel@tonic-gate 	if (!__TPI_PRIM_ISALIGNED(mp->b_rptr)) {
1642*7c478bd9Sstevel@tonic-gate 		/* The read pointer is not aligned correctly for TPI */
1643*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1644*7c478bd9Sstevel@tonic-gate 		    "sockfs: Unaligned TPI message received. rptr = %p\n",
1645*7c478bd9Sstevel@tonic-gate 		    (void *)mp->b_rptr);
1646*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1647*7c478bd9Sstevel@tonic-gate 		return (NULL);
1648*7c478bd9Sstevel@tonic-gate 	}
1649*7c478bd9Sstevel@tonic-gate 	tpr = (union T_primitives *)mp->b_rptr;
1650*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("strsock_proto: primitive %d\n", tpr->type));
1651*7c478bd9Sstevel@tonic-gate 
1652*7c478bd9Sstevel@tonic-gate 	switch (tpr->type) {
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate 	case T_DATA_IND:
1655*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_data_ind)) {
1656*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1657*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_DATA_IND. Len = %ld\n",
1658*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
1659*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1660*7c478bd9Sstevel@tonic-gate 			return (NULL);
1661*7c478bd9Sstevel@tonic-gate 		}
1662*7c478bd9Sstevel@tonic-gate 		/*
1663*7c478bd9Sstevel@tonic-gate 		 * Ignore zero-length T_DATA_IND messages. These might be
1664*7c478bd9Sstevel@tonic-gate 		 * generated by some transports.
1665*7c478bd9Sstevel@tonic-gate 		 * This is needed to prevent read (which skips the M_PROTO
1666*7c478bd9Sstevel@tonic-gate 		 * part) to unexpectedly return 0 (or return EWOULDBLOCK
1667*7c478bd9Sstevel@tonic-gate 		 * on a non-blocking socket after select/poll has indicated
1668*7c478bd9Sstevel@tonic-gate 		 * that data is available).
1669*7c478bd9Sstevel@tonic-gate 		 */
1670*7c478bd9Sstevel@tonic-gate 		if (msgdsize(mp->b_cont) == 0) {
1671*7c478bd9Sstevel@tonic-gate 			dprintso(so, 0,
1672*7c478bd9Sstevel@tonic-gate 			    ("strsock_proto: zero length T_DATA_IND\n"));
1673*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1674*7c478bd9Sstevel@tonic-gate 			return (NULL);
1675*7c478bd9Sstevel@tonic-gate 		}
1676*7c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
1677*7c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
1678*7c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
1679*7c478bd9Sstevel@tonic-gate 		return (mp);
1680*7c478bd9Sstevel@tonic-gate 
1681*7c478bd9Sstevel@tonic-gate 	case T_UNITDATA_IND: {
1682*7c478bd9Sstevel@tonic-gate 		struct T_unitdata_ind	*tudi = &tpr->unitdata_ind;
1683*7c478bd9Sstevel@tonic-gate 		void			*addr;
1684*7c478bd9Sstevel@tonic-gate 		t_uscalar_t		addrlen;
1685*7c478bd9Sstevel@tonic-gate 
1686*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_unitdata_ind)) {
1687*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1688*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_UNITDATA_IND. Len = %ld\n",
1689*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
1690*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1691*7c478bd9Sstevel@tonic-gate 			return (NULL);
1692*7c478bd9Sstevel@tonic-gate 		}
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 		/* Is this is not a connected datagram socket? */
1695*7c478bd9Sstevel@tonic-gate 		if ((so->so_mode & SM_CONNREQUIRED) ||
1696*7c478bd9Sstevel@tonic-gate 		    !(so->so_state & SS_ISCONNECTED)) {
1697*7c478bd9Sstevel@tonic-gate 			/*
1698*7c478bd9Sstevel@tonic-gate 			 * Not a connected datagram socket. Look for
1699*7c478bd9Sstevel@tonic-gate 			 * the SO_UNIX_CLOSE option. If such an option is found
1700*7c478bd9Sstevel@tonic-gate 			 * discard the message (since it has no meaning
1701*7c478bd9Sstevel@tonic-gate 			 * unless connected).
1702*7c478bd9Sstevel@tonic-gate 			 */
1703*7c478bd9Sstevel@tonic-gate 			if (so->so_family == AF_UNIX && msgdsize(mp) == 0 &&
1704*7c478bd9Sstevel@tonic-gate 			    tudi->OPT_length != 0) {
1705*7c478bd9Sstevel@tonic-gate 				void *opt;
1706*7c478bd9Sstevel@tonic-gate 				t_uscalar_t optlen = tudi->OPT_length;
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate 				opt = sogetoff(mp, tudi->OPT_offset,
1709*7c478bd9Sstevel@tonic-gate 					optlen, __TPI_ALIGN_SIZE);
1710*7c478bd9Sstevel@tonic-gate 				if (opt == NULL) {
1711*7c478bd9Sstevel@tonic-gate 					/* The len/off falls outside mp */
1712*7c478bd9Sstevel@tonic-gate 					freemsg(mp);
1713*7c478bd9Sstevel@tonic-gate 					mutex_enter(&so->so_lock);
1714*7c478bd9Sstevel@tonic-gate 					soseterror(so, EPROTO);
1715*7c478bd9Sstevel@tonic-gate 					mutex_exit(&so->so_lock);
1716*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
1717*7c478bd9Sstevel@tonic-gate 					    "sockfs: T_unidata_ind with "
1718*7c478bd9Sstevel@tonic-gate 					    "invalid optlen/offset %u/%d\n",
1719*7c478bd9Sstevel@tonic-gate 					    optlen, tudi->OPT_offset);
1720*7c478bd9Sstevel@tonic-gate 					return (NULL);
1721*7c478bd9Sstevel@tonic-gate 				}
1722*7c478bd9Sstevel@tonic-gate 				if (so_getopt_unix_close(opt, optlen)) {
1723*7c478bd9Sstevel@tonic-gate 					freemsg(mp);
1724*7c478bd9Sstevel@tonic-gate 					return (NULL);
1725*7c478bd9Sstevel@tonic-gate 				}
1726*7c478bd9Sstevel@tonic-gate 			}
1727*7c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_INPUT | S_RDNORM;
1728*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM;
1729*7c478bd9Sstevel@tonic-gate 			*wakeups = RSLEEP;
1730*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
1731*7c478bd9Sstevel@tonic-gate 			if (audit_active)
1732*7c478bd9Sstevel@tonic-gate 				audit_sock(T_UNITDATA_IND, strvp2wq(vp),
1733*7c478bd9Sstevel@tonic-gate 					mp, 0);
1734*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */
1735*7c478bd9Sstevel@tonic-gate 			return (mp);
1736*7c478bd9Sstevel@tonic-gate 		}
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate 		/*
1739*7c478bd9Sstevel@tonic-gate 		 * A connect datagram socket. For AF_INET{,6} we verify that
1740*7c478bd9Sstevel@tonic-gate 		 * the source address matches the "connected to" address.
1741*7c478bd9Sstevel@tonic-gate 		 * The semantics of AF_UNIX sockets is to not verify
1742*7c478bd9Sstevel@tonic-gate 		 * the source address.
1743*7c478bd9Sstevel@tonic-gate 		 * Note that this source address verification is transport
1744*7c478bd9Sstevel@tonic-gate 		 * specific. Thus the real fix would be to extent TPI
1745*7c478bd9Sstevel@tonic-gate 		 * to allow T_CONN_REQ messages to be send to connectionless
1746*7c478bd9Sstevel@tonic-gate 		 * transport providers and always let the transport provider
1747*7c478bd9Sstevel@tonic-gate 		 * do whatever filtering is needed.
1748*7c478bd9Sstevel@tonic-gate 		 *
1749*7c478bd9Sstevel@tonic-gate 		 * The verification/filtering semantics for transports
1750*7c478bd9Sstevel@tonic-gate 		 * other than AF_INET and AF_UNIX are unknown. The choice
1751*7c478bd9Sstevel@tonic-gate 		 * would be to either filter using bcmp or let all messages
1752*7c478bd9Sstevel@tonic-gate 		 * get through. This code does not filter other address
1753*7c478bd9Sstevel@tonic-gate 		 * families since this at least allows the application to
1754*7c478bd9Sstevel@tonic-gate 		 * work around any missing filtering.
1755*7c478bd9Sstevel@tonic-gate 		 *
1756*7c478bd9Sstevel@tonic-gate 		 * XXX Should we move filtering to UDP/ICMP???
1757*7c478bd9Sstevel@tonic-gate 		 * That would require passing e.g. a T_DISCON_REQ to UDP
1758*7c478bd9Sstevel@tonic-gate 		 * when the socket becomes unconnected.
1759*7c478bd9Sstevel@tonic-gate 		 */
1760*7c478bd9Sstevel@tonic-gate 		addrlen = tudi->SRC_length;
1761*7c478bd9Sstevel@tonic-gate 		/*
1762*7c478bd9Sstevel@tonic-gate 		 * The alignment restriction is really to strict but
1763*7c478bd9Sstevel@tonic-gate 		 * we want enough alignment to inspect the fields of
1764*7c478bd9Sstevel@tonic-gate 		 * a sockaddr_in.
1765*7c478bd9Sstevel@tonic-gate 		 */
1766*7c478bd9Sstevel@tonic-gate 		addr = sogetoff(mp, tudi->SRC_offset, addrlen,
1767*7c478bd9Sstevel@tonic-gate 				__TPI_ALIGN_SIZE);
1768*7c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
1769*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1770*7c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
1771*7c478bd9Sstevel@tonic-gate 			soseterror(so, EPROTO);
1772*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
1773*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1774*7c478bd9Sstevel@tonic-gate 			    "sockfs: T_unidata_ind with invalid "
1775*7c478bd9Sstevel@tonic-gate 			    "addrlen/offset %u/%d\n",
1776*7c478bd9Sstevel@tonic-gate 			    addrlen, tudi->SRC_offset);
1777*7c478bd9Sstevel@tonic-gate 			return (NULL);
1778*7c478bd9Sstevel@tonic-gate 		}
1779*7c478bd9Sstevel@tonic-gate 
1780*7c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_INET) {
1781*7c478bd9Sstevel@tonic-gate 			/*
1782*7c478bd9Sstevel@tonic-gate 			 * For AF_INET we allow wildcarding both sin_addr
1783*7c478bd9Sstevel@tonic-gate 			 * and sin_port.
1784*7c478bd9Sstevel@tonic-gate 			 */
1785*7c478bd9Sstevel@tonic-gate 			struct sockaddr_in *faddr, *sin;
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 			/* Prevent so_faddr_sa from changing while accessed */
1788*7c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
1789*7c478bd9Sstevel@tonic-gate 			ASSERT(so->so_faddr_len ==
1790*7c478bd9Sstevel@tonic-gate 				(socklen_t)sizeof (struct sockaddr_in));
1791*7c478bd9Sstevel@tonic-gate 			faddr = (struct sockaddr_in *)so->so_faddr_sa;
1792*7c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)addr;
1793*7c478bd9Sstevel@tonic-gate 			if (addrlen !=
1794*7c478bd9Sstevel@tonic-gate 				(t_uscalar_t)sizeof (struct sockaddr_in) ||
1795*7c478bd9Sstevel@tonic-gate 			    (sin->sin_addr.s_addr != faddr->sin_addr.s_addr &&
1796*7c478bd9Sstevel@tonic-gate 			    faddr->sin_addr.s_addr != INADDR_ANY) ||
1797*7c478bd9Sstevel@tonic-gate 			    (so->so_type != SOCK_RAW &&
1798*7c478bd9Sstevel@tonic-gate 			    sin->sin_port != faddr->sin_port &&
1799*7c478bd9Sstevel@tonic-gate 			    faddr->sin_port != 0)) {
1800*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1801*7c478bd9Sstevel@tonic-gate 				dprintso(so, 0,
1802*7c478bd9Sstevel@tonic-gate 					("sockfs: T_UNITDATA_IND mismatch: %s",
1803*7c478bd9Sstevel@tonic-gate 					pr_addr(so->so_family,
1804*7c478bd9Sstevel@tonic-gate 						(struct sockaddr *)addr,
1805*7c478bd9Sstevel@tonic-gate 						addrlen)));
1806*7c478bd9Sstevel@tonic-gate 				dprintso(so, 0, (" - %s\n",
1807*7c478bd9Sstevel@tonic-gate 					pr_addr(so->so_family, so->so_faddr_sa,
1808*7c478bd9Sstevel@tonic-gate 					    (t_uscalar_t)so->so_faddr_len)));
1809*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1810*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
1811*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1812*7c478bd9Sstevel@tonic-gate 				return (NULL);
1813*7c478bd9Sstevel@tonic-gate 			}
1814*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
1815*7c478bd9Sstevel@tonic-gate 		} else if (so->so_family == AF_INET6) {
1816*7c478bd9Sstevel@tonic-gate 			/*
1817*7c478bd9Sstevel@tonic-gate 			 * For AF_INET6 we allow wildcarding both sin6_addr
1818*7c478bd9Sstevel@tonic-gate 			 * and sin6_port.
1819*7c478bd9Sstevel@tonic-gate 			 */
1820*7c478bd9Sstevel@tonic-gate 			struct sockaddr_in6 *faddr6, *sin6;
1821*7c478bd9Sstevel@tonic-gate 			static struct in6_addr zeroes; /* inits to all zeros */
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 			/* Prevent so_faddr_sa from changing while accessed */
1824*7c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
1825*7c478bd9Sstevel@tonic-gate 			ASSERT(so->so_faddr_len ==
1826*7c478bd9Sstevel@tonic-gate 			    (socklen_t)sizeof (struct sockaddr_in6));
1827*7c478bd9Sstevel@tonic-gate 			faddr6 = (struct sockaddr_in6 *)so->so_faddr_sa;
1828*7c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addr;
1829*7c478bd9Sstevel@tonic-gate 			/* XXX could we get a mapped address ::ffff:0.0.0.0 ? */
1830*7c478bd9Sstevel@tonic-gate 			if (addrlen !=
1831*7c478bd9Sstevel@tonic-gate 			    (t_uscalar_t)sizeof (struct sockaddr_in6) ||
1832*7c478bd9Sstevel@tonic-gate 			    (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
1833*7c478bd9Sstevel@tonic-gate 				&faddr6->sin6_addr) &&
1834*7c478bd9Sstevel@tonic-gate 			    !IN6_ARE_ADDR_EQUAL(&faddr6->sin6_addr, &zeroes)) ||
1835*7c478bd9Sstevel@tonic-gate 			    (so->so_type != SOCK_RAW &&
1836*7c478bd9Sstevel@tonic-gate 			    sin6->sin6_port != faddr6->sin6_port &&
1837*7c478bd9Sstevel@tonic-gate 			    faddr6->sin6_port != 0)) {
1838*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1839*7c478bd9Sstevel@tonic-gate 				dprintso(so, 0,
1840*7c478bd9Sstevel@tonic-gate 				    ("sockfs: T_UNITDATA_IND mismatch: %s",
1841*7c478bd9Sstevel@tonic-gate 					pr_addr(so->so_family,
1842*7c478bd9Sstevel@tonic-gate 					    (struct sockaddr *)addr,
1843*7c478bd9Sstevel@tonic-gate 					    addrlen)));
1844*7c478bd9Sstevel@tonic-gate 				dprintso(so, 0, (" - %s\n",
1845*7c478bd9Sstevel@tonic-gate 				    pr_addr(so->so_family, so->so_faddr_sa,
1846*7c478bd9Sstevel@tonic-gate 					(t_uscalar_t)so->so_faddr_len)));
1847*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1848*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
1849*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1850*7c478bd9Sstevel@tonic-gate 				return (NULL);
1851*7c478bd9Sstevel@tonic-gate 			}
1852*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
1853*7c478bd9Sstevel@tonic-gate 		} else if (so->so_family == AF_UNIX &&
1854*7c478bd9Sstevel@tonic-gate 		    msgdsize(mp->b_cont) == 0 &&
1855*7c478bd9Sstevel@tonic-gate 		    tudi->OPT_length != 0) {
1856*7c478bd9Sstevel@tonic-gate 			/*
1857*7c478bd9Sstevel@tonic-gate 			 * Attempt to extract AF_UNIX
1858*7c478bd9Sstevel@tonic-gate 			 * SO_UNIX_CLOSE indication from options.
1859*7c478bd9Sstevel@tonic-gate 			 */
1860*7c478bd9Sstevel@tonic-gate 			void *opt;
1861*7c478bd9Sstevel@tonic-gate 			t_uscalar_t optlen = tudi->OPT_length;
1862*7c478bd9Sstevel@tonic-gate 
1863*7c478bd9Sstevel@tonic-gate 			opt = sogetoff(mp, tudi->OPT_offset,
1864*7c478bd9Sstevel@tonic-gate 				optlen, __TPI_ALIGN_SIZE);
1865*7c478bd9Sstevel@tonic-gate 			if (opt == NULL) {
1866*7c478bd9Sstevel@tonic-gate 				/* The len/off falls outside mp */
1867*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1868*7c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
1869*7c478bd9Sstevel@tonic-gate 				soseterror(so, EPROTO);
1870*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
1871*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1872*7c478bd9Sstevel@tonic-gate 				    "sockfs: T_unidata_ind with invalid "
1873*7c478bd9Sstevel@tonic-gate 				    "optlen/offset %u/%d\n",
1874*7c478bd9Sstevel@tonic-gate 				    optlen, tudi->OPT_offset);
1875*7c478bd9Sstevel@tonic-gate 				return (NULL);
1876*7c478bd9Sstevel@tonic-gate 			}
1877*7c478bd9Sstevel@tonic-gate 			/*
1878*7c478bd9Sstevel@tonic-gate 			 * If we received a unix close indication mark the
1879*7c478bd9Sstevel@tonic-gate 			 * socket and discard this message.
1880*7c478bd9Sstevel@tonic-gate 			 */
1881*7c478bd9Sstevel@tonic-gate 			if (so_getopt_unix_close(opt, optlen)) {
1882*7c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
1883*7c478bd9Sstevel@tonic-gate 				sobreakconn(so, ECONNRESET);
1884*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
1885*7c478bd9Sstevel@tonic-gate 				strsetrerror(SOTOV(so), 0, 0, sogetrderr);
1886*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1887*7c478bd9Sstevel@tonic-gate 				*pollwakeups = POLLIN | POLLRDNORM;
1888*7c478bd9Sstevel@tonic-gate 				*allmsgsigs = S_INPUT | S_RDNORM;
1889*7c478bd9Sstevel@tonic-gate 				*wakeups = RSLEEP;
1890*7c478bd9Sstevel@tonic-gate 				return (NULL);
1891*7c478bd9Sstevel@tonic-gate 			}
1892*7c478bd9Sstevel@tonic-gate 		}
1893*7c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
1894*7c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
1895*7c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
1896*7c478bd9Sstevel@tonic-gate 		return (mp);
1897*7c478bd9Sstevel@tonic-gate 	}
1898*7c478bd9Sstevel@tonic-gate 
1899*7c478bd9Sstevel@tonic-gate 	case T_OPTDATA_IND: {
1900*7c478bd9Sstevel@tonic-gate 		struct T_optdata_ind	*tdi = &tpr->optdata_ind;
1901*7c478bd9Sstevel@tonic-gate 
1902*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_optdata_ind)) {
1903*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1904*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_OPTDATA_IND. Len = %ld\n",
1905*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
1906*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1907*7c478bd9Sstevel@tonic-gate 			return (NULL);
1908*7c478bd9Sstevel@tonic-gate 		}
1909*7c478bd9Sstevel@tonic-gate 		/*
1910*7c478bd9Sstevel@tonic-gate 		 * Allow zero-length messages carrying options.
1911*7c478bd9Sstevel@tonic-gate 		 * This is used when carrying the SO_UNIX_CLOSE option.
1912*7c478bd9Sstevel@tonic-gate 		 */
1913*7c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_UNIX && msgdsize(mp->b_cont) == 0 &&
1914*7c478bd9Sstevel@tonic-gate 		    tdi->OPT_length != 0) {
1915*7c478bd9Sstevel@tonic-gate 			/*
1916*7c478bd9Sstevel@tonic-gate 			 * Attempt to extract AF_UNIX close indication
1917*7c478bd9Sstevel@tonic-gate 			 * from the options. Ignore any other options -
1918*7c478bd9Sstevel@tonic-gate 			 * those are handled once the message is removed
1919*7c478bd9Sstevel@tonic-gate 			 * from the queue.
1920*7c478bd9Sstevel@tonic-gate 			 * The close indication message should not carry data.
1921*7c478bd9Sstevel@tonic-gate 			 */
1922*7c478bd9Sstevel@tonic-gate 			void *opt;
1923*7c478bd9Sstevel@tonic-gate 			t_uscalar_t optlen = tdi->OPT_length;
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 			opt = sogetoff(mp, tdi->OPT_offset,
1926*7c478bd9Sstevel@tonic-gate 				optlen, __TPI_ALIGN_SIZE);
1927*7c478bd9Sstevel@tonic-gate 			if (opt == NULL) {
1928*7c478bd9Sstevel@tonic-gate 				/* The len/off falls outside mp */
1929*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1930*7c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
1931*7c478bd9Sstevel@tonic-gate 				soseterror(so, EPROTO);
1932*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
1933*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1934*7c478bd9Sstevel@tonic-gate 				    "sockfs: T_optdata_ind with invalid "
1935*7c478bd9Sstevel@tonic-gate 				    "optlen/offset %u/%d\n",
1936*7c478bd9Sstevel@tonic-gate 				    optlen, tdi->OPT_offset);
1937*7c478bd9Sstevel@tonic-gate 				return (NULL);
1938*7c478bd9Sstevel@tonic-gate 			}
1939*7c478bd9Sstevel@tonic-gate 			/*
1940*7c478bd9Sstevel@tonic-gate 			 * If we received a close indication mark the
1941*7c478bd9Sstevel@tonic-gate 			 * socket and discard this message.
1942*7c478bd9Sstevel@tonic-gate 			 */
1943*7c478bd9Sstevel@tonic-gate 			if (so_getopt_unix_close(opt, optlen)) {
1944*7c478bd9Sstevel@tonic-gate 				mutex_enter(&so->so_lock);
1945*7c478bd9Sstevel@tonic-gate 				socantsendmore(so);
1946*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
1947*7c478bd9Sstevel@tonic-gate 				strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
1948*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1949*7c478bd9Sstevel@tonic-gate 				return (NULL);
1950*7c478bd9Sstevel@tonic-gate 			}
1951*7c478bd9Sstevel@tonic-gate 		}
1952*7c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
1953*7c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
1954*7c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
1955*7c478bd9Sstevel@tonic-gate 		return (mp);
1956*7c478bd9Sstevel@tonic-gate 	}
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 	case T_EXDATA_IND: {
1959*7c478bd9Sstevel@tonic-gate 		mblk_t		*mctl, *mdata;
1960*7c478bd9Sstevel@tonic-gate 
1961*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_exdata_ind)) {
1962*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1963*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_EXDATA_IND. Len = %ld\n",
1964*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
1965*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1966*7c478bd9Sstevel@tonic-gate 			return (NULL);
1967*7c478bd9Sstevel@tonic-gate 		}
1968*7c478bd9Sstevel@tonic-gate 		/*
1969*7c478bd9Sstevel@tonic-gate 		 * Ignore zero-length T_EXDATA_IND messages. These might be
1970*7c478bd9Sstevel@tonic-gate 		 * generated by some transports.
1971*7c478bd9Sstevel@tonic-gate 		 *
1972*7c478bd9Sstevel@tonic-gate 		 * This is needed to prevent read (which skips the M_PROTO
1973*7c478bd9Sstevel@tonic-gate 		 * part) to unexpectedly return 0 (or return EWOULDBLOCK
1974*7c478bd9Sstevel@tonic-gate 		 * on a non-blocking socket after select/poll has indicated
1975*7c478bd9Sstevel@tonic-gate 		 * that data is available).
1976*7c478bd9Sstevel@tonic-gate 		 */
1977*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1,
1978*7c478bd9Sstevel@tonic-gate 			("T_EXDATA_IND(%p): counts %d/%d state %s\n",
1979*7c478bd9Sstevel@tonic-gate 			vp, so->so_oobsigcnt, so->so_oobcnt,
1980*7c478bd9Sstevel@tonic-gate 			pr_state(so->so_state, so->so_mode)));
1981*7c478bd9Sstevel@tonic-gate 
1982*7c478bd9Sstevel@tonic-gate 		if (msgdsize(mp->b_cont) == 0) {
1983*7c478bd9Sstevel@tonic-gate 			dprintso(so, 0,
1984*7c478bd9Sstevel@tonic-gate 				("strsock_proto: zero length T_EXDATA_IND\n"));
1985*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1986*7c478bd9Sstevel@tonic-gate 			return (NULL);
1987*7c478bd9Sstevel@tonic-gate 		}
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 		/*
1990*7c478bd9Sstevel@tonic-gate 		 * Split into the T_EXDATA_IND and the M_DATA part.
1991*7c478bd9Sstevel@tonic-gate 		 * We process these three pieces separately:
1992*7c478bd9Sstevel@tonic-gate 		 *	signal generation
1993*7c478bd9Sstevel@tonic-gate 		 *	handling T_EXDATA_IND
1994*7c478bd9Sstevel@tonic-gate 		 *	handling M_DATA component
1995*7c478bd9Sstevel@tonic-gate 		 */
1996*7c478bd9Sstevel@tonic-gate 		mctl = mp;
1997*7c478bd9Sstevel@tonic-gate 		mdata = mctl->b_cont;
1998*7c478bd9Sstevel@tonic-gate 		mctl->b_cont = NULL;
1999*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2000*7c478bd9Sstevel@tonic-gate 		so_oob_sig(so, 0, allmsgsigs, pollwakeups);
2001*7c478bd9Sstevel@tonic-gate 		mctl = so_oob_exdata(so, mctl, allmsgsigs, pollwakeups);
2002*7c478bd9Sstevel@tonic-gate 		mdata = so_oob_data(so, mdata, allmsgsigs, pollwakeups);
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 		/*
2005*7c478bd9Sstevel@tonic-gate 		 * Pass the T_EXDATA_IND and the M_DATA back separately
2006*7c478bd9Sstevel@tonic-gate 		 * by using b_next linkage. (The stream head will queue any
2007*7c478bd9Sstevel@tonic-gate 		 * b_next linked messages separately.) This is needed
2008*7c478bd9Sstevel@tonic-gate 		 * since MSGMARK applies to the last by of the message
2009*7c478bd9Sstevel@tonic-gate 		 * hence we can not have any M_DATA component attached
2010*7c478bd9Sstevel@tonic-gate 		 * to the marked T_EXDATA_IND. Note that the stream head
2011*7c478bd9Sstevel@tonic-gate 		 * will not consolidate M_DATA messages onto an MSGMARK'ed
2012*7c478bd9Sstevel@tonic-gate 		 * message in order to preserve the constraint that
2013*7c478bd9Sstevel@tonic-gate 		 * the T_EXDATA_IND always is a separate message.
2014*7c478bd9Sstevel@tonic-gate 		 */
2015*7c478bd9Sstevel@tonic-gate 		ASSERT(mctl != NULL);
2016*7c478bd9Sstevel@tonic-gate 		mctl->b_next = mdata;
2017*7c478bd9Sstevel@tonic-gate 		mp = mctl;
2018*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2019*7c478bd9Sstevel@tonic-gate 		if (mdata == NULL) {
2020*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2021*7c478bd9Sstevel@tonic-gate 				("after outofline T_EXDATA_IND(%p): "
2022*7c478bd9Sstevel@tonic-gate 				"counts %d/%d  poll 0x%x sig 0x%x state %s\n",
2023*7c478bd9Sstevel@tonic-gate 				vp, so->so_oobsigcnt,
2024*7c478bd9Sstevel@tonic-gate 				so->so_oobcnt, *pollwakeups, *allmsgsigs,
2025*7c478bd9Sstevel@tonic-gate 				pr_state(so->so_state, so->so_mode)));
2026*7c478bd9Sstevel@tonic-gate 		} else {
2027*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2028*7c478bd9Sstevel@tonic-gate 				("after inline T_EXDATA_IND(%p): "
2029*7c478bd9Sstevel@tonic-gate 				"counts %d/%d  poll 0x%x sig 0x%x state %s\n",
2030*7c478bd9Sstevel@tonic-gate 				vp, so->so_oobsigcnt,
2031*7c478bd9Sstevel@tonic-gate 				so->so_oobcnt, *pollwakeups, *allmsgsigs,
2032*7c478bd9Sstevel@tonic-gate 				pr_state(so->so_state, so->so_mode)));
2033*7c478bd9Sstevel@tonic-gate 		}
2034*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2035*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2036*7c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
2037*7c478bd9Sstevel@tonic-gate 		return (mp);
2038*7c478bd9Sstevel@tonic-gate 	}
2039*7c478bd9Sstevel@tonic-gate 
2040*7c478bd9Sstevel@tonic-gate 	case T_CONN_CON: {
2041*7c478bd9Sstevel@tonic-gate 		struct T_conn_con	*conn_con;
2042*7c478bd9Sstevel@tonic-gate 		void			*addr;
2043*7c478bd9Sstevel@tonic-gate 		t_uscalar_t		addrlen;
2044*7c478bd9Sstevel@tonic-gate 
2045*7c478bd9Sstevel@tonic-gate 		/*
2046*7c478bd9Sstevel@tonic-gate 		 * Verify the state, update the state to ISCONNECTED,
2047*7c478bd9Sstevel@tonic-gate 		 * record the potentially new address in the message,
2048*7c478bd9Sstevel@tonic-gate 		 * and drop the message.
2049*7c478bd9Sstevel@tonic-gate 		 */
2050*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_conn_con)) {
2051*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2052*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_CONN_CON. Len = %ld\n",
2053*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2054*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2055*7c478bd9Sstevel@tonic-gate 			return (NULL);
2056*7c478bd9Sstevel@tonic-gate 		}
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2059*7c478bd9Sstevel@tonic-gate 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) !=
2060*7c478bd9Sstevel@tonic-gate 		    SS_ISCONNECTING) {
2061*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2062*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2063*7c478bd9Sstevel@tonic-gate 				("T_CONN_CON: state %x\n", so->so_state));
2064*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2065*7c478bd9Sstevel@tonic-gate 			return (NULL);
2066*7c478bd9Sstevel@tonic-gate 		}
2067*7c478bd9Sstevel@tonic-gate 
2068*7c478bd9Sstevel@tonic-gate 		conn_con = &tpr->conn_con;
2069*7c478bd9Sstevel@tonic-gate 		addrlen = conn_con->RES_length;
2070*7c478bd9Sstevel@tonic-gate 		/*
2071*7c478bd9Sstevel@tonic-gate 		 * Allow the address to be of different size than sent down
2072*7c478bd9Sstevel@tonic-gate 		 * in the T_CONN_REQ as long as it doesn't exceed the maxlen.
2073*7c478bd9Sstevel@tonic-gate 		 * For AF_UNIX require the identical length.
2074*7c478bd9Sstevel@tonic-gate 		 */
2075*7c478bd9Sstevel@tonic-gate 		if (so->so_family == AF_UNIX ?
2076*7c478bd9Sstevel@tonic-gate 		    addrlen != (t_uscalar_t)sizeof (so->so_ux_laddr) :
2077*7c478bd9Sstevel@tonic-gate 		    addrlen > (t_uscalar_t)so->so_faddr_maxlen) {
2078*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2079*7c478bd9Sstevel@tonic-gate 			    "sockfs: T_conn_con with different "
2080*7c478bd9Sstevel@tonic-gate 			    "length %u/%d\n",
2081*7c478bd9Sstevel@tonic-gate 			    addrlen, conn_con->RES_length);
2082*7c478bd9Sstevel@tonic-gate 			soisdisconnected(so, EPROTO);
2083*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2084*7c478bd9Sstevel@tonic-gate 			strsetrerror(SOTOV(so), 0, 0, sogetrderr);
2085*7c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
2086*7c478bd9Sstevel@tonic-gate 			strseteof(SOTOV(so), 1);
2087*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2088*7c478bd9Sstevel@tonic-gate 			/*
2089*7c478bd9Sstevel@tonic-gate 			 * strseteof takes care of read side wakeups,
2090*7c478bd9Sstevel@tonic-gate 			 * pollwakeups, and signals.
2091*7c478bd9Sstevel@tonic-gate 			 */
2092*7c478bd9Sstevel@tonic-gate 			*wakeups = WSLEEP;
2093*7c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_OUTPUT;
2094*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLOUT;
2095*7c478bd9Sstevel@tonic-gate 			return (NULL);
2096*7c478bd9Sstevel@tonic-gate 		}
2097*7c478bd9Sstevel@tonic-gate 		addr = sogetoff(mp, conn_con->RES_offset, addrlen, 1);
2098*7c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
2099*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2100*7c478bd9Sstevel@tonic-gate 			    "sockfs: T_conn_con with invalid "
2101*7c478bd9Sstevel@tonic-gate 			    "addrlen/offset %u/%d\n",
2102*7c478bd9Sstevel@tonic-gate 			    addrlen, conn_con->RES_offset);
2103*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2104*7c478bd9Sstevel@tonic-gate 			strsetrerror(SOTOV(so), 0, 0, sogetrderr);
2105*7c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
2106*7c478bd9Sstevel@tonic-gate 			strseteof(SOTOV(so), 1);
2107*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2108*7c478bd9Sstevel@tonic-gate 			/*
2109*7c478bd9Sstevel@tonic-gate 			 * strseteof takes care of read side wakeups,
2110*7c478bd9Sstevel@tonic-gate 			 * pollwakeups, and signals.
2111*7c478bd9Sstevel@tonic-gate 			 */
2112*7c478bd9Sstevel@tonic-gate 			*wakeups = WSLEEP;
2113*7c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_OUTPUT;
2114*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLOUT;
2115*7c478bd9Sstevel@tonic-gate 			return (NULL);
2116*7c478bd9Sstevel@tonic-gate 		}
2117*7c478bd9Sstevel@tonic-gate 
2118*7c478bd9Sstevel@tonic-gate 		/*
2119*7c478bd9Sstevel@tonic-gate 		 * Save for getpeername.
2120*7c478bd9Sstevel@tonic-gate 		 */
2121*7c478bd9Sstevel@tonic-gate 		if (so->so_family != AF_UNIX) {
2122*7c478bd9Sstevel@tonic-gate 			so->so_faddr_len = (socklen_t)addrlen;
2123*7c478bd9Sstevel@tonic-gate 			ASSERT(so->so_faddr_len <= so->so_faddr_maxlen);
2124*7c478bd9Sstevel@tonic-gate 			bcopy(addr, so->so_faddr_sa, addrlen);
2125*7c478bd9Sstevel@tonic-gate 			so->so_state |= SS_FADDR_VALID;
2126*7c478bd9Sstevel@tonic-gate 		}
2127*7c478bd9Sstevel@tonic-gate 
2128*7c478bd9Sstevel@tonic-gate 		if (so->so_peercred != NULL)
2129*7c478bd9Sstevel@tonic-gate 			crfree(so->so_peercred);
2130*7c478bd9Sstevel@tonic-gate 		so->so_peercred = DB_CRED(mp);
2131*7c478bd9Sstevel@tonic-gate 		so->so_cpid = DB_CPID(mp);
2132*7c478bd9Sstevel@tonic-gate 		if (so->so_peercred != NULL)
2133*7c478bd9Sstevel@tonic-gate 			crhold(so->so_peercred);
2134*7c478bd9Sstevel@tonic-gate 
2135*7c478bd9Sstevel@tonic-gate 		/* Wakeup anybody sleeping in sowaitconnected */
2136*7c478bd9Sstevel@tonic-gate 		soisconnected(so);
2137*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2138*7c478bd9Sstevel@tonic-gate 
2139*7c478bd9Sstevel@tonic-gate 		/*
2140*7c478bd9Sstevel@tonic-gate 		 * The socket is now available for sending data.
2141*7c478bd9Sstevel@tonic-gate 		 */
2142*7c478bd9Sstevel@tonic-gate 		*wakeups = WSLEEP;
2143*7c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_OUTPUT;
2144*7c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLOUT;
2145*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2146*7c478bd9Sstevel@tonic-gate 		return (NULL);
2147*7c478bd9Sstevel@tonic-gate 	}
2148*7c478bd9Sstevel@tonic-gate 
2149*7c478bd9Sstevel@tonic-gate 	case T_CONN_IND:
2150*7c478bd9Sstevel@tonic-gate 		/*
2151*7c478bd9Sstevel@tonic-gate 		 * Verify the min size and queue the message on
2152*7c478bd9Sstevel@tonic-gate 		 * the so_conn_ind_head/tail list.
2153*7c478bd9Sstevel@tonic-gate 		 */
2154*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_conn_ind)) {
2155*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2156*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_CONN_IND. Len = %ld\n",
2157*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2158*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2159*7c478bd9Sstevel@tonic-gate 			return (NULL);
2160*7c478bd9Sstevel@tonic-gate 		}
2161*7c478bd9Sstevel@tonic-gate 
2162*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
2163*7c478bd9Sstevel@tonic-gate 		if (audit_active)
2164*7c478bd9Sstevel@tonic-gate 			audit_sock(T_CONN_IND, strvp2wq(vp), mp, 0);
2165*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */
2166*7c478bd9Sstevel@tonic-gate 		if (!(so->so_state & SS_ACCEPTCONN)) {
2167*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2168*7c478bd9Sstevel@tonic-gate 			    "sockfs: T_conn_ind on non-listening socket\n");
2169*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2170*7c478bd9Sstevel@tonic-gate 			return (NULL);
2171*7c478bd9Sstevel@tonic-gate 		}
2172*7c478bd9Sstevel@tonic-gate 		soqueueconnind(so, mp);
2173*7c478bd9Sstevel@tonic-gate 		*allmsgsigs = S_INPUT | S_RDNORM;
2174*7c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLIN | POLLRDNORM;
2175*7c478bd9Sstevel@tonic-gate 		*wakeups = RSLEEP;
2176*7c478bd9Sstevel@tonic-gate 		return (NULL);
2177*7c478bd9Sstevel@tonic-gate 
2178*7c478bd9Sstevel@tonic-gate 	case T_ORDREL_IND:
2179*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_ordrel_ind)) {
2180*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2181*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_ORDREL_IND. Len = %ld\n",
2182*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2183*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2184*7c478bd9Sstevel@tonic-gate 			return (NULL);
2185*7c478bd9Sstevel@tonic-gate 		}
2186*7c478bd9Sstevel@tonic-gate 
2187*7c478bd9Sstevel@tonic-gate 		/*
2188*7c478bd9Sstevel@tonic-gate 		 * Some providers send this when not fully connected.
2189*7c478bd9Sstevel@tonic-gate 		 * SunLink X.25 needs to retrieve disconnect reason after
2190*7c478bd9Sstevel@tonic-gate 		 * disconnect for compatibility. It uses T_ORDREL_IND
2191*7c478bd9Sstevel@tonic-gate 		 * instead of T_DISCON_IND so that it may use the
2192*7c478bd9Sstevel@tonic-gate 		 * endpoint after a connect failure to retrieve the
2193*7c478bd9Sstevel@tonic-gate 		 * reason using an ioctl. Thus we explicitly clear
2194*7c478bd9Sstevel@tonic-gate 		 * SS_ISCONNECTING here for SunLink X.25.
2195*7c478bd9Sstevel@tonic-gate 		 * This is a needed TPI violation.
2196*7c478bd9Sstevel@tonic-gate 		 */
2197*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2198*7c478bd9Sstevel@tonic-gate 		so->so_state &= ~SS_ISCONNECTING;
2199*7c478bd9Sstevel@tonic-gate 		socantrcvmore(so);
2200*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2201*7c478bd9Sstevel@tonic-gate 		strseteof(SOTOV(so), 1);
2202*7c478bd9Sstevel@tonic-gate 		/*
2203*7c478bd9Sstevel@tonic-gate 		 * strseteof takes care of read side wakeups,
2204*7c478bd9Sstevel@tonic-gate 		 * pollwakeups, and signals.
2205*7c478bd9Sstevel@tonic-gate 		 */
2206*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2207*7c478bd9Sstevel@tonic-gate 		return (NULL);
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate 	case T_DISCON_IND:
2210*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_discon_ind)) {
2211*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2212*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_DISCON_IND. Len = %ld\n",
2213*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2214*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2215*7c478bd9Sstevel@tonic-gate 			return (NULL);
2216*7c478bd9Sstevel@tonic-gate 		}
2217*7c478bd9Sstevel@tonic-gate 		if (so->so_state & SS_ACCEPTCONN) {
2218*7c478bd9Sstevel@tonic-gate 			/*
2219*7c478bd9Sstevel@tonic-gate 			 * This is a listener. Look for a queued T_CONN_IND
2220*7c478bd9Sstevel@tonic-gate 			 * with a matching sequence number and remove it
2221*7c478bd9Sstevel@tonic-gate 			 * from the list.
2222*7c478bd9Sstevel@tonic-gate 			 * It is normal to not find the sequence number since
2223*7c478bd9Sstevel@tonic-gate 			 * the soaccept might have already dequeued it
2224*7c478bd9Sstevel@tonic-gate 			 * (in which case the T_CONN_RES will fail with
2225*7c478bd9Sstevel@tonic-gate 			 * TBADSEQ).
2226*7c478bd9Sstevel@tonic-gate 			 */
2227*7c478bd9Sstevel@tonic-gate 			(void) soflushconnind(so, tpr->discon_ind.SEQ_number);
2228*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2229*7c478bd9Sstevel@tonic-gate 			return (0);
2230*7c478bd9Sstevel@tonic-gate 		}
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 		/*
2233*7c478bd9Sstevel@tonic-gate 		 * Not a listener
2234*7c478bd9Sstevel@tonic-gate 		 *
2235*7c478bd9Sstevel@tonic-gate 		 * If SS_CANTRCVMORE for AF_UNIX ignore the discon_reason.
2236*7c478bd9Sstevel@tonic-gate 		 * Such a discon_ind appears when the peer has first done
2237*7c478bd9Sstevel@tonic-gate 		 * a shutdown() followed by a close() in which case we just
2238*7c478bd9Sstevel@tonic-gate 		 * want to record socantsendmore.
2239*7c478bd9Sstevel@tonic-gate 		 * In this case sockfs first receives a T_ORDREL_IND followed
2240*7c478bd9Sstevel@tonic-gate 		 * by a T_DISCON_IND.
2241*7c478bd9Sstevel@tonic-gate 		 * Note that for other transports (e.g. TCP) we need to handle
2242*7c478bd9Sstevel@tonic-gate 		 * the discon_ind in this case since it signals an error.
2243*7c478bd9Sstevel@tonic-gate 		 */
2244*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2245*7c478bd9Sstevel@tonic-gate 		if ((so->so_state & SS_CANTRCVMORE) &&
2246*7c478bd9Sstevel@tonic-gate 		    (so->so_family == AF_UNIX)) {
2247*7c478bd9Sstevel@tonic-gate 			socantsendmore(so);
2248*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2249*7c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
2250*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2251*7c478bd9Sstevel@tonic-gate 				("T_DISCON_IND: error %d\n", so->so_error));
2252*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2253*7c478bd9Sstevel@tonic-gate 			/*
2254*7c478bd9Sstevel@tonic-gate 			 * Set these variables for caller to process them.
2255*7c478bd9Sstevel@tonic-gate 			 * For the else part where T_DISCON_IND is processed,
2256*7c478bd9Sstevel@tonic-gate 			 * this will be done in the function being called
2257*7c478bd9Sstevel@tonic-gate 			 * (strsock_discon_ind())
2258*7c478bd9Sstevel@tonic-gate 			 */
2259*7c478bd9Sstevel@tonic-gate 			*wakeups = WSLEEP;
2260*7c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_OUTPUT;
2261*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLOUT;
2262*7c478bd9Sstevel@tonic-gate 		} else if (so->so_flag & (SOASYNC_UNBIND | SOLOCKED)) {
2263*7c478bd9Sstevel@tonic-gate 			/*
2264*7c478bd9Sstevel@tonic-gate 			 * Deferred processing of T_DISCON_IND
2265*7c478bd9Sstevel@tonic-gate 			 */
2266*7c478bd9Sstevel@tonic-gate 			so_save_discon_ind(so, mp, strsock_discon_ind);
2267*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2268*7c478bd9Sstevel@tonic-gate 		} else {
2269*7c478bd9Sstevel@tonic-gate 			/*
2270*7c478bd9Sstevel@tonic-gate 			 * Process T_DISCON_IND now
2271*7c478bd9Sstevel@tonic-gate 			 */
2272*7c478bd9Sstevel@tonic-gate 			(void) strsock_discon_ind(so, mp);
2273*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2274*7c478bd9Sstevel@tonic-gate 		}
2275*7c478bd9Sstevel@tonic-gate 		return (NULL);
2276*7c478bd9Sstevel@tonic-gate 
2277*7c478bd9Sstevel@tonic-gate 	case T_UDERROR_IND: {
2278*7c478bd9Sstevel@tonic-gate 		struct T_uderror_ind	*tudi = &tpr->uderror_ind;
2279*7c478bd9Sstevel@tonic-gate 		void			*addr;
2280*7c478bd9Sstevel@tonic-gate 		t_uscalar_t		addrlen;
2281*7c478bd9Sstevel@tonic-gate 		int			error;
2282*7c478bd9Sstevel@tonic-gate 
2283*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
2284*7c478bd9Sstevel@tonic-gate 			("T_UDERROR_IND: error %d\n", tudi->ERROR_type));
2285*7c478bd9Sstevel@tonic-gate 
2286*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_uderror_ind)) {
2287*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2288*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_UDERROR_IND. Len = %ld\n",
2289*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2290*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2291*7c478bd9Sstevel@tonic-gate 			return (NULL);
2292*7c478bd9Sstevel@tonic-gate 		}
2293*7c478bd9Sstevel@tonic-gate 		/* Ignore on connection-oriented transports */
2294*7c478bd9Sstevel@tonic-gate 		if (so->so_mode & SM_CONNREQUIRED) {
2295*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2296*7c478bd9Sstevel@tonic-gate 			eprintsoline(so, 0);
2297*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2298*7c478bd9Sstevel@tonic-gate 			    "sockfs: T_uderror_ind on connection-oriented "
2299*7c478bd9Sstevel@tonic-gate 			    "transport\n");
2300*7c478bd9Sstevel@tonic-gate 			return (NULL);
2301*7c478bd9Sstevel@tonic-gate 		}
2302*7c478bd9Sstevel@tonic-gate 		addrlen = tudi->DEST_length;
2303*7c478bd9Sstevel@tonic-gate 		addr = sogetoff(mp, tudi->DEST_offset, addrlen, 1);
2304*7c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
2305*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2306*7c478bd9Sstevel@tonic-gate 			    "sockfs: T_uderror_ind with invalid "
2307*7c478bd9Sstevel@tonic-gate 			    "addrlen/offset %u/%d\n",
2308*7c478bd9Sstevel@tonic-gate 			    addrlen, tudi->DEST_offset);
2309*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2310*7c478bd9Sstevel@tonic-gate 			return (NULL);
2311*7c478bd9Sstevel@tonic-gate 		}
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate 		/* Verify source address for connected socket. */
2314*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2315*7c478bd9Sstevel@tonic-gate 		if (so->so_state & SS_ISCONNECTED) {
2316*7c478bd9Sstevel@tonic-gate 			void *faddr;
2317*7c478bd9Sstevel@tonic-gate 			t_uscalar_t faddr_len;
2318*7c478bd9Sstevel@tonic-gate 			boolean_t match = B_FALSE;
2319*7c478bd9Sstevel@tonic-gate 
2320*7c478bd9Sstevel@tonic-gate 			switch (so->so_family) {
2321*7c478bd9Sstevel@tonic-gate 			case AF_INET: {
2322*7c478bd9Sstevel@tonic-gate 				/* Compare just IP address and port */
2323*7c478bd9Sstevel@tonic-gate 				struct sockaddr_in *sin1, *sin2;
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate 				sin1 = (struct sockaddr_in *)so->so_faddr_sa;
2326*7c478bd9Sstevel@tonic-gate 				sin2 = (struct sockaddr_in *)addr;
2327*7c478bd9Sstevel@tonic-gate 				if (addrlen == sizeof (struct sockaddr_in) &&
2328*7c478bd9Sstevel@tonic-gate 				    sin1->sin_port == sin2->sin_port &&
2329*7c478bd9Sstevel@tonic-gate 				    sin1->sin_addr.s_addr ==
2330*7c478bd9Sstevel@tonic-gate 				    sin2->sin_addr.s_addr)
2331*7c478bd9Sstevel@tonic-gate 					match = B_TRUE;
2332*7c478bd9Sstevel@tonic-gate 				break;
2333*7c478bd9Sstevel@tonic-gate 			}
2334*7c478bd9Sstevel@tonic-gate 			case AF_INET6: {
2335*7c478bd9Sstevel@tonic-gate 				/* Compare just IP address and port. Not flow */
2336*7c478bd9Sstevel@tonic-gate 				struct sockaddr_in6 *sin1, *sin2;
2337*7c478bd9Sstevel@tonic-gate 
2338*7c478bd9Sstevel@tonic-gate 				sin1 = (struct sockaddr_in6 *)so->so_faddr_sa;
2339*7c478bd9Sstevel@tonic-gate 				sin2 = (struct sockaddr_in6 *)addr;
2340*7c478bd9Sstevel@tonic-gate 				if (addrlen == sizeof (struct sockaddr_in6) &&
2341*7c478bd9Sstevel@tonic-gate 				    sin1->sin6_port == sin2->sin6_port &&
2342*7c478bd9Sstevel@tonic-gate 				    IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr,
2343*7c478bd9Sstevel@tonic-gate 					&sin2->sin6_addr))
2344*7c478bd9Sstevel@tonic-gate 					match = B_TRUE;
2345*7c478bd9Sstevel@tonic-gate 				break;
2346*7c478bd9Sstevel@tonic-gate 			}
2347*7c478bd9Sstevel@tonic-gate 			case AF_UNIX:
2348*7c478bd9Sstevel@tonic-gate 				faddr = &so->so_ux_faddr;
2349*7c478bd9Sstevel@tonic-gate 				faddr_len =
2350*7c478bd9Sstevel@tonic-gate 					(t_uscalar_t)sizeof (so->so_ux_faddr);
2351*7c478bd9Sstevel@tonic-gate 				if (faddr_len == addrlen &&
2352*7c478bd9Sstevel@tonic-gate 				    bcmp(addr, faddr, addrlen) == 0)
2353*7c478bd9Sstevel@tonic-gate 					match = B_TRUE;
2354*7c478bd9Sstevel@tonic-gate 				break;
2355*7c478bd9Sstevel@tonic-gate 			default:
2356*7c478bd9Sstevel@tonic-gate 				faddr = so->so_faddr_sa;
2357*7c478bd9Sstevel@tonic-gate 				faddr_len = (t_uscalar_t)so->so_faddr_len;
2358*7c478bd9Sstevel@tonic-gate 				if (faddr_len == addrlen &&
2359*7c478bd9Sstevel@tonic-gate 				    bcmp(addr, faddr, addrlen) == 0)
2360*7c478bd9Sstevel@tonic-gate 					match = B_TRUE;
2361*7c478bd9Sstevel@tonic-gate 				break;
2362*7c478bd9Sstevel@tonic-gate 			}
2363*7c478bd9Sstevel@tonic-gate 
2364*7c478bd9Sstevel@tonic-gate 			if (!match) {
2365*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2366*7c478bd9Sstevel@tonic-gate 				dprintso(so, 0,
2367*7c478bd9Sstevel@tonic-gate 					("sockfs: T_UDERR_IND mismatch: %s - ",
2368*7c478bd9Sstevel@tonic-gate 					pr_addr(so->so_family,
2369*7c478bd9Sstevel@tonic-gate 						(struct sockaddr *)addr,
2370*7c478bd9Sstevel@tonic-gate 						addrlen)));
2371*7c478bd9Sstevel@tonic-gate 				dprintso(so, 0, ("%s\n",
2372*7c478bd9Sstevel@tonic-gate 					pr_addr(so->so_family, so->so_faddr_sa,
2373*7c478bd9Sstevel@tonic-gate 						so->so_faddr_len)));
2374*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2375*7c478bd9Sstevel@tonic-gate 				mutex_exit(&so->so_lock);
2376*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
2377*7c478bd9Sstevel@tonic-gate 				return (NULL);
2378*7c478bd9Sstevel@tonic-gate 			}
2379*7c478bd9Sstevel@tonic-gate 			/*
2380*7c478bd9Sstevel@tonic-gate 			 * Make the write error nonpersistent. If the error
2381*7c478bd9Sstevel@tonic-gate 			 * is zero we use ECONNRESET.
2382*7c478bd9Sstevel@tonic-gate 			 * This assumes that the name space for ERROR_type
2383*7c478bd9Sstevel@tonic-gate 			 * is the errno name space.
2384*7c478bd9Sstevel@tonic-gate 			 */
2385*7c478bd9Sstevel@tonic-gate 			if (tudi->ERROR_type != 0)
2386*7c478bd9Sstevel@tonic-gate 				error = tudi->ERROR_type;
2387*7c478bd9Sstevel@tonic-gate 			else
2388*7c478bd9Sstevel@tonic-gate 				error = ECONNRESET;
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 			soseterror(so, error);
2391*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2392*7c478bd9Sstevel@tonic-gate 			strsetrerror(SOTOV(so), 0, 0, sogetrderr);
2393*7c478bd9Sstevel@tonic-gate 			strsetwerror(SOTOV(so), 0, 0, sogetwrerr);
2394*7c478bd9Sstevel@tonic-gate 			*wakeups = RSLEEP | WSLEEP;
2395*7c478bd9Sstevel@tonic-gate 			*allmsgsigs = S_INPUT | S_RDNORM | S_OUTPUT;
2396*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM | POLLOUT;
2397*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2398*7c478bd9Sstevel@tonic-gate 			return (NULL);
2399*7c478bd9Sstevel@tonic-gate 		}
2400*7c478bd9Sstevel@tonic-gate 		/*
2401*7c478bd9Sstevel@tonic-gate 		 * If the application asked for delayed errors
2402*7c478bd9Sstevel@tonic-gate 		 * record the T_UDERROR_IND so_eaddr_mp and the reason in
2403*7c478bd9Sstevel@tonic-gate 		 * so_delayed_error for delayed error posting. If the reason
2404*7c478bd9Sstevel@tonic-gate 		 * is zero use ECONNRESET.
2405*7c478bd9Sstevel@tonic-gate 		 * Note that delayed error indications do not make sense for
2406*7c478bd9Sstevel@tonic-gate 		 * AF_UNIX sockets since sendto checks that the destination
2407*7c478bd9Sstevel@tonic-gate 		 * address is valid at the time of the sendto.
2408*7c478bd9Sstevel@tonic-gate 		 */
2409*7c478bd9Sstevel@tonic-gate 		if (!(so->so_options & SO_DGRAM_ERRIND)) {
2410*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2411*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2412*7c478bd9Sstevel@tonic-gate 			return (NULL);
2413*7c478bd9Sstevel@tonic-gate 		}
2414*7c478bd9Sstevel@tonic-gate 		if (so->so_eaddr_mp != NULL)
2415*7c478bd9Sstevel@tonic-gate 			freemsg(so->so_eaddr_mp);
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 		so->so_eaddr_mp = mp;
2418*7c478bd9Sstevel@tonic-gate 		if (tudi->ERROR_type != 0)
2419*7c478bd9Sstevel@tonic-gate 			error = tudi->ERROR_type;
2420*7c478bd9Sstevel@tonic-gate 		else
2421*7c478bd9Sstevel@tonic-gate 			error = ECONNRESET;
2422*7c478bd9Sstevel@tonic-gate 		so->so_delayed_error = (ushort_t)error;
2423*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2424*7c478bd9Sstevel@tonic-gate 		return (NULL);
2425*7c478bd9Sstevel@tonic-gate 	}
2426*7c478bd9Sstevel@tonic-gate 
2427*7c478bd9Sstevel@tonic-gate 	case T_ERROR_ACK:
2428*7c478bd9Sstevel@tonic-gate 		dprintso(so, 0,
2429*7c478bd9Sstevel@tonic-gate 			("strsock_proto: T_ERROR_ACK for %d, error %d/%d\n",
2430*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.ERROR_prim,
2431*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.TLI_error,
2432*7c478bd9Sstevel@tonic-gate 			tpr->error_ack.UNIX_error));
2433*7c478bd9Sstevel@tonic-gate 
2434*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_error_ack)) {
2435*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2436*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_ERROR_ACK. Len = %ld\n",
2437*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2438*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2439*7c478bd9Sstevel@tonic-gate 			return (NULL);
2440*7c478bd9Sstevel@tonic-gate 		}
2441*7c478bd9Sstevel@tonic-gate 		/*
2442*7c478bd9Sstevel@tonic-gate 		 * Check if we were waiting for the async message
2443*7c478bd9Sstevel@tonic-gate 		 */
2444*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2445*7c478bd9Sstevel@tonic-gate 		if ((so->so_flag & SOASYNC_UNBIND) &&
2446*7c478bd9Sstevel@tonic-gate 		    tpr->error_ack.ERROR_prim == T_UNBIND_REQ) {
2447*7c478bd9Sstevel@tonic-gate 			so_unlock_single(so, SOASYNC_UNBIND);
2448*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2449*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2450*7c478bd9Sstevel@tonic-gate 			return (NULL);
2451*7c478bd9Sstevel@tonic-gate 		}
2452*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2453*7c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
2454*7c478bd9Sstevel@tonic-gate 		return (NULL);
2455*7c478bd9Sstevel@tonic-gate 
2456*7c478bd9Sstevel@tonic-gate 	case T_OK_ACK:
2457*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_ok_ack)) {
2458*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2459*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_OK_ACK. Len = %ld\n",
2460*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2461*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2462*7c478bd9Sstevel@tonic-gate 			return (NULL);
2463*7c478bd9Sstevel@tonic-gate 		}
2464*7c478bd9Sstevel@tonic-gate 		/*
2465*7c478bd9Sstevel@tonic-gate 		 * Check if we were waiting for the async message
2466*7c478bd9Sstevel@tonic-gate 		 */
2467*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2468*7c478bd9Sstevel@tonic-gate 		if ((so->so_flag & SOASYNC_UNBIND) &&
2469*7c478bd9Sstevel@tonic-gate 		    tpr->ok_ack.CORRECT_prim == T_UNBIND_REQ) {
2470*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2471*7c478bd9Sstevel@tonic-gate 				("strsock_proto: T_OK_ACK async unbind\n"));
2472*7c478bd9Sstevel@tonic-gate 			so_unlock_single(so, SOASYNC_UNBIND);
2473*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2474*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2475*7c478bd9Sstevel@tonic-gate 			return (NULL);
2476*7c478bd9Sstevel@tonic-gate 		}
2477*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2478*7c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
2479*7c478bd9Sstevel@tonic-gate 		return (NULL);
2480*7c478bd9Sstevel@tonic-gate 
2481*7c478bd9Sstevel@tonic-gate 	case T_INFO_ACK:
2482*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_info_ack)) {
2483*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2484*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_INFO_ACK. Len = %ld\n",
2485*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2486*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2487*7c478bd9Sstevel@tonic-gate 			return (NULL);
2488*7c478bd9Sstevel@tonic-gate 		}
2489*7c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
2490*7c478bd9Sstevel@tonic-gate 		return (NULL);
2491*7c478bd9Sstevel@tonic-gate 
2492*7c478bd9Sstevel@tonic-gate 	case T_CAPABILITY_ACK:
2493*7c478bd9Sstevel@tonic-gate 		/*
2494*7c478bd9Sstevel@tonic-gate 		 * A T_capability_ack need only be large enough to hold
2495*7c478bd9Sstevel@tonic-gate 		 * the PRIM_type and CAP_bits1 fields; checking for anything
2496*7c478bd9Sstevel@tonic-gate 		 * larger might reject a correct response from an older
2497*7c478bd9Sstevel@tonic-gate 		 * provider.
2498*7c478bd9Sstevel@tonic-gate 		 */
2499*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < 2 * sizeof (t_uscalar_t)) {
2500*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2501*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_CAPABILITY_ACK. Len = %ld\n",
2502*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2503*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2504*7c478bd9Sstevel@tonic-gate 			return (NULL);
2505*7c478bd9Sstevel@tonic-gate 		}
2506*7c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
2507*7c478bd9Sstevel@tonic-gate 		return (NULL);
2508*7c478bd9Sstevel@tonic-gate 
2509*7c478bd9Sstevel@tonic-gate 	case T_BIND_ACK:
2510*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_bind_ack)) {
2511*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2512*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_BIND_ACK. Len = %ld\n",
2513*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2514*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2515*7c478bd9Sstevel@tonic-gate 			return (NULL);
2516*7c478bd9Sstevel@tonic-gate 		}
2517*7c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
2518*7c478bd9Sstevel@tonic-gate 		return (NULL);
2519*7c478bd9Sstevel@tonic-gate 
2520*7c478bd9Sstevel@tonic-gate 	case T_OPTMGMT_ACK:
2521*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct T_optmgmt_ack)) {
2522*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2523*7c478bd9Sstevel@tonic-gate 			    "sockfs: Too short T_OPTMGMT_ACK. Len = %ld\n",
2524*7c478bd9Sstevel@tonic-gate 			    (ptrdiff_t)(MBLKL(mp)));
2525*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2526*7c478bd9Sstevel@tonic-gate 			return (NULL);
2527*7c478bd9Sstevel@tonic-gate 		}
2528*7c478bd9Sstevel@tonic-gate 		soqueueack(so, mp);
2529*7c478bd9Sstevel@tonic-gate 		return (NULL);
2530*7c478bd9Sstevel@tonic-gate 	default:
2531*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2532*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
2533*7c478bd9Sstevel@tonic-gate 			"sockfs: unknown TPI primitive %d received\n",
2534*7c478bd9Sstevel@tonic-gate 			tpr->type);
2535*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2536*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2537*7c478bd9Sstevel@tonic-gate 		return (NULL);
2538*7c478bd9Sstevel@tonic-gate 	}
2539*7c478bd9Sstevel@tonic-gate }
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate /*
2542*7c478bd9Sstevel@tonic-gate  * This routine is registered with the stream head to receive other
2543*7c478bd9Sstevel@tonic-gate  * (non-data, and non-proto) messages.
2544*7c478bd9Sstevel@tonic-gate  *
2545*7c478bd9Sstevel@tonic-gate  * Returns NULL if the message was consumed.
2546*7c478bd9Sstevel@tonic-gate  * Returns an mblk to make that mblk be processed by the stream head.
2547*7c478bd9Sstevel@tonic-gate  *
2548*7c478bd9Sstevel@tonic-gate  * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and
2549*7c478bd9Sstevel@tonic-gate  * *pollwakeups) for the stream head to take action on.
2550*7c478bd9Sstevel@tonic-gate  */
2551*7c478bd9Sstevel@tonic-gate static mblk_t *
2552*7c478bd9Sstevel@tonic-gate strsock_misc(vnode_t *vp, mblk_t *mp,
2553*7c478bd9Sstevel@tonic-gate 		strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
2554*7c478bd9Sstevel@tonic-gate 		strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
2555*7c478bd9Sstevel@tonic-gate {
2556*7c478bd9Sstevel@tonic-gate 	struct sonode *so;
2557*7c478bd9Sstevel@tonic-gate 
2558*7c478bd9Sstevel@tonic-gate 	so = VTOSO(vp);
2559*7c478bd9Sstevel@tonic-gate 
2560*7c478bd9Sstevel@tonic-gate 	dprintso(so, 1, ("strsock_misc(%p, %p, 0x%x)\n",
2561*7c478bd9Sstevel@tonic-gate 			vp, mp, DB_TYPE(mp)));
2562*7c478bd9Sstevel@tonic-gate 
2563*7c478bd9Sstevel@tonic-gate 	/* Set default return values */
2564*7c478bd9Sstevel@tonic-gate 	*wakeups = *allmsgsigs = *firstmsgsigs = *pollwakeups = 0;
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
2567*7c478bd9Sstevel@tonic-gate 	case M_PCSIG:
2568*7c478bd9Sstevel@tonic-gate 		/*
2569*7c478bd9Sstevel@tonic-gate 		 * This assumes that an M_PCSIG for the urgent data arrives
2570*7c478bd9Sstevel@tonic-gate 		 * before the corresponding T_EXDATA_IND.
2571*7c478bd9Sstevel@tonic-gate 		 *
2572*7c478bd9Sstevel@tonic-gate 		 * Note: Just like in SunOS 4.X and 4.4BSD a poll will be
2573*7c478bd9Sstevel@tonic-gate 		 * awoken before the urgent data shows up.
2574*7c478bd9Sstevel@tonic-gate 		 * For OOBINLINE this can result in select returning
2575*7c478bd9Sstevel@tonic-gate 		 * only exceptions as opposed to except|read.
2576*7c478bd9Sstevel@tonic-gate 		 */
2577*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr == SIGURG) {
2578*7c478bd9Sstevel@tonic-gate 			mutex_enter(&so->so_lock);
2579*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2580*7c478bd9Sstevel@tonic-gate 				("SIGURG(%p): counts %d/%d state %s\n",
2581*7c478bd9Sstevel@tonic-gate 				vp, so->so_oobsigcnt,
2582*7c478bd9Sstevel@tonic-gate 				so->so_oobcnt,
2583*7c478bd9Sstevel@tonic-gate 				pr_state(so->so_state, so->so_mode)));
2584*7c478bd9Sstevel@tonic-gate 			so_oob_sig(so, 1, allmsgsigs, pollwakeups);
2585*7c478bd9Sstevel@tonic-gate 			dprintso(so, 1,
2586*7c478bd9Sstevel@tonic-gate 				("after SIGURG(%p): counts %d/%d "
2587*7c478bd9Sstevel@tonic-gate 				" poll 0x%x sig 0x%x state %s\n",
2588*7c478bd9Sstevel@tonic-gate 				vp, so->so_oobsigcnt,
2589*7c478bd9Sstevel@tonic-gate 				so->so_oobcnt, *pollwakeups, *allmsgsigs,
2590*7c478bd9Sstevel@tonic-gate 				pr_state(so->so_state, so->so_mode)));
2591*7c478bd9Sstevel@tonic-gate 			mutex_exit(&so->so_lock);
2592*7c478bd9Sstevel@tonic-gate 		}
2593*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2594*7c478bd9Sstevel@tonic-gate 		return (NULL);
2595*7c478bd9Sstevel@tonic-gate 
2596*7c478bd9Sstevel@tonic-gate 	case M_SIG:
2597*7c478bd9Sstevel@tonic-gate 	case M_HANGUP:
2598*7c478bd9Sstevel@tonic-gate 	case M_UNHANGUP:
2599*7c478bd9Sstevel@tonic-gate 	case M_ERROR:
2600*7c478bd9Sstevel@tonic-gate 		/* M_ERRORs etc are ignored */
2601*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2602*7c478bd9Sstevel@tonic-gate 		return (NULL);
2603*7c478bd9Sstevel@tonic-gate 
2604*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
2605*7c478bd9Sstevel@tonic-gate 		/*
2606*7c478bd9Sstevel@tonic-gate 		 * Do not flush read queue. If the M_FLUSH
2607*7c478bd9Sstevel@tonic-gate 		 * arrives because of an impending T_discon_ind
2608*7c478bd9Sstevel@tonic-gate 		 * we still have to keep any queued data - this is part of
2609*7c478bd9Sstevel@tonic-gate 		 * socket semantics.
2610*7c478bd9Sstevel@tonic-gate 		 */
2611*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
2612*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHR;
2613*7c478bd9Sstevel@tonic-gate 			return (mp);
2614*7c478bd9Sstevel@tonic-gate 		}
2615*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2616*7c478bd9Sstevel@tonic-gate 		return (NULL);
2617*7c478bd9Sstevel@tonic-gate 
2618*7c478bd9Sstevel@tonic-gate 	default:
2619*7c478bd9Sstevel@tonic-gate 		return (mp);
2620*7c478bd9Sstevel@tonic-gate 	}
2621*7c478bd9Sstevel@tonic-gate }
2622*7c478bd9Sstevel@tonic-gate 
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate /* Register to receive signals for certain events */
2625*7c478bd9Sstevel@tonic-gate int
2626*7c478bd9Sstevel@tonic-gate so_set_asyncsigs(vnode_t *vp, pid_t pgrp, int events, int mode, cred_t *cr)
2627*7c478bd9Sstevel@tonic-gate {
2628*7c478bd9Sstevel@tonic-gate 	struct strsigset ss;
2629*7c478bd9Sstevel@tonic-gate 	int32_t rval;
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate 	/*
2632*7c478bd9Sstevel@tonic-gate 	 * Note that SOLOCKED will be set except for the call from soaccept().
2633*7c478bd9Sstevel@tonic-gate 	 */
2634*7c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&VTOSO(vp)->so_lock));
2635*7c478bd9Sstevel@tonic-gate 	ss.ss_pid = pgrp;
2636*7c478bd9Sstevel@tonic-gate 	ss.ss_events = events;
2637*7c478bd9Sstevel@tonic-gate 	return (strioctl(vp, I_ESETSIG, (intptr_t)&ss, mode, K_TO_K, cr,
2638*7c478bd9Sstevel@tonic-gate 	    &rval));
2639*7c478bd9Sstevel@tonic-gate }
2640*7c478bd9Sstevel@tonic-gate 
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate /* Register for events matching the SS_ASYNC flag */
2643*7c478bd9Sstevel@tonic-gate int
2644*7c478bd9Sstevel@tonic-gate so_set_events(struct sonode *so, vnode_t *vp, cred_t *cr)
2645*7c478bd9Sstevel@tonic-gate {
2646*7c478bd9Sstevel@tonic-gate 	int events = so->so_state & SS_ASYNC ?
2647*7c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT :
2648*7c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG;
2649*7c478bd9Sstevel@tonic-gate 
2650*7c478bd9Sstevel@tonic-gate 	return (so_set_asyncsigs(vp, so->so_pgrp, events, 0, cr));
2651*7c478bd9Sstevel@tonic-gate }
2652*7c478bd9Sstevel@tonic-gate 
2653*7c478bd9Sstevel@tonic-gate 
2654*7c478bd9Sstevel@tonic-gate /* Change the SS_ASYNC flag, and update signal delivery if needed */
2655*7c478bd9Sstevel@tonic-gate int
2656*7c478bd9Sstevel@tonic-gate so_flip_async(struct sonode *so, vnode_t *vp, int mode, cred_t *cr)
2657*7c478bd9Sstevel@tonic-gate {
2658*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&so->so_lock));
2659*7c478bd9Sstevel@tonic-gate 	if (so->so_pgrp != 0) {
2660*7c478bd9Sstevel@tonic-gate 		int error;
2661*7c478bd9Sstevel@tonic-gate 		int events = so->so_state & SS_ASYNC ?		/* Old flag */
2662*7c478bd9Sstevel@tonic-gate 		    S_RDBAND | S_BANDURG :			/* New sigs */
2663*7c478bd9Sstevel@tonic-gate 		    S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT;
2664*7c478bd9Sstevel@tonic-gate 
2665*7c478bd9Sstevel@tonic-gate 		so_lock_single(so);
2666*7c478bd9Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
2667*7c478bd9Sstevel@tonic-gate 
2668*7c478bd9Sstevel@tonic-gate 		error = so_set_asyncsigs(vp, so->so_pgrp, events, mode, cr);
2669*7c478bd9Sstevel@tonic-gate 
2670*7c478bd9Sstevel@tonic-gate 		mutex_enter(&so->so_lock);
2671*7c478bd9Sstevel@tonic-gate 		so_unlock_single(so, SOLOCKED);
2672*7c478bd9Sstevel@tonic-gate 		if (error)
2673*7c478bd9Sstevel@tonic-gate 			return (error);
2674*7c478bd9Sstevel@tonic-gate 	}
2675*7c478bd9Sstevel@tonic-gate 	so->so_state ^= SS_ASYNC;
2676*7c478bd9Sstevel@tonic-gate 	return (0);
2677*7c478bd9Sstevel@tonic-gate }
2678*7c478bd9Sstevel@tonic-gate 
2679*7c478bd9Sstevel@tonic-gate /*
2680*7c478bd9Sstevel@tonic-gate  * Set new pid/pgrp for SIGPOLL (or SIGIO for FIOASYNC mode), replacing
2681*7c478bd9Sstevel@tonic-gate  * any existing one.  If passed zero, just clear the existing one.
2682*7c478bd9Sstevel@tonic-gate  */
2683*7c478bd9Sstevel@tonic-gate int
2684*7c478bd9Sstevel@tonic-gate so_set_siggrp(struct sonode *so, vnode_t *vp, pid_t pgrp, int mode, cred_t *cr)
2685*7c478bd9Sstevel@tonic-gate {
2686*7c478bd9Sstevel@tonic-gate 	int events = so->so_state & SS_ASYNC ?
2687*7c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT :
2688*7c478bd9Sstevel@tonic-gate 	    S_RDBAND | S_BANDURG;
2689*7c478bd9Sstevel@tonic-gate 	int error;
2690*7c478bd9Sstevel@tonic-gate 
2691*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&so->so_lock));
2692*7c478bd9Sstevel@tonic-gate 
2693*7c478bd9Sstevel@tonic-gate 	/*
2694*7c478bd9Sstevel@tonic-gate 	 * Change socket process (group).
2695*7c478bd9Sstevel@tonic-gate 	 *
2696*7c478bd9Sstevel@tonic-gate 	 * strioctl (via so_set_asyncsigs) will perform permission check and
2697*7c478bd9Sstevel@tonic-gate 	 * also keep a PID_HOLD to prevent the pid from being reused.
2698*7c478bd9Sstevel@tonic-gate 	 */
2699*7c478bd9Sstevel@tonic-gate 	so_lock_single(so);
2700*7c478bd9Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
2701*7c478bd9Sstevel@tonic-gate 
2702*7c478bd9Sstevel@tonic-gate 	if (pgrp != 0) {
2703*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("setown: adding pgrp %d ev 0x%x\n",
2704*7c478bd9Sstevel@tonic-gate 		    pgrp, events));
2705*7c478bd9Sstevel@tonic-gate 		error = so_set_asyncsigs(vp, pgrp, events, mode, cr);
2706*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
2707*7c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
2708*7c478bd9Sstevel@tonic-gate 			goto bad;
2709*7c478bd9Sstevel@tonic-gate 		}
2710*7c478bd9Sstevel@tonic-gate 	}
2711*7c478bd9Sstevel@tonic-gate 	/* Remove the previously registered process/group */
2712*7c478bd9Sstevel@tonic-gate 	if (so->so_pgrp != 0) {
2713*7c478bd9Sstevel@tonic-gate 		dprintso(so, 1, ("setown: removing pgrp %d\n", so->so_pgrp));
2714*7c478bd9Sstevel@tonic-gate 		error = so_set_asyncsigs(vp, so->so_pgrp, 0, mode, cr);
2715*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
2716*7c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
2717*7c478bd9Sstevel@tonic-gate 			error = 0;
2718*7c478bd9Sstevel@tonic-gate 		}
2719*7c478bd9Sstevel@tonic-gate 	}
2720*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
2721*7c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
2722*7c478bd9Sstevel@tonic-gate 	so->so_pgrp = pgrp;
2723*7c478bd9Sstevel@tonic-gate 	return (0);
2724*7c478bd9Sstevel@tonic-gate bad:
2725*7c478bd9Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
2726*7c478bd9Sstevel@tonic-gate 	so_unlock_single(so, SOLOCKED);
2727*7c478bd9Sstevel@tonic-gate 	return (error);
2728*7c478bd9Sstevel@tonic-gate }
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 
2731*7c478bd9Sstevel@tonic-gate 
2732*7c478bd9Sstevel@tonic-gate /*
2733*7c478bd9Sstevel@tonic-gate  * Translate a TLI(/XTI) error into a system error as best we can.
2734*7c478bd9Sstevel@tonic-gate  */
2735*7c478bd9Sstevel@tonic-gate static const int tli_errs[] = {
2736*7c478bd9Sstevel@tonic-gate 		0,		/* no error	*/
2737*7c478bd9Sstevel@tonic-gate 		EADDRNOTAVAIL,  /* TBADADDR	*/
2738*7c478bd9Sstevel@tonic-gate 		ENOPROTOOPT,	/* TBADOPT	*/
2739*7c478bd9Sstevel@tonic-gate 		EACCES,		/* TACCES	*/
2740*7c478bd9Sstevel@tonic-gate 		EBADF,		/* TBADF	*/
2741*7c478bd9Sstevel@tonic-gate 		EADDRNOTAVAIL,	/* TNOADDR	*/
2742*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TOUTSTATE	*/
2743*7c478bd9Sstevel@tonic-gate 		ECONNABORTED,	/* TBADSEQ	*/
2744*7c478bd9Sstevel@tonic-gate 		0,		/* TSYSERR - will never get	*/
2745*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TLOOK - should never be sent by transport */
2746*7c478bd9Sstevel@tonic-gate 		EMSGSIZE,	/* TBADDATA	*/
2747*7c478bd9Sstevel@tonic-gate 		EMSGSIZE,	/* TBUFOVFLW	*/
2748*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TFLOW	*/
2749*7c478bd9Sstevel@tonic-gate 		EWOULDBLOCK,	/* TNODATA	*/
2750*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TNODIS	*/
2751*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TNOUDERR	*/
2752*7c478bd9Sstevel@tonic-gate 		EINVAL,		/* TBADFLAG	*/
2753*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TNOREL	*/
2754*7c478bd9Sstevel@tonic-gate 		EOPNOTSUPP,	/* TNOTSUPPORT	*/
2755*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TSTATECHNG	*/
2756*7c478bd9Sstevel@tonic-gate 		/* following represent error namespace expansion with XTI */
2757*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TNOSTRUCTYPE - never sent by transport */
2758*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TBADNAME - never sent by transport */
2759*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TBADQLEN - never sent by transport */
2760*7c478bd9Sstevel@tonic-gate 		EADDRINUSE,	/* TADDRBUSY	*/
2761*7c478bd9Sstevel@tonic-gate 		EBADF,		/* TINDOUT	*/
2762*7c478bd9Sstevel@tonic-gate 		EBADF,		/* TPROVMISMATCH */
2763*7c478bd9Sstevel@tonic-gate 		EBADF,		/* TRESQLEN	*/
2764*7c478bd9Sstevel@tonic-gate 		EBADF,		/* TRESADDR	*/
2765*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TQFULL - never sent by transport */
2766*7c478bd9Sstevel@tonic-gate 		EPROTO,		/* TPROTO	*/
2767*7c478bd9Sstevel@tonic-gate };
2768*7c478bd9Sstevel@tonic-gate 
2769*7c478bd9Sstevel@tonic-gate static int
2770*7c478bd9Sstevel@tonic-gate tlitosyserr(int terr)
2771*7c478bd9Sstevel@tonic-gate {
2772*7c478bd9Sstevel@tonic-gate 	ASSERT(terr != TSYSERR);
2773*7c478bd9Sstevel@tonic-gate 	if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0])))
2774*7c478bd9Sstevel@tonic-gate 		return (EPROTO);
2775*7c478bd9Sstevel@tonic-gate 	else
2776*7c478bd9Sstevel@tonic-gate 		return (tli_errs[terr]);
2777*7c478bd9Sstevel@tonic-gate }
2778