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