xref: /titanic_44/usr/src/uts/common/os/streamio.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/var.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/poll.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/termio.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/sad.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/priocntl.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/jioctl.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/procset.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/session.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/filio.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/strredir.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/fs/fifonode.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
68*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
69*7c478bd9Sstevel@tonic-gate #include <sys/project.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
71*7c478bd9Sstevel@tonic-gate #include <sys/msio.h>
72*7c478bd9Sstevel@tonic-gate #include <sys/tty.h>
73*7c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h>
74*7c478bd9Sstevel@tonic-gate #include <sys/vuid_event.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/sunldi_impl.h>
78*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
79*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * what is mblk_pull_len?
83*7c478bd9Sstevel@tonic-gate  *
84*7c478bd9Sstevel@tonic-gate  * If a streams message consists of many short messages,
85*7c478bd9Sstevel@tonic-gate  * a performance degradation occurs from copyout overhead.
86*7c478bd9Sstevel@tonic-gate  * To decrease the per mblk overhead, messages that are
87*7c478bd9Sstevel@tonic-gate  * likely to consist of many small mblks are pulled up into
88*7c478bd9Sstevel@tonic-gate  * one continuous chunk of memory.
89*7c478bd9Sstevel@tonic-gate  *
90*7c478bd9Sstevel@tonic-gate  * To avoid the processing overhead of examining every
91*7c478bd9Sstevel@tonic-gate  * mblk, a quick heuristic is used. If the first mblk in
92*7c478bd9Sstevel@tonic-gate  * the message is shorter than mblk_pull_len, it is likely
93*7c478bd9Sstevel@tonic-gate  * that the rest of the mblk will be short.
94*7c478bd9Sstevel@tonic-gate  *
95*7c478bd9Sstevel@tonic-gate  * This heuristic was decided upon after performance tests
96*7c478bd9Sstevel@tonic-gate  * indicated that anything more complex slowed down the main
97*7c478bd9Sstevel@tonic-gate  * code path.
98*7c478bd9Sstevel@tonic-gate  */
99*7c478bd9Sstevel@tonic-gate #define	MBLK_PULL_LEN 64
100*7c478bd9Sstevel@tonic-gate uint32_t mblk_pull_len = MBLK_PULL_LEN;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * The sgttyb_handling flag controls the handling of the old BSD
104*7c478bd9Sstevel@tonic-gate  * TIOCGETP, TIOCSETP, and TIOCSETN ioctls as follows:
105*7c478bd9Sstevel@tonic-gate  *
106*7c478bd9Sstevel@tonic-gate  * 0 - Emit no warnings at all and retain old, broken behavior.
107*7c478bd9Sstevel@tonic-gate  * 1 - Emit no warnings and silently handle new semantics.
108*7c478bd9Sstevel@tonic-gate  * 2 - Send cmn_err(CE_NOTE) when either TIOCSETP or TIOCSETN is used
109*7c478bd9Sstevel@tonic-gate  *     (once per system invocation).  Handle with new semantics.
110*7c478bd9Sstevel@tonic-gate  * 3 - Send SIGSYS when any TIOCGETP, TIOCSETP, or TIOCSETN call is
111*7c478bd9Sstevel@tonic-gate  *     made (so that offenders drop core and are easy to debug).
112*7c478bd9Sstevel@tonic-gate  *
113*7c478bd9Sstevel@tonic-gate  * The "new semantics" are that TIOCGETP returns B38400 for
114*7c478bd9Sstevel@tonic-gate  * sg_[io]speed if the corresponding value is over B38400, and that
115*7c478bd9Sstevel@tonic-gate  * TIOCSET[PN] accept B38400 in these cases to mean "retain current
116*7c478bd9Sstevel@tonic-gate  * bit rate."
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate int sgttyb_handling = 1;
119*7c478bd9Sstevel@tonic-gate static boolean_t sgttyb_complaint;
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /* don't push drcompat module by default on Style-2 streams */
122*7c478bd9Sstevel@tonic-gate static int push_drcompat = 0;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate /*
125*7c478bd9Sstevel@tonic-gate  * id value used to distinguish between different ioctl messages
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate static uint32_t ioc_id;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate static void putback(struct stdata *, queue_t *, mblk_t *, int);
130*7c478bd9Sstevel@tonic-gate static void strcleanall(struct vnode *);
131*7c478bd9Sstevel@tonic-gate static int strwsrv(queue_t *);
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate /*
134*7c478bd9Sstevel@tonic-gate  * qinit and module_info structures for stream head read and write queues
135*7c478bd9Sstevel@tonic-gate  */
136*7c478bd9Sstevel@tonic-gate struct module_info strm_info = { 0, "strrhead", 0, INFPSZ, STRHIGH, STRLOW };
137*7c478bd9Sstevel@tonic-gate struct module_info stwm_info = { 0, "strwhead", 0, 0, 0, 0 };
138*7c478bd9Sstevel@tonic-gate struct qinit strdata = { strrput, NULL, NULL, NULL, NULL, &strm_info };
139*7c478bd9Sstevel@tonic-gate struct qinit stwdata = { NULL, strwsrv, NULL, NULL, NULL, &stwm_info };
140*7c478bd9Sstevel@tonic-gate struct module_info fiform_info = { 0, "fifostrrhead", 0, PIPE_BUF, FIFOHIWAT,
141*7c478bd9Sstevel@tonic-gate     FIFOLOWAT };
142*7c478bd9Sstevel@tonic-gate struct module_info fifowm_info = { 0, "fifostrwhead", 0, 0, 0, 0 };
143*7c478bd9Sstevel@tonic-gate struct qinit fifo_strdata = { strrput, NULL, NULL, NULL, NULL, &fiform_info };
144*7c478bd9Sstevel@tonic-gate struct qinit fifo_stwdata = { NULL, strwsrv, NULL, NULL, NULL, &fifowm_info };
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate extern kmutex_t	strresources;	/* protects global resources */
147*7c478bd9Sstevel@tonic-gate extern kmutex_t muxifier;	/* single-threads multiplexor creation */
148*7c478bd9Sstevel@tonic-gate kmutex_t sad_lock;		/* protects sad drivers autopush */
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate static boolean_t msghasdata(mblk_t *bp);
151*7c478bd9Sstevel@tonic-gate #define	msgnodata(bp) (!msghasdata(bp))
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /*
154*7c478bd9Sstevel@tonic-gate  * Stream head locking notes:
155*7c478bd9Sstevel@tonic-gate  *	There are four monitors associated with the stream head:
156*7c478bd9Sstevel@tonic-gate  *	1. v_stream monitor: in stropen() and strclose() v_lock
157*7c478bd9Sstevel@tonic-gate  *		is held while the association of vnode and stream
158*7c478bd9Sstevel@tonic-gate  *		head is established or tested for.
159*7c478bd9Sstevel@tonic-gate  *	2. open/close/push/pop monitor: sd_lock is held while each
160*7c478bd9Sstevel@tonic-gate  *		thread bids for exclusive access to this monitor
161*7c478bd9Sstevel@tonic-gate  *		for opening or closing a stream.  In addition, this
162*7c478bd9Sstevel@tonic-gate  *		monitor is entered during pushes and pops.  This
163*7c478bd9Sstevel@tonic-gate  *		guarantees that during plumbing operations there
164*7c478bd9Sstevel@tonic-gate  *		is only one thread trying to change the plumbing.
165*7c478bd9Sstevel@tonic-gate  *		Any other threads present in the stream are only
166*7c478bd9Sstevel@tonic-gate  *		using the plumbing.
167*7c478bd9Sstevel@tonic-gate  *	3. read/write monitor: in the case of read, a thread holds
168*7c478bd9Sstevel@tonic-gate  *		sd_lock while trying to get data from the stream
169*7c478bd9Sstevel@tonic-gate  *		head queue.  if there is none to fulfill a read
170*7c478bd9Sstevel@tonic-gate  *		request, it sets RSLEEP and calls cv_wait_sig() down
171*7c478bd9Sstevel@tonic-gate  *		in strwaitq() to await the arrival of new data.
172*7c478bd9Sstevel@tonic-gate  *		when new data arrives in strrput(), sd_lock is acquired
173*7c478bd9Sstevel@tonic-gate  *		before testing for RSLEEP and calling cv_broadcast().
174*7c478bd9Sstevel@tonic-gate  *		the behavior of strwrite(), strwsrv(), and WSLEEP
175*7c478bd9Sstevel@tonic-gate  *		mirror this.
176*7c478bd9Sstevel@tonic-gate  *	4. ioctl monitor: sd_lock is gotten to ensure that only one
177*7c478bd9Sstevel@tonic-gate  *		thread is doing an ioctl at a time.
178*7c478bd9Sstevel@tonic-gate  */
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate static int
181*7c478bd9Sstevel@tonic-gate push_mod(queue_t *qp, dev_t *devp, struct stdata *stp, const char *name,
182*7c478bd9Sstevel@tonic-gate     int anchor, cred_t *crp)
183*7c478bd9Sstevel@tonic-gate {
184*7c478bd9Sstevel@tonic-gate 	int error;
185*7c478bd9Sstevel@tonic-gate 	fmodsw_impl_t *fp;
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STRHUP|STRDERR|STWRERR)) {
188*7c478bd9Sstevel@tonic-gate 		error = (stp->sd_flag & STRHUP) ? ENXIO : EIO;
189*7c478bd9Sstevel@tonic-gate 		return (error);
190*7c478bd9Sstevel@tonic-gate 	}
191*7c478bd9Sstevel@tonic-gate 	if (stp->sd_pushcnt >= nstrpush) {
192*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if ((fp = fmodsw_find(name, FMODSW_HOLD | FMODSW_LOAD)) == NULL) {
196*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STREOPENFAIL;
197*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
198*7c478bd9Sstevel@tonic-gate 	}
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/*
201*7c478bd9Sstevel@tonic-gate 	 * push new module and call its open routine via qattach
202*7c478bd9Sstevel@tonic-gate 	 */
203*7c478bd9Sstevel@tonic-gate 	if ((error = qattach(qp, devp, 0, crp, fp, B_FALSE)) != 0)
204*7c478bd9Sstevel@tonic-gate 		return (error);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	/*
207*7c478bd9Sstevel@tonic-gate 	 * If flow control is on, don't break it - enable
208*7c478bd9Sstevel@tonic-gate 	 * first back queue with svc procedure
209*7c478bd9Sstevel@tonic-gate 	 */
210*7c478bd9Sstevel@tonic-gate 	if (_RD(stp->sd_wrq)->q_flag & QWANTW) {
211*7c478bd9Sstevel@tonic-gate 		/* Note: no setqback here - use pri -1. */
212*7c478bd9Sstevel@tonic-gate 		backenable(_RD(stp->sd_wrq->q_next), -1);
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	/*
216*7c478bd9Sstevel@tonic-gate 	 * Check to see if caller wants a STREAMS anchor
217*7c478bd9Sstevel@tonic-gate 	 * put at this place in the stream, and add if so.
218*7c478bd9Sstevel@tonic-gate 	 */
219*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
220*7c478bd9Sstevel@tonic-gate 	if (anchor == stp->sd_pushcnt)
221*7c478bd9Sstevel@tonic-gate 		stp->sd_anchor = stp->sd_pushcnt;
222*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	return (0);
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate /*
228*7c478bd9Sstevel@tonic-gate  * Open a stream device.
229*7c478bd9Sstevel@tonic-gate  */
230*7c478bd9Sstevel@tonic-gate int
231*7c478bd9Sstevel@tonic-gate stropen(vnode_t *vp, dev_t *devp, int flag, cred_t *crp)
232*7c478bd9Sstevel@tonic-gate {
233*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
234*7c478bd9Sstevel@tonic-gate 	queue_t *qp;
235*7c478bd9Sstevel@tonic-gate 	int s;
236*7c478bd9Sstevel@tonic-gate 	dev_t dummydev;
237*7c478bd9Sstevel@tonic-gate 	struct autopush *ap;
238*7c478bd9Sstevel@tonic-gate 	int error = 0;
239*7c478bd9Sstevel@tonic-gate 	ssize_t	rmin, rmax;
240*7c478bd9Sstevel@tonic-gate 	int cloneopen;
241*7c478bd9Sstevel@tonic-gate 	queue_t *brq;
242*7c478bd9Sstevel@tonic-gate 	major_t major;
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
245*7c478bd9Sstevel@tonic-gate 	if (audit_active)
246*7c478bd9Sstevel@tonic-gate 		audit_stropen(vp, devp, flag, crp);
247*7c478bd9Sstevel@tonic-gate #endif
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	/*
250*7c478bd9Sstevel@tonic-gate 	 * If the stream already exists, wait for any open in progress
251*7c478bd9Sstevel@tonic-gate 	 * to complete, then call the open function of each module and
252*7c478bd9Sstevel@tonic-gate 	 * driver in the stream.  Otherwise create the stream.
253*7c478bd9Sstevel@tonic-gate 	 */
254*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STROPEN, "stropen:%p", vp);
255*7c478bd9Sstevel@tonic-gate retry:
256*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
257*7c478bd9Sstevel@tonic-gate 	if ((stp = vp->v_stream) != NULL) {
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		/*
260*7c478bd9Sstevel@tonic-gate 		 * Waiting for stream to be created to device
261*7c478bd9Sstevel@tonic-gate 		 * due to another open.
262*7c478bd9Sstevel@tonic-gate 		 */
263*7c478bd9Sstevel@tonic-gate 	    mutex_exit(&vp->v_lock);
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	    if (STRMATED(stp)) {
266*7c478bd9Sstevel@tonic-gate 		struct stdata *strmatep = stp->sd_mate;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 		STRLOCKMATES(stp);
269*7c478bd9Sstevel@tonic-gate 		if (strmatep->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
270*7c478bd9Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
271*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
272*7c478bd9Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
273*7c478bd9Sstevel@tonic-gate 				goto ckreturn;
274*7c478bd9Sstevel@tonic-gate 			}
275*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
276*7c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&strmatep->sd_monitor,
277*7c478bd9Sstevel@tonic-gate 			    &strmatep->sd_lock)) {
278*7c478bd9Sstevel@tonic-gate 				error = EINTR;
279*7c478bd9Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
280*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
281*7c478bd9Sstevel@tonic-gate 				goto ckreturn;
282*7c478bd9Sstevel@tonic-gate 			}
283*7c478bd9Sstevel@tonic-gate 			mutex_exit(&strmatep->sd_lock);
284*7c478bd9Sstevel@tonic-gate 			goto retry;
285*7c478bd9Sstevel@tonic-gate 		}
286*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
287*7c478bd9Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
288*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
289*7c478bd9Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
290*7c478bd9Sstevel@tonic-gate 				goto ckreturn;
291*7c478bd9Sstevel@tonic-gate 			}
292*7c478bd9Sstevel@tonic-gate 			mutex_exit(&strmatep->sd_lock);
293*7c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&stp->sd_monitor, &stp->sd_lock)) {
294*7c478bd9Sstevel@tonic-gate 				error = EINTR;
295*7c478bd9Sstevel@tonic-gate 				goto ckreturn;
296*7c478bd9Sstevel@tonic-gate 			}
297*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
298*7c478bd9Sstevel@tonic-gate 			goto retry;
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR)) {
302*7c478bd9Sstevel@tonic-gate 			error = EIO;
303*7c478bd9Sstevel@tonic-gate 			mutex_exit(&strmatep->sd_lock);
304*7c478bd9Sstevel@tonic-gate 			goto ckreturn;
305*7c478bd9Sstevel@tonic-gate 		}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STWOPEN;
308*7c478bd9Sstevel@tonic-gate 		STRUNLOCKMATES(stp);
309*7c478bd9Sstevel@tonic-gate 	    } else {
310*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
311*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
312*7c478bd9Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
313*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
314*7c478bd9Sstevel@tonic-gate 				goto ckreturn;
315*7c478bd9Sstevel@tonic-gate 			}
316*7c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&stp->sd_monitor, &stp->sd_lock)) {
317*7c478bd9Sstevel@tonic-gate 				error = EINTR;
318*7c478bd9Sstevel@tonic-gate 				goto ckreturn;
319*7c478bd9Sstevel@tonic-gate 			}
320*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
321*7c478bd9Sstevel@tonic-gate 			goto retry;  /* could be clone! */
322*7c478bd9Sstevel@tonic-gate 		}
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR)) {
325*7c478bd9Sstevel@tonic-gate 			error = EIO;
326*7c478bd9Sstevel@tonic-gate 			goto ckreturn;
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STWOPEN;
330*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
331*7c478bd9Sstevel@tonic-gate 	    }
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 		/*
334*7c478bd9Sstevel@tonic-gate 		 * Open all modules and devices down stream to notify
335*7c478bd9Sstevel@tonic-gate 		 * that another user is streaming.  For modules, set the
336*7c478bd9Sstevel@tonic-gate 		 * last argument to MODOPEN and do not pass any open flags.
337*7c478bd9Sstevel@tonic-gate 		 * Ignore dummydev since this is not the first open.
338*7c478bd9Sstevel@tonic-gate 		 */
339*7c478bd9Sstevel@tonic-gate 	    claimstr(stp->sd_wrq);
340*7c478bd9Sstevel@tonic-gate 	    qp = stp->sd_wrq;
341*7c478bd9Sstevel@tonic-gate 	    while (_SAMESTR(qp)) {
342*7c478bd9Sstevel@tonic-gate 		qp = qp->q_next;
343*7c478bd9Sstevel@tonic-gate 		if ((error = qreopen(_RD(qp), devp, flag, crp)) != 0)
344*7c478bd9Sstevel@tonic-gate 			break;
345*7c478bd9Sstevel@tonic-gate 	    }
346*7c478bd9Sstevel@tonic-gate 	    releasestr(stp->sd_wrq);
347*7c478bd9Sstevel@tonic-gate 	    mutex_enter(&stp->sd_lock);
348*7c478bd9Sstevel@tonic-gate 	    stp->sd_flag &= ~(STRHUP|STWOPEN|STRDERR|STWRERR);
349*7c478bd9Sstevel@tonic-gate 	    stp->sd_rerror = 0;
350*7c478bd9Sstevel@tonic-gate 	    stp->sd_werror = 0;
351*7c478bd9Sstevel@tonic-gate ckreturn:
352*7c478bd9Sstevel@tonic-gate 	    cv_broadcast(&stp->sd_monitor);
353*7c478bd9Sstevel@tonic-gate 	    mutex_exit(&stp->sd_lock);
354*7c478bd9Sstevel@tonic-gate 	    return (error);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	/*
358*7c478bd9Sstevel@tonic-gate 	 * This vnode isn't streaming.  SPECFS already
359*7c478bd9Sstevel@tonic-gate 	 * checked for multiple vnodes pointing to the
360*7c478bd9Sstevel@tonic-gate 	 * same stream, so create a stream to the driver.
361*7c478bd9Sstevel@tonic-gate 	 */
362*7c478bd9Sstevel@tonic-gate 	qp = allocq();
363*7c478bd9Sstevel@tonic-gate 	stp = shalloc(qp);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	/*
366*7c478bd9Sstevel@tonic-gate 	 * Initialize stream head.  shalloc() has given us
367*7c478bd9Sstevel@tonic-gate 	 * exclusive access, and we have the vnode locked;
368*7c478bd9Sstevel@tonic-gate 	 * we can do whatever we want with stp.
369*7c478bd9Sstevel@tonic-gate 	 */
370*7c478bd9Sstevel@tonic-gate 	stp->sd_flag = STWOPEN;
371*7c478bd9Sstevel@tonic-gate 	stp->sd_siglist = NULL;
372*7c478bd9Sstevel@tonic-gate 	stp->sd_pollist.ph_list = NULL;
373*7c478bd9Sstevel@tonic-gate 	stp->sd_sigflags = 0;
374*7c478bd9Sstevel@tonic-gate 	stp->sd_mark = NULL;
375*7c478bd9Sstevel@tonic-gate 	stp->sd_closetime = STRTIMOUT;
376*7c478bd9Sstevel@tonic-gate 	stp->sd_sidp = NULL;
377*7c478bd9Sstevel@tonic-gate 	stp->sd_pgidp = NULL;
378*7c478bd9Sstevel@tonic-gate 	stp->sd_vnode = vp;
379*7c478bd9Sstevel@tonic-gate 	stp->sd_rerror = 0;
380*7c478bd9Sstevel@tonic-gate 	stp->sd_werror = 0;
381*7c478bd9Sstevel@tonic-gate 	stp->sd_wroff = 0;
382*7c478bd9Sstevel@tonic-gate 	stp->sd_iocblk = NULL;
383*7c478bd9Sstevel@tonic-gate 	stp->sd_pushcnt = 0;
384*7c478bd9Sstevel@tonic-gate 	stp->sd_qn_minpsz = 0;
385*7c478bd9Sstevel@tonic-gate 	stp->sd_qn_maxpsz = INFPSZ - 1;	/* used to check for initialization */
386*7c478bd9Sstevel@tonic-gate 	stp->sd_maxblk = INFPSZ;
387*7c478bd9Sstevel@tonic-gate 	qp->q_ptr = _WR(qp)->q_ptr = stp;
388*7c478bd9Sstevel@tonic-gate 	STREAM(qp) = STREAM(_WR(qp)) = stp;
389*7c478bd9Sstevel@tonic-gate 	vp->v_stream = stp;
390*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
391*7c478bd9Sstevel@tonic-gate 	if (vp->v_type == VFIFO) {
392*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= OLDNDELAY;
393*7c478bd9Sstevel@tonic-gate 		/*
394*7c478bd9Sstevel@tonic-gate 		 * This means, both for pipes and fifos
395*7c478bd9Sstevel@tonic-gate 		 * strwrite will send SIGPIPE if the other
396*7c478bd9Sstevel@tonic-gate 		 * end is closed. For putmsg it depends
397*7c478bd9Sstevel@tonic-gate 		 * on whether it is a XPG4_2 application
398*7c478bd9Sstevel@tonic-gate 		 * or not
399*7c478bd9Sstevel@tonic-gate 		 */
400*7c478bd9Sstevel@tonic-gate 		stp->sd_wput_opt = SW_SIGPIPE;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 		/* setq might sleep in kmem_alloc - avoid holding locks. */
403*7c478bd9Sstevel@tonic-gate 		setq(qp, &fifo_strdata, &fifo_stwdata, NULL, QMTSAFE,
404*7c478bd9Sstevel@tonic-gate 		    SQ_CI|SQ_CO, B_FALSE);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		set_qend(qp);
407*7c478bd9Sstevel@tonic-gate 		stp->sd_strtab = (struct streamtab *)fifo_getinfo();
408*7c478bd9Sstevel@tonic-gate 		_WR(qp)->q_nfsrv = _WR(qp);
409*7c478bd9Sstevel@tonic-gate 		qp->q_nfsrv = qp;
410*7c478bd9Sstevel@tonic-gate 		/*
411*7c478bd9Sstevel@tonic-gate 		 * Wake up others that are waiting for stream to be created.
412*7c478bd9Sstevel@tonic-gate 		 */
413*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
414*7c478bd9Sstevel@tonic-gate 		/*
415*7c478bd9Sstevel@tonic-gate 		 * nothing is be pushed on stream yet, so
416*7c478bd9Sstevel@tonic-gate 		 * optimized stream head packetsizes are just that
417*7c478bd9Sstevel@tonic-gate 		 * of the read queue
418*7c478bd9Sstevel@tonic-gate 		 */
419*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_minpsz = qp->q_minpsz;
420*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_maxpsz = qp->q_maxpsz;
421*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~STWOPEN;
422*7c478bd9Sstevel@tonic-gate 		goto fifo_opendone;
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 	/* setq might sleep in kmem_alloc - avoid holding locks. */
425*7c478bd9Sstevel@tonic-gate 	setq(qp, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_FALSE);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	set_qend(qp);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	/*
430*7c478bd9Sstevel@tonic-gate 	 * Open driver and create stream to it (via qattach).
431*7c478bd9Sstevel@tonic-gate 	 */
432*7c478bd9Sstevel@tonic-gate 	cloneopen = (getmajor(*devp) == clone_major);
433*7c478bd9Sstevel@tonic-gate 	if ((error = qattach(qp, devp, flag, crp, NULL, B_FALSE)) != 0) {
434*7c478bd9Sstevel@tonic-gate 		mutex_enter(&vp->v_lock);
435*7c478bd9Sstevel@tonic-gate 		vp->v_stream = NULL;
436*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
437*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
438*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
439*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
440*7c478bd9Sstevel@tonic-gate 		freeq(_RD(qp));
441*7c478bd9Sstevel@tonic-gate 		shfree(stp);
442*7c478bd9Sstevel@tonic-gate 		return (error);
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate 	/*
445*7c478bd9Sstevel@tonic-gate 	 * Set sd_strtab after open in order to handle clonable drivers
446*7c478bd9Sstevel@tonic-gate 	 */
447*7c478bd9Sstevel@tonic-gate 	stp->sd_strtab = STREAMSTAB(getmajor(*devp));
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	/*
450*7c478bd9Sstevel@tonic-gate 	 * Historical note: dummydev used to be be prior to the initial
451*7c478bd9Sstevel@tonic-gate 	 * open (via qattach above), which made the value seen
452*7c478bd9Sstevel@tonic-gate 	 * inconsistent between an I_PUSH and an autopush of a module.
453*7c478bd9Sstevel@tonic-gate 	 */
454*7c478bd9Sstevel@tonic-gate 	dummydev = *devp;
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	/*
457*7c478bd9Sstevel@tonic-gate 	 * For clone open of old style (Q not associated) network driver,
458*7c478bd9Sstevel@tonic-gate 	 * push DRMODNAME module to handle DL_ATTACH/DL_DETACH
459*7c478bd9Sstevel@tonic-gate 	 */
460*7c478bd9Sstevel@tonic-gate 	brq = _RD(_WR(qp)->q_next);
461*7c478bd9Sstevel@tonic-gate 	major = getmajor(*devp);
462*7c478bd9Sstevel@tonic-gate 	if (push_drcompat && cloneopen && NETWORK_DRV(major) &&
463*7c478bd9Sstevel@tonic-gate 	    ((brq->q_flag & _QASSOCIATED) == 0)) {
464*7c478bd9Sstevel@tonic-gate 		if (push_mod(qp, &dummydev, stp, DRMODNAME, 0, crp) != 0)
465*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "cannot push " DRMODNAME
466*7c478bd9Sstevel@tonic-gate 			    " streams module");
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/*
470*7c478bd9Sstevel@tonic-gate 	 * check for autopush
471*7c478bd9Sstevel@tonic-gate 	 */
472*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sad_lock);
473*7c478bd9Sstevel@tonic-gate 	ap = strphash(getemajor(*devp));
474*7c478bd9Sstevel@tonic-gate #define	DEVT(ap)	makedevice(ap->ap_major, ap->ap_minor)
475*7c478bd9Sstevel@tonic-gate #define	DEVLT(ap)	makedevice(ap->ap_major, ap->ap_lastminor)
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	while (ap) {
478*7c478bd9Sstevel@tonic-gate 		if (ap->ap_major == (getemajor(*devp))) {
479*7c478bd9Sstevel@tonic-gate 			if (ap->ap_type == SAP_ALL)
480*7c478bd9Sstevel@tonic-gate 				break;
481*7c478bd9Sstevel@tonic-gate 			else if ((ap->ap_type == SAP_ONE) &&
482*7c478bd9Sstevel@tonic-gate 			    (getminor(DEVT(ap)) == getminor(*devp)))
483*7c478bd9Sstevel@tonic-gate 				break;
484*7c478bd9Sstevel@tonic-gate 			else if (ap->ap_type == SAP_RANGE &&
485*7c478bd9Sstevel@tonic-gate 			    getminor(*devp) >= getminor(DEVT(ap)) &&
486*7c478bd9Sstevel@tonic-gate 			    getminor(*devp) <= getminor(DEVLT(ap)))
487*7c478bd9Sstevel@tonic-gate 				break;
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 		ap = ap->ap_nextp;
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 	if (ap == NULL) {
492*7c478bd9Sstevel@tonic-gate 		mutex_exit(&sad_lock);
493*7c478bd9Sstevel@tonic-gate 		goto opendone;
494*7c478bd9Sstevel@tonic-gate 	}
495*7c478bd9Sstevel@tonic-gate 	ap->ap_cnt++;
496*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sad_lock);
497*7c478bd9Sstevel@tonic-gate 	for (s = 0; s < ap->ap_npush; s++) {
498*7c478bd9Sstevel@tonic-gate 		error = push_mod(qp, &dummydev, stp, ap->ap_list[s],
499*7c478bd9Sstevel@tonic-gate 		    ap->ap_anchor, crp);
500*7c478bd9Sstevel@tonic-gate 		if (error != 0)
501*7c478bd9Sstevel@tonic-gate 			break;
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sad_lock);
504*7c478bd9Sstevel@tonic-gate 	if (--(ap->ap_cnt) <= 0)
505*7c478bd9Sstevel@tonic-gate 		ap_free(ap);
506*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sad_lock);
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	/*
509*7c478bd9Sstevel@tonic-gate 	 * let specfs know that open failed part way through
510*7c478bd9Sstevel@tonic-gate 	 */
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	if (error) {
513*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
514*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STREOPENFAIL;
515*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
516*7c478bd9Sstevel@tonic-gate 	}
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate opendone:
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	/*
521*7c478bd9Sstevel@tonic-gate 	 * Wake up others that are waiting for stream to be created.
522*7c478bd9Sstevel@tonic-gate 	 */
523*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
524*7c478bd9Sstevel@tonic-gate 	stp->sd_flag &= ~STWOPEN;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	/*
527*7c478bd9Sstevel@tonic-gate 	 * As a performance concern we are caching the values of
528*7c478bd9Sstevel@tonic-gate 	 * q_minpsz and q_maxpsz of the module below the stream
529*7c478bd9Sstevel@tonic-gate 	 * head in the stream head.
530*7c478bd9Sstevel@tonic-gate 	 */
531*7c478bd9Sstevel@tonic-gate 	mutex_enter(QLOCK(stp->sd_wrq->q_next));
532*7c478bd9Sstevel@tonic-gate 	rmin = stp->sd_wrq->q_next->q_minpsz;
533*7c478bd9Sstevel@tonic-gate 	rmax = stp->sd_wrq->q_next->q_maxpsz;
534*7c478bd9Sstevel@tonic-gate 	mutex_exit(QLOCK(stp->sd_wrq->q_next));
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	/* do this processing here as a performance concern */
537*7c478bd9Sstevel@tonic-gate 	if (strmsgsz != 0) {
538*7c478bd9Sstevel@tonic-gate 		if (rmax == INFPSZ)
539*7c478bd9Sstevel@tonic-gate 			rmax = strmsgsz;
540*7c478bd9Sstevel@tonic-gate 		else
541*7c478bd9Sstevel@tonic-gate 			rmax = MIN(strmsgsz, rmax);
542*7c478bd9Sstevel@tonic-gate 	}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	mutex_enter(QLOCK(stp->sd_wrq));
545*7c478bd9Sstevel@tonic-gate 	stp->sd_qn_minpsz = rmin;
546*7c478bd9Sstevel@tonic-gate 	stp->sd_qn_maxpsz = rmax;
547*7c478bd9Sstevel@tonic-gate 	mutex_exit(QLOCK(stp->sd_wrq));
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate fifo_opendone:
550*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&stp->sd_monitor);
551*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
552*7c478bd9Sstevel@tonic-gate 	return (error);
553*7c478bd9Sstevel@tonic-gate }
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate static int strsink(queue_t *, mblk_t *);
556*7c478bd9Sstevel@tonic-gate static struct qinit deadrend = {
557*7c478bd9Sstevel@tonic-gate 	strsink, NULL, NULL, NULL, NULL, &strm_info, NULL
558*7c478bd9Sstevel@tonic-gate };
559*7c478bd9Sstevel@tonic-gate static struct qinit deadwend = {
560*7c478bd9Sstevel@tonic-gate 	NULL, NULL, NULL, NULL, NULL, &stwm_info, NULL
561*7c478bd9Sstevel@tonic-gate };
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate /*
564*7c478bd9Sstevel@tonic-gate  * Close a stream.
565*7c478bd9Sstevel@tonic-gate  * This is called from closef() on the last close of an open stream.
566*7c478bd9Sstevel@tonic-gate  * Strclean() will already have removed the siglist and pollist
567*7c478bd9Sstevel@tonic-gate  * information, so all that remains is to remove all multiplexor links
568*7c478bd9Sstevel@tonic-gate  * for the stream, pop all the modules (and the driver), and free the
569*7c478bd9Sstevel@tonic-gate  * stream structure.
570*7c478bd9Sstevel@tonic-gate  */
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate int
573*7c478bd9Sstevel@tonic-gate strclose(struct vnode *vp, int flag, cred_t *crp)
574*7c478bd9Sstevel@tonic-gate {
575*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
576*7c478bd9Sstevel@tonic-gate 	queue_t *qp;
577*7c478bd9Sstevel@tonic-gate 	int rval;
578*7c478bd9Sstevel@tonic-gate 	int freestp = 1;
579*7c478bd9Sstevel@tonic-gate 	queue_t *rmq;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
582*7c478bd9Sstevel@tonic-gate 	if (audit_active)
583*7c478bd9Sstevel@tonic-gate 		audit_strclose(vp, flag, crp);
584*7c478bd9Sstevel@tonic-gate #endif
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
587*7c478bd9Sstevel@tonic-gate 		TR_STRCLOSE, "strclose:%p", vp);
588*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
591*7c478bd9Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
592*7c478bd9Sstevel@tonic-gate 	qp = stp->sd_wrq;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	/*
595*7c478bd9Sstevel@tonic-gate 	 * Needed so that strpoll will return non-zero for this fd.
596*7c478bd9Sstevel@tonic-gate 	 * Note that with POLLNOERR STRHUP does still cause POLLHUP.
597*7c478bd9Sstevel@tonic-gate 	 */
598*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
599*7c478bd9Sstevel@tonic-gate 	stp->sd_flag |= STRHUP;
600*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	/*
603*7c478bd9Sstevel@tonic-gate 	 * Since we call pollwakeup in close() now, the poll list should
604*7c478bd9Sstevel@tonic-gate 	 * be empty in most cases. The only exception is the layered devices
605*7c478bd9Sstevel@tonic-gate 	 * (e.g. the console drivers with redirection modules pushed on top
606*7c478bd9Sstevel@tonic-gate 	 * of it).
607*7c478bd9Sstevel@tonic-gate 	 */
608*7c478bd9Sstevel@tonic-gate 	if (stp->sd_pollist.ph_list != NULL) {
609*7c478bd9Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, POLLERR);
610*7c478bd9Sstevel@tonic-gate 		pollhead_clean(&stp->sd_pollist);
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_pollist.ph_list == NULL);
613*7c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_sidp == NULL);
614*7c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_pgidp == NULL);
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	/*
617*7c478bd9Sstevel@tonic-gate 	 * If the registered process or process group did not have an
618*7c478bd9Sstevel@tonic-gate 	 * open instance of this stream then strclean would not be
619*7c478bd9Sstevel@tonic-gate 	 * called. Thus at the time of closing all remaining siglist entries
620*7c478bd9Sstevel@tonic-gate 	 * are removed.
621*7c478bd9Sstevel@tonic-gate 	 */
622*7c478bd9Sstevel@tonic-gate 	if (stp->sd_siglist != NULL)
623*7c478bd9Sstevel@tonic-gate 		strcleanall(vp);
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_siglist == NULL);
626*7c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_sigflags == 0);
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	if (STRMATED(stp)) {
629*7c478bd9Sstevel@tonic-gate 		struct stdata *strmatep = stp->sd_mate;
630*7c478bd9Sstevel@tonic-gate 		int waited = 1;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 		STRLOCKMATES(stp);
633*7c478bd9Sstevel@tonic-gate 		while (waited) {
634*7c478bd9Sstevel@tonic-gate 			waited = 0;
635*7c478bd9Sstevel@tonic-gate 			while (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) {
636*7c478bd9Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
637*7c478bd9Sstevel@tonic-gate 				cv_wait(&stp->sd_monitor, &stp->sd_lock);
638*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
639*7c478bd9Sstevel@tonic-gate 				STRLOCKMATES(stp);
640*7c478bd9Sstevel@tonic-gate 				waited = 1;
641*7c478bd9Sstevel@tonic-gate 			}
642*7c478bd9Sstevel@tonic-gate 			while (strmatep->sd_flag &
643*7c478bd9Sstevel@tonic-gate 			    (STWOPEN|STRCLOSE|STRPLUMB)) {
644*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
645*7c478bd9Sstevel@tonic-gate 				cv_wait(&strmatep->sd_monitor,
646*7c478bd9Sstevel@tonic-gate 				    &strmatep->sd_lock);
647*7c478bd9Sstevel@tonic-gate 				mutex_exit(&strmatep->sd_lock);
648*7c478bd9Sstevel@tonic-gate 				STRLOCKMATES(stp);
649*7c478bd9Sstevel@tonic-gate 				waited = 1;
650*7c478bd9Sstevel@tonic-gate 			}
651*7c478bd9Sstevel@tonic-gate 		}
652*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STRCLOSE;
653*7c478bd9Sstevel@tonic-gate 		STRUNLOCKMATES(stp);
654*7c478bd9Sstevel@tonic-gate 	} else {
655*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
656*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STRCLOSE;
657*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
658*7c478bd9Sstevel@tonic-gate 	}
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	ASSERT(qp->q_first == NULL);	/* No more delayed write */
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	/* Check if an I_LINK was ever done on this stream */
663*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & STRHASLINKS) {
664*7c478bd9Sstevel@tonic-gate 		(void) munlinkall(stp, LINKCLOSE|LINKNORMAL, crp, &rval);
665*7c478bd9Sstevel@tonic-gate 	}
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	while (_SAMESTR(qp)) {
668*7c478bd9Sstevel@tonic-gate 		/*
669*7c478bd9Sstevel@tonic-gate 		 * Holding sd_lock prevents q_next from changing in
670*7c478bd9Sstevel@tonic-gate 		 * this stream.
671*7c478bd9Sstevel@tonic-gate 		 */
672*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
673*7c478bd9Sstevel@tonic-gate 		if (!(flag & (FNDELAY|FNONBLOCK)) && (stp->sd_closetime > 0)) {
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 			/*
676*7c478bd9Sstevel@tonic-gate 			 * sleep until awakened by strwsrv() or timeout
677*7c478bd9Sstevel@tonic-gate 			 */
678*7c478bd9Sstevel@tonic-gate 			for (;;) {
679*7c478bd9Sstevel@tonic-gate 				mutex_enter(QLOCK(qp->q_next));
680*7c478bd9Sstevel@tonic-gate 				if (!(qp->q_next->q_mblkcnt)) {
681*7c478bd9Sstevel@tonic-gate 					mutex_exit(QLOCK(qp->q_next));
682*7c478bd9Sstevel@tonic-gate 					break;
683*7c478bd9Sstevel@tonic-gate 				}
684*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= WSLEEP;
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 				/* ensure strwsrv gets enabled */
687*7c478bd9Sstevel@tonic-gate 				qp->q_next->q_flag |= QWANTW;
688*7c478bd9Sstevel@tonic-gate 				mutex_exit(QLOCK(qp->q_next));
689*7c478bd9Sstevel@tonic-gate 				/* get out if we timed out or recv'd a signal */
690*7c478bd9Sstevel@tonic-gate 				if (str_cv_wait(&qp->q_wait, &stp->sd_lock,
691*7c478bd9Sstevel@tonic-gate 				    stp->sd_closetime, 0) <= 0) {
692*7c478bd9Sstevel@tonic-gate 					break;
693*7c478bd9Sstevel@tonic-gate 				}
694*7c478bd9Sstevel@tonic-gate 			}
695*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~WSLEEP;
696*7c478bd9Sstevel@tonic-gate 		}
697*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 		rmq = qp->q_next;
700*7c478bd9Sstevel@tonic-gate 		if (rmq->q_flag & QISDRV) {
701*7c478bd9Sstevel@tonic-gate 			ASSERT(!_SAMESTR(rmq));
702*7c478bd9Sstevel@tonic-gate 			wait_sq_svc(_RD(qp)->q_syncq);
703*7c478bd9Sstevel@tonic-gate 		}
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 		qdetach(_RD(rmq), 1, flag, crp, B_FALSE);
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	/* Prevent qenable from re-enabling the stream head queue */
709*7c478bd9Sstevel@tonic-gate 	disable_svc(_RD(qp));
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	/*
712*7c478bd9Sstevel@tonic-gate 	 * Wait until service procedure of each queue is
713*7c478bd9Sstevel@tonic-gate 	 * run, if QINSERVICE is set.
714*7c478bd9Sstevel@tonic-gate 	 */
715*7c478bd9Sstevel@tonic-gate 	wait_svc(_RD(qp));
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	/*
718*7c478bd9Sstevel@tonic-gate 	 * Now, flush both queues.
719*7c478bd9Sstevel@tonic-gate 	 */
720*7c478bd9Sstevel@tonic-gate 	flushq(_RD(qp), FLUSHALL);
721*7c478bd9Sstevel@tonic-gate 	flushq(qp, FLUSHALL);
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	/*
724*7c478bd9Sstevel@tonic-gate 	 * If the write queue of the stream head is pointing to a
725*7c478bd9Sstevel@tonic-gate 	 * read queue, we have a twisted stream.  If the read queue
726*7c478bd9Sstevel@tonic-gate 	 * is alive, convert the stream head queues into a dead end.
727*7c478bd9Sstevel@tonic-gate 	 * If the read queue is dead, free the dead pair.
728*7c478bd9Sstevel@tonic-gate 	 */
729*7c478bd9Sstevel@tonic-gate 	if (qp->q_next && !_SAMESTR(qp)) {
730*7c478bd9Sstevel@tonic-gate 		if (qp->q_next->q_qinfo == &deadrend) {	/* half-closed pipe */
731*7c478bd9Sstevel@tonic-gate 			flushq(qp->q_next, FLUSHALL); /* ensure no message */
732*7c478bd9Sstevel@tonic-gate 			shfree(qp->q_next->q_stream);
733*7c478bd9Sstevel@tonic-gate 			freeq(qp->q_next);
734*7c478bd9Sstevel@tonic-gate 			freeq(_RD(qp));
735*7c478bd9Sstevel@tonic-gate 		} else if (qp->q_next == _RD(qp)) {	/* fifo */
736*7c478bd9Sstevel@tonic-gate 			freeq(_RD(qp));
737*7c478bd9Sstevel@tonic-gate 		} else {				/* pipe */
738*7c478bd9Sstevel@tonic-gate 			freestp = 0;
739*7c478bd9Sstevel@tonic-gate 			/*
740*7c478bd9Sstevel@tonic-gate 			 * The q_info pointers are never accessed when
741*7c478bd9Sstevel@tonic-gate 			 * SQLOCK is held.
742*7c478bd9Sstevel@tonic-gate 			 */
743*7c478bd9Sstevel@tonic-gate 			ASSERT(qp->q_syncq == _RD(qp)->q_syncq);
744*7c478bd9Sstevel@tonic-gate 			mutex_enter(SQLOCK(qp->q_syncq));
745*7c478bd9Sstevel@tonic-gate 			qp->q_qinfo = &deadwend;
746*7c478bd9Sstevel@tonic-gate 			_RD(qp)->q_qinfo = &deadrend;
747*7c478bd9Sstevel@tonic-gate 			mutex_exit(SQLOCK(qp->q_syncq));
748*7c478bd9Sstevel@tonic-gate 		}
749*7c478bd9Sstevel@tonic-gate 	} else {
750*7c478bd9Sstevel@tonic-gate 		freeq(_RD(qp)); /* free stream head queue pair */
751*7c478bd9Sstevel@tonic-gate 	}
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
754*7c478bd9Sstevel@tonic-gate 	if (stp->sd_iocblk) {
755*7c478bd9Sstevel@tonic-gate 		if (stp->sd_iocblk != (mblk_t *)-1) {
756*7c478bd9Sstevel@tonic-gate 			freemsg(stp->sd_iocblk);
757*7c478bd9Sstevel@tonic-gate 		}
758*7c478bd9Sstevel@tonic-gate 		stp->sd_iocblk = NULL;
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 	stp->sd_vnode = NULL;
761*7c478bd9Sstevel@tonic-gate 	vp->v_stream = NULL;
762*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
763*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
764*7c478bd9Sstevel@tonic-gate 	stp->sd_flag &= ~STRCLOSE;
765*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&stp->sd_monitor);
766*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	if (freestp)
769*7c478bd9Sstevel@tonic-gate 		shfree(stp);
770*7c478bd9Sstevel@tonic-gate 	return (0);
771*7c478bd9Sstevel@tonic-gate }
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate static int
774*7c478bd9Sstevel@tonic-gate strsink(queue_t *q, mblk_t *bp)
775*7c478bd9Sstevel@tonic-gate {
776*7c478bd9Sstevel@tonic-gate 	struct copyresp *resp;
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
779*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
780*7c478bd9Sstevel@tonic-gate 		if ((*bp->b_rptr & FLUSHW) && !(bp->b_flag & MSGNOLOOP)) {
781*7c478bd9Sstevel@tonic-gate 			*bp->b_rptr &= ~FLUSHR;
782*7c478bd9Sstevel@tonic-gate 			bp->b_flag |= MSGNOLOOP;
783*7c478bd9Sstevel@tonic-gate 			/*
784*7c478bd9Sstevel@tonic-gate 			 * Protect against the driver passing up
785*7c478bd9Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
786*7c478bd9Sstevel@tonic-gate 			 */
787*7c478bd9Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
788*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
789*7c478bd9Sstevel@tonic-gate 			else
790*7c478bd9Sstevel@tonic-gate 				qreply(q, bp);
791*7c478bd9Sstevel@tonic-gate 		} else {
792*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
793*7c478bd9Sstevel@tonic-gate 		}
794*7c478bd9Sstevel@tonic-gate 		break;
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	case M_COPYIN:
797*7c478bd9Sstevel@tonic-gate 	case M_COPYOUT:
798*7c478bd9Sstevel@tonic-gate 		if (bp->b_cont) {
799*7c478bd9Sstevel@tonic-gate 			freemsg(bp->b_cont);
800*7c478bd9Sstevel@tonic-gate 			bp->b_cont = NULL;
801*7c478bd9Sstevel@tonic-gate 		}
802*7c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
803*7c478bd9Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
804*7c478bd9Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
805*7c478bd9Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)1;	/* failure */
806*7c478bd9Sstevel@tonic-gate 		/*
807*7c478bd9Sstevel@tonic-gate 		 * Protect against the driver passing up
808*7c478bd9Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
809*7c478bd9Sstevel@tonic-gate 		 */
810*7c478bd9Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
811*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
812*7c478bd9Sstevel@tonic-gate 		else
813*7c478bd9Sstevel@tonic-gate 			qreply(q, bp);
814*7c478bd9Sstevel@tonic-gate 		break;
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
817*7c478bd9Sstevel@tonic-gate 		if (bp->b_cont) {
818*7c478bd9Sstevel@tonic-gate 			freemsg(bp->b_cont);
819*7c478bd9Sstevel@tonic-gate 			bp->b_cont = NULL;
820*7c478bd9Sstevel@tonic-gate 		}
821*7c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCNAK;
822*7c478bd9Sstevel@tonic-gate 		/*
823*7c478bd9Sstevel@tonic-gate 		 * Protect against the driver passing up
824*7c478bd9Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
825*7c478bd9Sstevel@tonic-gate 		 */
826*7c478bd9Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
827*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
828*7c478bd9Sstevel@tonic-gate 		else
829*7c478bd9Sstevel@tonic-gate 			qreply(q, bp);
830*7c478bd9Sstevel@tonic-gate 		break;
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	default:
833*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
834*7c478bd9Sstevel@tonic-gate 		break;
835*7c478bd9Sstevel@tonic-gate 	}
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	return (0);
838*7c478bd9Sstevel@tonic-gate }
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate /*
841*7c478bd9Sstevel@tonic-gate  * Clean up after a process when it closes a stream.  This is called
842*7c478bd9Sstevel@tonic-gate  * from closef for all closes, whereas strclose is called only for the
843*7c478bd9Sstevel@tonic-gate  * last close on a stream.  The siglist is scanned for entries for the
844*7c478bd9Sstevel@tonic-gate  * current process, and these are removed.
845*7c478bd9Sstevel@tonic-gate  */
846*7c478bd9Sstevel@tonic-gate void
847*7c478bd9Sstevel@tonic-gate strclean(struct vnode *vp)
848*7c478bd9Sstevel@tonic-gate {
849*7c478bd9Sstevel@tonic-gate 	strsig_t *ssp, *pssp, *tssp;
850*7c478bd9Sstevel@tonic-gate 	stdata_t *stp;
851*7c478bd9Sstevel@tonic-gate 	int update = 0;
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
854*7c478bd9Sstevel@tonic-gate 		TR_STRCLEAN, "strclean:%p", vp);
855*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
856*7c478bd9Sstevel@tonic-gate 	pssp = NULL;
857*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
858*7c478bd9Sstevel@tonic-gate 	ssp = stp->sd_siglist;
859*7c478bd9Sstevel@tonic-gate 	while (ssp) {
860*7c478bd9Sstevel@tonic-gate 		if (ssp->ss_pidp == curproc->p_pidp) {
861*7c478bd9Sstevel@tonic-gate 			tssp = ssp->ss_next;
862*7c478bd9Sstevel@tonic-gate 			if (pssp)
863*7c478bd9Sstevel@tonic-gate 				pssp->ss_next = tssp;
864*7c478bd9Sstevel@tonic-gate 			else
865*7c478bd9Sstevel@tonic-gate 				stp->sd_siglist = tssp;
866*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
867*7c478bd9Sstevel@tonic-gate 			PID_RELE(ssp->ss_pidp);
868*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
869*7c478bd9Sstevel@tonic-gate 			kmem_free(ssp, sizeof (strsig_t));
870*7c478bd9Sstevel@tonic-gate 			update = 1;
871*7c478bd9Sstevel@tonic-gate 			ssp = tssp;
872*7c478bd9Sstevel@tonic-gate 		} else {
873*7c478bd9Sstevel@tonic-gate 			pssp = ssp;
874*7c478bd9Sstevel@tonic-gate 			ssp = ssp->ss_next;
875*7c478bd9Sstevel@tonic-gate 		}
876*7c478bd9Sstevel@tonic-gate 	}
877*7c478bd9Sstevel@tonic-gate 	if (update) {
878*7c478bd9Sstevel@tonic-gate 		stp->sd_sigflags = 0;
879*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
880*7c478bd9Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
883*7c478bd9Sstevel@tonic-gate }
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate /*
886*7c478bd9Sstevel@tonic-gate  * Used on the last close to remove any remaining items on the siglist.
887*7c478bd9Sstevel@tonic-gate  * These could be present on the siglist due to I_ESETSIG calls that
888*7c478bd9Sstevel@tonic-gate  * use process groups or processed that do not have an open file descriptor
889*7c478bd9Sstevel@tonic-gate  * for this stream (Such entries would not be removed by strclean).
890*7c478bd9Sstevel@tonic-gate  */
891*7c478bd9Sstevel@tonic-gate static void
892*7c478bd9Sstevel@tonic-gate strcleanall(struct vnode *vp)
893*7c478bd9Sstevel@tonic-gate {
894*7c478bd9Sstevel@tonic-gate 	strsig_t *ssp, *nssp;
895*7c478bd9Sstevel@tonic-gate 	stdata_t *stp;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
898*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
899*7c478bd9Sstevel@tonic-gate 	ssp = stp->sd_siglist;
900*7c478bd9Sstevel@tonic-gate 	stp->sd_siglist = NULL;
901*7c478bd9Sstevel@tonic-gate 	while (ssp) {
902*7c478bd9Sstevel@tonic-gate 		nssp = ssp->ss_next;
903*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
904*7c478bd9Sstevel@tonic-gate 		PID_RELE(ssp->ss_pidp);
905*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
906*7c478bd9Sstevel@tonic-gate 		kmem_free(ssp, sizeof (strsig_t));
907*7c478bd9Sstevel@tonic-gate 		ssp = nssp;
908*7c478bd9Sstevel@tonic-gate 	}
909*7c478bd9Sstevel@tonic-gate 	stp->sd_sigflags = 0;
910*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
911*7c478bd9Sstevel@tonic-gate }
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate /*
914*7c478bd9Sstevel@tonic-gate  * Retrieve the next message from the logical stream head read queue
915*7c478bd9Sstevel@tonic-gate  * using either rwnext (if sync stream) or getq_noenab.
916*7c478bd9Sstevel@tonic-gate  * It is the callers responsibility to call qbackenable after
917*7c478bd9Sstevel@tonic-gate  * it is finished with the message. The caller should not call
918*7c478bd9Sstevel@tonic-gate  * qbackenable until after any putback calls to avoid spurious backenabling.
919*7c478bd9Sstevel@tonic-gate  */
920*7c478bd9Sstevel@tonic-gate mblk_t *
921*7c478bd9Sstevel@tonic-gate strget(struct stdata *stp, queue_t *q, struct uio *uiop, int first,
922*7c478bd9Sstevel@tonic-gate     int *errorp)
923*7c478bd9Sstevel@tonic-gate {
924*7c478bd9Sstevel@tonic-gate 	mblk_t *bp;
925*7c478bd9Sstevel@tonic-gate 	int error;
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
928*7c478bd9Sstevel@tonic-gate 	/* Holding sd_lock prevents the read queue from changing  */
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 	if (uiop != NULL && stp->sd_struiordq != NULL &&
931*7c478bd9Sstevel@tonic-gate 	    q->q_first == NULL &&
932*7c478bd9Sstevel@tonic-gate 	    (!first || (stp->sd_wakeq & RSLEEP))) {
933*7c478bd9Sstevel@tonic-gate 		/*
934*7c478bd9Sstevel@tonic-gate 		 * Stream supports rwnext() for the read side.
935*7c478bd9Sstevel@tonic-gate 		 * If this is the first time we're called by e.g. strread
936*7c478bd9Sstevel@tonic-gate 		 * only do the downcall if there is a deferred wakeup
937*7c478bd9Sstevel@tonic-gate 		 * (registered in sd_wakeq).
938*7c478bd9Sstevel@tonic-gate 		 */
939*7c478bd9Sstevel@tonic-gate 		struiod_t uiod;
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 		if (first)
942*7c478bd9Sstevel@tonic-gate 			stp->sd_wakeq &= ~RSLEEP;
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 		(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
945*7c478bd9Sstevel@tonic-gate 			sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
946*7c478bd9Sstevel@tonic-gate 		uiod.d_mp = 0;
947*7c478bd9Sstevel@tonic-gate 		/*
948*7c478bd9Sstevel@tonic-gate 		 * Mark that a thread is in rwnext on the read side
949*7c478bd9Sstevel@tonic-gate 		 * to prevent strrput from nacking ioctls immediately.
950*7c478bd9Sstevel@tonic-gate 		 * When the last concurrent rwnext returns
951*7c478bd9Sstevel@tonic-gate 		 * the ioctls are nack'ed.
952*7c478bd9Sstevel@tonic-gate 		 */
953*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
954*7c478bd9Sstevel@tonic-gate 		stp->sd_struiodnak++;
955*7c478bd9Sstevel@tonic-gate 		/*
956*7c478bd9Sstevel@tonic-gate 		 * Note: rwnext will drop sd_lock.
957*7c478bd9Sstevel@tonic-gate 		 */
958*7c478bd9Sstevel@tonic-gate 		error = rwnext(q, &uiod);
959*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
960*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
961*7c478bd9Sstevel@tonic-gate 		stp->sd_struiodnak--;
962*7c478bd9Sstevel@tonic-gate 		while (stp->sd_struiodnak == 0 &&
963*7c478bd9Sstevel@tonic-gate 		    ((bp = stp->sd_struionak) != NULL)) {
964*7c478bd9Sstevel@tonic-gate 			stp->sd_struionak = bp->b_next;
965*7c478bd9Sstevel@tonic-gate 			bp->b_next = NULL;
966*7c478bd9Sstevel@tonic-gate 			bp->b_datap->db_type = M_IOCNAK;
967*7c478bd9Sstevel@tonic-gate 			/*
968*7c478bd9Sstevel@tonic-gate 			 * Protect against the driver passing up
969*7c478bd9Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
970*7c478bd9Sstevel@tonic-gate 			 */
971*7c478bd9Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
972*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
973*7c478bd9Sstevel@tonic-gate 			else {
974*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
975*7c478bd9Sstevel@tonic-gate 				qreply(q, bp);
976*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
977*7c478bd9Sstevel@tonic-gate 			}
978*7c478bd9Sstevel@tonic-gate 		}
979*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
980*7c478bd9Sstevel@tonic-gate 		if (error == 0 || error == EWOULDBLOCK) {
981*7c478bd9Sstevel@tonic-gate 			if ((bp = uiod.d_mp) != NULL) {
982*7c478bd9Sstevel@tonic-gate 				*errorp = 0;
983*7c478bd9Sstevel@tonic-gate 				ASSERT(MUTEX_HELD(&stp->sd_lock));
984*7c478bd9Sstevel@tonic-gate 				return (bp);
985*7c478bd9Sstevel@tonic-gate 			}
986*7c478bd9Sstevel@tonic-gate 			error = 0;
987*7c478bd9Sstevel@tonic-gate 		} else if (error == EINVAL) {
988*7c478bd9Sstevel@tonic-gate 			/*
989*7c478bd9Sstevel@tonic-gate 			 * The stream plumbing must have
990*7c478bd9Sstevel@tonic-gate 			 * changed while we were away, so
991*7c478bd9Sstevel@tonic-gate 			 * just turn off rwnext()s.
992*7c478bd9Sstevel@tonic-gate 			 */
993*7c478bd9Sstevel@tonic-gate 			error = 0;
994*7c478bd9Sstevel@tonic-gate 		} else if (error == EBUSY) {
995*7c478bd9Sstevel@tonic-gate 			/*
996*7c478bd9Sstevel@tonic-gate 			 * The module might have data in transit using putnext
997*7c478bd9Sstevel@tonic-gate 			 * Fall back on waiting + getq.
998*7c478bd9Sstevel@tonic-gate 			 */
999*7c478bd9Sstevel@tonic-gate 			error = 0;
1000*7c478bd9Sstevel@tonic-gate 		} else {
1001*7c478bd9Sstevel@tonic-gate 			*errorp = error;
1002*7c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
1003*7c478bd9Sstevel@tonic-gate 			return (NULL);
1004*7c478bd9Sstevel@tonic-gate 		}
1005*7c478bd9Sstevel@tonic-gate 		/*
1006*7c478bd9Sstevel@tonic-gate 		 * Try a getq in case a rwnext() generated mblk
1007*7c478bd9Sstevel@tonic-gate 		 * has bubbled up via strrput().
1008*7c478bd9Sstevel@tonic-gate 		 */
1009*7c478bd9Sstevel@tonic-gate 	}
1010*7c478bd9Sstevel@tonic-gate 	*errorp = 0;
1011*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
1012*7c478bd9Sstevel@tonic-gate 	return (getq_noenab(q));
1013*7c478bd9Sstevel@tonic-gate }
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate /*
1016*7c478bd9Sstevel@tonic-gate  * Copy out the message pointed to by `bp' into the uio pointed to by `uiop'.
1017*7c478bd9Sstevel@tonic-gate  * If the message does not fit in the uio the remainder of it is returned;
1018*7c478bd9Sstevel@tonic-gate  * otherwise NULL is returned.  Any embedded zero-length mblk_t's are
1019*7c478bd9Sstevel@tonic-gate  * consumed, even if uio_resid reaches zero.  On error, `*errorp' is set to
1020*7c478bd9Sstevel@tonic-gate  * the error code, the message is consumed, and NULL is returned.
1021*7c478bd9Sstevel@tonic-gate  */
1022*7c478bd9Sstevel@tonic-gate static mblk_t *
1023*7c478bd9Sstevel@tonic-gate struiocopyout(mblk_t *bp, struct uio *uiop, int *errorp)
1024*7c478bd9Sstevel@tonic-gate {
1025*7c478bd9Sstevel@tonic-gate 	int error;
1026*7c478bd9Sstevel@tonic-gate 	ptrdiff_t n;
1027*7c478bd9Sstevel@tonic-gate 	mblk_t *nbp;
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	ASSERT(bp->b_wptr >= bp->b_rptr);
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	do {
1032*7c478bd9Sstevel@tonic-gate 		if ((n = MIN(uiop->uio_resid, MBLKL(bp))) != 0) {
1033*7c478bd9Sstevel@tonic-gate 			ASSERT(n > 0);
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 			error = uiomove(bp->b_rptr, n, UIO_READ, uiop);
1036*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
1037*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
1038*7c478bd9Sstevel@tonic-gate 				*errorp = error;
1039*7c478bd9Sstevel@tonic-gate 				return (NULL);
1040*7c478bd9Sstevel@tonic-gate 			}
1041*7c478bd9Sstevel@tonic-gate 		}
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 		bp->b_rptr += n;
1044*7c478bd9Sstevel@tonic-gate 		while (bp != NULL && (bp->b_rptr >= bp->b_wptr)) {
1045*7c478bd9Sstevel@tonic-gate 			nbp = bp;
1046*7c478bd9Sstevel@tonic-gate 			bp = bp->b_cont;
1047*7c478bd9Sstevel@tonic-gate 			freeb(nbp);
1048*7c478bd9Sstevel@tonic-gate 		}
1049*7c478bd9Sstevel@tonic-gate 	} while (bp != NULL && uiop->uio_resid > 0);
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 	*errorp = 0;
1052*7c478bd9Sstevel@tonic-gate 	return (bp);
1053*7c478bd9Sstevel@tonic-gate }
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate /*
1056*7c478bd9Sstevel@tonic-gate  * Read a stream according to the mode flags in sd_flag:
1057*7c478bd9Sstevel@tonic-gate  *
1058*7c478bd9Sstevel@tonic-gate  * (default mode)		- Byte stream, msg boundaries are ignored
1059*7c478bd9Sstevel@tonic-gate  * RD_MSGDIS (msg discard)	- Read on msg boundaries and throw away
1060*7c478bd9Sstevel@tonic-gate  *				any data remaining in msg
1061*7c478bd9Sstevel@tonic-gate  * RD_MSGNODIS (msg non-discard) - Read on msg boundaries and put back
1062*7c478bd9Sstevel@tonic-gate  *				any remaining data on head of read queue
1063*7c478bd9Sstevel@tonic-gate  *
1064*7c478bd9Sstevel@tonic-gate  * Consume readable messages on the front of the queue until
1065*7c478bd9Sstevel@tonic-gate  * ttolwp(curthread)->lwp_count
1066*7c478bd9Sstevel@tonic-gate  * is satisfied, the readable messages are exhausted, or a message
1067*7c478bd9Sstevel@tonic-gate  * boundary is reached in a message mode.  If no data was read and
1068*7c478bd9Sstevel@tonic-gate  * the stream was not opened with the NDELAY flag, block until data arrives.
1069*7c478bd9Sstevel@tonic-gate  * Otherwise return the data read and update the count.
1070*7c478bd9Sstevel@tonic-gate  *
1071*7c478bd9Sstevel@tonic-gate  * In default mode a 0 length message signifies end-of-file and terminates
1072*7c478bd9Sstevel@tonic-gate  * a read in progress.  The 0 length message is removed from the queue
1073*7c478bd9Sstevel@tonic-gate  * only if it is the only message read (no data is read).
1074*7c478bd9Sstevel@tonic-gate  *
1075*7c478bd9Sstevel@tonic-gate  * An attempt to read an M_PROTO or M_PCPROTO message results in an
1076*7c478bd9Sstevel@tonic-gate  * EBADMSG error return, unless either RD_PROTDAT or RD_PROTDIS are set.
1077*7c478bd9Sstevel@tonic-gate  * If RD_PROTDAT is set, M_PROTO and M_PCPROTO messages are read as data.
1078*7c478bd9Sstevel@tonic-gate  * If RD_PROTDIS is set, the M_PROTO and M_PCPROTO parts of the message
1079*7c478bd9Sstevel@tonic-gate  * are unlinked from and M_DATA blocks in the message, the protos are
1080*7c478bd9Sstevel@tonic-gate  * thrown away, and the data is read.
1081*7c478bd9Sstevel@tonic-gate  */
1082*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1083*7c478bd9Sstevel@tonic-gate int
1084*7c478bd9Sstevel@tonic-gate strread(struct vnode *vp, struct uio *uiop, cred_t *crp)
1085*7c478bd9Sstevel@tonic-gate {
1086*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
1087*7c478bd9Sstevel@tonic-gate 	mblk_t *bp, *nbp;
1088*7c478bd9Sstevel@tonic-gate 	queue_t *q;
1089*7c478bd9Sstevel@tonic-gate 	int error = 0;
1090*7c478bd9Sstevel@tonic-gate 	uint_t old_sd_flag;
1091*7c478bd9Sstevel@tonic-gate 	int first;
1092*7c478bd9Sstevel@tonic-gate 	char rflg;
1093*7c478bd9Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
1094*7c478bd9Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
1095*7c478bd9Sstevel@tonic-gate 	short delim;
1096*7c478bd9Sstevel@tonic-gate 	unsigned char pri = 0;
1097*7c478bd9Sstevel@tonic-gate 	char waitflag;
1098*7c478bd9Sstevel@tonic-gate 	unsigned char type;
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
1101*7c478bd9Sstevel@tonic-gate 		TR_STRREAD_ENTER, "strread:%p", vp);
1102*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
1103*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
1106*7c478bd9Sstevel@tonic-gate 		if (error = straccess(stp, JCREAD))
1107*7c478bd9Sstevel@tonic-gate 			return (error);
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
1110*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
1111*7c478bd9Sstevel@tonic-gate 		error = strgeterr(stp, STRDERR|STPLEX, 0);
1112*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
1113*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
1114*7c478bd9Sstevel@tonic-gate 			return (error);
1115*7c478bd9Sstevel@tonic-gate 		}
1116*7c478bd9Sstevel@tonic-gate 	}
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	/*
1119*7c478bd9Sstevel@tonic-gate 	 * Loop terminates when uiop->uio_resid == 0.
1120*7c478bd9Sstevel@tonic-gate 	 */
1121*7c478bd9Sstevel@tonic-gate 	rflg = 0;
1122*7c478bd9Sstevel@tonic-gate 	waitflag = READWAIT;
1123*7c478bd9Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
1124*7c478bd9Sstevel@tonic-gate 	for (;;) {
1125*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
1126*7c478bd9Sstevel@tonic-gate 		old_sd_flag = stp->sd_flag;
1127*7c478bd9Sstevel@tonic-gate 		mark = 0;
1128*7c478bd9Sstevel@tonic-gate 		delim = 0;
1129*7c478bd9Sstevel@tonic-gate 		first = 1;
1130*7c478bd9Sstevel@tonic-gate 		while ((bp = strget(stp, q, uiop, first, &error)) == NULL) {
1131*7c478bd9Sstevel@tonic-gate 			int done = 0;
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 			if (error != 0)
1136*7c478bd9Sstevel@tonic-gate 				goto oops;
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 			if (stp->sd_flag & (STRHUP|STREOF)) {
1139*7c478bd9Sstevel@tonic-gate 				goto oops;
1140*7c478bd9Sstevel@tonic-gate 			}
1141*7c478bd9Sstevel@tonic-gate 			if (rflg && !(stp->sd_flag & STRDELIM)) {
1142*7c478bd9Sstevel@tonic-gate 				goto oops;
1143*7c478bd9Sstevel@tonic-gate 			}
1144*7c478bd9Sstevel@tonic-gate 			/*
1145*7c478bd9Sstevel@tonic-gate 			 * If a read(fd,buf,0) has been done, there is no
1146*7c478bd9Sstevel@tonic-gate 			 * need to sleep. We always have zero bytes to
1147*7c478bd9Sstevel@tonic-gate 			 * return.
1148*7c478bd9Sstevel@tonic-gate 			 */
1149*7c478bd9Sstevel@tonic-gate 			if (uiop->uio_resid == 0) {
1150*7c478bd9Sstevel@tonic-gate 				goto oops;
1151*7c478bd9Sstevel@tonic-gate 			}
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 			qbackenable(q, 0);
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_WAIT,
1156*7c478bd9Sstevel@tonic-gate 				"strread calls strwaitq:%p, %p, %p",
1157*7c478bd9Sstevel@tonic-gate 				vp, uiop, crp);
1158*7c478bd9Sstevel@tonic-gate 			if ((error = strwaitq(stp, waitflag, uiop->uio_resid,
1159*7c478bd9Sstevel@tonic-gate 			    uiop->uio_fmode, -1, &done)) != 0 || done) {
1160*7c478bd9Sstevel@tonic-gate 				TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_DONE,
1161*7c478bd9Sstevel@tonic-gate 					"strread error or done:%p, %p, %p",
1162*7c478bd9Sstevel@tonic-gate 					vp, uiop, crp);
1163*7c478bd9Sstevel@tonic-gate 				if ((uiop->uio_fmode & FNDELAY) &&
1164*7c478bd9Sstevel@tonic-gate 				    (stp->sd_flag & OLDNDELAY) &&
1165*7c478bd9Sstevel@tonic-gate 				    (error == EAGAIN))
1166*7c478bd9Sstevel@tonic-gate 					error = 0;
1167*7c478bd9Sstevel@tonic-gate 				goto oops;
1168*7c478bd9Sstevel@tonic-gate 			}
1169*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRREAD_AWAKE,
1170*7c478bd9Sstevel@tonic-gate 				"strread awakes:%p, %p, %p", vp, uiop, crp);
1171*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
1172*7c478bd9Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
1173*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1174*7c478bd9Sstevel@tonic-gate 				if (error = straccess(stp, JCREAD))
1175*7c478bd9Sstevel@tonic-gate 					goto oops1;
1176*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
1177*7c478bd9Sstevel@tonic-gate 			}
1178*7c478bd9Sstevel@tonic-gate 			first = 0;
1179*7c478bd9Sstevel@tonic-gate 		}
1180*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&stp->sd_lock));
1181*7c478bd9Sstevel@tonic-gate 		ASSERT(bp);
1182*7c478bd9Sstevel@tonic-gate 		pri = bp->b_band;
1183*7c478bd9Sstevel@tonic-gate 		/*
1184*7c478bd9Sstevel@tonic-gate 		 * Extract any mark information. If the message is not
1185*7c478bd9Sstevel@tonic-gate 		 * completely consumed this information will be put in the mblk
1186*7c478bd9Sstevel@tonic-gate 		 * that is putback.
1187*7c478bd9Sstevel@tonic-gate 		 * If MSGMARKNEXT is set and the message is completely consumed
1188*7c478bd9Sstevel@tonic-gate 		 * the STRATMARK flag will be set below. Likewise, if
1189*7c478bd9Sstevel@tonic-gate 		 * MSGNOTMARKNEXT is set and the message is
1190*7c478bd9Sstevel@tonic-gate 		 * completely consumed STRNOTATMARK will be set.
1191*7c478bd9Sstevel@tonic-gate 		 *
1192*7c478bd9Sstevel@tonic-gate 		 * For some unknown reason strread only breaks the read at the
1193*7c478bd9Sstevel@tonic-gate 		 * last mark.
1194*7c478bd9Sstevel@tonic-gate 		 */
1195*7c478bd9Sstevel@tonic-gate 		mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
1196*7c478bd9Sstevel@tonic-gate 		ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
1197*7c478bd9Sstevel@tonic-gate 			(MSGMARKNEXT|MSGNOTMARKNEXT));
1198*7c478bd9Sstevel@tonic-gate 		if (mark != 0 && bp == stp->sd_mark) {
1199*7c478bd9Sstevel@tonic-gate 			if (rflg) {
1200*7c478bd9Sstevel@tonic-gate 				putback(stp, q, bp, pri);
1201*7c478bd9Sstevel@tonic-gate 				goto oops;
1202*7c478bd9Sstevel@tonic-gate 			}
1203*7c478bd9Sstevel@tonic-gate 			mark |= _LASTMARK;
1204*7c478bd9Sstevel@tonic-gate 			stp->sd_mark = NULL;
1205*7c478bd9Sstevel@tonic-gate 		}
1206*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & STRDELIM) && (bp->b_flag & MSGDELIM))
1207*7c478bd9Sstevel@tonic-gate 			delim = 1;
1208*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
1211*7c478bd9Sstevel@tonic-gate 			stream_runservice(stp);
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 		type = bp->b_datap->db_type;
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 		switch (type) {
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 		case M_DATA:
1218*7c478bd9Sstevel@tonic-gate ismdata:
1219*7c478bd9Sstevel@tonic-gate 			if (msgnodata(bp)) {
1220*7c478bd9Sstevel@tonic-gate 				if (mark || delim) {
1221*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
1222*7c478bd9Sstevel@tonic-gate 				} else if (rflg) {
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 					/*
1225*7c478bd9Sstevel@tonic-gate 					 * If already read data put zero
1226*7c478bd9Sstevel@tonic-gate 					 * length message back on queue else
1227*7c478bd9Sstevel@tonic-gate 					 * free msg and return 0.
1228*7c478bd9Sstevel@tonic-gate 					 */
1229*7c478bd9Sstevel@tonic-gate 					bp->b_band = pri;
1230*7c478bd9Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
1231*7c478bd9Sstevel@tonic-gate 					putback(stp, q, bp, pri);
1232*7c478bd9Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
1233*7c478bd9Sstevel@tonic-gate 				} else {
1234*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
1235*7c478bd9Sstevel@tonic-gate 				}
1236*7c478bd9Sstevel@tonic-gate 				error =  0;
1237*7c478bd9Sstevel@tonic-gate 				goto oops1;
1238*7c478bd9Sstevel@tonic-gate 			}
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 			rflg = 1;
1241*7c478bd9Sstevel@tonic-gate 			waitflag |= NOINTR;
1242*7c478bd9Sstevel@tonic-gate 			bp = struiocopyout(bp, uiop, &error);
1243*7c478bd9Sstevel@tonic-gate 			if (error != 0)
1244*7c478bd9Sstevel@tonic-gate 				goto oops1;
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
1247*7c478bd9Sstevel@tonic-gate 			if (bp) {
1248*7c478bd9Sstevel@tonic-gate 				/*
1249*7c478bd9Sstevel@tonic-gate 				 * Have remaining data in message.
1250*7c478bd9Sstevel@tonic-gate 				 * Free msg if in discard mode.
1251*7c478bd9Sstevel@tonic-gate 				 */
1252*7c478bd9Sstevel@tonic-gate 				if (stp->sd_read_opt & RD_MSGDIS) {
1253*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
1254*7c478bd9Sstevel@tonic-gate 				} else {
1255*7c478bd9Sstevel@tonic-gate 					bp->b_band = pri;
1256*7c478bd9Sstevel@tonic-gate 					if ((mark & _LASTMARK) &&
1257*7c478bd9Sstevel@tonic-gate 					    (stp->sd_mark == NULL))
1258*7c478bd9Sstevel@tonic-gate 						stp->sd_mark = bp;
1259*7c478bd9Sstevel@tonic-gate 					bp->b_flag |= mark & ~_LASTMARK;
1260*7c478bd9Sstevel@tonic-gate 					if (delim)
1261*7c478bd9Sstevel@tonic-gate 						bp->b_flag |= MSGDELIM;
1262*7c478bd9Sstevel@tonic-gate 					if (msgnodata(bp))
1263*7c478bd9Sstevel@tonic-gate 						freemsg(bp);
1264*7c478bd9Sstevel@tonic-gate 					else
1265*7c478bd9Sstevel@tonic-gate 						putback(stp, q, bp, pri);
1266*7c478bd9Sstevel@tonic-gate 				}
1267*7c478bd9Sstevel@tonic-gate 			} else {
1268*7c478bd9Sstevel@tonic-gate 				/*
1269*7c478bd9Sstevel@tonic-gate 				 * Consumed the complete message.
1270*7c478bd9Sstevel@tonic-gate 				 * Move the MSG*MARKNEXT information
1271*7c478bd9Sstevel@tonic-gate 				 * to the stream head just in case
1272*7c478bd9Sstevel@tonic-gate 				 * the read queue becomes empty.
1273*7c478bd9Sstevel@tonic-gate 				 *
1274*7c478bd9Sstevel@tonic-gate 				 * If the stream head was at the mark
1275*7c478bd9Sstevel@tonic-gate 				 * (STRATMARK) before we dropped sd_lock above
1276*7c478bd9Sstevel@tonic-gate 				 * and some data was consumed then we have
1277*7c478bd9Sstevel@tonic-gate 				 * moved past the mark thus STRATMARK is
1278*7c478bd9Sstevel@tonic-gate 				 * cleared. However, if a message arrived in
1279*7c478bd9Sstevel@tonic-gate 				 * strrput during the copyout above causing
1280*7c478bd9Sstevel@tonic-gate 				 * STRATMARK to be set we can not clear that
1281*7c478bd9Sstevel@tonic-gate 				 * flag.
1282*7c478bd9Sstevel@tonic-gate 				 */
1283*7c478bd9Sstevel@tonic-gate 				if (mark &
1284*7c478bd9Sstevel@tonic-gate 				    (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
1285*7c478bd9Sstevel@tonic-gate 					if (mark & MSGMARKNEXT) {
1286*7c478bd9Sstevel@tonic-gate 						stp->sd_flag &= ~STRNOTATMARK;
1287*7c478bd9Sstevel@tonic-gate 						stp->sd_flag |= STRATMARK;
1288*7c478bd9Sstevel@tonic-gate 					} else if (mark & MSGNOTMARKNEXT) {
1289*7c478bd9Sstevel@tonic-gate 						stp->sd_flag &= ~STRATMARK;
1290*7c478bd9Sstevel@tonic-gate 						stp->sd_flag |= STRNOTATMARK;
1291*7c478bd9Sstevel@tonic-gate 					} else {
1292*7c478bd9Sstevel@tonic-gate 						stp->sd_flag &=
1293*7c478bd9Sstevel@tonic-gate 						    ~(STRATMARK|STRNOTATMARK);
1294*7c478bd9Sstevel@tonic-gate 					}
1295*7c478bd9Sstevel@tonic-gate 				} else if (rflg && (old_sd_flag & STRATMARK)) {
1296*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRATMARK;
1297*7c478bd9Sstevel@tonic-gate 				}
1298*7c478bd9Sstevel@tonic-gate 			}
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 			/*
1301*7c478bd9Sstevel@tonic-gate 			 * Check for signal messages at the front of the read
1302*7c478bd9Sstevel@tonic-gate 			 * queue and generate the signal(s) if appropriate.
1303*7c478bd9Sstevel@tonic-gate 			 * The only signal that can be on queue is M_SIG at
1304*7c478bd9Sstevel@tonic-gate 			 * this point.
1305*7c478bd9Sstevel@tonic-gate 			 */
1306*7c478bd9Sstevel@tonic-gate 			while ((((bp = q->q_first)) != NULL) &&
1307*7c478bd9Sstevel@tonic-gate 				(bp->b_datap->db_type == M_SIG)) {
1308*7c478bd9Sstevel@tonic-gate 				bp = getq_noenab(q);
1309*7c478bd9Sstevel@tonic-gate 				/*
1310*7c478bd9Sstevel@tonic-gate 				 * sd_lock is held so the content of the
1311*7c478bd9Sstevel@tonic-gate 				 * read queue can not change.
1312*7c478bd9Sstevel@tonic-gate 				 */
1313*7c478bd9Sstevel@tonic-gate 				ASSERT(bp != NULL &&
1314*7c478bd9Sstevel@tonic-gate 					bp->b_datap->db_type == M_SIG);
1315*7c478bd9Sstevel@tonic-gate 				strsignal_nolock(stp, *bp->b_rptr,
1316*7c478bd9Sstevel@tonic-gate 					(int32_t)bp->b_band);
1317*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1318*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
1319*7c478bd9Sstevel@tonic-gate 				if (STREAM_NEEDSERVICE(stp))
1320*7c478bd9Sstevel@tonic-gate 					stream_runservice(stp);
1321*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
1322*7c478bd9Sstevel@tonic-gate 			}
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 			if ((uiop->uio_resid == 0) || (mark & _LASTMARK) ||
1325*7c478bd9Sstevel@tonic-gate 			    delim ||
1326*7c478bd9Sstevel@tonic-gate 			    (stp->sd_read_opt & (RD_MSGDIS|RD_MSGNODIS))) {
1327*7c478bd9Sstevel@tonic-gate 				goto oops;
1328*7c478bd9Sstevel@tonic-gate 			}
1329*7c478bd9Sstevel@tonic-gate 			continue;
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 		case M_SIG:
1332*7c478bd9Sstevel@tonic-gate 			strsignal(stp, *bp->b_rptr, (int32_t)bp->b_band);
1333*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
1334*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
1335*7c478bd9Sstevel@tonic-gate 			continue;
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 		case M_PROTO:
1338*7c478bd9Sstevel@tonic-gate 		case M_PCPROTO:
1339*7c478bd9Sstevel@tonic-gate 			/*
1340*7c478bd9Sstevel@tonic-gate 			 * Only data messages are readable.
1341*7c478bd9Sstevel@tonic-gate 			 * Any others generate an error, unless
1342*7c478bd9Sstevel@tonic-gate 			 * RD_PROTDIS or RD_PROTDAT is set.
1343*7c478bd9Sstevel@tonic-gate 			 */
1344*7c478bd9Sstevel@tonic-gate 			if (stp->sd_read_opt & RD_PROTDAT) {
1345*7c478bd9Sstevel@tonic-gate 				for (nbp = bp; nbp; nbp = nbp->b_next) {
1346*7c478bd9Sstevel@tonic-gate 				    if ((nbp->b_datap->db_type == M_PROTO) ||
1347*7c478bd9Sstevel@tonic-gate 					(nbp->b_datap->db_type == M_PCPROTO))
1348*7c478bd9Sstevel@tonic-gate 					nbp->b_datap->db_type = M_DATA;
1349*7c478bd9Sstevel@tonic-gate 				    else
1350*7c478bd9Sstevel@tonic-gate 					break;
1351*7c478bd9Sstevel@tonic-gate 				}
1352*7c478bd9Sstevel@tonic-gate 				/*
1353*7c478bd9Sstevel@tonic-gate 				 * clear stream head hi pri flag based on
1354*7c478bd9Sstevel@tonic-gate 				 * first message
1355*7c478bd9Sstevel@tonic-gate 				 */
1356*7c478bd9Sstevel@tonic-gate 				if (type == M_PCPROTO) {
1357*7c478bd9Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
1358*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
1359*7c478bd9Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
1360*7c478bd9Sstevel@tonic-gate 				}
1361*7c478bd9Sstevel@tonic-gate 				goto ismdata;
1362*7c478bd9Sstevel@tonic-gate 			} else if (stp->sd_read_opt & RD_PROTDIS) {
1363*7c478bd9Sstevel@tonic-gate 				/*
1364*7c478bd9Sstevel@tonic-gate 				 * discard non-data messages
1365*7c478bd9Sstevel@tonic-gate 				 */
1366*7c478bd9Sstevel@tonic-gate 				while (bp &&
1367*7c478bd9Sstevel@tonic-gate 				    ((bp->b_datap->db_type == M_PROTO) ||
1368*7c478bd9Sstevel@tonic-gate 				    (bp->b_datap->db_type == M_PCPROTO))) {
1369*7c478bd9Sstevel@tonic-gate 					nbp = unlinkb(bp);
1370*7c478bd9Sstevel@tonic-gate 					freeb(bp);
1371*7c478bd9Sstevel@tonic-gate 					bp = nbp;
1372*7c478bd9Sstevel@tonic-gate 				}
1373*7c478bd9Sstevel@tonic-gate 				/*
1374*7c478bd9Sstevel@tonic-gate 				 * clear stream head hi pri flag based on
1375*7c478bd9Sstevel@tonic-gate 				 * first message
1376*7c478bd9Sstevel@tonic-gate 				 */
1377*7c478bd9Sstevel@tonic-gate 				if (type == M_PCPROTO) {
1378*7c478bd9Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
1379*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
1380*7c478bd9Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
1381*7c478bd9Sstevel@tonic-gate 				}
1382*7c478bd9Sstevel@tonic-gate 				if (bp) {
1383*7c478bd9Sstevel@tonic-gate 					bp->b_band = pri;
1384*7c478bd9Sstevel@tonic-gate 					goto ismdata;
1385*7c478bd9Sstevel@tonic-gate 				} else {
1386*7c478bd9Sstevel@tonic-gate 					break;
1387*7c478bd9Sstevel@tonic-gate 				}
1388*7c478bd9Sstevel@tonic-gate 			}
1389*7c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
1390*7c478bd9Sstevel@tonic-gate 		case M_PASSFP:
1391*7c478bd9Sstevel@tonic-gate 			if ((bp->b_datap->db_type == M_PASSFP) &&
1392*7c478bd9Sstevel@tonic-gate 			    (stp->sd_read_opt & RD_PROTDIS)) {
1393*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
1394*7c478bd9Sstevel@tonic-gate 				break;
1395*7c478bd9Sstevel@tonic-gate 			}
1396*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
1397*7c478bd9Sstevel@tonic-gate 			putback(stp, q, bp, pri);
1398*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
1399*7c478bd9Sstevel@tonic-gate 			if (rflg == 0)
1400*7c478bd9Sstevel@tonic-gate 				error = EBADMSG;
1401*7c478bd9Sstevel@tonic-gate 			goto oops1;
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate 		default:
1404*7c478bd9Sstevel@tonic-gate 			/*
1405*7c478bd9Sstevel@tonic-gate 			 * Garbage on stream head read queue.
1406*7c478bd9Sstevel@tonic-gate 			 */
1407*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "bad %x found at stream head\n",
1408*7c478bd9Sstevel@tonic-gate 				bp->b_datap->db_type);
1409*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
1410*7c478bd9Sstevel@tonic-gate 			goto oops1;
1411*7c478bd9Sstevel@tonic-gate 		}
1412*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate oops:
1415*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
1416*7c478bd9Sstevel@tonic-gate oops1:
1417*7c478bd9Sstevel@tonic-gate 	qbackenable(q, pri);
1418*7c478bd9Sstevel@tonic-gate 	return (error);
1419*7c478bd9Sstevel@tonic-gate #undef	_LASTMARK
1420*7c478bd9Sstevel@tonic-gate }
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate /*
1423*7c478bd9Sstevel@tonic-gate  * Default processing of M_PROTO/M_PCPROTO messages.
1424*7c478bd9Sstevel@tonic-gate  * Determine which wakeups and signals are needed.
1425*7c478bd9Sstevel@tonic-gate  * This can be replaced by a user-specified procedure for kernel users
1426*7c478bd9Sstevel@tonic-gate  * of STREAMS.
1427*7c478bd9Sstevel@tonic-gate  */
1428*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1429*7c478bd9Sstevel@tonic-gate mblk_t *
1430*7c478bd9Sstevel@tonic-gate strrput_proto(vnode_t *vp, mblk_t *mp,
1431*7c478bd9Sstevel@tonic-gate     strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1432*7c478bd9Sstevel@tonic-gate     strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
1433*7c478bd9Sstevel@tonic-gate {
1434*7c478bd9Sstevel@tonic-gate 	*wakeups = RSLEEP;
1435*7c478bd9Sstevel@tonic-gate 	*allmsgsigs = 0;
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
1438*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
1439*7c478bd9Sstevel@tonic-gate 		if (mp->b_band == 0) {
1440*7c478bd9Sstevel@tonic-gate 			*firstmsgsigs = S_INPUT | S_RDNORM;
1441*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDNORM;
1442*7c478bd9Sstevel@tonic-gate 		} else {
1443*7c478bd9Sstevel@tonic-gate 			*firstmsgsigs = S_INPUT | S_RDBAND;
1444*7c478bd9Sstevel@tonic-gate 			*pollwakeups = POLLIN | POLLRDBAND;
1445*7c478bd9Sstevel@tonic-gate 		}
1446*7c478bd9Sstevel@tonic-gate 		break;
1447*7c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
1448*7c478bd9Sstevel@tonic-gate 		*firstmsgsigs = S_HIPRI;
1449*7c478bd9Sstevel@tonic-gate 		*pollwakeups = POLLPRI;
1450*7c478bd9Sstevel@tonic-gate 		break;
1451*7c478bd9Sstevel@tonic-gate 	}
1452*7c478bd9Sstevel@tonic-gate 	return (mp);
1453*7c478bd9Sstevel@tonic-gate }
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate /*
1456*7c478bd9Sstevel@tonic-gate  * Default processing of everything but M_DATA, M_PROTO, M_PCPROTO and
1457*7c478bd9Sstevel@tonic-gate  * M_PASSFP messages.
1458*7c478bd9Sstevel@tonic-gate  * Determine which wakeups and signals are needed.
1459*7c478bd9Sstevel@tonic-gate  * This can be replaced by a user-specified procedure for kernel users
1460*7c478bd9Sstevel@tonic-gate  * of STREAMS.
1461*7c478bd9Sstevel@tonic-gate  */
1462*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1463*7c478bd9Sstevel@tonic-gate mblk_t *
1464*7c478bd9Sstevel@tonic-gate strrput_misc(vnode_t *vp, mblk_t *mp,
1465*7c478bd9Sstevel@tonic-gate     strwakeup_t *wakeups, strsigset_t *firstmsgsigs,
1466*7c478bd9Sstevel@tonic-gate     strsigset_t *allmsgsigs, strpollset_t *pollwakeups)
1467*7c478bd9Sstevel@tonic-gate {
1468*7c478bd9Sstevel@tonic-gate 	*wakeups = 0;
1469*7c478bd9Sstevel@tonic-gate 	*firstmsgsigs = 0;
1470*7c478bd9Sstevel@tonic-gate 	*allmsgsigs = 0;
1471*7c478bd9Sstevel@tonic-gate 	*pollwakeups = 0;
1472*7c478bd9Sstevel@tonic-gate 	return (mp);
1473*7c478bd9Sstevel@tonic-gate }
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate /*
1476*7c478bd9Sstevel@tonic-gate  * Stream read put procedure.  Called from downstream driver/module
1477*7c478bd9Sstevel@tonic-gate  * with messages for the stream head.  Data, protocol, and in-stream
1478*7c478bd9Sstevel@tonic-gate  * signal messages are placed on the queue, others are handled directly.
1479*7c478bd9Sstevel@tonic-gate  */
1480*7c478bd9Sstevel@tonic-gate int
1481*7c478bd9Sstevel@tonic-gate strrput(queue_t *q, mblk_t *bp)
1482*7c478bd9Sstevel@tonic-gate {
1483*7c478bd9Sstevel@tonic-gate 	struct stdata	*stp;
1484*7c478bd9Sstevel@tonic-gate 	ulong_t		rput_opt;
1485*7c478bd9Sstevel@tonic-gate 	strwakeup_t	wakeups;
1486*7c478bd9Sstevel@tonic-gate 	strsigset_t	firstmsgsigs;	/* Signals if first message on queue */
1487*7c478bd9Sstevel@tonic-gate 	strsigset_t	allmsgsigs;	/* Signals for all messages */
1488*7c478bd9Sstevel@tonic-gate 	strsigset_t	signals;	/* Signals events to generate */
1489*7c478bd9Sstevel@tonic-gate 	strpollset_t	pollwakeups;
1490*7c478bd9Sstevel@tonic-gate 	mblk_t		*nextbp;
1491*7c478bd9Sstevel@tonic-gate 	uchar_t		band = 0;
1492*7c478bd9Sstevel@tonic-gate 	int		hipri_sig;
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
1495*7c478bd9Sstevel@tonic-gate 	/*
1496*7c478bd9Sstevel@tonic-gate 	 * Use rput_opt for optimized access to the SR_ flags except
1497*7c478bd9Sstevel@tonic-gate 	 * SR_POLLIN. That flag has to be checked under sd_lock since it
1498*7c478bd9Sstevel@tonic-gate 	 * is modified by strpoll().
1499*7c478bd9Sstevel@tonic-gate 	 */
1500*7c478bd9Sstevel@tonic-gate 	rput_opt = stp->sd_rput_opt;
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	ASSERT(qclaimed(q));
1503*7c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR, TR_STRRPUT_ENTER,
1504*7c478bd9Sstevel@tonic-gate 		"strrput called with message type:q %p bp %p", q, bp);
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	/*
1507*7c478bd9Sstevel@tonic-gate 	 * Perform initial processing and pass to the parameterized functions.
1508*7c478bd9Sstevel@tonic-gate 	 */
1509*7c478bd9Sstevel@tonic-gate 	ASSERT(bp->b_next == NULL);
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
1512*7c478bd9Sstevel@tonic-gate 	case M_DATA:
1513*7c478bd9Sstevel@tonic-gate 		/*
1514*7c478bd9Sstevel@tonic-gate 		 * sockfs is the only consumer of STREOF and when it is set,
1515*7c478bd9Sstevel@tonic-gate 		 * it implies that the receiver is not interested in receiving
1516*7c478bd9Sstevel@tonic-gate 		 * any more data, hence the mblk is freed to prevent unnecessary
1517*7c478bd9Sstevel@tonic-gate 		 * message queueing at the stream head.
1518*7c478bd9Sstevel@tonic-gate 		 */
1519*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag == STREOF) {
1520*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
1521*7c478bd9Sstevel@tonic-gate 			return (0);
1522*7c478bd9Sstevel@tonic-gate 		}
1523*7c478bd9Sstevel@tonic-gate 		if ((rput_opt & SR_IGN_ZEROLEN) &&
1524*7c478bd9Sstevel@tonic-gate 		    bp->b_rptr == bp->b_wptr && msgnodata(bp)) {
1525*7c478bd9Sstevel@tonic-gate 			/*
1526*7c478bd9Sstevel@tonic-gate 			 * Ignore zero-length M_DATA messages. These might be
1527*7c478bd9Sstevel@tonic-gate 			 * generated by some transports.
1528*7c478bd9Sstevel@tonic-gate 			 * The zero-length M_DATA messages, even if they
1529*7c478bd9Sstevel@tonic-gate 			 * are ignored, should effect the atmark tracking and
1530*7c478bd9Sstevel@tonic-gate 			 * should wake up a thread sleeping in strwaitmark.
1531*7c478bd9Sstevel@tonic-gate 			 */
1532*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
1533*7c478bd9Sstevel@tonic-gate 			if (bp->b_flag & MSGMARKNEXT) {
1534*7c478bd9Sstevel@tonic-gate 				/*
1535*7c478bd9Sstevel@tonic-gate 				 * Record the position of the mark either
1536*7c478bd9Sstevel@tonic-gate 				 * in q_last or in STRATMARK.
1537*7c478bd9Sstevel@tonic-gate 				 */
1538*7c478bd9Sstevel@tonic-gate 				if (q->q_last != NULL) {
1539*7c478bd9Sstevel@tonic-gate 					q->q_last->b_flag &= ~MSGNOTMARKNEXT;
1540*7c478bd9Sstevel@tonic-gate 					q->q_last->b_flag |= MSGMARKNEXT;
1541*7c478bd9Sstevel@tonic-gate 				} else {
1542*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRNOTATMARK;
1543*7c478bd9Sstevel@tonic-gate 					stp->sd_flag |= STRATMARK;
1544*7c478bd9Sstevel@tonic-gate 				}
1545*7c478bd9Sstevel@tonic-gate 			} else if (bp->b_flag & MSGNOTMARKNEXT) {
1546*7c478bd9Sstevel@tonic-gate 				/*
1547*7c478bd9Sstevel@tonic-gate 				 * Record that this is not the position of
1548*7c478bd9Sstevel@tonic-gate 				 * the mark either in q_last or in
1549*7c478bd9Sstevel@tonic-gate 				 * STRNOTATMARK.
1550*7c478bd9Sstevel@tonic-gate 				 */
1551*7c478bd9Sstevel@tonic-gate 				if (q->q_last != NULL) {
1552*7c478bd9Sstevel@tonic-gate 					q->q_last->b_flag &= ~MSGMARKNEXT;
1553*7c478bd9Sstevel@tonic-gate 					q->q_last->b_flag |= MSGNOTMARKNEXT;
1554*7c478bd9Sstevel@tonic-gate 				} else {
1555*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRATMARK;
1556*7c478bd9Sstevel@tonic-gate 					stp->sd_flag |= STRNOTATMARK;
1557*7c478bd9Sstevel@tonic-gate 				}
1558*7c478bd9Sstevel@tonic-gate 			}
1559*7c478bd9Sstevel@tonic-gate 			if (stp->sd_flag & RSLEEP) {
1560*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~RSLEEP;
1561*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&q->q_wait);
1562*7c478bd9Sstevel@tonic-gate 			}
1563*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
1564*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
1565*7c478bd9Sstevel@tonic-gate 			return (0);
1566*7c478bd9Sstevel@tonic-gate 		}
1567*7c478bd9Sstevel@tonic-gate 		wakeups = RSLEEP;
1568*7c478bd9Sstevel@tonic-gate 		if (bp->b_band == 0) {
1569*7c478bd9Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDNORM;
1570*7c478bd9Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDNORM;
1571*7c478bd9Sstevel@tonic-gate 		} else {
1572*7c478bd9Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDBAND;
1573*7c478bd9Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDBAND;
1574*7c478bd9Sstevel@tonic-gate 		}
1575*7c478bd9Sstevel@tonic-gate 		if (rput_opt & SR_SIGALLDATA)
1576*7c478bd9Sstevel@tonic-gate 			allmsgsigs = firstmsgsigs;
1577*7c478bd9Sstevel@tonic-gate 		else
1578*7c478bd9Sstevel@tonic-gate 			allmsgsigs = 0;
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1581*7c478bd9Sstevel@tonic-gate 		if ((rput_opt & SR_CONSOL_DATA) &&
1582*7c478bd9Sstevel@tonic-gate 		    (bp->b_flag & (MSGMARK|MSGDELIM)) == 0) {
1583*7c478bd9Sstevel@tonic-gate 			/*
1584*7c478bd9Sstevel@tonic-gate 			 * Consolidate on M_DATA message onto an M_DATA,
1585*7c478bd9Sstevel@tonic-gate 			 * M_PROTO, or M_PCPROTO by merging it with q_last.
1586*7c478bd9Sstevel@tonic-gate 			 * The consolidation does not take place if
1587*7c478bd9Sstevel@tonic-gate 			 * the old message is marked with either of the
1588*7c478bd9Sstevel@tonic-gate 			 * marks or the delim flag or if the new
1589*7c478bd9Sstevel@tonic-gate 			 * message is marked with MSGMARK. The MSGMARK
1590*7c478bd9Sstevel@tonic-gate 			 * check is needed to handle the odd semantics of
1591*7c478bd9Sstevel@tonic-gate 			 * MSGMARK where essentially the whole message
1592*7c478bd9Sstevel@tonic-gate 			 * is to be treated as marked.
1593*7c478bd9Sstevel@tonic-gate 			 * Carry any MSGMARKNEXT  and MSGNOTMARKNEXT from the
1594*7c478bd9Sstevel@tonic-gate 			 * new message to the front of the b_cont chain.
1595*7c478bd9Sstevel@tonic-gate 			 */
1596*7c478bd9Sstevel@tonic-gate 			mblk_t *lbp;
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate 			lbp = q->q_last;
1599*7c478bd9Sstevel@tonic-gate 			if (lbp != NULL &&
1600*7c478bd9Sstevel@tonic-gate 			    (lbp->b_datap->db_type == M_DATA ||
1601*7c478bd9Sstevel@tonic-gate 			    lbp->b_datap->db_type == M_PROTO ||
1602*7c478bd9Sstevel@tonic-gate 			    lbp->b_datap->db_type == M_PCPROTO) &&
1603*7c478bd9Sstevel@tonic-gate 			    !(lbp->b_flag & (MSGDELIM|MSGMARK|
1604*7c478bd9Sstevel@tonic-gate 			    MSGMARKNEXT))) {
1605*7c478bd9Sstevel@tonic-gate 				rmvq_noenab(q, lbp);
1606*7c478bd9Sstevel@tonic-gate 				/*
1607*7c478bd9Sstevel@tonic-gate 				 * The first message in the b_cont list
1608*7c478bd9Sstevel@tonic-gate 				 * tracks MSGMARKNEXT and MSGNOTMARKNEXT.
1609*7c478bd9Sstevel@tonic-gate 				 * We need to handle the case where we
1610*7c478bd9Sstevel@tonic-gate 				 * are appending
1611*7c478bd9Sstevel@tonic-gate 				 *
1612*7c478bd9Sstevel@tonic-gate 				 * 1) a MSGMARKNEXT to a MSGNOTMARKNEXT.
1613*7c478bd9Sstevel@tonic-gate 				 * 2) a MSGMARKNEXT to a plain message.
1614*7c478bd9Sstevel@tonic-gate 				 * 3) a MSGNOTMARKNEXT to a plain message
1615*7c478bd9Sstevel@tonic-gate 				 * 4) a MSGNOTMARKNEXT to a MSGNOTMARKNEXT
1616*7c478bd9Sstevel@tonic-gate 				 *    message.
1617*7c478bd9Sstevel@tonic-gate 				 *
1618*7c478bd9Sstevel@tonic-gate 				 * Thus we never append a MSGMARKNEXT or
1619*7c478bd9Sstevel@tonic-gate 				 * MSGNOTMARKNEXT to a MSGMARKNEXT message.
1620*7c478bd9Sstevel@tonic-gate 				 */
1621*7c478bd9Sstevel@tonic-gate 				if (bp->b_flag & MSGMARKNEXT) {
1622*7c478bd9Sstevel@tonic-gate 					lbp->b_flag |= MSGMARKNEXT;
1623*7c478bd9Sstevel@tonic-gate 					lbp->b_flag &= ~MSGNOTMARKNEXT;
1624*7c478bd9Sstevel@tonic-gate 					bp->b_flag &= ~MSGMARKNEXT;
1625*7c478bd9Sstevel@tonic-gate 				} else if (bp->b_flag & MSGNOTMARKNEXT) {
1626*7c478bd9Sstevel@tonic-gate 					lbp->b_flag |= MSGNOTMARKNEXT;
1627*7c478bd9Sstevel@tonic-gate 					bp->b_flag &= ~MSGNOTMARKNEXT;
1628*7c478bd9Sstevel@tonic-gate 				}
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate 				linkb(lbp, bp);
1631*7c478bd9Sstevel@tonic-gate 				bp = lbp;
1632*7c478bd9Sstevel@tonic-gate 				/*
1633*7c478bd9Sstevel@tonic-gate 				 * The new message logically isn't the first
1634*7c478bd9Sstevel@tonic-gate 				 * even though the q_first check below thinks
1635*7c478bd9Sstevel@tonic-gate 				 * it is. Clear the firstmsgsigs to make it
1636*7c478bd9Sstevel@tonic-gate 				 * not appear to be first.
1637*7c478bd9Sstevel@tonic-gate 				 */
1638*7c478bd9Sstevel@tonic-gate 				firstmsgsigs = 0;
1639*7c478bd9Sstevel@tonic-gate 			}
1640*7c478bd9Sstevel@tonic-gate 		}
1641*7c478bd9Sstevel@tonic-gate 		break;
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 	case M_PASSFP:
1644*7c478bd9Sstevel@tonic-gate 		wakeups = RSLEEP;
1645*7c478bd9Sstevel@tonic-gate 		allmsgsigs = 0;
1646*7c478bd9Sstevel@tonic-gate 		if (bp->b_band == 0) {
1647*7c478bd9Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDNORM;
1648*7c478bd9Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDNORM;
1649*7c478bd9Sstevel@tonic-gate 		} else {
1650*7c478bd9Sstevel@tonic-gate 			firstmsgsigs = S_INPUT | S_RDBAND;
1651*7c478bd9Sstevel@tonic-gate 			pollwakeups = POLLIN | POLLRDBAND;
1652*7c478bd9Sstevel@tonic-gate 		}
1653*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1654*7c478bd9Sstevel@tonic-gate 		break;
1655*7c478bd9Sstevel@tonic-gate 
1656*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
1657*7c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
1658*7c478bd9Sstevel@tonic-gate 		ASSERT(stp->sd_rprotofunc != NULL);
1659*7c478bd9Sstevel@tonic-gate 		bp = (stp->sd_rprotofunc)(stp->sd_vnode, bp,
1660*7c478bd9Sstevel@tonic-gate 			&wakeups, &firstmsgsigs, &allmsgsigs, &pollwakeups);
1661*7c478bd9Sstevel@tonic-gate #define	ALLSIG	(S_INPUT|S_HIPRI|S_OUTPUT|S_MSG|S_ERROR|S_HANGUP|S_RDNORM|\
1662*7c478bd9Sstevel@tonic-gate 		S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)
1663*7c478bd9Sstevel@tonic-gate #define	ALLPOLL	(POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLWRNORM|POLLRDBAND|\
1664*7c478bd9Sstevel@tonic-gate 		POLLWRBAND)
1665*7c478bd9Sstevel@tonic-gate 
1666*7c478bd9Sstevel@tonic-gate 		ASSERT((wakeups & ~(RSLEEP|WSLEEP)) == 0);
1667*7c478bd9Sstevel@tonic-gate 		ASSERT((firstmsgsigs & ~ALLSIG) == 0);
1668*7c478bd9Sstevel@tonic-gate 		ASSERT((allmsgsigs & ~ALLSIG) == 0);
1669*7c478bd9Sstevel@tonic-gate 		ASSERT((pollwakeups & ~ALLPOLL) == 0);
1670*7c478bd9Sstevel@tonic-gate 
1671*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1672*7c478bd9Sstevel@tonic-gate 		break;
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 	default:
1675*7c478bd9Sstevel@tonic-gate 		ASSERT(stp->sd_rmiscfunc != NULL);
1676*7c478bd9Sstevel@tonic-gate 		bp = (stp->sd_rmiscfunc)(stp->sd_vnode, bp,
1677*7c478bd9Sstevel@tonic-gate 			&wakeups, &firstmsgsigs, &allmsgsigs, &pollwakeups);
1678*7c478bd9Sstevel@tonic-gate 		ASSERT((wakeups & ~(RSLEEP|WSLEEP)) == 0);
1679*7c478bd9Sstevel@tonic-gate 		ASSERT((firstmsgsigs & ~ALLSIG) == 0);
1680*7c478bd9Sstevel@tonic-gate 		ASSERT((allmsgsigs & ~ALLSIG) == 0);
1681*7c478bd9Sstevel@tonic-gate 		ASSERT((pollwakeups & ~ALLPOLL) == 0);
1682*7c478bd9Sstevel@tonic-gate #undef	ALLSIG
1683*7c478bd9Sstevel@tonic-gate #undef	ALLPOLL
1684*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1685*7c478bd9Sstevel@tonic-gate 		break;
1686*7c478bd9Sstevel@tonic-gate 	}
1687*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 	/* By default generate superset of signals */
1690*7c478bd9Sstevel@tonic-gate 	signals = (firstmsgsigs | allmsgsigs);
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 	/*
1693*7c478bd9Sstevel@tonic-gate 	 * The  proto and misc functions can return multiple messages
1694*7c478bd9Sstevel@tonic-gate 	 * as a b_next chain. Such messages are processed separately.
1695*7c478bd9Sstevel@tonic-gate 	 */
1696*7c478bd9Sstevel@tonic-gate one_more:
1697*7c478bd9Sstevel@tonic-gate 	hipri_sig = 0;
1698*7c478bd9Sstevel@tonic-gate 	if (bp == NULL) {
1699*7c478bd9Sstevel@tonic-gate 		nextbp = NULL;
1700*7c478bd9Sstevel@tonic-gate 	} else {
1701*7c478bd9Sstevel@tonic-gate 		nextbp = bp->b_next;
1702*7c478bd9Sstevel@tonic-gate 		bp->b_next = NULL;
1703*7c478bd9Sstevel@tonic-gate 
1704*7c478bd9Sstevel@tonic-gate 		switch (bp->b_datap->db_type) {
1705*7c478bd9Sstevel@tonic-gate 		case M_PCPROTO:
1706*7c478bd9Sstevel@tonic-gate 			/*
1707*7c478bd9Sstevel@tonic-gate 			 * Only one priority protocol message is allowed at the
1708*7c478bd9Sstevel@tonic-gate 			 * stream head at a time.
1709*7c478bd9Sstevel@tonic-gate 			 */
1710*7c478bd9Sstevel@tonic-gate 			if (stp->sd_flag & STRPRI) {
1711*7c478bd9Sstevel@tonic-gate 				TRACE_0(TR_FAC_STREAMS_FR, TR_STRRPUT_PROTERR,
1712*7c478bd9Sstevel@tonic-gate 				    "M_PCPROTO already at head");
1713*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
1714*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1715*7c478bd9Sstevel@tonic-gate 				goto done;
1716*7c478bd9Sstevel@tonic-gate 			}
1717*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= STRPRI;
1718*7c478bd9Sstevel@tonic-gate 			hipri_sig = 1;
1719*7c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
1720*7c478bd9Sstevel@tonic-gate 		case M_DATA:
1721*7c478bd9Sstevel@tonic-gate 		case M_PROTO:
1722*7c478bd9Sstevel@tonic-gate 		case M_PASSFP:
1723*7c478bd9Sstevel@tonic-gate 			band = bp->b_band;
1724*7c478bd9Sstevel@tonic-gate 			/*
1725*7c478bd9Sstevel@tonic-gate 			 * Marking doesn't work well when messages
1726*7c478bd9Sstevel@tonic-gate 			 * are marked in more than one band.  We only
1727*7c478bd9Sstevel@tonic-gate 			 * remember the last message received, even if
1728*7c478bd9Sstevel@tonic-gate 			 * it is placed on the queue ahead of other
1729*7c478bd9Sstevel@tonic-gate 			 * marked messages.
1730*7c478bd9Sstevel@tonic-gate 			 */
1731*7c478bd9Sstevel@tonic-gate 			if (bp->b_flag & MSGMARK)
1732*7c478bd9Sstevel@tonic-gate 				stp->sd_mark = bp;
1733*7c478bd9Sstevel@tonic-gate 			(void) putq(q, bp);
1734*7c478bd9Sstevel@tonic-gate 
1735*7c478bd9Sstevel@tonic-gate 			/*
1736*7c478bd9Sstevel@tonic-gate 			 * If message is a PCPROTO message, always use
1737*7c478bd9Sstevel@tonic-gate 			 * firstmsgsigs to determine if a signal should be
1738*7c478bd9Sstevel@tonic-gate 			 * sent as strrput is the only place to send
1739*7c478bd9Sstevel@tonic-gate 			 * signals for PCPROTO. Other messages are based on
1740*7c478bd9Sstevel@tonic-gate 			 * the STRGETINPROG flag. The flag determines if
1741*7c478bd9Sstevel@tonic-gate 			 * strrput or (k)strgetmsg will be responsible for
1742*7c478bd9Sstevel@tonic-gate 			 * sending the signals, in the firstmsgsigs case.
1743*7c478bd9Sstevel@tonic-gate 			 */
1744*7c478bd9Sstevel@tonic-gate 			if ((hipri_sig == 1) ||
1745*7c478bd9Sstevel@tonic-gate 			    (((stp->sd_flag & STRGETINPROG) == 0) &&
1746*7c478bd9Sstevel@tonic-gate 			    (q->q_first == bp)))
1747*7c478bd9Sstevel@tonic-gate 				signals = (firstmsgsigs | allmsgsigs);
1748*7c478bd9Sstevel@tonic-gate 			else
1749*7c478bd9Sstevel@tonic-gate 				signals = allmsgsigs;
1750*7c478bd9Sstevel@tonic-gate 			break;
1751*7c478bd9Sstevel@tonic-gate 
1752*7c478bd9Sstevel@tonic-gate 		default:
1753*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
1754*7c478bd9Sstevel@tonic-gate 			(void) strrput_nondata(q, bp);
1755*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
1756*7c478bd9Sstevel@tonic-gate 			break;
1757*7c478bd9Sstevel@tonic-gate 		}
1758*7c478bd9Sstevel@tonic-gate 	}
1759*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
1760*7c478bd9Sstevel@tonic-gate 	/*
1761*7c478bd9Sstevel@tonic-gate 	 * Wake sleeping read/getmsg and cancel deferred wakeup
1762*7c478bd9Sstevel@tonic-gate 	 */
1763*7c478bd9Sstevel@tonic-gate 	if (wakeups & RSLEEP)
1764*7c478bd9Sstevel@tonic-gate 		stp->sd_wakeq &= ~RSLEEP;
1765*7c478bd9Sstevel@tonic-gate 
1766*7c478bd9Sstevel@tonic-gate 	wakeups &= stp->sd_flag;
1767*7c478bd9Sstevel@tonic-gate 	if (wakeups & RSLEEP) {
1768*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~RSLEEP;
1769*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);
1770*7c478bd9Sstevel@tonic-gate 	}
1771*7c478bd9Sstevel@tonic-gate 	if (wakeups & WSLEEP) {
1772*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
1773*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&_WR(q)->q_wait);
1774*7c478bd9Sstevel@tonic-gate 	}
1775*7c478bd9Sstevel@tonic-gate 
1776*7c478bd9Sstevel@tonic-gate 	if (pollwakeups != 0) {
1777*7c478bd9Sstevel@tonic-gate 		if (pollwakeups == (POLLIN | POLLRDNORM)) {
1778*7c478bd9Sstevel@tonic-gate 			/*
1779*7c478bd9Sstevel@tonic-gate 			 * Can't use rput_opt since it was not
1780*7c478bd9Sstevel@tonic-gate 			 * read when sd_lock was held and SR_POLLIN is changed
1781*7c478bd9Sstevel@tonic-gate 			 * by strpoll() under sd_lock.
1782*7c478bd9Sstevel@tonic-gate 			 */
1783*7c478bd9Sstevel@tonic-gate 			if (!(stp->sd_rput_opt & SR_POLLIN))
1784*7c478bd9Sstevel@tonic-gate 				goto no_pollwake;
1785*7c478bd9Sstevel@tonic-gate 			stp->sd_rput_opt &= ~SR_POLLIN;
1786*7c478bd9Sstevel@tonic-gate 		}
1787*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
1788*7c478bd9Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, pollwakeups);
1789*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
1790*7c478bd9Sstevel@tonic-gate 	}
1791*7c478bd9Sstevel@tonic-gate no_pollwake:
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 	/*
1794*7c478bd9Sstevel@tonic-gate 	 * strsendsig can handle multiple signals with a
1795*7c478bd9Sstevel@tonic-gate 	 * single call.
1796*7c478bd9Sstevel@tonic-gate 	 */
1797*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sigflags & signals)
1798*7c478bd9Sstevel@tonic-gate 		strsendsig(stp->sd_siglist, signals, band, 0);
1799*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate 
1802*7c478bd9Sstevel@tonic-gate done:
1803*7c478bd9Sstevel@tonic-gate 	if (nextbp == NULL)
1804*7c478bd9Sstevel@tonic-gate 		return (0);
1805*7c478bd9Sstevel@tonic-gate 
1806*7c478bd9Sstevel@tonic-gate 	/*
1807*7c478bd9Sstevel@tonic-gate 	 * Any signals were handled the first time.
1808*7c478bd9Sstevel@tonic-gate 	 * Wakeups and pollwakeups are redone to avoid any race
1809*7c478bd9Sstevel@tonic-gate 	 * conditions - all the messages are not queued until the
1810*7c478bd9Sstevel@tonic-gate 	 * last message has been processed by strrput.
1811*7c478bd9Sstevel@tonic-gate 	 */
1812*7c478bd9Sstevel@tonic-gate 	bp = nextbp;
1813*7c478bd9Sstevel@tonic-gate 	signals = firstmsgsigs = allmsgsigs = 0;
1814*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
1815*7c478bd9Sstevel@tonic-gate 	goto one_more;
1816*7c478bd9Sstevel@tonic-gate }
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate static void
1819*7c478bd9Sstevel@tonic-gate log_dupioc(queue_t *rq, mblk_t *bp)
1820*7c478bd9Sstevel@tonic-gate {
1821*7c478bd9Sstevel@tonic-gate 	queue_t *wq, *qp;
1822*7c478bd9Sstevel@tonic-gate 	char *modnames, *mnp, *dname;
1823*7c478bd9Sstevel@tonic-gate 	size_t maxmodstr;
1824*7c478bd9Sstevel@tonic-gate 	boolean_t islast;
1825*7c478bd9Sstevel@tonic-gate 
1826*7c478bd9Sstevel@tonic-gate 	/*
1827*7c478bd9Sstevel@tonic-gate 	 * Allocate a buffer large enough to hold the names of nstrpush modules
1828*7c478bd9Sstevel@tonic-gate 	 * and one driver, with spaces between and NUL terminator.  If we can't
1829*7c478bd9Sstevel@tonic-gate 	 * get memory, then we'll just log the driver name.
1830*7c478bd9Sstevel@tonic-gate 	 */
1831*7c478bd9Sstevel@tonic-gate 	maxmodstr = nstrpush * (FMNAMESZ + 1);
1832*7c478bd9Sstevel@tonic-gate 	mnp = modnames = kmem_alloc(maxmodstr, KM_NOSLEEP);
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate 	/* march down write side to print log message down to the driver */
1835*7c478bd9Sstevel@tonic-gate 	wq = WR(rq);
1836*7c478bd9Sstevel@tonic-gate 
1837*7c478bd9Sstevel@tonic-gate 	/* make sure q_next doesn't shift around while we're grabbing data */
1838*7c478bd9Sstevel@tonic-gate 	claimstr(wq);
1839*7c478bd9Sstevel@tonic-gate 	qp = wq->q_next;
1840*7c478bd9Sstevel@tonic-gate 	do {
1841*7c478bd9Sstevel@tonic-gate 		if ((dname = qp->q_qinfo->qi_minfo->mi_idname) == NULL)
1842*7c478bd9Sstevel@tonic-gate 			dname = "?";
1843*7c478bd9Sstevel@tonic-gate 		islast = !SAMESTR(qp) || qp->q_next == NULL;
1844*7c478bd9Sstevel@tonic-gate 		if (modnames == NULL) {
1845*7c478bd9Sstevel@tonic-gate 			/*
1846*7c478bd9Sstevel@tonic-gate 			 * If we don't have memory, then get the driver name in
1847*7c478bd9Sstevel@tonic-gate 			 * the log where we can see it.  Note that memory
1848*7c478bd9Sstevel@tonic-gate 			 * pressure is a possible cause of these sorts of bugs.
1849*7c478bd9Sstevel@tonic-gate 			 */
1850*7c478bd9Sstevel@tonic-gate 			if (islast) {
1851*7c478bd9Sstevel@tonic-gate 				modnames = dname;
1852*7c478bd9Sstevel@tonic-gate 				maxmodstr = 0;
1853*7c478bd9Sstevel@tonic-gate 			}
1854*7c478bd9Sstevel@tonic-gate 		} else {
1855*7c478bd9Sstevel@tonic-gate 			mnp += snprintf(mnp, FMNAMESZ + 1, "%s", dname);
1856*7c478bd9Sstevel@tonic-gate 			if (!islast)
1857*7c478bd9Sstevel@tonic-gate 				*mnp++ = ' ';
1858*7c478bd9Sstevel@tonic-gate 		}
1859*7c478bd9Sstevel@tonic-gate 		qp = qp->q_next;
1860*7c478bd9Sstevel@tonic-gate 	} while (!islast);
1861*7c478bd9Sstevel@tonic-gate 	releasestr(wq);
1862*7c478bd9Sstevel@tonic-gate 	/* Cannot happen unless stream head is corrupt. */
1863*7c478bd9Sstevel@tonic-gate 	ASSERT(modnames != NULL);
1864*7c478bd9Sstevel@tonic-gate 	(void) strlog(rq->q_qinfo->qi_minfo->mi_idnum, 0, 1,
1865*7c478bd9Sstevel@tonic-gate 	    SL_CONSOLE|SL_TRACE|SL_ERROR,
1866*7c478bd9Sstevel@tonic-gate 	    "Warning: stream %p received duplicate %X M_IOC%s; module list: %s",
1867*7c478bd9Sstevel@tonic-gate 	    rq->q_ptr, ((struct iocblk *)bp->b_rptr)->ioc_cmd,
1868*7c478bd9Sstevel@tonic-gate 	    (DB_TYPE(bp) == M_IOCACK ? "ACK" : "NAK"), modnames);
1869*7c478bd9Sstevel@tonic-gate 	if (maxmodstr != 0)
1870*7c478bd9Sstevel@tonic-gate 		kmem_free(modnames, maxmodstr);
1871*7c478bd9Sstevel@tonic-gate }
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate int
1874*7c478bd9Sstevel@tonic-gate strrput_nondata(queue_t *q, mblk_t *bp)
1875*7c478bd9Sstevel@tonic-gate {
1876*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
1877*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocbp;
1878*7c478bd9Sstevel@tonic-gate 	struct stroptions *sop;
1879*7c478bd9Sstevel@tonic-gate 	struct copyreq *reqp;
1880*7c478bd9Sstevel@tonic-gate 	struct copyresp *resp;
1881*7c478bd9Sstevel@tonic-gate 	unsigned char bpri;
1882*7c478bd9Sstevel@tonic-gate 	unsigned char  flushed_already = 0;
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
1887*7c478bd9Sstevel@tonic-gate 	ASSERT(qclaimed(q));
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
1890*7c478bd9Sstevel@tonic-gate 	case M_ERROR:
1891*7c478bd9Sstevel@tonic-gate 		/*
1892*7c478bd9Sstevel@tonic-gate 		 * An error has occurred downstream, the errno is in the first
1893*7c478bd9Sstevel@tonic-gate 		 * bytes of the message.
1894*7c478bd9Sstevel@tonic-gate 		 */
1895*7c478bd9Sstevel@tonic-gate 		if ((bp->b_wptr - bp->b_rptr) == 2) {	/* New flavor */
1896*7c478bd9Sstevel@tonic-gate 			unsigned char rw = 0;
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
1899*7c478bd9Sstevel@tonic-gate 			if (*bp->b_rptr != NOERROR) {	/* read error */
1900*7c478bd9Sstevel@tonic-gate 				if (*bp->b_rptr != 0) {
1901*7c478bd9Sstevel@tonic-gate 					if (stp->sd_flag & STRDERR)
1902*7c478bd9Sstevel@tonic-gate 						flushed_already |= FLUSHR;
1903*7c478bd9Sstevel@tonic-gate 					stp->sd_flag |= STRDERR;
1904*7c478bd9Sstevel@tonic-gate 					rw |= FLUSHR;
1905*7c478bd9Sstevel@tonic-gate 				} else {
1906*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRDERR;
1907*7c478bd9Sstevel@tonic-gate 				}
1908*7c478bd9Sstevel@tonic-gate 				stp->sd_rerror = *bp->b_rptr;
1909*7c478bd9Sstevel@tonic-gate 			}
1910*7c478bd9Sstevel@tonic-gate 			bp->b_rptr++;
1911*7c478bd9Sstevel@tonic-gate 			if (*bp->b_rptr != NOERROR) {	/* write error */
1912*7c478bd9Sstevel@tonic-gate 				if (*bp->b_rptr != 0) {
1913*7c478bd9Sstevel@tonic-gate 					if (stp->sd_flag & STWRERR)
1914*7c478bd9Sstevel@tonic-gate 						flushed_already |= FLUSHW;
1915*7c478bd9Sstevel@tonic-gate 					stp->sd_flag |= STWRERR;
1916*7c478bd9Sstevel@tonic-gate 					rw |= FLUSHW;
1917*7c478bd9Sstevel@tonic-gate 				} else {
1918*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STWRERR;
1919*7c478bd9Sstevel@tonic-gate 				}
1920*7c478bd9Sstevel@tonic-gate 				stp->sd_werror = *bp->b_rptr;
1921*7c478bd9Sstevel@tonic-gate 			}
1922*7c478bd9Sstevel@tonic-gate 			if (rw) {
1923*7c478bd9Sstevel@tonic-gate 				TRACE_2(TR_FAC_STREAMS_FR, TR_STRRPUT_WAKE,
1924*7c478bd9Sstevel@tonic-gate 					"strrput cv_broadcast:q %p, bp %p",
1925*7c478bd9Sstevel@tonic-gate 					q, bp);
1926*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&q->q_wait); /* readers */
1927*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&_WR(q)->q_wait); /* writers */
1928*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&stp->sd_monitor); /* ioctllers */
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1931*7c478bd9Sstevel@tonic-gate 				pollwakeup(&stp->sd_pollist, POLLERR);
1932*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
1933*7c478bd9Sstevel@tonic-gate 
1934*7c478bd9Sstevel@tonic-gate 				if (stp->sd_sigflags & S_ERROR)
1935*7c478bd9Sstevel@tonic-gate 					strsendsig(stp->sd_siglist, S_ERROR, 0,
1936*7c478bd9Sstevel@tonic-gate 					    ((rw & FLUSHR) ? stp->sd_rerror :
1937*7c478bd9Sstevel@tonic-gate 					    stp->sd_werror));
1938*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1939*7c478bd9Sstevel@tonic-gate 				/*
1940*7c478bd9Sstevel@tonic-gate 				 * Send the M_FLUSH only
1941*7c478bd9Sstevel@tonic-gate 				 * for the first M_ERROR
1942*7c478bd9Sstevel@tonic-gate 				 * message on the stream
1943*7c478bd9Sstevel@tonic-gate 				 */
1944*7c478bd9Sstevel@tonic-gate 				if (flushed_already == rw) {
1945*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
1946*7c478bd9Sstevel@tonic-gate 					return (0);
1947*7c478bd9Sstevel@tonic-gate 				}
1948*7c478bd9Sstevel@tonic-gate 
1949*7c478bd9Sstevel@tonic-gate 				bp->b_datap->db_type = M_FLUSH;
1950*7c478bd9Sstevel@tonic-gate 				*bp->b_rptr = rw;
1951*7c478bd9Sstevel@tonic-gate 				bp->b_wptr = bp->b_rptr + 1;
1952*7c478bd9Sstevel@tonic-gate 				/*
1953*7c478bd9Sstevel@tonic-gate 				 * Protect against the driver
1954*7c478bd9Sstevel@tonic-gate 				 * passing up messages after
1955*7c478bd9Sstevel@tonic-gate 				 * it has done a qprocsoff
1956*7c478bd9Sstevel@tonic-gate 				 */
1957*7c478bd9Sstevel@tonic-gate 				if (_OTHERQ(q)->q_next == NULL)
1958*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
1959*7c478bd9Sstevel@tonic-gate 				else
1960*7c478bd9Sstevel@tonic-gate 					qreply(q, bp);
1961*7c478bd9Sstevel@tonic-gate 				return (0);
1962*7c478bd9Sstevel@tonic-gate 			} else
1963*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1964*7c478bd9Sstevel@tonic-gate 		} else if (*bp->b_rptr != 0) {		/* Old flavor */
1965*7c478bd9Sstevel@tonic-gate 				if (stp->sd_flag & (STRDERR|STWRERR))
1966*7c478bd9Sstevel@tonic-gate 					flushed_already = FLUSHRW;
1967*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
1968*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= (STRDERR|STWRERR);
1969*7c478bd9Sstevel@tonic-gate 				stp->sd_rerror = *bp->b_rptr;
1970*7c478bd9Sstevel@tonic-gate 				stp->sd_werror = *bp->b_rptr;
1971*7c478bd9Sstevel@tonic-gate 				TRACE_2(TR_FAC_STREAMS_FR,
1972*7c478bd9Sstevel@tonic-gate 					TR_STRRPUT_WAKE2,
1973*7c478bd9Sstevel@tonic-gate 					"strrput wakeup #2:q %p, bp %p", q, bp);
1974*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&q->q_wait); /* the readers */
1975*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&_WR(q)->q_wait); /* the writers */
1976*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&stp->sd_monitor); /* ioctllers */
1977*7c478bd9Sstevel@tonic-gate 
1978*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1979*7c478bd9Sstevel@tonic-gate 				pollwakeup(&stp->sd_pollist, POLLERR);
1980*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
1981*7c478bd9Sstevel@tonic-gate 
1982*7c478bd9Sstevel@tonic-gate 				if (stp->sd_sigflags & S_ERROR)
1983*7c478bd9Sstevel@tonic-gate 					strsendsig(stp->sd_siglist, S_ERROR, 0,
1984*7c478bd9Sstevel@tonic-gate 					    (stp->sd_werror ? stp->sd_werror :
1985*7c478bd9Sstevel@tonic-gate 					    stp->sd_rerror));
1986*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate 				/*
1989*7c478bd9Sstevel@tonic-gate 				 * Send the M_FLUSH only
1990*7c478bd9Sstevel@tonic-gate 				 * for the first M_ERROR
1991*7c478bd9Sstevel@tonic-gate 				 * message on the stream
1992*7c478bd9Sstevel@tonic-gate 				 */
1993*7c478bd9Sstevel@tonic-gate 				if (flushed_already != FLUSHRW) {
1994*7c478bd9Sstevel@tonic-gate 					bp->b_datap->db_type = M_FLUSH;
1995*7c478bd9Sstevel@tonic-gate 					*bp->b_rptr = FLUSHRW;
1996*7c478bd9Sstevel@tonic-gate 					/*
1997*7c478bd9Sstevel@tonic-gate 					 * Protect against the driver passing up
1998*7c478bd9Sstevel@tonic-gate 					 * messages after it has done a
1999*7c478bd9Sstevel@tonic-gate 					 * qprocsoff.
2000*7c478bd9Sstevel@tonic-gate 					 */
2001*7c478bd9Sstevel@tonic-gate 				if (_OTHERQ(q)->q_next == NULL)
2002*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
2003*7c478bd9Sstevel@tonic-gate 				else
2004*7c478bd9Sstevel@tonic-gate 					qreply(q, bp);
2005*7c478bd9Sstevel@tonic-gate 				return (0);
2006*7c478bd9Sstevel@tonic-gate 				}
2007*7c478bd9Sstevel@tonic-gate 		}
2008*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2009*7c478bd9Sstevel@tonic-gate 		return (0);
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate 	case M_HANGUP:
2012*7c478bd9Sstevel@tonic-gate 
2013*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2014*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2015*7c478bd9Sstevel@tonic-gate 		stp->sd_werror = ENXIO;
2016*7c478bd9Sstevel@tonic-gate 		stp->sd_flag |= STRHUP;
2017*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~(WSLEEP|RSLEEP);
2018*7c478bd9Sstevel@tonic-gate 
2019*7c478bd9Sstevel@tonic-gate 		/*
2020*7c478bd9Sstevel@tonic-gate 		 * send signal if controlling tty
2021*7c478bd9Sstevel@tonic-gate 		 */
2022*7c478bd9Sstevel@tonic-gate 
2023*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp) {
2024*7c478bd9Sstevel@tonic-gate 			prsignal(stp->sd_sidp, SIGHUP);
2025*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sidp != stp->sd_pgidp)
2026*7c478bd9Sstevel@tonic-gate 				pgsignal(stp->sd_pgidp, SIGTSTP);
2027*7c478bd9Sstevel@tonic-gate 		}
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 		/*
2030*7c478bd9Sstevel@tonic-gate 		 * wake up read, write, and exception pollers and
2031*7c478bd9Sstevel@tonic-gate 		 * reset wakeup mechanism.
2032*7c478bd9Sstevel@tonic-gate 		 */
2033*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);	/* the readers */
2034*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&_WR(q)->q_wait);	/* the writers */
2035*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);	/* the ioctllers */
2036*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2037*7c478bd9Sstevel@tonic-gate 		strhup(stp);
2038*7c478bd9Sstevel@tonic-gate 		return (0);
2039*7c478bd9Sstevel@tonic-gate 
2040*7c478bd9Sstevel@tonic-gate 	case M_UNHANGUP:
2041*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2042*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2043*7c478bd9Sstevel@tonic-gate 		stp->sd_werror = 0;
2044*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~STRHUP;
2045*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2046*7c478bd9Sstevel@tonic-gate 		return (0);
2047*7c478bd9Sstevel@tonic-gate 
2048*7c478bd9Sstevel@tonic-gate 	case M_SIG:
2049*7c478bd9Sstevel@tonic-gate 		/*
2050*7c478bd9Sstevel@tonic-gate 		 * Someone downstream wants to post a signal.  The
2051*7c478bd9Sstevel@tonic-gate 		 * signal to post is contained in the first byte of the
2052*7c478bd9Sstevel@tonic-gate 		 * message.  If the message would go on the front of
2053*7c478bd9Sstevel@tonic-gate 		 * the queue, send a signal to the process group
2054*7c478bd9Sstevel@tonic-gate 		 * (if not SIGPOLL) or to the siglist processes
2055*7c478bd9Sstevel@tonic-gate 		 * (SIGPOLL).  If something is already on the queue,
2056*7c478bd9Sstevel@tonic-gate 		 * OR if we are delivering a delayed suspend (*sigh*
2057*7c478bd9Sstevel@tonic-gate 		 * another "tty" hack) and there's no one sleeping already,
2058*7c478bd9Sstevel@tonic-gate 		 * just enqueue the message.
2059*7c478bd9Sstevel@tonic-gate 		 */
2060*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2061*7c478bd9Sstevel@tonic-gate 		if (q->q_first || (*bp->b_rptr == SIGTSTP &&
2062*7c478bd9Sstevel@tonic-gate 		    !(stp->sd_flag & RSLEEP))) {
2063*7c478bd9Sstevel@tonic-gate 			(void) putq(q, bp);
2064*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2065*7c478bd9Sstevel@tonic-gate 			return (0);
2066*7c478bd9Sstevel@tonic-gate 		}
2067*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2068*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 	case M_PCSIG:
2071*7c478bd9Sstevel@tonic-gate 		/*
2072*7c478bd9Sstevel@tonic-gate 		 * Don't enqueue, just post the signal.
2073*7c478bd9Sstevel@tonic-gate 		 */
2074*7c478bd9Sstevel@tonic-gate 		strsignal(stp, *bp->b_rptr, 0L);
2075*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2076*7c478bd9Sstevel@tonic-gate 		return (0);
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
2079*7c478bd9Sstevel@tonic-gate 		/*
2080*7c478bd9Sstevel@tonic-gate 		 * Flush queues.  The indication of which queues to flush
2081*7c478bd9Sstevel@tonic-gate 		 * is in the first byte of the message.  If the read queue
2082*7c478bd9Sstevel@tonic-gate 		 * is specified, then flush it.  If FLUSHBAND is set, just
2083*7c478bd9Sstevel@tonic-gate 		 * flush the band specified by the second byte of the message.
2084*7c478bd9Sstevel@tonic-gate 		 *
2085*7c478bd9Sstevel@tonic-gate 		 * If a module has issued a M_SETOPT to not flush hi
2086*7c478bd9Sstevel@tonic-gate 		 * priority messages off of the stream head, then pass this
2087*7c478bd9Sstevel@tonic-gate 		 * flag into the flushq code to preserve such messages.
2088*7c478bd9Sstevel@tonic-gate 		 */
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 		if (*bp->b_rptr & FLUSHR) {
2091*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
2092*7c478bd9Sstevel@tonic-gate 			if (*bp->b_rptr & FLUSHBAND) {
2093*7c478bd9Sstevel@tonic-gate 				ASSERT((bp->b_wptr - bp->b_rptr) >= 2);
2094*7c478bd9Sstevel@tonic-gate 				flushband(q, *(bp->b_rptr + 1), FLUSHALL);
2095*7c478bd9Sstevel@tonic-gate 			} else
2096*7c478bd9Sstevel@tonic-gate 				flushq_common(q, FLUSHALL,
2097*7c478bd9Sstevel@tonic-gate 				    stp->sd_read_opt & RFLUSHPCPROT);
2098*7c478bd9Sstevel@tonic-gate 			if ((q->q_first == NULL) ||
2099*7c478bd9Sstevel@tonic-gate 			    (q->q_first->b_datap->db_type < QPCTL))
2100*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
2101*7c478bd9Sstevel@tonic-gate 			else {
2102*7c478bd9Sstevel@tonic-gate 				ASSERT(stp->sd_flag & STRPRI);
2103*7c478bd9Sstevel@tonic-gate 			}
2104*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2105*7c478bd9Sstevel@tonic-gate 		}
2106*7c478bd9Sstevel@tonic-gate 		if ((*bp->b_rptr & FLUSHW) && !(bp->b_flag & MSGNOLOOP)) {
2107*7c478bd9Sstevel@tonic-gate 			*bp->b_rptr &= ~FLUSHR;
2108*7c478bd9Sstevel@tonic-gate 			bp->b_flag |= MSGNOLOOP;
2109*7c478bd9Sstevel@tonic-gate 			/*
2110*7c478bd9Sstevel@tonic-gate 			 * Protect against the driver passing up
2111*7c478bd9Sstevel@tonic-gate 			 * messages after it has done a qprocsoff.
2112*7c478bd9Sstevel@tonic-gate 			 */
2113*7c478bd9Sstevel@tonic-gate 			if (_OTHERQ(q)->q_next == NULL)
2114*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
2115*7c478bd9Sstevel@tonic-gate 			else
2116*7c478bd9Sstevel@tonic-gate 				qreply(q, bp);
2117*7c478bd9Sstevel@tonic-gate 			return (0);
2118*7c478bd9Sstevel@tonic-gate 		}
2119*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2120*7c478bd9Sstevel@tonic-gate 		return (0);
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 	case M_IOCACK:
2123*7c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
2124*7c478bd9Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
2125*7c478bd9Sstevel@tonic-gate 		/*
2126*7c478bd9Sstevel@tonic-gate 		 * If not waiting for ACK or NAK then just free msg.
2127*7c478bd9Sstevel@tonic-gate 		 * If incorrect id sequence number then just free msg.
2128*7c478bd9Sstevel@tonic-gate 		 * If already have ACK or NAK for user then this is a
2129*7c478bd9Sstevel@tonic-gate 		 *    duplicate, display a warning and free the msg.
2130*7c478bd9Sstevel@tonic-gate 		 */
2131*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2132*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & IOCWAIT) == 0 || stp->sd_iocblk ||
2133*7c478bd9Sstevel@tonic-gate 		    (stp->sd_iocid != iocbp->ioc_id)) {
2134*7c478bd9Sstevel@tonic-gate 			/*
2135*7c478bd9Sstevel@tonic-gate 			 * If the ACK/NAK is a dup, display a message
2136*7c478bd9Sstevel@tonic-gate 			 * Dup is when sd_iocid == ioc_id, and
2137*7c478bd9Sstevel@tonic-gate 			 * sd_iocblk == <valid ptr> or -1 (the former
2138*7c478bd9Sstevel@tonic-gate 			 * is when an ioctl has been put on the stream
2139*7c478bd9Sstevel@tonic-gate 			 * head, but has not yet been consumed, the
2140*7c478bd9Sstevel@tonic-gate 			 * later is when it has been consumed).
2141*7c478bd9Sstevel@tonic-gate 			 */
2142*7c478bd9Sstevel@tonic-gate 			if ((stp->sd_iocid == iocbp->ioc_id) &&
2143*7c478bd9Sstevel@tonic-gate 			    (stp->sd_iocblk != NULL)) {
2144*7c478bd9Sstevel@tonic-gate 				log_dupioc(q, bp);
2145*7c478bd9Sstevel@tonic-gate 			}
2146*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
2147*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2148*7c478bd9Sstevel@tonic-gate 			return (0);
2149*7c478bd9Sstevel@tonic-gate 		}
2150*7c478bd9Sstevel@tonic-gate 
2151*7c478bd9Sstevel@tonic-gate 		/*
2152*7c478bd9Sstevel@tonic-gate 		 * Assign ACK or NAK to user and wake up.
2153*7c478bd9Sstevel@tonic-gate 		 */
2154*7c478bd9Sstevel@tonic-gate 		stp->sd_iocblk = bp;
2155*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
2156*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2157*7c478bd9Sstevel@tonic-gate 		return (0);
2158*7c478bd9Sstevel@tonic-gate 
2159*7c478bd9Sstevel@tonic-gate 	case M_COPYIN:
2160*7c478bd9Sstevel@tonic-gate 	case M_COPYOUT:
2161*7c478bd9Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
2162*7c478bd9Sstevel@tonic-gate 
2163*7c478bd9Sstevel@tonic-gate 		/*
2164*7c478bd9Sstevel@tonic-gate 		 * If not waiting for ACK or NAK then just fail request.
2165*7c478bd9Sstevel@tonic-gate 		 * If already have ACK, NAK, or copy request, then just
2166*7c478bd9Sstevel@tonic-gate 		 * fail request.
2167*7c478bd9Sstevel@tonic-gate 		 * If incorrect id sequence number then just fail request.
2168*7c478bd9Sstevel@tonic-gate 		 */
2169*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2170*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & IOCWAIT) == 0 || stp->sd_iocblk ||
2171*7c478bd9Sstevel@tonic-gate 		    (stp->sd_iocid != reqp->cq_id)) {
2172*7c478bd9Sstevel@tonic-gate 			if (bp->b_cont) {
2173*7c478bd9Sstevel@tonic-gate 				freemsg(bp->b_cont);
2174*7c478bd9Sstevel@tonic-gate 				bp->b_cont = NULL;
2175*7c478bd9Sstevel@tonic-gate 			}
2176*7c478bd9Sstevel@tonic-gate 			bp->b_datap->db_type = M_IOCDATA;
2177*7c478bd9Sstevel@tonic-gate 			bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
2178*7c478bd9Sstevel@tonic-gate 			resp = (struct copyresp *)bp->b_rptr;
2179*7c478bd9Sstevel@tonic-gate 			resp->cp_rval = (caddr_t)1;	/* failure */
2180*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2181*7c478bd9Sstevel@tonic-gate 			putnext(stp->sd_wrq, bp);
2182*7c478bd9Sstevel@tonic-gate 			return (0);
2183*7c478bd9Sstevel@tonic-gate 		}
2184*7c478bd9Sstevel@tonic-gate 
2185*7c478bd9Sstevel@tonic-gate 		/*
2186*7c478bd9Sstevel@tonic-gate 		 * Assign copy request to user and wake up.
2187*7c478bd9Sstevel@tonic-gate 		 */
2188*7c478bd9Sstevel@tonic-gate 		stp->sd_iocblk = bp;
2189*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_monitor);
2190*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2191*7c478bd9Sstevel@tonic-gate 		return (0);
2192*7c478bd9Sstevel@tonic-gate 
2193*7c478bd9Sstevel@tonic-gate 	case M_SETOPTS:
2194*7c478bd9Sstevel@tonic-gate 		/*
2195*7c478bd9Sstevel@tonic-gate 		 * Set stream head options (read option, write offset,
2196*7c478bd9Sstevel@tonic-gate 		 * min/max packet size, and/or high/low water marks for
2197*7c478bd9Sstevel@tonic-gate 		 * the read side only).
2198*7c478bd9Sstevel@tonic-gate 		 */
2199*7c478bd9Sstevel@tonic-gate 
2200*7c478bd9Sstevel@tonic-gate 		bpri = 0;
2201*7c478bd9Sstevel@tonic-gate 		sop = (struct stroptions *)bp->b_rptr;
2202*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2203*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_READOPT) {
2204*7c478bd9Sstevel@tonic-gate 			switch (sop->so_readopt & RMODEMASK) {
2205*7c478bd9Sstevel@tonic-gate 			case RNORM:
2206*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt &= ~(RD_MSGDIS | RD_MSGNODIS);
2207*7c478bd9Sstevel@tonic-gate 				break;
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate 			case RMSGD:
2210*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt =
2211*7c478bd9Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_MSGNODIS) |
2212*7c478bd9Sstevel@tonic-gate 				    RD_MSGDIS);
2213*7c478bd9Sstevel@tonic-gate 				break;
2214*7c478bd9Sstevel@tonic-gate 
2215*7c478bd9Sstevel@tonic-gate 			case RMSGN:
2216*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt =
2217*7c478bd9Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_MSGDIS) |
2218*7c478bd9Sstevel@tonic-gate 				    RD_MSGNODIS);
2219*7c478bd9Sstevel@tonic-gate 				break;
2220*7c478bd9Sstevel@tonic-gate 			}
2221*7c478bd9Sstevel@tonic-gate 			switch (sop->so_readopt & RPROTMASK) {
2222*7c478bd9Sstevel@tonic-gate 			case RPROTNORM:
2223*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt &= ~(RD_PROTDAT | RD_PROTDIS);
2224*7c478bd9Sstevel@tonic-gate 				break;
2225*7c478bd9Sstevel@tonic-gate 
2226*7c478bd9Sstevel@tonic-gate 			case RPROTDAT:
2227*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt =
2228*7c478bd9Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_PROTDIS) |
2229*7c478bd9Sstevel@tonic-gate 				    RD_PROTDAT);
2230*7c478bd9Sstevel@tonic-gate 				break;
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 			case RPROTDIS:
2233*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt =
2234*7c478bd9Sstevel@tonic-gate 				    ((stp->sd_read_opt & ~RD_PROTDAT) |
2235*7c478bd9Sstevel@tonic-gate 				    RD_PROTDIS);
2236*7c478bd9Sstevel@tonic-gate 				break;
2237*7c478bd9Sstevel@tonic-gate 			}
2238*7c478bd9Sstevel@tonic-gate 			switch (sop->so_readopt & RFLUSHMASK) {
2239*7c478bd9Sstevel@tonic-gate 			case RFLUSHPCPROT:
2240*7c478bd9Sstevel@tonic-gate 				/*
2241*7c478bd9Sstevel@tonic-gate 				 * This sets the stream head to NOT flush
2242*7c478bd9Sstevel@tonic-gate 				 * M_PCPROTO messages.
2243*7c478bd9Sstevel@tonic-gate 				 */
2244*7c478bd9Sstevel@tonic-gate 				stp->sd_read_opt |= RFLUSHPCPROT;
2245*7c478bd9Sstevel@tonic-gate 				break;
2246*7c478bd9Sstevel@tonic-gate 			}
2247*7c478bd9Sstevel@tonic-gate 		}
2248*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_ERROPT) {
2249*7c478bd9Sstevel@tonic-gate 			switch (sop->so_erropt & RERRMASK) {
2250*7c478bd9Sstevel@tonic-gate 			case RERRNORM:
2251*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRDERRNONPERSIST;
2252*7c478bd9Sstevel@tonic-gate 				break;
2253*7c478bd9Sstevel@tonic-gate 			case RERRNONPERSIST:
2254*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= STRDERRNONPERSIST;
2255*7c478bd9Sstevel@tonic-gate 				break;
2256*7c478bd9Sstevel@tonic-gate 			}
2257*7c478bd9Sstevel@tonic-gate 			switch (sop->so_erropt & WERRMASK) {
2258*7c478bd9Sstevel@tonic-gate 			case WERRNORM:
2259*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STWRERRNONPERSIST;
2260*7c478bd9Sstevel@tonic-gate 				break;
2261*7c478bd9Sstevel@tonic-gate 			case WERRNONPERSIST:
2262*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= STWRERRNONPERSIST;
2263*7c478bd9Sstevel@tonic-gate 				break;
2264*7c478bd9Sstevel@tonic-gate 			}
2265*7c478bd9Sstevel@tonic-gate 		}
2266*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_COPYOPT) {
2267*7c478bd9Sstevel@tonic-gate 			if (sop->so_copyopt & ZCVMSAFE) {
2268*7c478bd9Sstevel@tonic-gate 				stp->sd_copyflag |= STZCVMSAFE;
2269*7c478bd9Sstevel@tonic-gate 				stp->sd_copyflag &= ~STZCVMUNSAFE;
2270*7c478bd9Sstevel@tonic-gate 			} else if (sop->so_copyopt & ZCVMUNSAFE) {
2271*7c478bd9Sstevel@tonic-gate 				stp->sd_copyflag |= STZCVMUNSAFE;
2272*7c478bd9Sstevel@tonic-gate 				stp->sd_copyflag &= ~STZCVMSAFE;
2273*7c478bd9Sstevel@tonic-gate 			}
2274*7c478bd9Sstevel@tonic-gate 
2275*7c478bd9Sstevel@tonic-gate 			if (sop->so_copyopt & COPYCACHED) {
2276*7c478bd9Sstevel@tonic-gate 				stp->sd_copyflag |= STRCOPYCACHED;
2277*7c478bd9Sstevel@tonic-gate 			}
2278*7c478bd9Sstevel@tonic-gate 		}
2279*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_WROFF)
2280*7c478bd9Sstevel@tonic-gate 			stp->sd_wroff = sop->so_wroff;
2281*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_MINPSZ)
2282*7c478bd9Sstevel@tonic-gate 			q->q_minpsz = sop->so_minpsz;
2283*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_MAXPSZ)
2284*7c478bd9Sstevel@tonic-gate 			q->q_maxpsz = sop->so_maxpsz;
2285*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_MAXBLK)
2286*7c478bd9Sstevel@tonic-gate 			stp->sd_maxblk = sop->so_maxblk;
2287*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_HIWAT) {
2288*7c478bd9Sstevel@tonic-gate 		    if (sop->so_flags & SO_BAND) {
2289*7c478bd9Sstevel@tonic-gate 			if (strqset(q, QHIWAT, sop->so_band, sop->so_hiwat))
2290*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
2291*7c478bd9Sstevel@tonic-gate 				    "strrput: could not allocate qband\n");
2292*7c478bd9Sstevel@tonic-gate 			else
2293*7c478bd9Sstevel@tonic-gate 				bpri = sop->so_band;
2294*7c478bd9Sstevel@tonic-gate 		    } else {
2295*7c478bd9Sstevel@tonic-gate 			q->q_hiwat = sop->so_hiwat;
2296*7c478bd9Sstevel@tonic-gate 		    }
2297*7c478bd9Sstevel@tonic-gate 		}
2298*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_LOWAT) {
2299*7c478bd9Sstevel@tonic-gate 		    if (sop->so_flags & SO_BAND) {
2300*7c478bd9Sstevel@tonic-gate 			if (strqset(q, QLOWAT, sop->so_band, sop->so_lowat))
2301*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
2302*7c478bd9Sstevel@tonic-gate 				    "strrput: could not allocate qband\n");
2303*7c478bd9Sstevel@tonic-gate 			else
2304*7c478bd9Sstevel@tonic-gate 				bpri = sop->so_band;
2305*7c478bd9Sstevel@tonic-gate 		    } else {
2306*7c478bd9Sstevel@tonic-gate 			q->q_lowat = sop->so_lowat;
2307*7c478bd9Sstevel@tonic-gate 		    }
2308*7c478bd9Sstevel@tonic-gate 		}
2309*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_MREADON)
2310*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= SNDMREAD;
2311*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_MREADOFF)
2312*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~SNDMREAD;
2313*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_NDELON)
2314*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= OLDNDELAY;
2315*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_NDELOFF)
2316*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~OLDNDELAY;
2317*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_ISTTY)
2318*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= STRISTTY;
2319*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_ISNTTY)
2320*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRISTTY;
2321*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_TOSTOP)
2322*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= STRTOSTOP;
2323*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_TONSTOP)
2324*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRTOSTOP;
2325*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_DELIM)
2326*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= STRDELIM;
2327*7c478bd9Sstevel@tonic-gate 		if (sop->so_flags & SO_NODELIM)
2328*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRDELIM;
2329*7c478bd9Sstevel@tonic-gate 
2330*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2331*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2332*7c478bd9Sstevel@tonic-gate 
2333*7c478bd9Sstevel@tonic-gate 		/* Check backenable in case the water marks changed */
2334*7c478bd9Sstevel@tonic-gate 		qbackenable(q, bpri);
2335*7c478bd9Sstevel@tonic-gate 		return (0);
2336*7c478bd9Sstevel@tonic-gate 
2337*7c478bd9Sstevel@tonic-gate 	/*
2338*7c478bd9Sstevel@tonic-gate 	 * The following set of cases deal with situations where two stream
2339*7c478bd9Sstevel@tonic-gate 	 * heads are connected to each other (twisted streams).  These messages
2340*7c478bd9Sstevel@tonic-gate 	 * have no meaning at the stream head.
2341*7c478bd9Sstevel@tonic-gate 	 */
2342*7c478bd9Sstevel@tonic-gate 	case M_BREAK:
2343*7c478bd9Sstevel@tonic-gate 	case M_CTL:
2344*7c478bd9Sstevel@tonic-gate 	case M_DELAY:
2345*7c478bd9Sstevel@tonic-gate 	case M_START:
2346*7c478bd9Sstevel@tonic-gate 	case M_STOP:
2347*7c478bd9Sstevel@tonic-gate 	case M_IOCDATA:
2348*7c478bd9Sstevel@tonic-gate 	case M_STARTI:
2349*7c478bd9Sstevel@tonic-gate 	case M_STOPI:
2350*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2351*7c478bd9Sstevel@tonic-gate 		return (0);
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
2354*7c478bd9Sstevel@tonic-gate 		/*
2355*7c478bd9Sstevel@tonic-gate 		 * Always NAK this condition
2356*7c478bd9Sstevel@tonic-gate 		 * (makes no sense)
2357*7c478bd9Sstevel@tonic-gate 		 * If there is one or more threads in the read side
2358*7c478bd9Sstevel@tonic-gate 		 * rwnext we have to defer the nacking until that thread
2359*7c478bd9Sstevel@tonic-gate 		 * returns (in strget).
2360*7c478bd9Sstevel@tonic-gate 		 */
2361*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2362*7c478bd9Sstevel@tonic-gate 		if (stp->sd_struiodnak != 0) {
2363*7c478bd9Sstevel@tonic-gate 			/*
2364*7c478bd9Sstevel@tonic-gate 			 * Defer NAK to the streamhead. Queue at the end
2365*7c478bd9Sstevel@tonic-gate 			 * the list.
2366*7c478bd9Sstevel@tonic-gate 			 */
2367*7c478bd9Sstevel@tonic-gate 			mblk_t *mp = stp->sd_struionak;
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate 			while (mp && mp->b_next)
2370*7c478bd9Sstevel@tonic-gate 				mp = mp->b_next;
2371*7c478bd9Sstevel@tonic-gate 			if (mp)
2372*7c478bd9Sstevel@tonic-gate 				mp->b_next = bp;
2373*7c478bd9Sstevel@tonic-gate 			else
2374*7c478bd9Sstevel@tonic-gate 				stp->sd_struionak = bp;
2375*7c478bd9Sstevel@tonic-gate 			bp->b_next = NULL;
2376*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2377*7c478bd9Sstevel@tonic-gate 			return (0);
2378*7c478bd9Sstevel@tonic-gate 		}
2379*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2380*7c478bd9Sstevel@tonic-gate 
2381*7c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCNAK;
2382*7c478bd9Sstevel@tonic-gate 		/*
2383*7c478bd9Sstevel@tonic-gate 		 * Protect against the driver passing up
2384*7c478bd9Sstevel@tonic-gate 		 * messages after it has done a qprocsoff.
2385*7c478bd9Sstevel@tonic-gate 		 */
2386*7c478bd9Sstevel@tonic-gate 		if (_OTHERQ(q)->q_next == NULL)
2387*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
2388*7c478bd9Sstevel@tonic-gate 		else
2389*7c478bd9Sstevel@tonic-gate 			qreply(q, bp);
2390*7c478bd9Sstevel@tonic-gate 		return (0);
2391*7c478bd9Sstevel@tonic-gate 
2392*7c478bd9Sstevel@tonic-gate 	default:
2393*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2394*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
2395*7c478bd9Sstevel@tonic-gate 			"bad message type %x received at stream head\n",
2396*7c478bd9Sstevel@tonic-gate 			bp->b_datap->db_type);
2397*7c478bd9Sstevel@tonic-gate #endif
2398*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
2399*7c478bd9Sstevel@tonic-gate 		return (0);
2400*7c478bd9Sstevel@tonic-gate 	}
2401*7c478bd9Sstevel@tonic-gate 
2402*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2403*7c478bd9Sstevel@tonic-gate }
2404*7c478bd9Sstevel@tonic-gate 
2405*7c478bd9Sstevel@tonic-gate /*
2406*7c478bd9Sstevel@tonic-gate  * Check if the stream pointed to by `stp' can be written to, and return an
2407*7c478bd9Sstevel@tonic-gate  * error code if not.  If `eiohup' is set, then return EIO if STRHUP is set.
2408*7c478bd9Sstevel@tonic-gate  * If `sigpipeok' is set and the SW_SIGPIPE option is enabled on the stream,
2409*7c478bd9Sstevel@tonic-gate  * then always return EPIPE and send a SIGPIPE to the invoking thread.
2410*7c478bd9Sstevel@tonic-gate  */
2411*7c478bd9Sstevel@tonic-gate static int
2412*7c478bd9Sstevel@tonic-gate strwriteable(struct stdata *stp, boolean_t eiohup, boolean_t sigpipeok)
2413*7c478bd9Sstevel@tonic-gate {
2414*7c478bd9Sstevel@tonic-gate 	int error;
2415*7c478bd9Sstevel@tonic-gate 
2416*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 	/*
2419*7c478bd9Sstevel@tonic-gate 	 * For modem support, POSIX states that on writes, EIO should
2420*7c478bd9Sstevel@tonic-gate 	 * be returned if the stream has been hung up.
2421*7c478bd9Sstevel@tonic-gate 	 */
2422*7c478bd9Sstevel@tonic-gate 	if (eiohup && (stp->sd_flag & (STPLEX|STRHUP)) == STRHUP)
2423*7c478bd9Sstevel@tonic-gate 		error = EIO;
2424*7c478bd9Sstevel@tonic-gate 	else
2425*7c478bd9Sstevel@tonic-gate 		error = strgeterr(stp, STRHUP|STPLEX|STWRERR, 0);
2426*7c478bd9Sstevel@tonic-gate 
2427*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
2428*7c478bd9Sstevel@tonic-gate 		if (!(stp->sd_flag & STPLEX) &&
2429*7c478bd9Sstevel@tonic-gate 		    (stp->sd_wput_opt & SW_SIGPIPE) && sigpipeok) {
2430*7c478bd9Sstevel@tonic-gate 			tsignal(curthread, SIGPIPE);
2431*7c478bd9Sstevel@tonic-gate 			error = EPIPE;
2432*7c478bd9Sstevel@tonic-gate 		}
2433*7c478bd9Sstevel@tonic-gate 	}
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate 	return (error);
2436*7c478bd9Sstevel@tonic-gate }
2437*7c478bd9Sstevel@tonic-gate 
2438*7c478bd9Sstevel@tonic-gate /*
2439*7c478bd9Sstevel@tonic-gate  * Copyin and send data down a stream.
2440*7c478bd9Sstevel@tonic-gate  * The caller will allocate and copyin any control part that precedes the
2441*7c478bd9Sstevel@tonic-gate  * message and pass than in as mctl.
2442*7c478bd9Sstevel@tonic-gate  *
2443*7c478bd9Sstevel@tonic-gate  * Caller should *not* hold sd_lock.
2444*7c478bd9Sstevel@tonic-gate  * When EWOULDBLOCK is returned the caller has to redo the canputnext
2445*7c478bd9Sstevel@tonic-gate  * under sd_lock in order to avoid missing a backenabling wakeup.
2446*7c478bd9Sstevel@tonic-gate  *
2447*7c478bd9Sstevel@tonic-gate  * Use iosize = -1 to not send any M_DATA. iosize = 0 sends zero-length M_DATA.
2448*7c478bd9Sstevel@tonic-gate  *
2449*7c478bd9Sstevel@tonic-gate  * Set MSG_IGNFLOW in flags to ignore flow control for hipri messages.
2450*7c478bd9Sstevel@tonic-gate  * For sync streams we can only ignore flow control by reverting to using
2451*7c478bd9Sstevel@tonic-gate  * putnext.
2452*7c478bd9Sstevel@tonic-gate  *
2453*7c478bd9Sstevel@tonic-gate  * If sd_maxblk is less than *iosize this routine might return without
2454*7c478bd9Sstevel@tonic-gate  * transferring all of *iosize. In all cases, on return *iosize will contain
2455*7c478bd9Sstevel@tonic-gate  * the amount of data that was transferred.
2456*7c478bd9Sstevel@tonic-gate  */
2457*7c478bd9Sstevel@tonic-gate static int
2458*7c478bd9Sstevel@tonic-gate strput(struct stdata *stp, mblk_t *mctl, struct uio *uiop, ssize_t *iosize,
2459*7c478bd9Sstevel@tonic-gate     int b_flag, int pri, int flags)
2460*7c478bd9Sstevel@tonic-gate {
2461*7c478bd9Sstevel@tonic-gate 	struiod_t uiod;
2462*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
2463*7c478bd9Sstevel@tonic-gate 	queue_t *wqp = stp->sd_wrq;
2464*7c478bd9Sstevel@tonic-gate 	int error = 0;
2465*7c478bd9Sstevel@tonic-gate 	ssize_t count = *iosize;
2466*7c478bd9Sstevel@tonic-gate 	cred_t *cr;
2467*7c478bd9Sstevel@tonic-gate 
2468*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate 	if (uiop != NULL && count >= 0)
2471*7c478bd9Sstevel@tonic-gate 		flags |= stp->sd_struiowrq ? STRUIO_POSTPONE : 0;
2472*7c478bd9Sstevel@tonic-gate 
2473*7c478bd9Sstevel@tonic-gate 	if (!(flags & STRUIO_POSTPONE)) {
2474*7c478bd9Sstevel@tonic-gate 		/*
2475*7c478bd9Sstevel@tonic-gate 		 * Use regular canputnext, strmakedata, putnext sequence.
2476*7c478bd9Sstevel@tonic-gate 		 */
2477*7c478bd9Sstevel@tonic-gate 		if (pri == 0) {
2478*7c478bd9Sstevel@tonic-gate 			if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
2479*7c478bd9Sstevel@tonic-gate 				freemsg(mctl);
2480*7c478bd9Sstevel@tonic-gate 				return (EWOULDBLOCK);
2481*7c478bd9Sstevel@tonic-gate 			}
2482*7c478bd9Sstevel@tonic-gate 		} else {
2483*7c478bd9Sstevel@tonic-gate 			if (!(flags & MSG_IGNFLOW) && !bcanputnext(wqp, pri)) {
2484*7c478bd9Sstevel@tonic-gate 				freemsg(mctl);
2485*7c478bd9Sstevel@tonic-gate 				return (EWOULDBLOCK);
2486*7c478bd9Sstevel@tonic-gate 			}
2487*7c478bd9Sstevel@tonic-gate 		}
2488*7c478bd9Sstevel@tonic-gate 
2489*7c478bd9Sstevel@tonic-gate 		if ((error = strmakedata(iosize, uiop, stp, flags,
2490*7c478bd9Sstevel@tonic-gate 					&mp)) != 0) {
2491*7c478bd9Sstevel@tonic-gate 			freemsg(mctl);
2492*7c478bd9Sstevel@tonic-gate 			/*
2493*7c478bd9Sstevel@tonic-gate 			 * need to change return code to ENOMEM
2494*7c478bd9Sstevel@tonic-gate 			 * so that this is not confused with
2495*7c478bd9Sstevel@tonic-gate 			 * flow control, EAGAIN.
2496*7c478bd9Sstevel@tonic-gate 			 */
2497*7c478bd9Sstevel@tonic-gate 
2498*7c478bd9Sstevel@tonic-gate 			if (error == EAGAIN)
2499*7c478bd9Sstevel@tonic-gate 				return (ENOMEM);
2500*7c478bd9Sstevel@tonic-gate 			else
2501*7c478bd9Sstevel@tonic-gate 				return (error);
2502*7c478bd9Sstevel@tonic-gate 		}
2503*7c478bd9Sstevel@tonic-gate 		if (mctl != NULL) {
2504*7c478bd9Sstevel@tonic-gate 			if (mctl->b_cont == NULL)
2505*7c478bd9Sstevel@tonic-gate 				mctl->b_cont = mp;
2506*7c478bd9Sstevel@tonic-gate 			else if (mp != NULL)
2507*7c478bd9Sstevel@tonic-gate 				linkb(mctl, mp);
2508*7c478bd9Sstevel@tonic-gate 			mp = mctl;
2509*7c478bd9Sstevel@tonic-gate 			/*
2510*7c478bd9Sstevel@tonic-gate 			 * Note that for interrupt thread, the CRED() is
2511*7c478bd9Sstevel@tonic-gate 			 * NULL. Don't bother with the pid either.
2512*7c478bd9Sstevel@tonic-gate 			 */
2513*7c478bd9Sstevel@tonic-gate 			if ((cr = CRED()) != NULL) {
2514*7c478bd9Sstevel@tonic-gate 				mblk_setcred(mp, cr);
2515*7c478bd9Sstevel@tonic-gate 				DB_CPID(mp) = curproc->p_pid;
2516*7c478bd9Sstevel@tonic-gate 			}
2517*7c478bd9Sstevel@tonic-gate 		} else if (mp == NULL)
2518*7c478bd9Sstevel@tonic-gate 			return (0);
2519*7c478bd9Sstevel@tonic-gate 
2520*7c478bd9Sstevel@tonic-gate 		mp->b_flag |= b_flag;
2521*7c478bd9Sstevel@tonic-gate 		mp->b_band = (uchar_t)pri;
2522*7c478bd9Sstevel@tonic-gate 
2523*7c478bd9Sstevel@tonic-gate 		if (flags & MSG_IGNFLOW) {
2524*7c478bd9Sstevel@tonic-gate 			/*
2525*7c478bd9Sstevel@tonic-gate 			 * XXX Hack: Don't get stuck running service
2526*7c478bd9Sstevel@tonic-gate 			 * procedures. This is needed for sockfs when
2527*7c478bd9Sstevel@tonic-gate 			 * sending the unbind message out of the rput
2528*7c478bd9Sstevel@tonic-gate 			 * procedure - we don't want a put procedure
2529*7c478bd9Sstevel@tonic-gate 			 * to run service procedures.
2530*7c478bd9Sstevel@tonic-gate 			 */
2531*7c478bd9Sstevel@tonic-gate 			putnext(wqp, mp);
2532*7c478bd9Sstevel@tonic-gate 		} else {
2533*7c478bd9Sstevel@tonic-gate 			stream_willservice(stp);
2534*7c478bd9Sstevel@tonic-gate 			putnext(wqp, mp);
2535*7c478bd9Sstevel@tonic-gate 			stream_runservice(stp);
2536*7c478bd9Sstevel@tonic-gate 		}
2537*7c478bd9Sstevel@tonic-gate 		return (0);
2538*7c478bd9Sstevel@tonic-gate 	}
2539*7c478bd9Sstevel@tonic-gate 	/*
2540*7c478bd9Sstevel@tonic-gate 	 * Stream supports rwnext() for the write side.
2541*7c478bd9Sstevel@tonic-gate 	 */
2542*7c478bd9Sstevel@tonic-gate 	if ((error = strmakedata(iosize, uiop, stp, flags, &mp)) != 0) {
2543*7c478bd9Sstevel@tonic-gate 		freemsg(mctl);
2544*7c478bd9Sstevel@tonic-gate 		/*
2545*7c478bd9Sstevel@tonic-gate 		 * map EAGAIN to ENOMEM since EAGAIN means "flow controlled".
2546*7c478bd9Sstevel@tonic-gate 		 */
2547*7c478bd9Sstevel@tonic-gate 		return (error == EAGAIN ? ENOMEM : error);
2548*7c478bd9Sstevel@tonic-gate 	}
2549*7c478bd9Sstevel@tonic-gate 	if (mctl != NULL) {
2550*7c478bd9Sstevel@tonic-gate 		if (mctl->b_cont == NULL)
2551*7c478bd9Sstevel@tonic-gate 			mctl->b_cont = mp;
2552*7c478bd9Sstevel@tonic-gate 		else if (mp != NULL)
2553*7c478bd9Sstevel@tonic-gate 			linkb(mctl, mp);
2554*7c478bd9Sstevel@tonic-gate 		mp = mctl;
2555*7c478bd9Sstevel@tonic-gate 		/*
2556*7c478bd9Sstevel@tonic-gate 		 * Note that for interrupt thread, the CRED() is
2557*7c478bd9Sstevel@tonic-gate 		 * NULL.  Don't bother with the pid either.
2558*7c478bd9Sstevel@tonic-gate 		 */
2559*7c478bd9Sstevel@tonic-gate 		if ((cr = CRED()) != NULL) {
2560*7c478bd9Sstevel@tonic-gate 			mblk_setcred(mp, cr);
2561*7c478bd9Sstevel@tonic-gate 			DB_CPID(mp) = curproc->p_pid;
2562*7c478bd9Sstevel@tonic-gate 		}
2563*7c478bd9Sstevel@tonic-gate 	} else if (mp == NULL) {
2564*7c478bd9Sstevel@tonic-gate 		return (0);
2565*7c478bd9Sstevel@tonic-gate 	}
2566*7c478bd9Sstevel@tonic-gate 
2567*7c478bd9Sstevel@tonic-gate 	mp->b_flag |= b_flag;
2568*7c478bd9Sstevel@tonic-gate 	mp->b_band = (uchar_t)pri;
2569*7c478bd9Sstevel@tonic-gate 
2570*7c478bd9Sstevel@tonic-gate 	(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
2571*7c478bd9Sstevel@tonic-gate 		sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
2572*7c478bd9Sstevel@tonic-gate 	uiod.d_uio.uio_offset = 0;
2573*7c478bd9Sstevel@tonic-gate 	uiod.d_mp = mp;
2574*7c478bd9Sstevel@tonic-gate 	error = rwnext(wqp, &uiod);
2575*7c478bd9Sstevel@tonic-gate 	if (! uiod.d_mp) {
2576*7c478bd9Sstevel@tonic-gate 		uioskip(uiop, *iosize);
2577*7c478bd9Sstevel@tonic-gate 		return (error);
2578*7c478bd9Sstevel@tonic-gate 	}
2579*7c478bd9Sstevel@tonic-gate 	ASSERT(mp == uiod.d_mp);
2580*7c478bd9Sstevel@tonic-gate 	if (error == EINVAL) {
2581*7c478bd9Sstevel@tonic-gate 		/*
2582*7c478bd9Sstevel@tonic-gate 		 * The stream plumbing must have changed while
2583*7c478bd9Sstevel@tonic-gate 		 * we were away, so just turn off rwnext()s.
2584*7c478bd9Sstevel@tonic-gate 		 */
2585*7c478bd9Sstevel@tonic-gate 		error = 0;
2586*7c478bd9Sstevel@tonic-gate 	} else if (error == EBUSY || error == EWOULDBLOCK) {
2587*7c478bd9Sstevel@tonic-gate 		/*
2588*7c478bd9Sstevel@tonic-gate 		 * Couldn't enter a perimeter or took a page fault,
2589*7c478bd9Sstevel@tonic-gate 		 * so fall-back to putnext().
2590*7c478bd9Sstevel@tonic-gate 		 */
2591*7c478bd9Sstevel@tonic-gate 		error = 0;
2592*7c478bd9Sstevel@tonic-gate 	} else {
2593*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2594*7c478bd9Sstevel@tonic-gate 		return (error);
2595*7c478bd9Sstevel@tonic-gate 	}
2596*7c478bd9Sstevel@tonic-gate 	/* Have to check canput before consuming data from the uio */
2597*7c478bd9Sstevel@tonic-gate 	if (pri == 0) {
2598*7c478bd9Sstevel@tonic-gate 		if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
2599*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2600*7c478bd9Sstevel@tonic-gate 			return (EWOULDBLOCK);
2601*7c478bd9Sstevel@tonic-gate 		}
2602*7c478bd9Sstevel@tonic-gate 	} else {
2603*7c478bd9Sstevel@tonic-gate 		if (!bcanputnext(wqp, pri) && !(flags & MSG_IGNFLOW)) {
2604*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2605*7c478bd9Sstevel@tonic-gate 			return (EWOULDBLOCK);
2606*7c478bd9Sstevel@tonic-gate 		}
2607*7c478bd9Sstevel@tonic-gate 	}
2608*7c478bd9Sstevel@tonic-gate 	ASSERT(mp == uiod.d_mp);
2609*7c478bd9Sstevel@tonic-gate 	/* Copyin data from the uio */
2610*7c478bd9Sstevel@tonic-gate 	if ((error = struioget(wqp, mp, &uiod, 0)) != 0) {
2611*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2612*7c478bd9Sstevel@tonic-gate 		return (error);
2613*7c478bd9Sstevel@tonic-gate 	}
2614*7c478bd9Sstevel@tonic-gate 	uioskip(uiop, *iosize);
2615*7c478bd9Sstevel@tonic-gate 	if (flags & MSG_IGNFLOW) {
2616*7c478bd9Sstevel@tonic-gate 		/*
2617*7c478bd9Sstevel@tonic-gate 		 * XXX Hack: Don't get stuck running service procedures.
2618*7c478bd9Sstevel@tonic-gate 		 * This is needed for sockfs when sending the unbind message
2619*7c478bd9Sstevel@tonic-gate 		 * out of the rput procedure - we don't want a put procedure
2620*7c478bd9Sstevel@tonic-gate 		 * to run service procedures.
2621*7c478bd9Sstevel@tonic-gate 		 */
2622*7c478bd9Sstevel@tonic-gate 		putnext(wqp, mp);
2623*7c478bd9Sstevel@tonic-gate 	} else {
2624*7c478bd9Sstevel@tonic-gate 		stream_willservice(stp);
2625*7c478bd9Sstevel@tonic-gate 		putnext(wqp, mp);
2626*7c478bd9Sstevel@tonic-gate 		stream_runservice(stp);
2627*7c478bd9Sstevel@tonic-gate 	}
2628*7c478bd9Sstevel@tonic-gate 	return (0);
2629*7c478bd9Sstevel@tonic-gate }
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate /*
2632*7c478bd9Sstevel@tonic-gate  * Write attempts to break the write request into messages conforming
2633*7c478bd9Sstevel@tonic-gate  * with the minimum and maximum packet sizes set downstream.
2634*7c478bd9Sstevel@tonic-gate  *
2635*7c478bd9Sstevel@tonic-gate  * Write will not block if downstream queue is full and
2636*7c478bd9Sstevel@tonic-gate  * O_NDELAY is set, otherwise it will block waiting for the queue to get room.
2637*7c478bd9Sstevel@tonic-gate  *
2638*7c478bd9Sstevel@tonic-gate  * A write of zero bytes gets packaged into a zero length message and sent
2639*7c478bd9Sstevel@tonic-gate  * downstream like any other message.
2640*7c478bd9Sstevel@tonic-gate  *
2641*7c478bd9Sstevel@tonic-gate  * If buffers of the requested sizes are not available, the write will
2642*7c478bd9Sstevel@tonic-gate  * sleep until the buffers become available.
2643*7c478bd9Sstevel@tonic-gate  *
2644*7c478bd9Sstevel@tonic-gate  * Write (if specified) will supply a write offset in a message if it
2645*7c478bd9Sstevel@tonic-gate  * makes sense. This can be specified by downstream modules as part of
2646*7c478bd9Sstevel@tonic-gate  * a M_SETOPTS message.  Write will not supply the write offset if it
2647*7c478bd9Sstevel@tonic-gate  * cannot supply any data in a buffer.  In other words, write will never
2648*7c478bd9Sstevel@tonic-gate  * send down an empty packet due to a write offset.
2649*7c478bd9Sstevel@tonic-gate  */
2650*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
2651*7c478bd9Sstevel@tonic-gate int
2652*7c478bd9Sstevel@tonic-gate strwrite(struct vnode *vp, struct uio *uiop, cred_t *crp)
2653*7c478bd9Sstevel@tonic-gate {
2654*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
2655*7c478bd9Sstevel@tonic-gate 	struct queue *wqp;
2656*7c478bd9Sstevel@tonic-gate 	ssize_t rmin, rmax;
2657*7c478bd9Sstevel@tonic-gate 	ssize_t iosize;
2658*7c478bd9Sstevel@tonic-gate 	char waitflag;
2659*7c478bd9Sstevel@tonic-gate 	int tempmode;
2660*7c478bd9Sstevel@tonic-gate 	int error = 0;
2661*7c478bd9Sstevel@tonic-gate 	int b_flag;
2662*7c478bd9Sstevel@tonic-gate 
2663*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
2664*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
2667*7c478bd9Sstevel@tonic-gate 		if ((error = straccess(stp, JCWRITE)) != 0)
2668*7c478bd9Sstevel@tonic-gate 			return (error);
2669*7c478bd9Sstevel@tonic-gate 
2670*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
2671*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2672*7c478bd9Sstevel@tonic-gate 		error = strwriteable(stp, B_TRUE, B_TRUE);
2673*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2674*7c478bd9Sstevel@tonic-gate 		if (error != 0)
2675*7c478bd9Sstevel@tonic-gate 			return (error);
2676*7c478bd9Sstevel@tonic-gate 	}
2677*7c478bd9Sstevel@tonic-gate 
2678*7c478bd9Sstevel@tonic-gate 	wqp = stp->sd_wrq;
2679*7c478bd9Sstevel@tonic-gate 
2680*7c478bd9Sstevel@tonic-gate 	/* get these values from them cached in the stream head */
2681*7c478bd9Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
2682*7c478bd9Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
2683*7c478bd9Sstevel@tonic-gate 
2684*7c478bd9Sstevel@tonic-gate 	/*
2685*7c478bd9Sstevel@tonic-gate 	 * Check the min/max packet size constraints.  If min packet size
2686*7c478bd9Sstevel@tonic-gate 	 * is non-zero, the write cannot be split into multiple messages
2687*7c478bd9Sstevel@tonic-gate 	 * and still guarantee the size constraints.
2688*7c478bd9Sstevel@tonic-gate 	 */
2689*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_IN, "strwrite in:q %p", wqp);
2690*7c478bd9Sstevel@tonic-gate 
2691*7c478bd9Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
2692*7c478bd9Sstevel@tonic-gate 	if (rmax == 0) {
2693*7c478bd9Sstevel@tonic-gate 		return (0);
2694*7c478bd9Sstevel@tonic-gate 	}
2695*7c478bd9Sstevel@tonic-gate 	if (rmin > 0) {
2696*7c478bd9Sstevel@tonic-gate 		if (uiop->uio_resid < rmin) {
2697*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
2698*7c478bd9Sstevel@tonic-gate 				"strwrite out:q %p out %d error %d",
2699*7c478bd9Sstevel@tonic-gate 				wqp, 0, ERANGE);
2700*7c478bd9Sstevel@tonic-gate 			return (ERANGE);
2701*7c478bd9Sstevel@tonic-gate 		}
2702*7c478bd9Sstevel@tonic-gate 		if ((rmax != INFPSZ) && (uiop->uio_resid > rmax)) {
2703*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
2704*7c478bd9Sstevel@tonic-gate 				"strwrite out:q %p out %d error %d",
2705*7c478bd9Sstevel@tonic-gate 				wqp, 1, ERANGE);
2706*7c478bd9Sstevel@tonic-gate 			return (ERANGE);
2707*7c478bd9Sstevel@tonic-gate 		}
2708*7c478bd9Sstevel@tonic-gate 	}
2709*7c478bd9Sstevel@tonic-gate 
2710*7c478bd9Sstevel@tonic-gate 	/*
2711*7c478bd9Sstevel@tonic-gate 	 * Do until count satisfied or error.
2712*7c478bd9Sstevel@tonic-gate 	 */
2713*7c478bd9Sstevel@tonic-gate 	waitflag = WRITEWAIT;
2714*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & OLDNDELAY)
2715*7c478bd9Sstevel@tonic-gate 		tempmode = uiop->uio_fmode & ~FNDELAY;
2716*7c478bd9Sstevel@tonic-gate 	else
2717*7c478bd9Sstevel@tonic-gate 		tempmode = uiop->uio_fmode;
2718*7c478bd9Sstevel@tonic-gate 
2719*7c478bd9Sstevel@tonic-gate 	if (rmax == INFPSZ)
2720*7c478bd9Sstevel@tonic-gate 		rmax = uiop->uio_resid;
2721*7c478bd9Sstevel@tonic-gate 
2722*7c478bd9Sstevel@tonic-gate 	/*
2723*7c478bd9Sstevel@tonic-gate 	 * Note that tempmode does not get used in strput/strmakedata
2724*7c478bd9Sstevel@tonic-gate 	 * but only in strwaitq. The other routines use uio_fmode
2725*7c478bd9Sstevel@tonic-gate 	 * unmodified.
2726*7c478bd9Sstevel@tonic-gate 	 */
2727*7c478bd9Sstevel@tonic-gate 
2728*7c478bd9Sstevel@tonic-gate 	/* LINTED: constant in conditional context */
2729*7c478bd9Sstevel@tonic-gate 	while (1) {	/* breaks when uio_resid reaches zero */
2730*7c478bd9Sstevel@tonic-gate 		/*
2731*7c478bd9Sstevel@tonic-gate 		 * Determine the size of the next message to be
2732*7c478bd9Sstevel@tonic-gate 		 * packaged.  May have to break write into several
2733*7c478bd9Sstevel@tonic-gate 		 * messages based on max packet size.
2734*7c478bd9Sstevel@tonic-gate 		 */
2735*7c478bd9Sstevel@tonic-gate 		iosize = MIN(uiop->uio_resid, rmax);
2736*7c478bd9Sstevel@tonic-gate 
2737*7c478bd9Sstevel@tonic-gate 		/*
2738*7c478bd9Sstevel@tonic-gate 		 * Put block downstream when flow control allows it.
2739*7c478bd9Sstevel@tonic-gate 		 */
2740*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & STRDELIM) && (uiop->uio_resid == iosize))
2741*7c478bd9Sstevel@tonic-gate 			b_flag = MSGDELIM;
2742*7c478bd9Sstevel@tonic-gate 		else
2743*7c478bd9Sstevel@tonic-gate 			b_flag = 0;
2744*7c478bd9Sstevel@tonic-gate 
2745*7c478bd9Sstevel@tonic-gate 		for (;;) {
2746*7c478bd9Sstevel@tonic-gate 			int done = 0;
2747*7c478bd9Sstevel@tonic-gate 
2748*7c478bd9Sstevel@tonic-gate 			error = strput(stp, NULL, uiop, &iosize, b_flag,
2749*7c478bd9Sstevel@tonic-gate 				0, 0);
2750*7c478bd9Sstevel@tonic-gate 			if (error == 0)
2751*7c478bd9Sstevel@tonic-gate 				break;
2752*7c478bd9Sstevel@tonic-gate 			if (error != EWOULDBLOCK)
2753*7c478bd9Sstevel@tonic-gate 				goto out;
2754*7c478bd9Sstevel@tonic-gate 
2755*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
2756*7c478bd9Sstevel@tonic-gate 			/*
2757*7c478bd9Sstevel@tonic-gate 			 * Check for a missed wakeup.
2758*7c478bd9Sstevel@tonic-gate 			 * Needed since strput did not hold sd_lock across
2759*7c478bd9Sstevel@tonic-gate 			 * the canputnext.
2760*7c478bd9Sstevel@tonic-gate 			 */
2761*7c478bd9Sstevel@tonic-gate 			if (canputnext(wqp)) {
2762*7c478bd9Sstevel@tonic-gate 				/* Try again */
2763*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
2764*7c478bd9Sstevel@tonic-gate 				continue;
2765*7c478bd9Sstevel@tonic-gate 			}
2766*7c478bd9Sstevel@tonic-gate 			TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_WAIT,
2767*7c478bd9Sstevel@tonic-gate 				"strwrite wait:q %p wait", wqp);
2768*7c478bd9Sstevel@tonic-gate 			if ((error = strwaitq(stp, waitflag, (ssize_t)0,
2769*7c478bd9Sstevel@tonic-gate 			    tempmode, -1, &done)) != 0 || done) {
2770*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
2771*7c478bd9Sstevel@tonic-gate 				if ((vp->v_type == VFIFO) &&
2772*7c478bd9Sstevel@tonic-gate 				    (uiop->uio_fmode & FNDELAY) &&
2773*7c478bd9Sstevel@tonic-gate 				    (error == EAGAIN))
2774*7c478bd9Sstevel@tonic-gate 					error = 0;
2775*7c478bd9Sstevel@tonic-gate 				goto out;
2776*7c478bd9Sstevel@tonic-gate 			}
2777*7c478bd9Sstevel@tonic-gate 			TRACE_1(TR_FAC_STREAMS_FR, TR_STRWRITE_WAKE,
2778*7c478bd9Sstevel@tonic-gate 				"strwrite wake:q %p awakes", wqp);
2779*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2780*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
2781*7c478bd9Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO)
2782*7c478bd9Sstevel@tonic-gate 				if (error = straccess(stp, JCWRITE))
2783*7c478bd9Sstevel@tonic-gate 					goto out;
2784*7c478bd9Sstevel@tonic-gate 		}
2785*7c478bd9Sstevel@tonic-gate 		waitflag |= NOINTR;
2786*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRWRITE_RESID,
2787*7c478bd9Sstevel@tonic-gate 			"strwrite resid:q %p uiop %p", wqp, uiop);
2788*7c478bd9Sstevel@tonic-gate 		if (uiop->uio_resid) {
2789*7c478bd9Sstevel@tonic-gate 			/* Recheck for errors - needed for sockets */
2790*7c478bd9Sstevel@tonic-gate 			if ((stp->sd_wput_opt & SW_RECHECK_ERR) &&
2791*7c478bd9Sstevel@tonic-gate 			    (stp->sd_flag & (STWRERR|STRHUP|STPLEX))) {
2792*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
2793*7c478bd9Sstevel@tonic-gate 				error = strwriteable(stp, B_FALSE, B_TRUE);
2794*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
2795*7c478bd9Sstevel@tonic-gate 				if (error != 0)
2796*7c478bd9Sstevel@tonic-gate 					return (error);
2797*7c478bd9Sstevel@tonic-gate 			}
2798*7c478bd9Sstevel@tonic-gate 			continue;
2799*7c478bd9Sstevel@tonic-gate 		}
2800*7c478bd9Sstevel@tonic-gate 		break;
2801*7c478bd9Sstevel@tonic-gate 	}
2802*7c478bd9Sstevel@tonic-gate out:
2803*7c478bd9Sstevel@tonic-gate 	/*
2804*7c478bd9Sstevel@tonic-gate 	 * For historical reasons, applications expect EAGAIN when a data
2805*7c478bd9Sstevel@tonic-gate 	 * mblk_t cannot be allocated, so change ENOMEM back to EAGAIN.
2806*7c478bd9Sstevel@tonic-gate 	 */
2807*7c478bd9Sstevel@tonic-gate 	if (error == ENOMEM)
2808*7c478bd9Sstevel@tonic-gate 		error = EAGAIN;
2809*7c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_STRWRITE_OUT,
2810*7c478bd9Sstevel@tonic-gate 		"strwrite out:q %p out %d error %d", wqp, 2, error);
2811*7c478bd9Sstevel@tonic-gate 	return (error);
2812*7c478bd9Sstevel@tonic-gate }
2813*7c478bd9Sstevel@tonic-gate 
2814*7c478bd9Sstevel@tonic-gate /*
2815*7c478bd9Sstevel@tonic-gate  * kstrwritemp() has very similar semantics as that of strwrite().
2816*7c478bd9Sstevel@tonic-gate  * The main difference is it obtains mblks from the caller and also
2817*7c478bd9Sstevel@tonic-gate  * does not do any copy as done in strwrite() from user buffers to
2818*7c478bd9Sstevel@tonic-gate  * kernel buffers.
2819*7c478bd9Sstevel@tonic-gate  *
2820*7c478bd9Sstevel@tonic-gate  *
2821*7c478bd9Sstevel@tonic-gate  * Currently, this routine is used by sendfile to send data allocated
2822*7c478bd9Sstevel@tonic-gate  * within the kernel without any copying. This interface does not use the
2823*7c478bd9Sstevel@tonic-gate  * synchronous stream interface as synch. stream interface implies
2824*7c478bd9Sstevel@tonic-gate  * copying.
2825*7c478bd9Sstevel@tonic-gate  */
2826*7c478bd9Sstevel@tonic-gate int
2827*7c478bd9Sstevel@tonic-gate kstrwritemp(struct vnode *vp, mblk_t *mp, ushort_t fmode)
2828*7c478bd9Sstevel@tonic-gate {
2829*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
2830*7c478bd9Sstevel@tonic-gate 	struct queue *wqp;
2831*7c478bd9Sstevel@tonic-gate 	char waitflag;
2832*7c478bd9Sstevel@tonic-gate 	int tempmode;
2833*7c478bd9Sstevel@tonic-gate 	int error;
2834*7c478bd9Sstevel@tonic-gate 	int done = 0;
2835*7c478bd9Sstevel@tonic-gate 
2836*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
2837*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
2838*7c478bd9Sstevel@tonic-gate 
2839*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
2840*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
2841*7c478bd9Sstevel@tonic-gate 		error = strwriteable(stp, B_FALSE, B_TRUE);
2842*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
2843*7c478bd9Sstevel@tonic-gate 		if (error != 0)
2844*7c478bd9Sstevel@tonic-gate 			return (error);
2845*7c478bd9Sstevel@tonic-gate 	}
2846*7c478bd9Sstevel@tonic-gate 
2847*7c478bd9Sstevel@tonic-gate 	/*
2848*7c478bd9Sstevel@tonic-gate 	 * First, check for flow control without grabbing the sd_lock.
2849*7c478bd9Sstevel@tonic-gate 	 * If we would block, re-check with the lock. This is similar
2850*7c478bd9Sstevel@tonic-gate 	 * to the logic used by strwrite().
2851*7c478bd9Sstevel@tonic-gate 	 */
2852*7c478bd9Sstevel@tonic-gate 	wqp = stp->sd_wrq;
2853*7c478bd9Sstevel@tonic-gate 	if (canputnext(wqp)) {
2854*7c478bd9Sstevel@tonic-gate 		putnext(wqp, mp);
2855*7c478bd9Sstevel@tonic-gate 		return (0);
2856*7c478bd9Sstevel@tonic-gate 	}
2857*7c478bd9Sstevel@tonic-gate 
2858*7c478bd9Sstevel@tonic-gate 	waitflag = WRITEWAIT;
2859*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & OLDNDELAY)
2860*7c478bd9Sstevel@tonic-gate 		tempmode = fmode & ~FNDELAY;
2861*7c478bd9Sstevel@tonic-gate 	else
2862*7c478bd9Sstevel@tonic-gate 		tempmode = fmode;
2863*7c478bd9Sstevel@tonic-gate 
2864*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
2865*7c478bd9Sstevel@tonic-gate 	do {
2866*7c478bd9Sstevel@tonic-gate 		if (canputnext(wqp)) {
2867*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2868*7c478bd9Sstevel@tonic-gate 			putnext(wqp, mp);
2869*7c478bd9Sstevel@tonic-gate 			return (0);
2870*7c478bd9Sstevel@tonic-gate 		}
2871*7c478bd9Sstevel@tonic-gate 		error = strwaitq(stp, waitflag, (ssize_t)0, tempmode, -1,
2872*7c478bd9Sstevel@tonic-gate 		    &done);
2873*7c478bd9Sstevel@tonic-gate 	} while (error == 0 && !done);
2874*7c478bd9Sstevel@tonic-gate 
2875*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
2876*7c478bd9Sstevel@tonic-gate 	/*
2877*7c478bd9Sstevel@tonic-gate 	 * EAGAIN tells the application to try again. ENOMEM
2878*7c478bd9Sstevel@tonic-gate 	 * is returned only if the memory allocation size
2879*7c478bd9Sstevel@tonic-gate 	 * exceeds the physical limits of the system. ENOMEM
2880*7c478bd9Sstevel@tonic-gate 	 * can't be true here.
2881*7c478bd9Sstevel@tonic-gate 	 */
2882*7c478bd9Sstevel@tonic-gate 	if (error == ENOMEM)
2883*7c478bd9Sstevel@tonic-gate 		error = EAGAIN;
2884*7c478bd9Sstevel@tonic-gate 	return (error);
2885*7c478bd9Sstevel@tonic-gate }
2886*7c478bd9Sstevel@tonic-gate 
2887*7c478bd9Sstevel@tonic-gate /*
2888*7c478bd9Sstevel@tonic-gate  * Stream head write service routine.
2889*7c478bd9Sstevel@tonic-gate  * Its job is to wake up any sleeping writers when a queue
2890*7c478bd9Sstevel@tonic-gate  * downstream needs data (part of the flow control in putq and getq).
2891*7c478bd9Sstevel@tonic-gate  * It also must wake anyone sleeping on a poll().
2892*7c478bd9Sstevel@tonic-gate  * For stream head right below mux module, it must also invoke put procedure
2893*7c478bd9Sstevel@tonic-gate  * of next downstream module.
2894*7c478bd9Sstevel@tonic-gate  */
2895*7c478bd9Sstevel@tonic-gate int
2896*7c478bd9Sstevel@tonic-gate strwsrv(queue_t *q)
2897*7c478bd9Sstevel@tonic-gate {
2898*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
2899*7c478bd9Sstevel@tonic-gate 	queue_t *tq;
2900*7c478bd9Sstevel@tonic-gate 	qband_t *qbp;
2901*7c478bd9Sstevel@tonic-gate 	int i;
2902*7c478bd9Sstevel@tonic-gate 	qband_t *myqbp;
2903*7c478bd9Sstevel@tonic-gate 	int isevent;
2904*7c478bd9Sstevel@tonic-gate 	unsigned char	qbf[NBAND];	/* band flushing backenable flags */
2905*7c478bd9Sstevel@tonic-gate 
2906*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
2907*7c478bd9Sstevel@tonic-gate 		TR_STRWSRV, "strwsrv:q %p", q);
2908*7c478bd9Sstevel@tonic-gate 	stp = (struct stdata *)q->q_ptr;
2909*7c478bd9Sstevel@tonic-gate 	ASSERT(qclaimed(q));
2910*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
2911*7c478bd9Sstevel@tonic-gate 	ASSERT(!(stp->sd_flag & STPLEX));
2912*7c478bd9Sstevel@tonic-gate 
2913*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & WSLEEP) {
2914*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~WSLEEP;
2915*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&q->q_wait);
2916*7c478bd9Sstevel@tonic-gate 	}
2917*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
2918*7c478bd9Sstevel@tonic-gate 
2919*7c478bd9Sstevel@tonic-gate 	/* The other end of a stream pipe went away. */
2920*7c478bd9Sstevel@tonic-gate 	if ((tq = q->q_next) == NULL) {
2921*7c478bd9Sstevel@tonic-gate 		return (0);
2922*7c478bd9Sstevel@tonic-gate 	}
2923*7c478bd9Sstevel@tonic-gate 
2924*7c478bd9Sstevel@tonic-gate 	/* Find the next module forward that has a service procedure */
2925*7c478bd9Sstevel@tonic-gate 	claimstr(q);
2926*7c478bd9Sstevel@tonic-gate 	tq = q->q_nfsrv;
2927*7c478bd9Sstevel@tonic-gate 	ASSERT(tq != NULL);
2928*7c478bd9Sstevel@tonic-gate 
2929*7c478bd9Sstevel@tonic-gate 	if ((q->q_flag & QBACK)) {
2930*7c478bd9Sstevel@tonic-gate 		if ((tq->q_flag & QFULL)) {
2931*7c478bd9Sstevel@tonic-gate 			mutex_enter(QLOCK(tq));
2932*7c478bd9Sstevel@tonic-gate 			if (!(tq->q_flag & QFULL)) {
2933*7c478bd9Sstevel@tonic-gate 				mutex_exit(QLOCK(tq));
2934*7c478bd9Sstevel@tonic-gate 				goto wakeup;
2935*7c478bd9Sstevel@tonic-gate 			}
2936*7c478bd9Sstevel@tonic-gate 			/*
2937*7c478bd9Sstevel@tonic-gate 			 * The queue must have become full again. Set QWANTW
2938*7c478bd9Sstevel@tonic-gate 			 * again so strwsrv will be back enabled when
2939*7c478bd9Sstevel@tonic-gate 			 * the queue becomes non-full next time.
2940*7c478bd9Sstevel@tonic-gate 			 */
2941*7c478bd9Sstevel@tonic-gate 			tq->q_flag |= QWANTW;
2942*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(tq));
2943*7c478bd9Sstevel@tonic-gate 		} else {
2944*7c478bd9Sstevel@tonic-gate 		wakeup:
2945*7c478bd9Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, POLLWRNORM);
2946*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
2947*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sigflags & S_WRNORM)
2948*7c478bd9Sstevel@tonic-gate 				strsendsig(stp->sd_siglist, S_WRNORM, 0, 0);
2949*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2950*7c478bd9Sstevel@tonic-gate 		}
2951*7c478bd9Sstevel@tonic-gate 	}
2952*7c478bd9Sstevel@tonic-gate 
2953*7c478bd9Sstevel@tonic-gate 	isevent = 0;
2954*7c478bd9Sstevel@tonic-gate 	i = 1;
2955*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)qbf, NBAND);
2956*7c478bd9Sstevel@tonic-gate 	mutex_enter(QLOCK(tq));
2957*7c478bd9Sstevel@tonic-gate 	if ((myqbp = q->q_bandp) != NULL)
2958*7c478bd9Sstevel@tonic-gate 		for (qbp = tq->q_bandp; qbp && myqbp; qbp = qbp->qb_next) {
2959*7c478bd9Sstevel@tonic-gate 			ASSERT(myqbp);
2960*7c478bd9Sstevel@tonic-gate 			if ((myqbp->qb_flag & QB_BACK)) {
2961*7c478bd9Sstevel@tonic-gate 				if (qbp->qb_flag & QB_FULL) {
2962*7c478bd9Sstevel@tonic-gate 					/*
2963*7c478bd9Sstevel@tonic-gate 					 * The band must have become full again.
2964*7c478bd9Sstevel@tonic-gate 					 * Set QB_WANTW again so strwsrv will
2965*7c478bd9Sstevel@tonic-gate 					 * be back enabled when the band becomes
2966*7c478bd9Sstevel@tonic-gate 					 * non-full next time.
2967*7c478bd9Sstevel@tonic-gate 					 */
2968*7c478bd9Sstevel@tonic-gate 					qbp->qb_flag |= QB_WANTW;
2969*7c478bd9Sstevel@tonic-gate 				} else {
2970*7c478bd9Sstevel@tonic-gate 					isevent = 1;
2971*7c478bd9Sstevel@tonic-gate 					qbf[i] = 1;
2972*7c478bd9Sstevel@tonic-gate 				}
2973*7c478bd9Sstevel@tonic-gate 			}
2974*7c478bd9Sstevel@tonic-gate 			myqbp = myqbp->qb_next;
2975*7c478bd9Sstevel@tonic-gate 			i++;
2976*7c478bd9Sstevel@tonic-gate 		}
2977*7c478bd9Sstevel@tonic-gate 	mutex_exit(QLOCK(tq));
2978*7c478bd9Sstevel@tonic-gate 
2979*7c478bd9Sstevel@tonic-gate 	if (isevent) {
2980*7c478bd9Sstevel@tonic-gate 	    for (i = tq->q_nband; i; i--) {
2981*7c478bd9Sstevel@tonic-gate 		if (qbf[i]) {
2982*7c478bd9Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, POLLWRBAND);
2983*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
2984*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sigflags & S_WRBAND)
2985*7c478bd9Sstevel@tonic-gate 				strsendsig(stp->sd_siglist, S_WRBAND,
2986*7c478bd9Sstevel@tonic-gate 					(uchar_t)i, 0);
2987*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
2988*7c478bd9Sstevel@tonic-gate 		}
2989*7c478bd9Sstevel@tonic-gate 	    }
2990*7c478bd9Sstevel@tonic-gate 	}
2991*7c478bd9Sstevel@tonic-gate 
2992*7c478bd9Sstevel@tonic-gate 	releasestr(q);
2993*7c478bd9Sstevel@tonic-gate 	return (0);
2994*7c478bd9Sstevel@tonic-gate }
2995*7c478bd9Sstevel@tonic-gate 
2996*7c478bd9Sstevel@tonic-gate /*
2997*7c478bd9Sstevel@tonic-gate  * Special case of strcopyin/strcopyout for copying
2998*7c478bd9Sstevel@tonic-gate  * struct strioctl that can deal with both data
2999*7c478bd9Sstevel@tonic-gate  * models.
3000*7c478bd9Sstevel@tonic-gate  */
3001*7c478bd9Sstevel@tonic-gate 
3002*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
3003*7c478bd9Sstevel@tonic-gate 
3004*7c478bd9Sstevel@tonic-gate static int
3005*7c478bd9Sstevel@tonic-gate strcopyin_strioctl(void *from, void *to, int flag, int copyflag)
3006*7c478bd9Sstevel@tonic-gate {
3007*7c478bd9Sstevel@tonic-gate 	struct	strioctl32 strioc32;
3008*7c478bd9Sstevel@tonic-gate 	struct	strioctl *striocp;
3009*7c478bd9Sstevel@tonic-gate 
3010*7c478bd9Sstevel@tonic-gate 	if (copyflag & U_TO_K) {
3011*7c478bd9Sstevel@tonic-gate 		ASSERT((copyflag & K_TO_K) == 0);
3012*7c478bd9Sstevel@tonic-gate 
3013*7c478bd9Sstevel@tonic-gate 		if ((flag & FMODELS) == DATAMODEL_ILP32) {
3014*7c478bd9Sstevel@tonic-gate 			if (copyin(from, &strioc32, sizeof (strioc32)))
3015*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
3016*7c478bd9Sstevel@tonic-gate 
3017*7c478bd9Sstevel@tonic-gate 			striocp = (struct strioctl *)to;
3018*7c478bd9Sstevel@tonic-gate 			striocp->ic_cmd	= strioc32.ic_cmd;
3019*7c478bd9Sstevel@tonic-gate 			striocp->ic_timout = strioc32.ic_timout;
3020*7c478bd9Sstevel@tonic-gate 			striocp->ic_len	= strioc32.ic_len;
3021*7c478bd9Sstevel@tonic-gate 			striocp->ic_dp	= (char *)(uintptr_t)strioc32.ic_dp;
3022*7c478bd9Sstevel@tonic-gate 
3023*7c478bd9Sstevel@tonic-gate 		} else { /* NATIVE data model */
3024*7c478bd9Sstevel@tonic-gate 			if (copyin(from, to, sizeof (struct strioctl))) {
3025*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
3026*7c478bd9Sstevel@tonic-gate 			} else {
3027*7c478bd9Sstevel@tonic-gate 				return (0);
3028*7c478bd9Sstevel@tonic-gate 			}
3029*7c478bd9Sstevel@tonic-gate 		}
3030*7c478bd9Sstevel@tonic-gate 	} else {
3031*7c478bd9Sstevel@tonic-gate 		ASSERT(copyflag & K_TO_K);
3032*7c478bd9Sstevel@tonic-gate 		bcopy(from, to, sizeof (struct strioctl));
3033*7c478bd9Sstevel@tonic-gate 	}
3034*7c478bd9Sstevel@tonic-gate 	return (0);
3035*7c478bd9Sstevel@tonic-gate }
3036*7c478bd9Sstevel@tonic-gate 
3037*7c478bd9Sstevel@tonic-gate static int
3038*7c478bd9Sstevel@tonic-gate strcopyout_strioctl(void *from, void *to, int flag, int copyflag)
3039*7c478bd9Sstevel@tonic-gate {
3040*7c478bd9Sstevel@tonic-gate 	struct	strioctl32 strioc32;
3041*7c478bd9Sstevel@tonic-gate 	struct	strioctl *striocp;
3042*7c478bd9Sstevel@tonic-gate 
3043*7c478bd9Sstevel@tonic-gate 	if (copyflag & U_TO_K) {
3044*7c478bd9Sstevel@tonic-gate 		ASSERT((copyflag & K_TO_K) == 0);
3045*7c478bd9Sstevel@tonic-gate 
3046*7c478bd9Sstevel@tonic-gate 		if ((flag & FMODELS) == DATAMODEL_ILP32) {
3047*7c478bd9Sstevel@tonic-gate 			striocp = (struct strioctl *)from;
3048*7c478bd9Sstevel@tonic-gate 			strioc32.ic_cmd	= striocp->ic_cmd;
3049*7c478bd9Sstevel@tonic-gate 			strioc32.ic_timout = striocp->ic_timout;
3050*7c478bd9Sstevel@tonic-gate 			strioc32.ic_len	= striocp->ic_len;
3051*7c478bd9Sstevel@tonic-gate 			strioc32.ic_dp	= (caddr32_t)(uintptr_t)striocp->ic_dp;
3052*7c478bd9Sstevel@tonic-gate 			ASSERT((char *)(uintptr_t)strioc32.ic_dp ==
3053*7c478bd9Sstevel@tonic-gate 			    striocp->ic_dp);
3054*7c478bd9Sstevel@tonic-gate 
3055*7c478bd9Sstevel@tonic-gate 			if (copyout(&strioc32, to, sizeof (strioc32)))
3056*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
3057*7c478bd9Sstevel@tonic-gate 
3058*7c478bd9Sstevel@tonic-gate 		} else { /* NATIVE data model */
3059*7c478bd9Sstevel@tonic-gate 			if (copyout(from, to, sizeof (struct strioctl))) {
3060*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
3061*7c478bd9Sstevel@tonic-gate 			} else {
3062*7c478bd9Sstevel@tonic-gate 				return (0);
3063*7c478bd9Sstevel@tonic-gate 			}
3064*7c478bd9Sstevel@tonic-gate 		}
3065*7c478bd9Sstevel@tonic-gate 	} else {
3066*7c478bd9Sstevel@tonic-gate 		ASSERT(copyflag & K_TO_K);
3067*7c478bd9Sstevel@tonic-gate 		bcopy(from, to, sizeof (struct strioctl));
3068*7c478bd9Sstevel@tonic-gate 	}
3069*7c478bd9Sstevel@tonic-gate 	return (0);
3070*7c478bd9Sstevel@tonic-gate }
3071*7c478bd9Sstevel@tonic-gate 
3072*7c478bd9Sstevel@tonic-gate #else	/* ! _LP64 */
3073*7c478bd9Sstevel@tonic-gate 
3074*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
3075*7c478bd9Sstevel@tonic-gate static int
3076*7c478bd9Sstevel@tonic-gate strcopyin_strioctl(void *from, void *to, int flag, int copyflag)
3077*7c478bd9Sstevel@tonic-gate {
3078*7c478bd9Sstevel@tonic-gate 	return (strcopyin(from, to, sizeof (struct strioctl), copyflag));
3079*7c478bd9Sstevel@tonic-gate }
3080*7c478bd9Sstevel@tonic-gate 
3081*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
3082*7c478bd9Sstevel@tonic-gate static int
3083*7c478bd9Sstevel@tonic-gate strcopyout_strioctl(void *from, void *to, int flag, int copyflag)
3084*7c478bd9Sstevel@tonic-gate {
3085*7c478bd9Sstevel@tonic-gate 	return (strcopyout(from, to, sizeof (struct strioctl), copyflag));
3086*7c478bd9Sstevel@tonic-gate }
3087*7c478bd9Sstevel@tonic-gate 
3088*7c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
3089*7c478bd9Sstevel@tonic-gate 
3090*7c478bd9Sstevel@tonic-gate /*
3091*7c478bd9Sstevel@tonic-gate  * Determine type of job control semantics expected by user.  The
3092*7c478bd9Sstevel@tonic-gate  * possibilities are:
3093*7c478bd9Sstevel@tonic-gate  *	JCREAD	- Behaves like read() on fd; send SIGTTIN
3094*7c478bd9Sstevel@tonic-gate  *	JCWRITE	- Behaves like write() on fd; send SIGTTOU if TOSTOP set
3095*7c478bd9Sstevel@tonic-gate  *	JCSETP	- Sets a value in the stream; send SIGTTOU, ignore TOSTOP
3096*7c478bd9Sstevel@tonic-gate  *	JCGETP	- Gets a value in the stream; no signals.
3097*7c478bd9Sstevel@tonic-gate  * See straccess in strsubr.c for usage of these values.
3098*7c478bd9Sstevel@tonic-gate  *
3099*7c478bd9Sstevel@tonic-gate  * This routine also returns -1 for I_STR as a special case; the
3100*7c478bd9Sstevel@tonic-gate  * caller must call again with the real ioctl number for
3101*7c478bd9Sstevel@tonic-gate  * classification.
3102*7c478bd9Sstevel@tonic-gate  */
3103*7c478bd9Sstevel@tonic-gate static int
3104*7c478bd9Sstevel@tonic-gate job_control_type(int cmd)
3105*7c478bd9Sstevel@tonic-gate {
3106*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3107*7c478bd9Sstevel@tonic-gate 	case I_STR:
3108*7c478bd9Sstevel@tonic-gate 		return (-1);
3109*7c478bd9Sstevel@tonic-gate 
3110*7c478bd9Sstevel@tonic-gate 	case I_RECVFD:
3111*7c478bd9Sstevel@tonic-gate 	case I_E_RECVFD:
3112*7c478bd9Sstevel@tonic-gate 		return (JCREAD);
3113*7c478bd9Sstevel@tonic-gate 
3114*7c478bd9Sstevel@tonic-gate 	case I_FDINSERT:
3115*7c478bd9Sstevel@tonic-gate 	case I_SENDFD:
3116*7c478bd9Sstevel@tonic-gate 		return (JCWRITE);
3117*7c478bd9Sstevel@tonic-gate 
3118*7c478bd9Sstevel@tonic-gate 	case TCSETA:
3119*7c478bd9Sstevel@tonic-gate 	case TCSETAW:
3120*7c478bd9Sstevel@tonic-gate 	case TCSETAF:
3121*7c478bd9Sstevel@tonic-gate 	case TCSBRK:
3122*7c478bd9Sstevel@tonic-gate 	case TCXONC:
3123*7c478bd9Sstevel@tonic-gate 	case TCFLSH:
3124*7c478bd9Sstevel@tonic-gate 	case TCDSET:	/* Obsolete */
3125*7c478bd9Sstevel@tonic-gate 	case TIOCSWINSZ:
3126*7c478bd9Sstevel@tonic-gate 	case TCSETS:
3127*7c478bd9Sstevel@tonic-gate 	case TCSETSW:
3128*7c478bd9Sstevel@tonic-gate 	case TCSETSF:
3129*7c478bd9Sstevel@tonic-gate 	case TIOCSETD:
3130*7c478bd9Sstevel@tonic-gate 	case TIOCHPCL:
3131*7c478bd9Sstevel@tonic-gate 	case TIOCSETP:
3132*7c478bd9Sstevel@tonic-gate 	case TIOCSETN:
3133*7c478bd9Sstevel@tonic-gate 	case TIOCEXCL:
3134*7c478bd9Sstevel@tonic-gate 	case TIOCNXCL:
3135*7c478bd9Sstevel@tonic-gate 	case TIOCFLUSH:
3136*7c478bd9Sstevel@tonic-gate 	case TIOCSETC:
3137*7c478bd9Sstevel@tonic-gate 	case TIOCLBIS:
3138*7c478bd9Sstevel@tonic-gate 	case TIOCLBIC:
3139*7c478bd9Sstevel@tonic-gate 	case TIOCLSET:
3140*7c478bd9Sstevel@tonic-gate 	case TIOCSBRK:
3141*7c478bd9Sstevel@tonic-gate 	case TIOCCBRK:
3142*7c478bd9Sstevel@tonic-gate 	case TIOCSDTR:
3143*7c478bd9Sstevel@tonic-gate 	case TIOCCDTR:
3144*7c478bd9Sstevel@tonic-gate 	case TIOCSLTC:
3145*7c478bd9Sstevel@tonic-gate 	case TIOCSTOP:
3146*7c478bd9Sstevel@tonic-gate 	case TIOCSTART:
3147*7c478bd9Sstevel@tonic-gate 	case TIOCSTI:
3148*7c478bd9Sstevel@tonic-gate 	case TIOCSPGRP:
3149*7c478bd9Sstevel@tonic-gate 	case TIOCMSET:
3150*7c478bd9Sstevel@tonic-gate 	case TIOCMBIS:
3151*7c478bd9Sstevel@tonic-gate 	case TIOCMBIC:
3152*7c478bd9Sstevel@tonic-gate 	case TIOCREMOTE:
3153*7c478bd9Sstevel@tonic-gate 	case TIOCSIGNAL:
3154*7c478bd9Sstevel@tonic-gate 	case LDSETT:
3155*7c478bd9Sstevel@tonic-gate 	case LDSMAP:	/* Obsolete */
3156*7c478bd9Sstevel@tonic-gate 	case DIOCSETP:
3157*7c478bd9Sstevel@tonic-gate 	case I_FLUSH:
3158*7c478bd9Sstevel@tonic-gate 	case I_SRDOPT:
3159*7c478bd9Sstevel@tonic-gate 	case I_SETSIG:
3160*7c478bd9Sstevel@tonic-gate 	case I_SWROPT:
3161*7c478bd9Sstevel@tonic-gate 	case I_FLUSHBAND:
3162*7c478bd9Sstevel@tonic-gate 	case I_SETCLTIME:
3163*7c478bd9Sstevel@tonic-gate 	case I_SERROPT:
3164*7c478bd9Sstevel@tonic-gate 	case I_ESETSIG:
3165*7c478bd9Sstevel@tonic-gate 	case FIONBIO:
3166*7c478bd9Sstevel@tonic-gate 	case FIOASYNC:
3167*7c478bd9Sstevel@tonic-gate 	case FIOSETOWN:
3168*7c478bd9Sstevel@tonic-gate 	case JBOOT:	/* Obsolete */
3169*7c478bd9Sstevel@tonic-gate 	case JTERM:	/* Obsolete */
3170*7c478bd9Sstevel@tonic-gate 	case JTIMOM:	/* Obsolete */
3171*7c478bd9Sstevel@tonic-gate 	case JZOMBOOT:	/* Obsolete */
3172*7c478bd9Sstevel@tonic-gate 	case JAGENT:	/* Obsolete */
3173*7c478bd9Sstevel@tonic-gate 	case JTRUN:	/* Obsolete */
3174*7c478bd9Sstevel@tonic-gate 	case JXTPROTO:	/* Obsolete */
3175*7c478bd9Sstevel@tonic-gate 		return (JCSETP);
3176*7c478bd9Sstevel@tonic-gate 	}
3177*7c478bd9Sstevel@tonic-gate 
3178*7c478bd9Sstevel@tonic-gate 	return (JCGETP);
3179*7c478bd9Sstevel@tonic-gate }
3180*7c478bd9Sstevel@tonic-gate 
3181*7c478bd9Sstevel@tonic-gate /*
3182*7c478bd9Sstevel@tonic-gate  * ioctl for streams
3183*7c478bd9Sstevel@tonic-gate  */
3184*7c478bd9Sstevel@tonic-gate int
3185*7c478bd9Sstevel@tonic-gate strioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, int copyflag,
3186*7c478bd9Sstevel@tonic-gate     cred_t *crp, int *rvalp)
3187*7c478bd9Sstevel@tonic-gate {
3188*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
3189*7c478bd9Sstevel@tonic-gate 	struct strioctl strioc;
3190*7c478bd9Sstevel@tonic-gate 	struct uio uio;
3191*7c478bd9Sstevel@tonic-gate 	struct iovec iov;
3192*7c478bd9Sstevel@tonic-gate 	int access;
3193*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
3194*7c478bd9Sstevel@tonic-gate 	int error = 0;
3195*7c478bd9Sstevel@tonic-gate 	int done = 0;
3196*7c478bd9Sstevel@tonic-gate 	ssize_t	rmin, rmax;
3197*7c478bd9Sstevel@tonic-gate 	queue_t *wrq;
3198*7c478bd9Sstevel@tonic-gate 	queue_t *rdq;
3199*7c478bd9Sstevel@tonic-gate 	boolean_t kioctl = B_FALSE;
3200*7c478bd9Sstevel@tonic-gate 
3201*7c478bd9Sstevel@tonic-gate 	if (flag & FKIOCTL) {
3202*7c478bd9Sstevel@tonic-gate 		copyflag = K_TO_K;
3203*7c478bd9Sstevel@tonic-gate 		kioctl = B_TRUE;
3204*7c478bd9Sstevel@tonic-gate 	}
3205*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
3206*7c478bd9Sstevel@tonic-gate 	ASSERT(copyflag == U_TO_K || copyflag == K_TO_K);
3207*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
3208*7c478bd9Sstevel@tonic-gate 
3209*7c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_IOCTL_ENTER,
3210*7c478bd9Sstevel@tonic-gate 		"strioctl:stp %p cmd %X arg %lX", stp, cmd, arg);
3211*7c478bd9Sstevel@tonic-gate 
3212*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
3213*7c478bd9Sstevel@tonic-gate 	if (audit_active)
3214*7c478bd9Sstevel@tonic-gate 		audit_strioctl(vp, cmd, arg, flag, copyflag, crp, rvalp);
3215*7c478bd9Sstevel@tonic-gate #endif
3216*7c478bd9Sstevel@tonic-gate 
3217*7c478bd9Sstevel@tonic-gate 	/*
3218*7c478bd9Sstevel@tonic-gate 	 * If the copy is kernel to kernel, make sure that the FNATIVE
3219*7c478bd9Sstevel@tonic-gate 	 * flag is set.  After this it would be a serious error to have
3220*7c478bd9Sstevel@tonic-gate 	 * no model flag.
3221*7c478bd9Sstevel@tonic-gate 	 */
3222*7c478bd9Sstevel@tonic-gate 	if (copyflag == K_TO_K)
3223*7c478bd9Sstevel@tonic-gate 		flag = (flag & ~FMODELS) | FNATIVE;
3224*7c478bd9Sstevel@tonic-gate 
3225*7c478bd9Sstevel@tonic-gate 	ASSERT((flag & FMODELS) != 0);
3226*7c478bd9Sstevel@tonic-gate 
3227*7c478bd9Sstevel@tonic-gate 	wrq = stp->sd_wrq;
3228*7c478bd9Sstevel@tonic-gate 	rdq = _RD(wrq);
3229*7c478bd9Sstevel@tonic-gate 
3230*7c478bd9Sstevel@tonic-gate 	access = job_control_type(cmd);
3231*7c478bd9Sstevel@tonic-gate 
3232*7c478bd9Sstevel@tonic-gate 	/* We should never see these here, should be handled by iwscn */
3233*7c478bd9Sstevel@tonic-gate 	if (cmd == SRIOCSREDIR || cmd == SRIOCISREDIR)
3234*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
3235*7c478bd9Sstevel@tonic-gate 
3236*7c478bd9Sstevel@tonic-gate 	if (access != -1 && stp->sd_sidp != NULL &&
3237*7c478bd9Sstevel@tonic-gate 	    stp->sd_vnode->v_type != VFIFO)
3238*7c478bd9Sstevel@tonic-gate 		if (error = straccess(stp, access))
3239*7c478bd9Sstevel@tonic-gate 			return (error);
3240*7c478bd9Sstevel@tonic-gate 
3241*7c478bd9Sstevel@tonic-gate 	/*
3242*7c478bd9Sstevel@tonic-gate 	 * Check for sgttyb-related ioctls first, and complain as
3243*7c478bd9Sstevel@tonic-gate 	 * necessary.
3244*7c478bd9Sstevel@tonic-gate 	 */
3245*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3246*7c478bd9Sstevel@tonic-gate 	case TIOCGETP:
3247*7c478bd9Sstevel@tonic-gate 	case TIOCSETP:
3248*7c478bd9Sstevel@tonic-gate 	case TIOCSETN:
3249*7c478bd9Sstevel@tonic-gate 		if (sgttyb_handling >= 2 && !sgttyb_complaint) {
3250*7c478bd9Sstevel@tonic-gate 			sgttyb_complaint = B_TRUE;
3251*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
3252*7c478bd9Sstevel@tonic-gate 			    "application used obsolete TIOC[GS]ET");
3253*7c478bd9Sstevel@tonic-gate 		}
3254*7c478bd9Sstevel@tonic-gate 		if (sgttyb_handling >= 3) {
3255*7c478bd9Sstevel@tonic-gate 			tsignal(curthread, SIGSYS);
3256*7c478bd9Sstevel@tonic-gate 			return (EIO);
3257*7c478bd9Sstevel@tonic-gate 		}
3258*7c478bd9Sstevel@tonic-gate 		break;
3259*7c478bd9Sstevel@tonic-gate 	}
3260*7c478bd9Sstevel@tonic-gate 
3261*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
3262*7c478bd9Sstevel@tonic-gate 
3263*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3264*7c478bd9Sstevel@tonic-gate 	case I_RECVFD:
3265*7c478bd9Sstevel@tonic-gate 	case I_E_RECVFD:
3266*7c478bd9Sstevel@tonic-gate 	case I_PEEK:
3267*7c478bd9Sstevel@tonic-gate 	case I_NREAD:
3268*7c478bd9Sstevel@tonic-gate 	case FIONREAD:
3269*7c478bd9Sstevel@tonic-gate 	case FIORDCHK:
3270*7c478bd9Sstevel@tonic-gate 	case I_ATMARK:
3271*7c478bd9Sstevel@tonic-gate 	case FIONBIO:
3272*7c478bd9Sstevel@tonic-gate 	case FIOASYNC:
3273*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STPLEX)) {
3274*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX, 0);
3275*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
3276*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
3277*7c478bd9Sstevel@tonic-gate 				return (error);
3278*7c478bd9Sstevel@tonic-gate 			}
3279*7c478bd9Sstevel@tonic-gate 		}
3280*7c478bd9Sstevel@tonic-gate 		break;
3281*7c478bd9Sstevel@tonic-gate 
3282*7c478bd9Sstevel@tonic-gate 	default:
3283*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STRDERR|STWRERR|STPLEX)) {
3284*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STWRERR|STPLEX, 0);
3285*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
3286*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
3287*7c478bd9Sstevel@tonic-gate 				return (error);
3288*7c478bd9Sstevel@tonic-gate 			}
3289*7c478bd9Sstevel@tonic-gate 		}
3290*7c478bd9Sstevel@tonic-gate 	}
3291*7c478bd9Sstevel@tonic-gate 
3292*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
3293*7c478bd9Sstevel@tonic-gate 
3294*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3295*7c478bd9Sstevel@tonic-gate 	default:
3296*7c478bd9Sstevel@tonic-gate 		/*
3297*7c478bd9Sstevel@tonic-gate 		 * The stream head has hardcoded knowledge of a
3298*7c478bd9Sstevel@tonic-gate 		 * miscellaneous collection of terminal-, keyboard- and
3299*7c478bd9Sstevel@tonic-gate 		 * mouse-related ioctls, enumerated below.  This hardcoded
3300*7c478bd9Sstevel@tonic-gate 		 * knowledge allows the stream head to automatically
3301*7c478bd9Sstevel@tonic-gate 		 * convert transparent ioctl requests made by userland
3302*7c478bd9Sstevel@tonic-gate 		 * programs into I_STR ioctls which many old STREAMS
3303*7c478bd9Sstevel@tonic-gate 		 * modules and drivers require.
3304*7c478bd9Sstevel@tonic-gate 		 *
3305*7c478bd9Sstevel@tonic-gate 		 * No new ioctls should ever be added to this list.
3306*7c478bd9Sstevel@tonic-gate 		 * Instead, the STREAMS module or driver should be written
3307*7c478bd9Sstevel@tonic-gate 		 * to either handle transparent ioctls or require any
3308*7c478bd9Sstevel@tonic-gate 		 * userland programs to use I_STR ioctls (by returning
3309*7c478bd9Sstevel@tonic-gate 		 * EINVAL to any transparent ioctl requests).
3310*7c478bd9Sstevel@tonic-gate 		 *
3311*7c478bd9Sstevel@tonic-gate 		 * More importantly, removing ioctls from this list should
3312*7c478bd9Sstevel@tonic-gate 		 * be done with the utmost care, since our STREAMS modules
3313*7c478bd9Sstevel@tonic-gate 		 * and drivers *count* on the stream head performing this
3314*7c478bd9Sstevel@tonic-gate 		 * conversion, and thus may panic while processing
3315*7c478bd9Sstevel@tonic-gate 		 * transparent ioctl request for one of these ioctls (keep
3316*7c478bd9Sstevel@tonic-gate 		 * in mind that third party modules and drivers may have
3317*7c478bd9Sstevel@tonic-gate 		 * similar problems).
3318*7c478bd9Sstevel@tonic-gate 		 */
3319*7c478bd9Sstevel@tonic-gate 		if (((cmd & IOCTYPE) == LDIOC) ||
3320*7c478bd9Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == tIOC) ||
3321*7c478bd9Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == TIOC) ||
3322*7c478bd9Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == KIOC) ||
3323*7c478bd9Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == MSIOC) ||
3324*7c478bd9Sstevel@tonic-gate 		    ((cmd & IOCTYPE) == VUIOC)) {
3325*7c478bd9Sstevel@tonic-gate 			/*
3326*7c478bd9Sstevel@tonic-gate 			 * The ioctl is a tty ioctl - set up strioc buffer
3327*7c478bd9Sstevel@tonic-gate 			 * and call strdoioctl() to do the work.
3328*7c478bd9Sstevel@tonic-gate 			 */
3329*7c478bd9Sstevel@tonic-gate 			if (stp->sd_flag & STRHUP)
3330*7c478bd9Sstevel@tonic-gate 				return (ENXIO);
3331*7c478bd9Sstevel@tonic-gate 			strioc.ic_cmd = cmd;
3332*7c478bd9Sstevel@tonic-gate 			strioc.ic_timout = INFTIM;
3333*7c478bd9Sstevel@tonic-gate 
3334*7c478bd9Sstevel@tonic-gate 			switch (cmd) {
3335*7c478bd9Sstevel@tonic-gate 
3336*7c478bd9Sstevel@tonic-gate 			case TCXONC:
3337*7c478bd9Sstevel@tonic-gate 			case TCSBRK:
3338*7c478bd9Sstevel@tonic-gate 			case TCFLSH:
3339*7c478bd9Sstevel@tonic-gate 			case TCDSET:
3340*7c478bd9Sstevel@tonic-gate 				{
3341*7c478bd9Sstevel@tonic-gate 				int native_arg = (int)arg;
3342*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (int);
3343*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)&native_arg;
3344*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3345*7c478bd9Sstevel@tonic-gate 				    K_TO_K, crp, rvalp));
3346*7c478bd9Sstevel@tonic-gate 				}
3347*7c478bd9Sstevel@tonic-gate 
3348*7c478bd9Sstevel@tonic-gate 			case TCSETA:
3349*7c478bd9Sstevel@tonic-gate 			case TCSETAW:
3350*7c478bd9Sstevel@tonic-gate 			case TCSETAF:
3351*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termio);
3352*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3353*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3354*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3355*7c478bd9Sstevel@tonic-gate 
3356*7c478bd9Sstevel@tonic-gate 			case TCSETS:
3357*7c478bd9Sstevel@tonic-gate 			case TCSETSW:
3358*7c478bd9Sstevel@tonic-gate 			case TCSETSF:
3359*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termios);
3360*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3361*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3362*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3363*7c478bd9Sstevel@tonic-gate 
3364*7c478bd9Sstevel@tonic-gate 			case LDSETT:
3365*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct termcb);
3366*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3367*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3368*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3369*7c478bd9Sstevel@tonic-gate 
3370*7c478bd9Sstevel@tonic-gate 			case TIOCSETP:
3371*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct sgttyb);
3372*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3373*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3374*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3375*7c478bd9Sstevel@tonic-gate 
3376*7c478bd9Sstevel@tonic-gate 			case TIOCSTI:
3377*7c478bd9Sstevel@tonic-gate 				if ((flag & FREAD) == 0 &&
3378*7c478bd9Sstevel@tonic-gate 				    secpolicy_sti(crp) != 0) {
3379*7c478bd9Sstevel@tonic-gate 					return (EPERM);
3380*7c478bd9Sstevel@tonic-gate 				}
3381*7c478bd9Sstevel@tonic-gate 				if (stp->sd_sidp !=
3382*7c478bd9Sstevel@tonic-gate 				    ttoproc(curthread)->p_sessp->s_sidp &&
3383*7c478bd9Sstevel@tonic-gate 				    secpolicy_sti(crp) != 0) {
3384*7c478bd9Sstevel@tonic-gate 					return (EACCES);
3385*7c478bd9Sstevel@tonic-gate 				}
3386*7c478bd9Sstevel@tonic-gate 
3387*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (char);
3388*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3389*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3390*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3391*7c478bd9Sstevel@tonic-gate 
3392*7c478bd9Sstevel@tonic-gate 			case TIOCSWINSZ:
3393*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct winsize);
3394*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3395*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3396*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3397*7c478bd9Sstevel@tonic-gate 
3398*7c478bd9Sstevel@tonic-gate 			case TIOCSSIZE:
3399*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct ttysize);
3400*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3401*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3402*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3403*7c478bd9Sstevel@tonic-gate 
3404*7c478bd9Sstevel@tonic-gate 			case TIOCSSOFTCAR:
3405*7c478bd9Sstevel@tonic-gate 			case KIOCTRANS:
3406*7c478bd9Sstevel@tonic-gate 			case KIOCTRANSABLE:
3407*7c478bd9Sstevel@tonic-gate 			case KIOCCMD:
3408*7c478bd9Sstevel@tonic-gate 			case KIOCSDIRECT:
3409*7c478bd9Sstevel@tonic-gate 			case KIOCSCOMPAT:
3410*7c478bd9Sstevel@tonic-gate 			case KIOCSKABORTEN:
3411*7c478bd9Sstevel@tonic-gate 			case KIOCSRPTDELAY:
3412*7c478bd9Sstevel@tonic-gate 			case KIOCSRPTRATE:
3413*7c478bd9Sstevel@tonic-gate 			case VUIDSFORMAT:
3414*7c478bd9Sstevel@tonic-gate 			case TIOCSPPS:
3415*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (int);
3416*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3417*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3418*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3419*7c478bd9Sstevel@tonic-gate 
3420*7c478bd9Sstevel@tonic-gate 			case KIOCSETKEY:
3421*7c478bd9Sstevel@tonic-gate 			case KIOCGETKEY:
3422*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct kiockey);
3423*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3424*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3425*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3426*7c478bd9Sstevel@tonic-gate 
3427*7c478bd9Sstevel@tonic-gate 			case KIOCSKEY:
3428*7c478bd9Sstevel@tonic-gate 			case KIOCGKEY:
3429*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct kiockeymap);
3430*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3431*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3432*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3433*7c478bd9Sstevel@tonic-gate 
3434*7c478bd9Sstevel@tonic-gate 			case KIOCSLED:
3435*7c478bd9Sstevel@tonic-gate 				/* arg is a pointer to char */
3436*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (char);
3437*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3438*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3439*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3440*7c478bd9Sstevel@tonic-gate 
3441*7c478bd9Sstevel@tonic-gate 			case MSIOSETPARMS:
3442*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (Ms_parms);
3443*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3444*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3445*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3446*7c478bd9Sstevel@tonic-gate 
3447*7c478bd9Sstevel@tonic-gate 			case VUIDSADDR:
3448*7c478bd9Sstevel@tonic-gate 			case VUIDGADDR:
3449*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = sizeof (struct vuid_addr_probe);
3450*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3451*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3452*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3453*7c478bd9Sstevel@tonic-gate 
3454*7c478bd9Sstevel@tonic-gate 			/*
3455*7c478bd9Sstevel@tonic-gate 			 * These M_IOCTL's don't require any data to be sent
3456*7c478bd9Sstevel@tonic-gate 			 * downstream, and the driver will allocate and link
3457*7c478bd9Sstevel@tonic-gate 			 * on its own mblk_t upon M_IOCACK -- thus we set
3458*7c478bd9Sstevel@tonic-gate 			 * ic_len to zero and set ic_dp to arg so we know
3459*7c478bd9Sstevel@tonic-gate 			 * where to copyout to later.
3460*7c478bd9Sstevel@tonic-gate 			 */
3461*7c478bd9Sstevel@tonic-gate 			case TIOCGSOFTCAR:
3462*7c478bd9Sstevel@tonic-gate 			case TIOCGWINSZ:
3463*7c478bd9Sstevel@tonic-gate 			case TIOCGSIZE:
3464*7c478bd9Sstevel@tonic-gate 			case KIOCGTRANS:
3465*7c478bd9Sstevel@tonic-gate 			case KIOCGTRANSABLE:
3466*7c478bd9Sstevel@tonic-gate 			case KIOCTYPE:
3467*7c478bd9Sstevel@tonic-gate 			case KIOCGDIRECT:
3468*7c478bd9Sstevel@tonic-gate 			case KIOCGCOMPAT:
3469*7c478bd9Sstevel@tonic-gate 			case KIOCLAYOUT:
3470*7c478bd9Sstevel@tonic-gate 			case KIOCGLED:
3471*7c478bd9Sstevel@tonic-gate 			case MSIOGETPARMS:
3472*7c478bd9Sstevel@tonic-gate 			case MSIOBUTTONS:
3473*7c478bd9Sstevel@tonic-gate 			case VUIDGFORMAT:
3474*7c478bd9Sstevel@tonic-gate 			case TIOCGPPS:
3475*7c478bd9Sstevel@tonic-gate 			case TIOCGPPSEV:
3476*7c478bd9Sstevel@tonic-gate 			case TCGETA:
3477*7c478bd9Sstevel@tonic-gate 			case TCGETS:
3478*7c478bd9Sstevel@tonic-gate 			case LDGETT:
3479*7c478bd9Sstevel@tonic-gate 			case TIOCGETP:
3480*7c478bd9Sstevel@tonic-gate 			case KIOCGRPTDELAY:
3481*7c478bd9Sstevel@tonic-gate 			case KIOCGRPTRATE:
3482*7c478bd9Sstevel@tonic-gate 				strioc.ic_len = 0;
3483*7c478bd9Sstevel@tonic-gate 				strioc.ic_dp = (char *)arg;
3484*7c478bd9Sstevel@tonic-gate 				return (strdoioctl(stp, &strioc, flag,
3485*7c478bd9Sstevel@tonic-gate 					copyflag, crp, rvalp));
3486*7c478bd9Sstevel@tonic-gate 			}
3487*7c478bd9Sstevel@tonic-gate 		}
3488*7c478bd9Sstevel@tonic-gate 
3489*7c478bd9Sstevel@tonic-gate 		/*
3490*7c478bd9Sstevel@tonic-gate 		 * Unknown cmd - send it down as a transparent ioctl.
3491*7c478bd9Sstevel@tonic-gate 		 */
3492*7c478bd9Sstevel@tonic-gate 		strioc.ic_cmd = cmd;
3493*7c478bd9Sstevel@tonic-gate 		strioc.ic_timout = INFTIM;
3494*7c478bd9Sstevel@tonic-gate 		strioc.ic_len = TRANSPARENT;
3495*7c478bd9Sstevel@tonic-gate 		strioc.ic_dp = (char *)&arg;
3496*7c478bd9Sstevel@tonic-gate 
3497*7c478bd9Sstevel@tonic-gate 		return (strdoioctl(stp, &strioc, flag, copyflag, crp, rvalp));
3498*7c478bd9Sstevel@tonic-gate 
3499*7c478bd9Sstevel@tonic-gate 	case I_STR:
3500*7c478bd9Sstevel@tonic-gate 		/*
3501*7c478bd9Sstevel@tonic-gate 		 * Stream ioctl.  Read in an strioctl buffer from the user
3502*7c478bd9Sstevel@tonic-gate 		 * along with any data specified and send it downstream.
3503*7c478bd9Sstevel@tonic-gate 		 * Strdoioctl will wait allow only one ioctl message at
3504*7c478bd9Sstevel@tonic-gate 		 * a time, and waits for the acknowledgement.
3505*7c478bd9Sstevel@tonic-gate 		 */
3506*7c478bd9Sstevel@tonic-gate 
3507*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
3508*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
3509*7c478bd9Sstevel@tonic-gate 
3510*7c478bd9Sstevel@tonic-gate 		error = strcopyin_strioctl((void *)arg, &strioc, flag,
3511*7c478bd9Sstevel@tonic-gate 		    copyflag);
3512*7c478bd9Sstevel@tonic-gate 		if (error != 0)
3513*7c478bd9Sstevel@tonic-gate 			return (error);
3514*7c478bd9Sstevel@tonic-gate 
3515*7c478bd9Sstevel@tonic-gate 		if ((strioc.ic_len < 0) || (strioc.ic_timout < -1))
3516*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3517*7c478bd9Sstevel@tonic-gate 
3518*7c478bd9Sstevel@tonic-gate 		access = job_control_type(strioc.ic_cmd);
3519*7c478bd9Sstevel@tonic-gate 		if (access != -1 && stp->sd_sidp != NULL &&
3520*7c478bd9Sstevel@tonic-gate 		    stp->sd_vnode->v_type != VFIFO &&
3521*7c478bd9Sstevel@tonic-gate 		    (error = straccess(stp, access)) != 0)
3522*7c478bd9Sstevel@tonic-gate 			return (error);
3523*7c478bd9Sstevel@tonic-gate 
3524*7c478bd9Sstevel@tonic-gate 		/*
3525*7c478bd9Sstevel@tonic-gate 		 * The I_STR facility provides a trap door for malicious
3526*7c478bd9Sstevel@tonic-gate 		 * code to send down bogus streamio(7I) ioctl commands to
3527*7c478bd9Sstevel@tonic-gate 		 * unsuspecting STREAMS modules and drivers which expect to
3528*7c478bd9Sstevel@tonic-gate 		 * only get these messages from the stream head.
3529*7c478bd9Sstevel@tonic-gate 		 * Explicitly prohibit any streamio ioctls which can be
3530*7c478bd9Sstevel@tonic-gate 		 * passed downstream by the stream head.  Note that we do
3531*7c478bd9Sstevel@tonic-gate 		 * not block all streamio ioctls because the ioctl
3532*7c478bd9Sstevel@tonic-gate 		 * numberspace is not well managed and thus it's possible
3533*7c478bd9Sstevel@tonic-gate 		 * that a module or driver's ioctl numbers may accidentally
3534*7c478bd9Sstevel@tonic-gate 		 * collide with them.
3535*7c478bd9Sstevel@tonic-gate 		 */
3536*7c478bd9Sstevel@tonic-gate 		switch (strioc.ic_cmd) {
3537*7c478bd9Sstevel@tonic-gate 		case I_LINK:
3538*7c478bd9Sstevel@tonic-gate 		case I_PLINK:
3539*7c478bd9Sstevel@tonic-gate 		case I_UNLINK:
3540*7c478bd9Sstevel@tonic-gate 		case I_PUNLINK:
3541*7c478bd9Sstevel@tonic-gate 		case _I_GETPEERCRED:
3542*7c478bd9Sstevel@tonic-gate 		case _I_PLINK_LH:
3543*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3544*7c478bd9Sstevel@tonic-gate 		}
3545*7c478bd9Sstevel@tonic-gate 
3546*7c478bd9Sstevel@tonic-gate 		error = strdoioctl(stp, &strioc, flag, copyflag, crp, rvalp);
3547*7c478bd9Sstevel@tonic-gate 		if (error == 0) {
3548*7c478bd9Sstevel@tonic-gate 			error = strcopyout_strioctl(&strioc, (void *)arg,
3549*7c478bd9Sstevel@tonic-gate 			    flag, copyflag);
3550*7c478bd9Sstevel@tonic-gate 		}
3551*7c478bd9Sstevel@tonic-gate 		return (error);
3552*7c478bd9Sstevel@tonic-gate 
3553*7c478bd9Sstevel@tonic-gate 	case I_NREAD:
3554*7c478bd9Sstevel@tonic-gate 		/*
3555*7c478bd9Sstevel@tonic-gate 		 * Return number of bytes of data in first message
3556*7c478bd9Sstevel@tonic-gate 		 * in queue in "arg" and return the number of messages
3557*7c478bd9Sstevel@tonic-gate 		 * in queue in return value.
3558*7c478bd9Sstevel@tonic-gate 		 */
3559*7c478bd9Sstevel@tonic-gate 	    {
3560*7c478bd9Sstevel@tonic-gate 		size_t	size;
3561*7c478bd9Sstevel@tonic-gate 		int	retval;
3562*7c478bd9Sstevel@tonic-gate 		int	count = 0;
3563*7c478bd9Sstevel@tonic-gate 
3564*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
3565*7c478bd9Sstevel@tonic-gate 
3566*7c478bd9Sstevel@tonic-gate 		size = msgdsize(rdq->q_first);
3567*7c478bd9Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
3568*7c478bd9Sstevel@tonic-gate 			count++;
3569*7c478bd9Sstevel@tonic-gate 
3570*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
3571*7c478bd9Sstevel@tonic-gate 		if (stp->sd_struiordq) {
3572*7c478bd9Sstevel@tonic-gate 			infod_t infod;
3573*7c478bd9Sstevel@tonic-gate 
3574*7c478bd9Sstevel@tonic-gate 			infod.d_cmd = INFOD_COUNT;
3575*7c478bd9Sstevel@tonic-gate 			infod.d_count = 0;
3576*7c478bd9Sstevel@tonic-gate 			if (count == 0) {
3577*7c478bd9Sstevel@tonic-gate 				infod.d_cmd |= INFOD_FIRSTBYTES;
3578*7c478bd9Sstevel@tonic-gate 				infod.d_bytes = 0;
3579*7c478bd9Sstevel@tonic-gate 			}
3580*7c478bd9Sstevel@tonic-gate 			infod.d_res = 0;
3581*7c478bd9Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
3582*7c478bd9Sstevel@tonic-gate 			count += infod.d_count;
3583*7c478bd9Sstevel@tonic-gate 			if (infod.d_res & INFOD_FIRSTBYTES)
3584*7c478bd9Sstevel@tonic-gate 				size = infod.d_bytes;
3585*7c478bd9Sstevel@tonic-gate 		}
3586*7c478bd9Sstevel@tonic-gate 
3587*7c478bd9Sstevel@tonic-gate 		/*
3588*7c478bd9Sstevel@tonic-gate 		 * Drop down from size_t to the "int" required by the
3589*7c478bd9Sstevel@tonic-gate 		 * interface.  Cap at INT_MAX.
3590*7c478bd9Sstevel@tonic-gate 		 */
3591*7c478bd9Sstevel@tonic-gate 		retval = MIN(size, INT_MAX);
3592*7c478bd9Sstevel@tonic-gate 		error = strcopyout(&retval, (void *)arg, sizeof (retval),
3593*7c478bd9Sstevel@tonic-gate 		    copyflag);
3594*7c478bd9Sstevel@tonic-gate 		if (!error)
3595*7c478bd9Sstevel@tonic-gate 			*rvalp = count;
3596*7c478bd9Sstevel@tonic-gate 		return (error);
3597*7c478bd9Sstevel@tonic-gate 	    }
3598*7c478bd9Sstevel@tonic-gate 
3599*7c478bd9Sstevel@tonic-gate 	case FIONREAD:
3600*7c478bd9Sstevel@tonic-gate 		/*
3601*7c478bd9Sstevel@tonic-gate 		 * Return number of bytes of data in all data messages
3602*7c478bd9Sstevel@tonic-gate 		 * in queue in "arg".
3603*7c478bd9Sstevel@tonic-gate 		 */
3604*7c478bd9Sstevel@tonic-gate 	    {
3605*7c478bd9Sstevel@tonic-gate 		size_t	size = 0;
3606*7c478bd9Sstevel@tonic-gate 		int	retval;
3607*7c478bd9Sstevel@tonic-gate 
3608*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
3609*7c478bd9Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
3610*7c478bd9Sstevel@tonic-gate 			size += msgdsize(mp);
3611*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
3612*7c478bd9Sstevel@tonic-gate 
3613*7c478bd9Sstevel@tonic-gate 		if (stp->sd_struiordq) {
3614*7c478bd9Sstevel@tonic-gate 			infod_t infod;
3615*7c478bd9Sstevel@tonic-gate 
3616*7c478bd9Sstevel@tonic-gate 			infod.d_cmd = INFOD_BYTES;
3617*7c478bd9Sstevel@tonic-gate 			infod.d_res = 0;
3618*7c478bd9Sstevel@tonic-gate 			infod.d_bytes = 0;
3619*7c478bd9Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
3620*7c478bd9Sstevel@tonic-gate 			size += infod.d_bytes;
3621*7c478bd9Sstevel@tonic-gate 		}
3622*7c478bd9Sstevel@tonic-gate 
3623*7c478bd9Sstevel@tonic-gate 		/*
3624*7c478bd9Sstevel@tonic-gate 		 * Drop down from size_t to the "int" required by the
3625*7c478bd9Sstevel@tonic-gate 		 * interface.  Cap at INT_MAX.
3626*7c478bd9Sstevel@tonic-gate 		 */
3627*7c478bd9Sstevel@tonic-gate 		retval = MIN(size, INT_MAX);
3628*7c478bd9Sstevel@tonic-gate 		error = strcopyout(&retval, (void *)arg, sizeof (retval),
3629*7c478bd9Sstevel@tonic-gate 		    copyflag);
3630*7c478bd9Sstevel@tonic-gate 
3631*7c478bd9Sstevel@tonic-gate 		*rvalp = 0;
3632*7c478bd9Sstevel@tonic-gate 		return (error);
3633*7c478bd9Sstevel@tonic-gate 	    }
3634*7c478bd9Sstevel@tonic-gate 	case FIORDCHK:
3635*7c478bd9Sstevel@tonic-gate 		/*
3636*7c478bd9Sstevel@tonic-gate 		 * FIORDCHK does not use arg value (like FIONREAD),
3637*7c478bd9Sstevel@tonic-gate 		 * instead a count is returned. I_NREAD value may
3638*7c478bd9Sstevel@tonic-gate 		 * not be accurate but safe. The real thing to do is
3639*7c478bd9Sstevel@tonic-gate 		 * to add the msgdsizes of all data  messages until
3640*7c478bd9Sstevel@tonic-gate 		 * a non-data message.
3641*7c478bd9Sstevel@tonic-gate 		 */
3642*7c478bd9Sstevel@tonic-gate 	    {
3643*7c478bd9Sstevel@tonic-gate 		size_t size = 0;
3644*7c478bd9Sstevel@tonic-gate 
3645*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
3646*7c478bd9Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
3647*7c478bd9Sstevel@tonic-gate 			size += msgdsize(mp);
3648*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
3649*7c478bd9Sstevel@tonic-gate 
3650*7c478bd9Sstevel@tonic-gate 		if (stp->sd_struiordq) {
3651*7c478bd9Sstevel@tonic-gate 			infod_t infod;
3652*7c478bd9Sstevel@tonic-gate 
3653*7c478bd9Sstevel@tonic-gate 			infod.d_cmd = INFOD_BYTES;
3654*7c478bd9Sstevel@tonic-gate 			infod.d_res = 0;
3655*7c478bd9Sstevel@tonic-gate 			infod.d_bytes = 0;
3656*7c478bd9Sstevel@tonic-gate 			(void) infonext(rdq, &infod);
3657*7c478bd9Sstevel@tonic-gate 			size += infod.d_bytes;
3658*7c478bd9Sstevel@tonic-gate 		}
3659*7c478bd9Sstevel@tonic-gate 
3660*7c478bd9Sstevel@tonic-gate 		/*
3661*7c478bd9Sstevel@tonic-gate 		 * Since ioctl returns an int, and memory sizes under
3662*7c478bd9Sstevel@tonic-gate 		 * LP64 may not fit, we return INT_MAX if the count was
3663*7c478bd9Sstevel@tonic-gate 		 * actually greater.
3664*7c478bd9Sstevel@tonic-gate 		 */
3665*7c478bd9Sstevel@tonic-gate 		*rvalp = MIN(size, INT_MAX);
3666*7c478bd9Sstevel@tonic-gate 		return (0);
3667*7c478bd9Sstevel@tonic-gate 	    }
3668*7c478bd9Sstevel@tonic-gate 
3669*7c478bd9Sstevel@tonic-gate 	case I_FIND:
3670*7c478bd9Sstevel@tonic-gate 		/*
3671*7c478bd9Sstevel@tonic-gate 		 * Get module name.
3672*7c478bd9Sstevel@tonic-gate 		 */
3673*7c478bd9Sstevel@tonic-gate 	    {
3674*7c478bd9Sstevel@tonic-gate 		char mname[FMNAMESZ + 1];
3675*7c478bd9Sstevel@tonic-gate 		queue_t *q;
3676*7c478bd9Sstevel@tonic-gate 
3677*7c478bd9Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr : copystr)((void *)arg,
3678*7c478bd9Sstevel@tonic-gate 		    mname, FMNAMESZ + 1, NULL);
3679*7c478bd9Sstevel@tonic-gate 		if (error)
3680*7c478bd9Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
3681*7c478bd9Sstevel@tonic-gate 
3682*7c478bd9Sstevel@tonic-gate 		/*
3683*7c478bd9Sstevel@tonic-gate 		 * Return EINVAL if we're handed a bogus module name.
3684*7c478bd9Sstevel@tonic-gate 		 */
3685*7c478bd9Sstevel@tonic-gate 		if (fmodsw_find(mname, FMODSW_LOAD) == NULL) {
3686*7c478bd9Sstevel@tonic-gate 			TRACE_0(TR_FAC_STREAMS_FR,
3687*7c478bd9Sstevel@tonic-gate 				TR_I_CANT_FIND, "couldn't I_FIND");
3688*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3689*7c478bd9Sstevel@tonic-gate 		}
3690*7c478bd9Sstevel@tonic-gate 
3691*7c478bd9Sstevel@tonic-gate 		*rvalp = 0;
3692*7c478bd9Sstevel@tonic-gate 
3693*7c478bd9Sstevel@tonic-gate 		/* Look downstream to see if module is there. */
3694*7c478bd9Sstevel@tonic-gate 		claimstr(stp->sd_wrq);
3695*7c478bd9Sstevel@tonic-gate 		for (q = stp->sd_wrq->q_next; q; q = q->q_next) {
3696*7c478bd9Sstevel@tonic-gate 			if (q->q_flag&QREADR) {
3697*7c478bd9Sstevel@tonic-gate 				q = NULL;
3698*7c478bd9Sstevel@tonic-gate 				break;
3699*7c478bd9Sstevel@tonic-gate 			}
3700*7c478bd9Sstevel@tonic-gate 			if (strcmp(mname, q->q_qinfo->qi_minfo->mi_idname) == 0)
3701*7c478bd9Sstevel@tonic-gate 				break;
3702*7c478bd9Sstevel@tonic-gate 		}
3703*7c478bd9Sstevel@tonic-gate 		releasestr(stp->sd_wrq);
3704*7c478bd9Sstevel@tonic-gate 
3705*7c478bd9Sstevel@tonic-gate 		*rvalp = (q ? 1 : 0);
3706*7c478bd9Sstevel@tonic-gate 		return (error);
3707*7c478bd9Sstevel@tonic-gate 	    }
3708*7c478bd9Sstevel@tonic-gate 
3709*7c478bd9Sstevel@tonic-gate 	case I_PUSH:
3710*7c478bd9Sstevel@tonic-gate 	case __I_PUSH_NOCTTY:
3711*7c478bd9Sstevel@tonic-gate 		/*
3712*7c478bd9Sstevel@tonic-gate 		 * Push a module.
3713*7c478bd9Sstevel@tonic-gate 		 * For the case __I_PUSH_NOCTTY push a module but
3714*7c478bd9Sstevel@tonic-gate 		 * do not allocate controlling tty. See bugid 4025044
3715*7c478bd9Sstevel@tonic-gate 		 */
3716*7c478bd9Sstevel@tonic-gate 
3717*7c478bd9Sstevel@tonic-gate 	    {
3718*7c478bd9Sstevel@tonic-gate 		char mname[FMNAMESZ + 1];
3719*7c478bd9Sstevel@tonic-gate 		fmodsw_impl_t *fp;
3720*7c478bd9Sstevel@tonic-gate 		dev_t dummydev;
3721*7c478bd9Sstevel@tonic-gate 
3722*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
3723*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
3724*7c478bd9Sstevel@tonic-gate 
3725*7c478bd9Sstevel@tonic-gate 		/*
3726*7c478bd9Sstevel@tonic-gate 		 * Get module name and look up in fmodsw.
3727*7c478bd9Sstevel@tonic-gate 		 */
3728*7c478bd9Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr : copystr)((void *)arg,
3729*7c478bd9Sstevel@tonic-gate 		    mname, FMNAMESZ + 1, NULL);
3730*7c478bd9Sstevel@tonic-gate 		if (error)
3731*7c478bd9Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
3732*7c478bd9Sstevel@tonic-gate 
3733*7c478bd9Sstevel@tonic-gate 		if ((fp = fmodsw_find(mname, FMODSW_HOLD | FMODSW_LOAD)) ==
3734*7c478bd9Sstevel@tonic-gate 		    NULL)
3735*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3736*7c478bd9Sstevel@tonic-gate 
3737*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_I_PUSH,
3738*7c478bd9Sstevel@tonic-gate 		    "I_PUSH:fp %p stp %p", fp, stp);
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd)) {
3741*7c478bd9Sstevel@tonic-gate 			fmodsw_rele(fp);
3742*7c478bd9Sstevel@tonic-gate 			return (error);
3743*7c478bd9Sstevel@tonic-gate 		}
3744*7c478bd9Sstevel@tonic-gate 
3745*7c478bd9Sstevel@tonic-gate 		/*
3746*7c478bd9Sstevel@tonic-gate 		 * See if any more modules can be pushed on this stream.
3747*7c478bd9Sstevel@tonic-gate 		 * Note that this check must be done after strstartplumb()
3748*7c478bd9Sstevel@tonic-gate 		 * since otherwise multiple threads issuing I_PUSHes on
3749*7c478bd9Sstevel@tonic-gate 		 * the same stream will be able to exceed nstrpush.
3750*7c478bd9Sstevel@tonic-gate 		 */
3751*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
3752*7c478bd9Sstevel@tonic-gate 		if (stp->sd_pushcnt >= nstrpush) {
3753*7c478bd9Sstevel@tonic-gate 			fmodsw_rele(fp);
3754*7c478bd9Sstevel@tonic-gate 			strendplumb(stp);
3755*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
3756*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3757*7c478bd9Sstevel@tonic-gate 		}
3758*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
3759*7c478bd9Sstevel@tonic-gate 
3760*7c478bd9Sstevel@tonic-gate 		/*
3761*7c478bd9Sstevel@tonic-gate 		 * Push new module and call its open routine
3762*7c478bd9Sstevel@tonic-gate 		 * via qattach().  Modules don't change device
3763*7c478bd9Sstevel@tonic-gate 		 * numbers, so just ignore dummydev here.
3764*7c478bd9Sstevel@tonic-gate 		 */
3765*7c478bd9Sstevel@tonic-gate 		dummydev = vp->v_rdev;
3766*7c478bd9Sstevel@tonic-gate 		if ((error = qattach(rdq, &dummydev, 0, crp, fp,
3767*7c478bd9Sstevel@tonic-gate 		    B_FALSE)) == 0) {
3768*7c478bd9Sstevel@tonic-gate 			if (vp->v_type == VCHR && /* sorry, no pipes allowed */
3769*7c478bd9Sstevel@tonic-gate 			    (cmd == I_PUSH) && (stp->sd_flag & STRISTTY)) {
3770*7c478bd9Sstevel@tonic-gate 				/*
3771*7c478bd9Sstevel@tonic-gate 				 * try to allocate it as a controlling terminal
3772*7c478bd9Sstevel@tonic-gate 				 */
3773*7c478bd9Sstevel@tonic-gate 				strctty(stp);
3774*7c478bd9Sstevel@tonic-gate 			}
3775*7c478bd9Sstevel@tonic-gate 		}
3776*7c478bd9Sstevel@tonic-gate 
3777*7c478bd9Sstevel@tonic-gate 		/*
3778*7c478bd9Sstevel@tonic-gate 		 * If flow control is on, don't break it - enable
3779*7c478bd9Sstevel@tonic-gate 		 * first back queue with svc procedure.
3780*7c478bd9Sstevel@tonic-gate 		 */
3781*7c478bd9Sstevel@tonic-gate 		if (rdq->q_flag & QWANTW) {
3782*7c478bd9Sstevel@tonic-gate 			/* Note: no setqback here - use pri -1. */
3783*7c478bd9Sstevel@tonic-gate 			backenable(_RD(wrq->q_next), -1);
3784*7c478bd9Sstevel@tonic-gate 		}
3785*7c478bd9Sstevel@tonic-gate 
3786*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
3787*7c478bd9Sstevel@tonic-gate 
3788*7c478bd9Sstevel@tonic-gate 		/*
3789*7c478bd9Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
3790*7c478bd9Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
3791*7c478bd9Sstevel@tonic-gate 		 * head in the stream head.
3792*7c478bd9Sstevel@tonic-gate 		 */
3793*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(stp->sd_wrq->q_next));
3794*7c478bd9Sstevel@tonic-gate 		rmin = stp->sd_wrq->q_next->q_minpsz;
3795*7c478bd9Sstevel@tonic-gate 		rmax = stp->sd_wrq->q_next->q_maxpsz;
3796*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(stp->sd_wrq->q_next));
3797*7c478bd9Sstevel@tonic-gate 
3798*7c478bd9Sstevel@tonic-gate 		/* Do this processing here as a performance concern */
3799*7c478bd9Sstevel@tonic-gate 		if (strmsgsz != 0) {
3800*7c478bd9Sstevel@tonic-gate 			if (rmax == INFPSZ)
3801*7c478bd9Sstevel@tonic-gate 				rmax = strmsgsz;
3802*7c478bd9Sstevel@tonic-gate 			else  {
3803*7c478bd9Sstevel@tonic-gate 				if (vp->v_type == VFIFO)
3804*7c478bd9Sstevel@tonic-gate 					rmax = MIN(PIPE_BUF, rmax);
3805*7c478bd9Sstevel@tonic-gate 				else	rmax = MIN(strmsgsz, rmax);
3806*7c478bd9Sstevel@tonic-gate 			}
3807*7c478bd9Sstevel@tonic-gate 		}
3808*7c478bd9Sstevel@tonic-gate 
3809*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq));
3810*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_minpsz = rmin;
3811*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_maxpsz = rmax;
3812*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq));
3813*7c478bd9Sstevel@tonic-gate 
3814*7c478bd9Sstevel@tonic-gate 		strendplumb(stp);
3815*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
3816*7c478bd9Sstevel@tonic-gate 		return (error);
3817*7c478bd9Sstevel@tonic-gate 	    }
3818*7c478bd9Sstevel@tonic-gate 
3819*7c478bd9Sstevel@tonic-gate 	case I_POP:
3820*7c478bd9Sstevel@tonic-gate 	    {
3821*7c478bd9Sstevel@tonic-gate 		queue_t	*q;
3822*7c478bd9Sstevel@tonic-gate 
3823*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
3824*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
3825*7c478bd9Sstevel@tonic-gate 		if (!wrq->q_next)	/* for broken pipes */
3826*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3827*7c478bd9Sstevel@tonic-gate 
3828*7c478bd9Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd))
3829*7c478bd9Sstevel@tonic-gate 			return (error);
3830*7c478bd9Sstevel@tonic-gate 
3831*7c478bd9Sstevel@tonic-gate 		/*
3832*7c478bd9Sstevel@tonic-gate 		 * If there is an anchor on this stream and popping
3833*7c478bd9Sstevel@tonic-gate 		 * the current module would attempt to pop through the
3834*7c478bd9Sstevel@tonic-gate 		 * anchor, then disallow the pop unless we have sufficient
3835*7c478bd9Sstevel@tonic-gate 		 * privileges; take the cheapest (non-locking) check
3836*7c478bd9Sstevel@tonic-gate 		 * first.
3837*7c478bd9Sstevel@tonic-gate 		 */
3838*7c478bd9Sstevel@tonic-gate 		if (secpolicy_net_config(crp, B_TRUE) != 0) {
3839*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
3840*7c478bd9Sstevel@tonic-gate 			/*
3841*7c478bd9Sstevel@tonic-gate 			 * Anchors only apply if there's at least one
3842*7c478bd9Sstevel@tonic-gate 			 * module on the stream (sd_pushcnt > 0).
3843*7c478bd9Sstevel@tonic-gate 			 */
3844*7c478bd9Sstevel@tonic-gate 			if (stp->sd_pushcnt > 0 &&
3845*7c478bd9Sstevel@tonic-gate 			    stp->sd_pushcnt == stp->sd_anchor &&
3846*7c478bd9Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
3847*7c478bd9Sstevel@tonic-gate 				strendplumb(stp);
3848*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
3849*7c478bd9Sstevel@tonic-gate 				/* Audit and report error */
3850*7c478bd9Sstevel@tonic-gate 				return (secpolicy_net_config(crp, B_FALSE));
3851*7c478bd9Sstevel@tonic-gate 			}
3852*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
3853*7c478bd9Sstevel@tonic-gate 		}
3854*7c478bd9Sstevel@tonic-gate 
3855*7c478bd9Sstevel@tonic-gate 		q = wrq->q_next;
3856*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_I_POP,
3857*7c478bd9Sstevel@tonic-gate 			"I_POP:%p from %p", q, stp);
3858*7c478bd9Sstevel@tonic-gate 		if (q->q_next == NULL || (q->q_flag & (QREADR|QISDRV))) {
3859*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
3860*7c478bd9Sstevel@tonic-gate 		} else {
3861*7c478bd9Sstevel@tonic-gate 			qdetach(_RD(q), 1, flag, crp, B_FALSE);
3862*7c478bd9Sstevel@tonic-gate 			error = 0;
3863*7c478bd9Sstevel@tonic-gate 		}
3864*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
3865*7c478bd9Sstevel@tonic-gate 
3866*7c478bd9Sstevel@tonic-gate 		/*
3867*7c478bd9Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
3868*7c478bd9Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
3869*7c478bd9Sstevel@tonic-gate 		 * head in the stream head.
3870*7c478bd9Sstevel@tonic-gate 		 */
3871*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq->q_next));
3872*7c478bd9Sstevel@tonic-gate 		rmin = wrq->q_next->q_minpsz;
3873*7c478bd9Sstevel@tonic-gate 		rmax = wrq->q_next->q_maxpsz;
3874*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq->q_next));
3875*7c478bd9Sstevel@tonic-gate 
3876*7c478bd9Sstevel@tonic-gate 		/* Do this processing here as a performance concern */
3877*7c478bd9Sstevel@tonic-gate 		if (strmsgsz != 0) {
3878*7c478bd9Sstevel@tonic-gate 			if (rmax == INFPSZ)
3879*7c478bd9Sstevel@tonic-gate 				rmax = strmsgsz;
3880*7c478bd9Sstevel@tonic-gate 			else  {
3881*7c478bd9Sstevel@tonic-gate 				if (vp->v_type == VFIFO)
3882*7c478bd9Sstevel@tonic-gate 					rmax = MIN(PIPE_BUF, rmax);
3883*7c478bd9Sstevel@tonic-gate 				else	rmax = MIN(strmsgsz, rmax);
3884*7c478bd9Sstevel@tonic-gate 			}
3885*7c478bd9Sstevel@tonic-gate 		}
3886*7c478bd9Sstevel@tonic-gate 
3887*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(wrq));
3888*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_minpsz = rmin;
3889*7c478bd9Sstevel@tonic-gate 		stp->sd_qn_maxpsz = rmax;
3890*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(wrq));
3891*7c478bd9Sstevel@tonic-gate 
3892*7c478bd9Sstevel@tonic-gate 		/* If we popped through the anchor, then reset the anchor. */
3893*7c478bd9Sstevel@tonic-gate 		if (stp->sd_pushcnt < stp->sd_anchor)
3894*7c478bd9Sstevel@tonic-gate 			stp->sd_anchor = 0;
3895*7c478bd9Sstevel@tonic-gate 
3896*7c478bd9Sstevel@tonic-gate 		strendplumb(stp);
3897*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
3898*7c478bd9Sstevel@tonic-gate 		return (error);
3899*7c478bd9Sstevel@tonic-gate 	    }
3900*7c478bd9Sstevel@tonic-gate 
3901*7c478bd9Sstevel@tonic-gate 	case _I_MUXID2FD:
3902*7c478bd9Sstevel@tonic-gate 	{
3903*7c478bd9Sstevel@tonic-gate 		/*
3904*7c478bd9Sstevel@tonic-gate 		 * Create a fd for a I_PLINK'ed lower stream with a given
3905*7c478bd9Sstevel@tonic-gate 		 * muxid.  With the fd, application can send down ioctls,
3906*7c478bd9Sstevel@tonic-gate 		 * like I_LIST, to the previously I_PLINK'ed stream.  Note
3907*7c478bd9Sstevel@tonic-gate 		 * that after getting the fd, the application has to do an
3908*7c478bd9Sstevel@tonic-gate 		 * I_PUNLINK on the muxid before it can do any operation
3909*7c478bd9Sstevel@tonic-gate 		 * on the lower stream.  This is required by spec1170.
3910*7c478bd9Sstevel@tonic-gate 		 *
3911*7c478bd9Sstevel@tonic-gate 		 * The fd used to do this ioctl should point to the same
3912*7c478bd9Sstevel@tonic-gate 		 * controlling device used to do the I_PLINK.  If it uses
3913*7c478bd9Sstevel@tonic-gate 		 * a different stream or an invalid muxid, I_MUXID2FD will
3914*7c478bd9Sstevel@tonic-gate 		 * fail.  The error code is set to EINVAL.
3915*7c478bd9Sstevel@tonic-gate 		 *
3916*7c478bd9Sstevel@tonic-gate 		 * The intended use of this interface is the following.
3917*7c478bd9Sstevel@tonic-gate 		 * An application I_PLINK'ed a stream and exits.  The fd
3918*7c478bd9Sstevel@tonic-gate 		 * to the lower stream is gone.  Another application
3919*7c478bd9Sstevel@tonic-gate 		 * wants to get a fd to the lower stream, it uses I_MUXID2FD.
3920*7c478bd9Sstevel@tonic-gate 		 */
3921*7c478bd9Sstevel@tonic-gate 		int muxid = (int)arg;
3922*7c478bd9Sstevel@tonic-gate 		int fd;
3923*7c478bd9Sstevel@tonic-gate 		linkinfo_t *linkp;
3924*7c478bd9Sstevel@tonic-gate 		struct file *fp;
3925*7c478bd9Sstevel@tonic-gate 
3926*7c478bd9Sstevel@tonic-gate 		/*
3927*7c478bd9Sstevel@tonic-gate 		 * Do not allow the wildcard muxid.  This ioctl is not
3928*7c478bd9Sstevel@tonic-gate 		 * intended to find arbitrary link.
3929*7c478bd9Sstevel@tonic-gate 		 */
3930*7c478bd9Sstevel@tonic-gate 		if (muxid == 0) {
3931*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3932*7c478bd9Sstevel@tonic-gate 		}
3933*7c478bd9Sstevel@tonic-gate 
3934*7c478bd9Sstevel@tonic-gate 		mutex_enter(&muxifier);
3935*7c478bd9Sstevel@tonic-gate 		linkp = findlinks(vp->v_stream, muxid, LINKPERSIST);
3936*7c478bd9Sstevel@tonic-gate 		if (linkp == NULL) {
3937*7c478bd9Sstevel@tonic-gate 			mutex_exit(&muxifier);
3938*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3939*7c478bd9Sstevel@tonic-gate 		}
3940*7c478bd9Sstevel@tonic-gate 
3941*7c478bd9Sstevel@tonic-gate 		if ((fd = ufalloc(0)) == -1) {
3942*7c478bd9Sstevel@tonic-gate 			mutex_exit(&muxifier);
3943*7c478bd9Sstevel@tonic-gate 			return (EMFILE);
3944*7c478bd9Sstevel@tonic-gate 		}
3945*7c478bd9Sstevel@tonic-gate 		fp = linkp->li_fpdown;
3946*7c478bd9Sstevel@tonic-gate 		mutex_enter(&fp->f_tlock);
3947*7c478bd9Sstevel@tonic-gate 		fp->f_count++;
3948*7c478bd9Sstevel@tonic-gate 		mutex_exit(&fp->f_tlock);
3949*7c478bd9Sstevel@tonic-gate 		mutex_exit(&muxifier);
3950*7c478bd9Sstevel@tonic-gate 		setf(fd, fp);
3951*7c478bd9Sstevel@tonic-gate 		*rvalp = fd;
3952*7c478bd9Sstevel@tonic-gate 		return (0);
3953*7c478bd9Sstevel@tonic-gate 	}
3954*7c478bd9Sstevel@tonic-gate 
3955*7c478bd9Sstevel@tonic-gate 	case _I_INSERT:
3956*7c478bd9Sstevel@tonic-gate 	{
3957*7c478bd9Sstevel@tonic-gate 		/*
3958*7c478bd9Sstevel@tonic-gate 		 * To insert a module to a given position in a stream.
3959*7c478bd9Sstevel@tonic-gate 		 * In the first release, only allow privileged user
3960*7c478bd9Sstevel@tonic-gate 		 * to use this ioctl.
3961*7c478bd9Sstevel@tonic-gate 		 *
3962*7c478bd9Sstevel@tonic-gate 		 * Note that we do not plan to support this ioctl
3963*7c478bd9Sstevel@tonic-gate 		 * on pipes in the first release.  We want to learn more
3964*7c478bd9Sstevel@tonic-gate 		 * about the implications of these ioctls before extending
3965*7c478bd9Sstevel@tonic-gate 		 * their support.  And we do not think these features are
3966*7c478bd9Sstevel@tonic-gate 		 * valuable for pipes.
3967*7c478bd9Sstevel@tonic-gate 		 *
3968*7c478bd9Sstevel@tonic-gate 		 * Neither do we support O/C hot stream.  Note that only
3969*7c478bd9Sstevel@tonic-gate 		 * the upper streams of TCP/IP stack are O/C hot streams.
3970*7c478bd9Sstevel@tonic-gate 		 * The lower IP stream is not.
3971*7c478bd9Sstevel@tonic-gate 		 * When there is a O/C cold barrier, we only allow inserts
3972*7c478bd9Sstevel@tonic-gate 		 * above the barrier.
3973*7c478bd9Sstevel@tonic-gate 		 */
3974*7c478bd9Sstevel@tonic-gate 		STRUCT_DECL(strmodconf, strmodinsert);
3975*7c478bd9Sstevel@tonic-gate 		char mod_name[FMNAMESZ + 1];
3976*7c478bd9Sstevel@tonic-gate 		fmodsw_impl_t *fp;
3977*7c478bd9Sstevel@tonic-gate 		dev_t dummydev;
3978*7c478bd9Sstevel@tonic-gate 		queue_t *tmp_wrq;
3979*7c478bd9Sstevel@tonic-gate 		int pos;
3980*7c478bd9Sstevel@tonic-gate 		boolean_t is_insert;
3981*7c478bd9Sstevel@tonic-gate 
3982*7c478bd9Sstevel@tonic-gate 		STRUCT_INIT(strmodinsert, flag);
3983*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
3984*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
3985*7c478bd9Sstevel@tonic-gate 		if (STRMATED(stp))
3986*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
3987*7c478bd9Sstevel@tonic-gate 		if ((error = secpolicy_net_config(crp, B_FALSE)) != 0)
3988*7c478bd9Sstevel@tonic-gate 			return (error);
3989*7c478bd9Sstevel@tonic-gate 
3990*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strmodinsert),
3991*7c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strmodinsert), copyflag);
3992*7c478bd9Sstevel@tonic-gate 		if (error)
3993*7c478bd9Sstevel@tonic-gate 			return (error);
3994*7c478bd9Sstevel@tonic-gate 
3995*7c478bd9Sstevel@tonic-gate 		/*
3996*7c478bd9Sstevel@tonic-gate 		 * Get module name and look up in fmodsw.
3997*7c478bd9Sstevel@tonic-gate 		 */
3998*7c478bd9Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr :
3999*7c478bd9Sstevel@tonic-gate 		    copystr)(STRUCT_FGETP(strmodinsert, mod_name),
4000*7c478bd9Sstevel@tonic-gate 		    mod_name, FMNAMESZ + 1, NULL);
4001*7c478bd9Sstevel@tonic-gate 		if (error)
4002*7c478bd9Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
4003*7c478bd9Sstevel@tonic-gate 
4004*7c478bd9Sstevel@tonic-gate 		if ((fp = fmodsw_find(mod_name, FMODSW_HOLD | FMODSW_LOAD)) ==
4005*7c478bd9Sstevel@tonic-gate 		    NULL)
4006*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4007*7c478bd9Sstevel@tonic-gate 
4008*7c478bd9Sstevel@tonic-gate 		if (error = strstartplumb(stp, flag, cmd)) {
4009*7c478bd9Sstevel@tonic-gate 			fmodsw_rele(fp);
4010*7c478bd9Sstevel@tonic-gate 			return (error);
4011*7c478bd9Sstevel@tonic-gate 		}
4012*7c478bd9Sstevel@tonic-gate 
4013*7c478bd9Sstevel@tonic-gate 		/*
4014*7c478bd9Sstevel@tonic-gate 		 * Is this _I_INSERT just like an I_PUSH?  We need to know
4015*7c478bd9Sstevel@tonic-gate 		 * this because we do some optimizations if this is a
4016*7c478bd9Sstevel@tonic-gate 		 * module being pushed.
4017*7c478bd9Sstevel@tonic-gate 		 */
4018*7c478bd9Sstevel@tonic-gate 		pos = STRUCT_FGET(strmodinsert, pos);
4019*7c478bd9Sstevel@tonic-gate 		is_insert = (pos != 0);
4020*7c478bd9Sstevel@tonic-gate 
4021*7c478bd9Sstevel@tonic-gate 		/*
4022*7c478bd9Sstevel@tonic-gate 		 * Make sure pos is valid.  Even though it is not an I_PUSH,
4023*7c478bd9Sstevel@tonic-gate 		 * we impose the same limit on the number of modules in a
4024*7c478bd9Sstevel@tonic-gate 		 * stream.
4025*7c478bd9Sstevel@tonic-gate 		 */
4026*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4027*7c478bd9Sstevel@tonic-gate 		if (stp->sd_pushcnt >= nstrpush || pos < 0 ||
4028*7c478bd9Sstevel@tonic-gate 		    pos > stp->sd_pushcnt) {
4029*7c478bd9Sstevel@tonic-gate 			fmodsw_rele(fp);
4030*7c478bd9Sstevel@tonic-gate 			strendplumb(stp);
4031*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
4032*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4033*7c478bd9Sstevel@tonic-gate 		}
4034*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4035*7c478bd9Sstevel@tonic-gate 
4036*7c478bd9Sstevel@tonic-gate 		/*
4037*7c478bd9Sstevel@tonic-gate 		 * First find the correct position this module to
4038*7c478bd9Sstevel@tonic-gate 		 * be inserted.  We don't need to call claimstr()
4039*7c478bd9Sstevel@tonic-gate 		 * as the stream should not be changing at this point.
4040*7c478bd9Sstevel@tonic-gate 		 *
4041*7c478bd9Sstevel@tonic-gate 		 * Insert new module and call its open routine
4042*7c478bd9Sstevel@tonic-gate 		 * via qattach().  Modules don't change device
4043*7c478bd9Sstevel@tonic-gate 		 * numbers, so just ignore dummydev here.
4044*7c478bd9Sstevel@tonic-gate 		 */
4045*7c478bd9Sstevel@tonic-gate 		for (tmp_wrq = stp->sd_wrq; pos > 0;
4046*7c478bd9Sstevel@tonic-gate 		    tmp_wrq = tmp_wrq->q_next, pos--) {
4047*7c478bd9Sstevel@tonic-gate 			ASSERT(SAMESTR(tmp_wrq));
4048*7c478bd9Sstevel@tonic-gate 		}
4049*7c478bd9Sstevel@tonic-gate 		dummydev = vp->v_rdev;
4050*7c478bd9Sstevel@tonic-gate 		if ((error = qattach(_RD(tmp_wrq), &dummydev, 0, crp,
4051*7c478bd9Sstevel@tonic-gate 		    fp, is_insert)) != 0) {
4052*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
4053*7c478bd9Sstevel@tonic-gate 			strendplumb(stp);
4054*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
4055*7c478bd9Sstevel@tonic-gate 			return (error);
4056*7c478bd9Sstevel@tonic-gate 		}
4057*7c478bd9Sstevel@tonic-gate 		/*
4058*7c478bd9Sstevel@tonic-gate 		 * If flow control is on, don't break it - enable
4059*7c478bd9Sstevel@tonic-gate 		 * first back queue with svc procedure.
4060*7c478bd9Sstevel@tonic-gate 		 */
4061*7c478bd9Sstevel@tonic-gate 		if (_RD(tmp_wrq)->q_nfsrv->q_flag & QWANTW) {
4062*7c478bd9Sstevel@tonic-gate 			/*
4063*7c478bd9Sstevel@tonic-gate 			 * Note: no setqback here - use pri -1.
4064*7c478bd9Sstevel@tonic-gate 			 * tmp_wrq->q_next is the new module.  We need
4065*7c478bd9Sstevel@tonic-gate 			 * to backenable() the module below the new module.
4066*7c478bd9Sstevel@tonic-gate 			 */
4067*7c478bd9Sstevel@tonic-gate 			backenable(_RD(tmp_wrq->q_next->q_next), -1);
4068*7c478bd9Sstevel@tonic-gate 		}
4069*7c478bd9Sstevel@tonic-gate 
4070*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4071*7c478bd9Sstevel@tonic-gate 
4072*7c478bd9Sstevel@tonic-gate 		/*
4073*7c478bd9Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
4074*7c478bd9Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
4075*7c478bd9Sstevel@tonic-gate 		 * head in the stream head.
4076*7c478bd9Sstevel@tonic-gate 		 */
4077*7c478bd9Sstevel@tonic-gate 		if (!is_insert) {
4078*7c478bd9Sstevel@tonic-gate 			mutex_enter(QLOCK(stp->sd_wrq->q_next));
4079*7c478bd9Sstevel@tonic-gate 			rmin = stp->sd_wrq->q_next->q_minpsz;
4080*7c478bd9Sstevel@tonic-gate 			rmax = stp->sd_wrq->q_next->q_maxpsz;
4081*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(stp->sd_wrq->q_next));
4082*7c478bd9Sstevel@tonic-gate 
4083*7c478bd9Sstevel@tonic-gate 			/* Do this processing here as a performance concern */
4084*7c478bd9Sstevel@tonic-gate 			if (strmsgsz != 0) {
4085*7c478bd9Sstevel@tonic-gate 				if (rmax == INFPSZ) {
4086*7c478bd9Sstevel@tonic-gate 					rmax = strmsgsz;
4087*7c478bd9Sstevel@tonic-gate 				} else  {
4088*7c478bd9Sstevel@tonic-gate 					rmax = MIN(strmsgsz, rmax);
4089*7c478bd9Sstevel@tonic-gate 				}
4090*7c478bd9Sstevel@tonic-gate 			}
4091*7c478bd9Sstevel@tonic-gate 
4092*7c478bd9Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq));
4093*7c478bd9Sstevel@tonic-gate 			stp->sd_qn_minpsz = rmin;
4094*7c478bd9Sstevel@tonic-gate 			stp->sd_qn_maxpsz = rmax;
4095*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq));
4096*7c478bd9Sstevel@tonic-gate 		}
4097*7c478bd9Sstevel@tonic-gate 
4098*7c478bd9Sstevel@tonic-gate 		/*
4099*7c478bd9Sstevel@tonic-gate 		 * Need to update the anchor value if this module is
4100*7c478bd9Sstevel@tonic-gate 		 * inserted below the anchor point.
4101*7c478bd9Sstevel@tonic-gate 		 */
4102*7c478bd9Sstevel@tonic-gate 		if (stp->sd_anchor != 0) {
4103*7c478bd9Sstevel@tonic-gate 			pos = STRUCT_FGET(strmodinsert, pos);
4104*7c478bd9Sstevel@tonic-gate 			if (pos >= (stp->sd_pushcnt - stp->sd_anchor))
4105*7c478bd9Sstevel@tonic-gate 				stp->sd_anchor++;
4106*7c478bd9Sstevel@tonic-gate 		}
4107*7c478bd9Sstevel@tonic-gate 
4108*7c478bd9Sstevel@tonic-gate 		strendplumb(stp);
4109*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4110*7c478bd9Sstevel@tonic-gate 		return (0);
4111*7c478bd9Sstevel@tonic-gate 	}
4112*7c478bd9Sstevel@tonic-gate 
4113*7c478bd9Sstevel@tonic-gate 	case _I_REMOVE:
4114*7c478bd9Sstevel@tonic-gate 	{
4115*7c478bd9Sstevel@tonic-gate 		/*
4116*7c478bd9Sstevel@tonic-gate 		 * To remove a module with a given name in a stream.  The
4117*7c478bd9Sstevel@tonic-gate 		 * caller of this ioctl needs to provide both the name and
4118*7c478bd9Sstevel@tonic-gate 		 * the position of the module to be removed.  This eliminates
4119*7c478bd9Sstevel@tonic-gate 		 * the ambiguity of removal if a module is inserted/pushed
4120*7c478bd9Sstevel@tonic-gate 		 * multiple times in a stream.  In the first release, only
4121*7c478bd9Sstevel@tonic-gate 		 * allow privileged user to use this ioctl.
4122*7c478bd9Sstevel@tonic-gate 		 *
4123*7c478bd9Sstevel@tonic-gate 		 * Note that we do not plan to support this ioctl
4124*7c478bd9Sstevel@tonic-gate 		 * on pipes in the first release.  We want to learn more
4125*7c478bd9Sstevel@tonic-gate 		 * about the implications of these ioctls before extending
4126*7c478bd9Sstevel@tonic-gate 		 * their support.  And we do not think these features are
4127*7c478bd9Sstevel@tonic-gate 		 * valuable for pipes.
4128*7c478bd9Sstevel@tonic-gate 		 *
4129*7c478bd9Sstevel@tonic-gate 		 * Neither do we support O/C hot stream.  Note that only
4130*7c478bd9Sstevel@tonic-gate 		 * the upper streams of TCP/IP stack are O/C hot streams.
4131*7c478bd9Sstevel@tonic-gate 		 * The lower IP stream is not.
4132*7c478bd9Sstevel@tonic-gate 		 * When there is a O/C cold barrier we do not allow removal
4133*7c478bd9Sstevel@tonic-gate 		 * below the barrier.
4134*7c478bd9Sstevel@tonic-gate 		 *
4135*7c478bd9Sstevel@tonic-gate 		 * Also note that _I_REMOVE cannot be used to remove a
4136*7c478bd9Sstevel@tonic-gate 		 * driver or the stream head.
4137*7c478bd9Sstevel@tonic-gate 		 */
4138*7c478bd9Sstevel@tonic-gate 		STRUCT_DECL(strmodconf, strmodremove);
4139*7c478bd9Sstevel@tonic-gate 		queue_t	*q;
4140*7c478bd9Sstevel@tonic-gate 		int pos;
4141*7c478bd9Sstevel@tonic-gate 		char mod_name[FMNAMESZ + 1];
4142*7c478bd9Sstevel@tonic-gate 		boolean_t is_remove;
4143*7c478bd9Sstevel@tonic-gate 
4144*7c478bd9Sstevel@tonic-gate 		STRUCT_INIT(strmodremove, flag);
4145*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
4146*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
4147*7c478bd9Sstevel@tonic-gate 		if (STRMATED(stp))
4148*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4149*7c478bd9Sstevel@tonic-gate 		if ((error = secpolicy_net_config(crp, B_FALSE)) != 0)
4150*7c478bd9Sstevel@tonic-gate 			return (error);
4151*7c478bd9Sstevel@tonic-gate 
4152*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strmodremove),
4153*7c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strmodremove), copyflag);
4154*7c478bd9Sstevel@tonic-gate 		if (error)
4155*7c478bd9Sstevel@tonic-gate 			return (error);
4156*7c478bd9Sstevel@tonic-gate 
4157*7c478bd9Sstevel@tonic-gate 		error = (copyflag & U_TO_K ? copyinstr :
4158*7c478bd9Sstevel@tonic-gate 		    copystr)(STRUCT_FGETP(strmodremove, mod_name),
4159*7c478bd9Sstevel@tonic-gate 		    mod_name, FMNAMESZ + 1, NULL);
4160*7c478bd9Sstevel@tonic-gate 		if (error)
4161*7c478bd9Sstevel@tonic-gate 			return ((error == ENAMETOOLONG) ? EINVAL : EFAULT);
4162*7c478bd9Sstevel@tonic-gate 
4163*7c478bd9Sstevel@tonic-gate 		if ((error = strstartplumb(stp, flag, cmd)) != 0)
4164*7c478bd9Sstevel@tonic-gate 			return (error);
4165*7c478bd9Sstevel@tonic-gate 
4166*7c478bd9Sstevel@tonic-gate 		/*
4167*7c478bd9Sstevel@tonic-gate 		 * Match the name of given module to the name of module at
4168*7c478bd9Sstevel@tonic-gate 		 * the given position.
4169*7c478bd9Sstevel@tonic-gate 		 */
4170*7c478bd9Sstevel@tonic-gate 		pos = STRUCT_FGET(strmodremove, pos);
4171*7c478bd9Sstevel@tonic-gate 
4172*7c478bd9Sstevel@tonic-gate 		is_remove = (pos != 0);
4173*7c478bd9Sstevel@tonic-gate 		for (q = stp->sd_wrq->q_next; SAMESTR(q) && pos > 0;
4174*7c478bd9Sstevel@tonic-gate 		    q = q->q_next, pos--)
4175*7c478bd9Sstevel@tonic-gate 			;
4176*7c478bd9Sstevel@tonic-gate 		if (pos > 0 || ! SAMESTR(q) ||
4177*7c478bd9Sstevel@tonic-gate 		    strncmp(q->q_qinfo->qi_minfo->mi_idname, mod_name,
4178*7c478bd9Sstevel@tonic-gate 		    strlen(q->q_qinfo->qi_minfo->mi_idname)) != 0) {
4179*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
4180*7c478bd9Sstevel@tonic-gate 			strendplumb(stp);
4181*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
4182*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4183*7c478bd9Sstevel@tonic-gate 		}
4184*7c478bd9Sstevel@tonic-gate 
4185*7c478bd9Sstevel@tonic-gate 		ASSERT(!(q->q_flag & QREADR));
4186*7c478bd9Sstevel@tonic-gate 		qdetach(_RD(q), 1, flag, crp, is_remove);
4187*7c478bd9Sstevel@tonic-gate 
4188*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4189*7c478bd9Sstevel@tonic-gate 
4190*7c478bd9Sstevel@tonic-gate 		/*
4191*7c478bd9Sstevel@tonic-gate 		 * As a performance concern we are caching the values of
4192*7c478bd9Sstevel@tonic-gate 		 * q_minpsz and q_maxpsz of the module below the stream
4193*7c478bd9Sstevel@tonic-gate 		 * head in the stream head.
4194*7c478bd9Sstevel@tonic-gate 		 */
4195*7c478bd9Sstevel@tonic-gate 		if (!is_remove) {
4196*7c478bd9Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq->q_next));
4197*7c478bd9Sstevel@tonic-gate 			rmin = wrq->q_next->q_minpsz;
4198*7c478bd9Sstevel@tonic-gate 			rmax = wrq->q_next->q_maxpsz;
4199*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq->q_next));
4200*7c478bd9Sstevel@tonic-gate 
4201*7c478bd9Sstevel@tonic-gate 			/* Do this processing here as a performance concern */
4202*7c478bd9Sstevel@tonic-gate 			if (strmsgsz != 0) {
4203*7c478bd9Sstevel@tonic-gate 				if (rmax == INFPSZ)
4204*7c478bd9Sstevel@tonic-gate 					rmax = strmsgsz;
4205*7c478bd9Sstevel@tonic-gate 				else  {
4206*7c478bd9Sstevel@tonic-gate 					if (vp->v_type == VFIFO)
4207*7c478bd9Sstevel@tonic-gate 						rmax = MIN(PIPE_BUF, rmax);
4208*7c478bd9Sstevel@tonic-gate 					else	rmax = MIN(strmsgsz, rmax);
4209*7c478bd9Sstevel@tonic-gate 				}
4210*7c478bd9Sstevel@tonic-gate 			}
4211*7c478bd9Sstevel@tonic-gate 
4212*7c478bd9Sstevel@tonic-gate 			mutex_enter(QLOCK(wrq));
4213*7c478bd9Sstevel@tonic-gate 			stp->sd_qn_minpsz = rmin;
4214*7c478bd9Sstevel@tonic-gate 			stp->sd_qn_maxpsz = rmax;
4215*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(wrq));
4216*7c478bd9Sstevel@tonic-gate 		}
4217*7c478bd9Sstevel@tonic-gate 
4218*7c478bd9Sstevel@tonic-gate 		/*
4219*7c478bd9Sstevel@tonic-gate 		 * Need to update the anchor value if this module is removed
4220*7c478bd9Sstevel@tonic-gate 		 * at or below the anchor point.  If the removed module is at
4221*7c478bd9Sstevel@tonic-gate 		 * the anchor point, remove the anchor for this stream if
4222*7c478bd9Sstevel@tonic-gate 		 * there is no module above the anchor point.  Otherwise, if
4223*7c478bd9Sstevel@tonic-gate 		 * the removed module is below the anchor point, decrement the
4224*7c478bd9Sstevel@tonic-gate 		 * anchor point by 1.
4225*7c478bd9Sstevel@tonic-gate 		 */
4226*7c478bd9Sstevel@tonic-gate 		if (stp->sd_anchor != 0) {
4227*7c478bd9Sstevel@tonic-gate 			pos = STRUCT_FGET(strmodremove, pos);
4228*7c478bd9Sstevel@tonic-gate 			if (pos == 0)
4229*7c478bd9Sstevel@tonic-gate 				stp->sd_anchor = 0;
4230*7c478bd9Sstevel@tonic-gate 			else if (pos > (stp->sd_pushcnt - stp->sd_anchor + 1))
4231*7c478bd9Sstevel@tonic-gate 				stp->sd_anchor--;
4232*7c478bd9Sstevel@tonic-gate 		}
4233*7c478bd9Sstevel@tonic-gate 
4234*7c478bd9Sstevel@tonic-gate 		strendplumb(stp);
4235*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4236*7c478bd9Sstevel@tonic-gate 		return (0);
4237*7c478bd9Sstevel@tonic-gate 	}
4238*7c478bd9Sstevel@tonic-gate 
4239*7c478bd9Sstevel@tonic-gate 	case I_ANCHOR:
4240*7c478bd9Sstevel@tonic-gate 		/*
4241*7c478bd9Sstevel@tonic-gate 		 * Set the anchor position on the stream to reside at
4242*7c478bd9Sstevel@tonic-gate 		 * the top module (in other words, the top module
4243*7c478bd9Sstevel@tonic-gate 		 * cannot be popped).  Anchors with a FIFO make no
4244*7c478bd9Sstevel@tonic-gate 		 * obvious sense, so they're not allowed.
4245*7c478bd9Sstevel@tonic-gate 		 */
4246*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4247*7c478bd9Sstevel@tonic-gate 
4248*7c478bd9Sstevel@tonic-gate 		if (stp->sd_vnode->v_type == VFIFO) {
4249*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
4250*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4251*7c478bd9Sstevel@tonic-gate 		}
4252*7c478bd9Sstevel@tonic-gate 
4253*7c478bd9Sstevel@tonic-gate 		stp->sd_anchor = stp->sd_pushcnt;
4254*7c478bd9Sstevel@tonic-gate 
4255*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4256*7c478bd9Sstevel@tonic-gate 		return (0);
4257*7c478bd9Sstevel@tonic-gate 
4258*7c478bd9Sstevel@tonic-gate 	case I_LOOK:
4259*7c478bd9Sstevel@tonic-gate 		/*
4260*7c478bd9Sstevel@tonic-gate 		 * Get name of first module downstream.
4261*7c478bd9Sstevel@tonic-gate 		 * If no module, return an error.
4262*7c478bd9Sstevel@tonic-gate 		 */
4263*7c478bd9Sstevel@tonic-gate 	    {
4264*7c478bd9Sstevel@tonic-gate 		claimstr(wrq);
4265*7c478bd9Sstevel@tonic-gate 		if (_SAMESTR(wrq) && wrq->q_next->q_next) {
4266*7c478bd9Sstevel@tonic-gate 			char *name = wrq->q_next->q_qinfo->qi_minfo->mi_idname;
4267*7c478bd9Sstevel@tonic-gate 			error = strcopyout(name, (void *)arg, strlen(name) + 1,
4268*7c478bd9Sstevel@tonic-gate 			    copyflag);
4269*7c478bd9Sstevel@tonic-gate 			releasestr(wrq);
4270*7c478bd9Sstevel@tonic-gate 			return (error);
4271*7c478bd9Sstevel@tonic-gate 		}
4272*7c478bd9Sstevel@tonic-gate 		releasestr(wrq);
4273*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
4274*7c478bd9Sstevel@tonic-gate 	    }
4275*7c478bd9Sstevel@tonic-gate 
4276*7c478bd9Sstevel@tonic-gate 	case I_LINK:
4277*7c478bd9Sstevel@tonic-gate 	case I_PLINK:
4278*7c478bd9Sstevel@tonic-gate 		/*
4279*7c478bd9Sstevel@tonic-gate 		 * Link a multiplexor.
4280*7c478bd9Sstevel@tonic-gate 		 */
4281*7c478bd9Sstevel@tonic-gate 		return (mlink(vp, cmd, (int)arg, crp, rvalp, 0));
4282*7c478bd9Sstevel@tonic-gate 
4283*7c478bd9Sstevel@tonic-gate 	case _I_PLINK_LH:
4284*7c478bd9Sstevel@tonic-gate 		/*
4285*7c478bd9Sstevel@tonic-gate 		 * Link a multiplexor: Call must originate from kernel.
4286*7c478bd9Sstevel@tonic-gate 		 */
4287*7c478bd9Sstevel@tonic-gate 		if (kioctl)
4288*7c478bd9Sstevel@tonic-gate 			return (ldi_mlink_lh(vp, cmd, arg, crp, rvalp));
4289*7c478bd9Sstevel@tonic-gate 
4290*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
4291*7c478bd9Sstevel@tonic-gate 	case I_UNLINK:
4292*7c478bd9Sstevel@tonic-gate 	case I_PUNLINK:
4293*7c478bd9Sstevel@tonic-gate 		/*
4294*7c478bd9Sstevel@tonic-gate 		 * Unlink a multiplexor.
4295*7c478bd9Sstevel@tonic-gate 		 * If arg is -1, unlink all links for which this is the
4296*7c478bd9Sstevel@tonic-gate 		 * controlling stream.  Otherwise, arg is an index number
4297*7c478bd9Sstevel@tonic-gate 		 * for a link to be removed.
4298*7c478bd9Sstevel@tonic-gate 		 */
4299*7c478bd9Sstevel@tonic-gate 	    {
4300*7c478bd9Sstevel@tonic-gate 		struct linkinfo *linkp;
4301*7c478bd9Sstevel@tonic-gate 		int native_arg = (int)arg;
4302*7c478bd9Sstevel@tonic-gate 		int type;
4303*7c478bd9Sstevel@tonic-gate 
4304*7c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR,
4305*7c478bd9Sstevel@tonic-gate 			TR_I_UNLINK, "I_UNLINK/I_PUNLINK:%p", stp);
4306*7c478bd9Sstevel@tonic-gate 		if (vp->v_type == VFIFO) {
4307*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4308*7c478bd9Sstevel@tonic-gate 		}
4309*7c478bd9Sstevel@tonic-gate 		if (cmd == I_UNLINK)
4310*7c478bd9Sstevel@tonic-gate 			type = LINKNORMAL;
4311*7c478bd9Sstevel@tonic-gate 		else	/* I_PUNLINK */
4312*7c478bd9Sstevel@tonic-gate 			type = LINKPERSIST;
4313*7c478bd9Sstevel@tonic-gate 		if (native_arg == 0) {
4314*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4315*7c478bd9Sstevel@tonic-gate 		}
4316*7c478bd9Sstevel@tonic-gate 		if (native_arg == MUXID_ALL)
4317*7c478bd9Sstevel@tonic-gate 			error = munlinkall(stp, type, crp, rvalp);
4318*7c478bd9Sstevel@tonic-gate 		else {
4319*7c478bd9Sstevel@tonic-gate 			mutex_enter(&muxifier);
4320*7c478bd9Sstevel@tonic-gate 			if (!(linkp = findlinks(stp, (int)arg, type))) {
4321*7c478bd9Sstevel@tonic-gate 				/* invalid user supplied index number */
4322*7c478bd9Sstevel@tonic-gate 				mutex_exit(&muxifier);
4323*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4324*7c478bd9Sstevel@tonic-gate 			}
4325*7c478bd9Sstevel@tonic-gate 			/* munlink drops the muxifier lock */
4326*7c478bd9Sstevel@tonic-gate 			error = munlink(stp, linkp, type, crp, rvalp);
4327*7c478bd9Sstevel@tonic-gate 		}
4328*7c478bd9Sstevel@tonic-gate 		return (error);
4329*7c478bd9Sstevel@tonic-gate 	    }
4330*7c478bd9Sstevel@tonic-gate 
4331*7c478bd9Sstevel@tonic-gate 	case I_FLUSH:
4332*7c478bd9Sstevel@tonic-gate 		/*
4333*7c478bd9Sstevel@tonic-gate 		 * send a flush message downstream
4334*7c478bd9Sstevel@tonic-gate 		 * flush message can indicate
4335*7c478bd9Sstevel@tonic-gate 		 * FLUSHR - flush read queue
4336*7c478bd9Sstevel@tonic-gate 		 * FLUSHW - flush write queue
4337*7c478bd9Sstevel@tonic-gate 		 * FLUSHRW - flush read/write queue
4338*7c478bd9Sstevel@tonic-gate 		 */
4339*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
4340*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
4341*7c478bd9Sstevel@tonic-gate 		if (arg & ~FLUSHRW)
4342*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4343*7c478bd9Sstevel@tonic-gate 
4344*7c478bd9Sstevel@tonic-gate 		for (;;) {
4345*7c478bd9Sstevel@tonic-gate 			if (putnextctl1(stp->sd_wrq, M_FLUSH, (int)arg)) {
4346*7c478bd9Sstevel@tonic-gate 				break;
4347*7c478bd9Sstevel@tonic-gate 			}
4348*7c478bd9Sstevel@tonic-gate 			if (error = strwaitbuf(1, BPRI_HI)) {
4349*7c478bd9Sstevel@tonic-gate 				return (error);
4350*7c478bd9Sstevel@tonic-gate 			}
4351*7c478bd9Sstevel@tonic-gate 		}
4352*7c478bd9Sstevel@tonic-gate 
4353*7c478bd9Sstevel@tonic-gate 		/*
4354*7c478bd9Sstevel@tonic-gate 		 * Send down an unsupported ioctl and wait for the nack
4355*7c478bd9Sstevel@tonic-gate 		 * in order to allow the M_FLUSH to propagate back
4356*7c478bd9Sstevel@tonic-gate 		 * up to the stream head.
4357*7c478bd9Sstevel@tonic-gate 		 * Replaces if (qready()) runqueues();
4358*7c478bd9Sstevel@tonic-gate 		 */
4359*7c478bd9Sstevel@tonic-gate 		strioc.ic_cmd = -1;	/* The unsupported ioctl */
4360*7c478bd9Sstevel@tonic-gate 		strioc.ic_timout = 0;
4361*7c478bd9Sstevel@tonic-gate 		strioc.ic_len = 0;
4362*7c478bd9Sstevel@tonic-gate 		strioc.ic_dp = NULL;
4363*7c478bd9Sstevel@tonic-gate 		(void) strdoioctl(stp, &strioc, flag, K_TO_K, crp, rvalp);
4364*7c478bd9Sstevel@tonic-gate 		*rvalp = 0;
4365*7c478bd9Sstevel@tonic-gate 		return (0);
4366*7c478bd9Sstevel@tonic-gate 
4367*7c478bd9Sstevel@tonic-gate 	case I_FLUSHBAND:
4368*7c478bd9Sstevel@tonic-gate 	    {
4369*7c478bd9Sstevel@tonic-gate 		struct bandinfo binfo;
4370*7c478bd9Sstevel@tonic-gate 
4371*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, &binfo, sizeof (binfo),
4372*7c478bd9Sstevel@tonic-gate 		    copyflag);
4373*7c478bd9Sstevel@tonic-gate 		if (error)
4374*7c478bd9Sstevel@tonic-gate 			return (error);
4375*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
4376*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
4377*7c478bd9Sstevel@tonic-gate 		if (binfo.bi_flag & ~FLUSHRW)
4378*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4379*7c478bd9Sstevel@tonic-gate 		while (!(mp = allocb(2, BPRI_HI))) {
4380*7c478bd9Sstevel@tonic-gate 			if (error = strwaitbuf(2, BPRI_HI))
4381*7c478bd9Sstevel@tonic-gate 				return (error);
4382*7c478bd9Sstevel@tonic-gate 		}
4383*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_FLUSH;
4384*7c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = binfo.bi_flag | FLUSHBAND;
4385*7c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = binfo.bi_pri;
4386*7c478bd9Sstevel@tonic-gate 		putnext(stp->sd_wrq, mp);
4387*7c478bd9Sstevel@tonic-gate 		/*
4388*7c478bd9Sstevel@tonic-gate 		 * Send down an unsupported ioctl and wait for the nack
4389*7c478bd9Sstevel@tonic-gate 		 * in order to allow the M_FLUSH to propagate back
4390*7c478bd9Sstevel@tonic-gate 		 * up to the stream head.
4391*7c478bd9Sstevel@tonic-gate 		 * Replaces if (qready()) runqueues();
4392*7c478bd9Sstevel@tonic-gate 		 */
4393*7c478bd9Sstevel@tonic-gate 		strioc.ic_cmd = -1;	/* The unsupported ioctl */
4394*7c478bd9Sstevel@tonic-gate 		strioc.ic_timout = 0;
4395*7c478bd9Sstevel@tonic-gate 		strioc.ic_len = 0;
4396*7c478bd9Sstevel@tonic-gate 		strioc.ic_dp = NULL;
4397*7c478bd9Sstevel@tonic-gate 		(void) strdoioctl(stp, &strioc, flag, K_TO_K, crp, rvalp);
4398*7c478bd9Sstevel@tonic-gate 		*rvalp = 0;
4399*7c478bd9Sstevel@tonic-gate 		return (0);
4400*7c478bd9Sstevel@tonic-gate 	    }
4401*7c478bd9Sstevel@tonic-gate 
4402*7c478bd9Sstevel@tonic-gate 	case I_SRDOPT:
4403*7c478bd9Sstevel@tonic-gate 		/*
4404*7c478bd9Sstevel@tonic-gate 		 * Set read options
4405*7c478bd9Sstevel@tonic-gate 		 *
4406*7c478bd9Sstevel@tonic-gate 		 * RNORM - default stream mode
4407*7c478bd9Sstevel@tonic-gate 		 * RMSGN - message no discard
4408*7c478bd9Sstevel@tonic-gate 		 * RMSGD - message discard
4409*7c478bd9Sstevel@tonic-gate 		 * RPROTNORM - fail read with EBADMSG for M_[PC]PROTOs
4410*7c478bd9Sstevel@tonic-gate 		 * RPROTDAT - convert M_[PC]PROTOs to M_DATAs
4411*7c478bd9Sstevel@tonic-gate 		 * RPROTDIS - discard M_[PC]PROTOs and retain M_DATAs
4412*7c478bd9Sstevel@tonic-gate 		 */
4413*7c478bd9Sstevel@tonic-gate 		if (arg & ~(RMODEMASK | RPROTMASK))
4414*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4415*7c478bd9Sstevel@tonic-gate 
4416*7c478bd9Sstevel@tonic-gate 		if ((arg & (RMSGD|RMSGN)) == (RMSGD|RMSGN))
4417*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4418*7c478bd9Sstevel@tonic-gate 
4419*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4420*7c478bd9Sstevel@tonic-gate 		switch (arg & RMODEMASK) {
4421*7c478bd9Sstevel@tonic-gate 		case RNORM:
4422*7c478bd9Sstevel@tonic-gate 			stp->sd_read_opt &= ~(RD_MSGDIS | RD_MSGNODIS);
4423*7c478bd9Sstevel@tonic-gate 			break;
4424*7c478bd9Sstevel@tonic-gate 		case RMSGD:
4425*7c478bd9Sstevel@tonic-gate 			stp->sd_read_opt = (stp->sd_read_opt & ~RD_MSGNODIS) |
4426*7c478bd9Sstevel@tonic-gate 			    RD_MSGDIS;
4427*7c478bd9Sstevel@tonic-gate 			break;
4428*7c478bd9Sstevel@tonic-gate 		case RMSGN:
4429*7c478bd9Sstevel@tonic-gate 			stp->sd_read_opt = (stp->sd_read_opt & ~RD_MSGDIS) |
4430*7c478bd9Sstevel@tonic-gate 			    RD_MSGNODIS;
4431*7c478bd9Sstevel@tonic-gate 			break;
4432*7c478bd9Sstevel@tonic-gate 		}
4433*7c478bd9Sstevel@tonic-gate 
4434*7c478bd9Sstevel@tonic-gate 		switch (arg & RPROTMASK) {
4435*7c478bd9Sstevel@tonic-gate 		case RPROTNORM:
4436*7c478bd9Sstevel@tonic-gate 			stp->sd_read_opt &= ~(RD_PROTDAT | RD_PROTDIS);
4437*7c478bd9Sstevel@tonic-gate 			break;
4438*7c478bd9Sstevel@tonic-gate 
4439*7c478bd9Sstevel@tonic-gate 		case RPROTDAT:
4440*7c478bd9Sstevel@tonic-gate 			stp->sd_read_opt = ((stp->sd_read_opt & ~RD_PROTDIS) |
4441*7c478bd9Sstevel@tonic-gate 			    RD_PROTDAT);
4442*7c478bd9Sstevel@tonic-gate 			break;
4443*7c478bd9Sstevel@tonic-gate 
4444*7c478bd9Sstevel@tonic-gate 		case RPROTDIS:
4445*7c478bd9Sstevel@tonic-gate 			stp->sd_read_opt = ((stp->sd_read_opt & ~RD_PROTDAT) |
4446*7c478bd9Sstevel@tonic-gate 			    RD_PROTDIS);
4447*7c478bd9Sstevel@tonic-gate 			break;
4448*7c478bd9Sstevel@tonic-gate 		}
4449*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4450*7c478bd9Sstevel@tonic-gate 		return (0);
4451*7c478bd9Sstevel@tonic-gate 
4452*7c478bd9Sstevel@tonic-gate 	case I_GRDOPT:
4453*7c478bd9Sstevel@tonic-gate 		/*
4454*7c478bd9Sstevel@tonic-gate 		 * Get read option and return the value
4455*7c478bd9Sstevel@tonic-gate 		 * to spot pointed to by arg
4456*7c478bd9Sstevel@tonic-gate 		 */
4457*7c478bd9Sstevel@tonic-gate 	    {
4458*7c478bd9Sstevel@tonic-gate 		int rdopt;
4459*7c478bd9Sstevel@tonic-gate 
4460*7c478bd9Sstevel@tonic-gate 		rdopt = ((stp->sd_read_opt & RD_MSGDIS) ? RMSGD :
4461*7c478bd9Sstevel@tonic-gate 		    ((stp->sd_read_opt & RD_MSGNODIS) ? RMSGN : RNORM));
4462*7c478bd9Sstevel@tonic-gate 		rdopt |= ((stp->sd_read_opt & RD_PROTDAT) ? RPROTDAT :
4463*7c478bd9Sstevel@tonic-gate 		    ((stp->sd_read_opt & RD_PROTDIS) ? RPROTDIS : RPROTNORM));
4464*7c478bd9Sstevel@tonic-gate 
4465*7c478bd9Sstevel@tonic-gate 		return (strcopyout(&rdopt, (void *)arg, sizeof (int),
4466*7c478bd9Sstevel@tonic-gate 		    copyflag));
4467*7c478bd9Sstevel@tonic-gate 	    }
4468*7c478bd9Sstevel@tonic-gate 
4469*7c478bd9Sstevel@tonic-gate 	case I_SERROPT:
4470*7c478bd9Sstevel@tonic-gate 		/*
4471*7c478bd9Sstevel@tonic-gate 		 * Set error options
4472*7c478bd9Sstevel@tonic-gate 		 *
4473*7c478bd9Sstevel@tonic-gate 		 * RERRNORM - persistent read errors
4474*7c478bd9Sstevel@tonic-gate 		 * RERRNONPERSIST - non-persistent read errors
4475*7c478bd9Sstevel@tonic-gate 		 * WERRNORM - persistent write errors
4476*7c478bd9Sstevel@tonic-gate 		 * WERRNONPERSIST - non-persistent write errors
4477*7c478bd9Sstevel@tonic-gate 		 */
4478*7c478bd9Sstevel@tonic-gate 		if (arg & ~(RERRMASK | WERRMASK))
4479*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
4480*7c478bd9Sstevel@tonic-gate 
4481*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4482*7c478bd9Sstevel@tonic-gate 		switch (arg & RERRMASK) {
4483*7c478bd9Sstevel@tonic-gate 		case RERRNORM:
4484*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRDERRNONPERSIST;
4485*7c478bd9Sstevel@tonic-gate 			break;
4486*7c478bd9Sstevel@tonic-gate 		case RERRNONPERSIST:
4487*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= STRDERRNONPERSIST;
4488*7c478bd9Sstevel@tonic-gate 			break;
4489*7c478bd9Sstevel@tonic-gate 		}
4490*7c478bd9Sstevel@tonic-gate 		switch (arg & WERRMASK) {
4491*7c478bd9Sstevel@tonic-gate 		case WERRNORM:
4492*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STWRERRNONPERSIST;
4493*7c478bd9Sstevel@tonic-gate 			break;
4494*7c478bd9Sstevel@tonic-gate 		case WERRNONPERSIST:
4495*7c478bd9Sstevel@tonic-gate 			stp->sd_flag |= STWRERRNONPERSIST;
4496*7c478bd9Sstevel@tonic-gate 			break;
4497*7c478bd9Sstevel@tonic-gate 		}
4498*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4499*7c478bd9Sstevel@tonic-gate 		return (0);
4500*7c478bd9Sstevel@tonic-gate 
4501*7c478bd9Sstevel@tonic-gate 	case I_GERROPT:
4502*7c478bd9Sstevel@tonic-gate 		/*
4503*7c478bd9Sstevel@tonic-gate 		 * Get error option and return the value
4504*7c478bd9Sstevel@tonic-gate 		 * to spot pointed to by arg
4505*7c478bd9Sstevel@tonic-gate 		 */
4506*7c478bd9Sstevel@tonic-gate 	    {
4507*7c478bd9Sstevel@tonic-gate 		int erropt = 0;
4508*7c478bd9Sstevel@tonic-gate 
4509*7c478bd9Sstevel@tonic-gate 		erropt |= (stp->sd_flag & STRDERRNONPERSIST) ? RERRNONPERSIST :
4510*7c478bd9Sstevel@tonic-gate 			RERRNORM;
4511*7c478bd9Sstevel@tonic-gate 		erropt |= (stp->sd_flag & STWRERRNONPERSIST) ? WERRNONPERSIST :
4512*7c478bd9Sstevel@tonic-gate 			WERRNORM;
4513*7c478bd9Sstevel@tonic-gate 		return (strcopyout(&erropt, (void *)arg, sizeof (int),
4514*7c478bd9Sstevel@tonic-gate 		    copyflag));
4515*7c478bd9Sstevel@tonic-gate 	    }
4516*7c478bd9Sstevel@tonic-gate 
4517*7c478bd9Sstevel@tonic-gate 	case I_SETSIG:
4518*7c478bd9Sstevel@tonic-gate 		/*
4519*7c478bd9Sstevel@tonic-gate 		 * Register the calling proc to receive the SIGPOLL
4520*7c478bd9Sstevel@tonic-gate 		 * signal based on the events given in arg.  If
4521*7c478bd9Sstevel@tonic-gate 		 * arg is zero, remove the proc from register list.
4522*7c478bd9Sstevel@tonic-gate 		 */
4523*7c478bd9Sstevel@tonic-gate 	    {
4524*7c478bd9Sstevel@tonic-gate 		strsig_t *ssp, *pssp;
4525*7c478bd9Sstevel@tonic-gate 		struct pid *pidp;
4526*7c478bd9Sstevel@tonic-gate 
4527*7c478bd9Sstevel@tonic-gate 		pssp = NULL;
4528*7c478bd9Sstevel@tonic-gate 		pidp = curproc->p_pidp;
4529*7c478bd9Sstevel@tonic-gate 		/*
4530*7c478bd9Sstevel@tonic-gate 		 * Hold sd_lock to prevent traversal of sd_siglist while
4531*7c478bd9Sstevel@tonic-gate 		 * it is modified.
4532*7c478bd9Sstevel@tonic-gate 		 */
4533*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4534*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp && (ssp->ss_pidp != pidp);
4535*7c478bd9Sstevel@tonic-gate 			pssp = ssp, ssp = ssp->ss_next)
4536*7c478bd9Sstevel@tonic-gate 			;
4537*7c478bd9Sstevel@tonic-gate 
4538*7c478bd9Sstevel@tonic-gate 		if (arg) {
4539*7c478bd9Sstevel@tonic-gate 			if (arg & ~(S_INPUT|S_HIPRI|S_MSG|S_HANGUP|S_ERROR|
4540*7c478bd9Sstevel@tonic-gate 			    S_RDNORM|S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)) {
4541*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4542*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4543*7c478bd9Sstevel@tonic-gate 			}
4544*7c478bd9Sstevel@tonic-gate 			if ((arg & S_BANDURG) && !(arg & S_RDBAND)) {
4545*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4546*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4547*7c478bd9Sstevel@tonic-gate 			}
4548*7c478bd9Sstevel@tonic-gate 
4549*7c478bd9Sstevel@tonic-gate 			/*
4550*7c478bd9Sstevel@tonic-gate 			 * If proc not already registered, add it
4551*7c478bd9Sstevel@tonic-gate 			 * to list.
4552*7c478bd9Sstevel@tonic-gate 			 */
4553*7c478bd9Sstevel@tonic-gate 			if (!ssp) {
4554*7c478bd9Sstevel@tonic-gate 				ssp = kmem_alloc(sizeof (strsig_t), KM_SLEEP);
4555*7c478bd9Sstevel@tonic-gate 				ssp->ss_pidp = pidp;
4556*7c478bd9Sstevel@tonic-gate 				ssp->ss_pid = pidp->pid_id;
4557*7c478bd9Sstevel@tonic-gate 				ssp->ss_next = NULL;
4558*7c478bd9Sstevel@tonic-gate 				if (pssp)
4559*7c478bd9Sstevel@tonic-gate 					pssp->ss_next = ssp;
4560*7c478bd9Sstevel@tonic-gate 				else
4561*7c478bd9Sstevel@tonic-gate 					stp->sd_siglist = ssp;
4562*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4563*7c478bd9Sstevel@tonic-gate 				PID_HOLD(pidp);
4564*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4565*7c478bd9Sstevel@tonic-gate 			}
4566*7c478bd9Sstevel@tonic-gate 
4567*7c478bd9Sstevel@tonic-gate 			/*
4568*7c478bd9Sstevel@tonic-gate 			 * Set events.
4569*7c478bd9Sstevel@tonic-gate 			 */
4570*7c478bd9Sstevel@tonic-gate 			ssp->ss_events = (int)arg;
4571*7c478bd9Sstevel@tonic-gate 		} else {
4572*7c478bd9Sstevel@tonic-gate 			/*
4573*7c478bd9Sstevel@tonic-gate 			 * Remove proc from register list.
4574*7c478bd9Sstevel@tonic-gate 			 */
4575*7c478bd9Sstevel@tonic-gate 			if (ssp) {
4576*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4577*7c478bd9Sstevel@tonic-gate 				PID_RELE(pidp);
4578*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4579*7c478bd9Sstevel@tonic-gate 				if (pssp)
4580*7c478bd9Sstevel@tonic-gate 					pssp->ss_next = ssp->ss_next;
4581*7c478bd9Sstevel@tonic-gate 				else
4582*7c478bd9Sstevel@tonic-gate 					stp->sd_siglist = ssp->ss_next;
4583*7c478bd9Sstevel@tonic-gate 				kmem_free(ssp, sizeof (strsig_t));
4584*7c478bd9Sstevel@tonic-gate 			} else {
4585*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4586*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4587*7c478bd9Sstevel@tonic-gate 			}
4588*7c478bd9Sstevel@tonic-gate 		}
4589*7c478bd9Sstevel@tonic-gate 
4590*7c478bd9Sstevel@tonic-gate 		/*
4591*7c478bd9Sstevel@tonic-gate 		 * Recalculate OR of sig events.
4592*7c478bd9Sstevel@tonic-gate 		 */
4593*7c478bd9Sstevel@tonic-gate 		stp->sd_sigflags = 0;
4594*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
4595*7c478bd9Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
4596*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4597*7c478bd9Sstevel@tonic-gate 		return (0);
4598*7c478bd9Sstevel@tonic-gate 	    }
4599*7c478bd9Sstevel@tonic-gate 
4600*7c478bd9Sstevel@tonic-gate 	case I_GETSIG:
4601*7c478bd9Sstevel@tonic-gate 		/*
4602*7c478bd9Sstevel@tonic-gate 		 * Return (in arg) the current registration of events
4603*7c478bd9Sstevel@tonic-gate 		 * for which the calling proc is to be signaled.
4604*7c478bd9Sstevel@tonic-gate 		 */
4605*7c478bd9Sstevel@tonic-gate 	    {
4606*7c478bd9Sstevel@tonic-gate 		struct strsig *ssp;
4607*7c478bd9Sstevel@tonic-gate 		struct pid  *pidp;
4608*7c478bd9Sstevel@tonic-gate 
4609*7c478bd9Sstevel@tonic-gate 		pidp = curproc->p_pidp;
4610*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4611*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
4612*7c478bd9Sstevel@tonic-gate 			if (ssp->ss_pidp == pidp) {
4613*7c478bd9Sstevel@tonic-gate 				error = strcopyout(&ssp->ss_events, (void *)arg,
4614*7c478bd9Sstevel@tonic-gate 				    sizeof (int), copyflag);
4615*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4616*7c478bd9Sstevel@tonic-gate 				return (error);
4617*7c478bd9Sstevel@tonic-gate 			}
4618*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4619*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
4620*7c478bd9Sstevel@tonic-gate 	    }
4621*7c478bd9Sstevel@tonic-gate 
4622*7c478bd9Sstevel@tonic-gate 	case I_ESETSIG:
4623*7c478bd9Sstevel@tonic-gate 		/*
4624*7c478bd9Sstevel@tonic-gate 		 * Register the ss_pid to receive the SIGPOLL
4625*7c478bd9Sstevel@tonic-gate 		 * signal based on the events is ss_events arg.  If
4626*7c478bd9Sstevel@tonic-gate 		 * ss_events is zero, remove the proc from register list.
4627*7c478bd9Sstevel@tonic-gate 		 */
4628*7c478bd9Sstevel@tonic-gate 	{
4629*7c478bd9Sstevel@tonic-gate 		struct strsig *ssp, *pssp;
4630*7c478bd9Sstevel@tonic-gate 		struct proc *proc;
4631*7c478bd9Sstevel@tonic-gate 		struct pid  *pidp;
4632*7c478bd9Sstevel@tonic-gate 		pid_t pid;
4633*7c478bd9Sstevel@tonic-gate 		struct strsigset ss;
4634*7c478bd9Sstevel@tonic-gate 
4635*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, &ss, sizeof (ss), copyflag);
4636*7c478bd9Sstevel@tonic-gate 		if (error)
4637*7c478bd9Sstevel@tonic-gate 			return (error);
4638*7c478bd9Sstevel@tonic-gate 
4639*7c478bd9Sstevel@tonic-gate 		pid = ss.ss_pid;
4640*7c478bd9Sstevel@tonic-gate 
4641*7c478bd9Sstevel@tonic-gate 		if (ss.ss_events != 0) {
4642*7c478bd9Sstevel@tonic-gate 			/*
4643*7c478bd9Sstevel@tonic-gate 			 * Permissions check by sending signal 0.
4644*7c478bd9Sstevel@tonic-gate 			 * Note that when kill fails it does a set_errno
4645*7c478bd9Sstevel@tonic-gate 			 * causing the system call to fail.
4646*7c478bd9Sstevel@tonic-gate 			 */
4647*7c478bd9Sstevel@tonic-gate 			error = kill(pid, 0);
4648*7c478bd9Sstevel@tonic-gate 			if (error) {
4649*7c478bd9Sstevel@tonic-gate 				return (error);
4650*7c478bd9Sstevel@tonic-gate 			}
4651*7c478bd9Sstevel@tonic-gate 		}
4652*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
4653*7c478bd9Sstevel@tonic-gate 		if (pid == 0)
4654*7c478bd9Sstevel@tonic-gate 			proc = curproc;
4655*7c478bd9Sstevel@tonic-gate 		else if (pid < 0)
4656*7c478bd9Sstevel@tonic-gate 			proc = pgfind(-pid);
4657*7c478bd9Sstevel@tonic-gate 		else
4658*7c478bd9Sstevel@tonic-gate 			proc = prfind(pid);
4659*7c478bd9Sstevel@tonic-gate 		if (proc == NULL) {
4660*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
4661*7c478bd9Sstevel@tonic-gate 			return (ESRCH);
4662*7c478bd9Sstevel@tonic-gate 		}
4663*7c478bd9Sstevel@tonic-gate 		if (pid < 0)
4664*7c478bd9Sstevel@tonic-gate 			pidp = proc->p_pgidp;
4665*7c478bd9Sstevel@tonic-gate 		else
4666*7c478bd9Sstevel@tonic-gate 			pidp = proc->p_pidp;
4667*7c478bd9Sstevel@tonic-gate 		ASSERT(pidp);
4668*7c478bd9Sstevel@tonic-gate 		/*
4669*7c478bd9Sstevel@tonic-gate 		 * Get a hold on the pid structure while referencing it.
4670*7c478bd9Sstevel@tonic-gate 		 * There is a separate PID_HOLD should it be inserted
4671*7c478bd9Sstevel@tonic-gate 		 * in the list below.
4672*7c478bd9Sstevel@tonic-gate 		 */
4673*7c478bd9Sstevel@tonic-gate 		PID_HOLD(pidp);
4674*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
4675*7c478bd9Sstevel@tonic-gate 
4676*7c478bd9Sstevel@tonic-gate 		pssp = NULL;
4677*7c478bd9Sstevel@tonic-gate 		/*
4678*7c478bd9Sstevel@tonic-gate 		 * Hold sd_lock to prevent traversal of sd_siglist while
4679*7c478bd9Sstevel@tonic-gate 		 * it is modified.
4680*7c478bd9Sstevel@tonic-gate 		 */
4681*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4682*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp && (ssp->ss_pid != pid);
4683*7c478bd9Sstevel@tonic-gate 				pssp = ssp, ssp = ssp->ss_next)
4684*7c478bd9Sstevel@tonic-gate 			;
4685*7c478bd9Sstevel@tonic-gate 
4686*7c478bd9Sstevel@tonic-gate 		if (ss.ss_events) {
4687*7c478bd9Sstevel@tonic-gate 			if (ss.ss_events &
4688*7c478bd9Sstevel@tonic-gate 			    ~(S_INPUT|S_HIPRI|S_MSG|S_HANGUP|S_ERROR|
4689*7c478bd9Sstevel@tonic-gate 			    S_RDNORM|S_WRNORM|S_RDBAND|S_WRBAND|S_BANDURG)) {
4690*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4691*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4692*7c478bd9Sstevel@tonic-gate 				PID_RELE(pidp);
4693*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4694*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4695*7c478bd9Sstevel@tonic-gate 			}
4696*7c478bd9Sstevel@tonic-gate 			if ((ss.ss_events & S_BANDURG) &&
4697*7c478bd9Sstevel@tonic-gate 			    !(ss.ss_events & S_RDBAND)) {
4698*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4699*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4700*7c478bd9Sstevel@tonic-gate 				PID_RELE(pidp);
4701*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4702*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4703*7c478bd9Sstevel@tonic-gate 			}
4704*7c478bd9Sstevel@tonic-gate 
4705*7c478bd9Sstevel@tonic-gate 			/*
4706*7c478bd9Sstevel@tonic-gate 			 * If proc not already registered, add it
4707*7c478bd9Sstevel@tonic-gate 			 * to list.
4708*7c478bd9Sstevel@tonic-gate 			 */
4709*7c478bd9Sstevel@tonic-gate 			if (!ssp) {
4710*7c478bd9Sstevel@tonic-gate 				ssp = kmem_alloc(sizeof (strsig_t), KM_SLEEP);
4711*7c478bd9Sstevel@tonic-gate 				ssp->ss_pidp = pidp;
4712*7c478bd9Sstevel@tonic-gate 				ssp->ss_pid = pid;
4713*7c478bd9Sstevel@tonic-gate 				ssp->ss_next = NULL;
4714*7c478bd9Sstevel@tonic-gate 				if (pssp)
4715*7c478bd9Sstevel@tonic-gate 					pssp->ss_next = ssp;
4716*7c478bd9Sstevel@tonic-gate 				else
4717*7c478bd9Sstevel@tonic-gate 					stp->sd_siglist = ssp;
4718*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4719*7c478bd9Sstevel@tonic-gate 				PID_HOLD(pidp);
4720*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4721*7c478bd9Sstevel@tonic-gate 			}
4722*7c478bd9Sstevel@tonic-gate 
4723*7c478bd9Sstevel@tonic-gate 			/*
4724*7c478bd9Sstevel@tonic-gate 			 * Set events.
4725*7c478bd9Sstevel@tonic-gate 			 */
4726*7c478bd9Sstevel@tonic-gate 			ssp->ss_events = ss.ss_events;
4727*7c478bd9Sstevel@tonic-gate 		} else {
4728*7c478bd9Sstevel@tonic-gate 			/*
4729*7c478bd9Sstevel@tonic-gate 			 * Remove proc from register list.
4730*7c478bd9Sstevel@tonic-gate 			 */
4731*7c478bd9Sstevel@tonic-gate 			if (ssp) {
4732*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4733*7c478bd9Sstevel@tonic-gate 				PID_RELE(pidp);
4734*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4735*7c478bd9Sstevel@tonic-gate 				if (pssp)
4736*7c478bd9Sstevel@tonic-gate 					pssp->ss_next = ssp->ss_next;
4737*7c478bd9Sstevel@tonic-gate 				else
4738*7c478bd9Sstevel@tonic-gate 					stp->sd_siglist = ssp->ss_next;
4739*7c478bd9Sstevel@tonic-gate 				kmem_free(ssp, sizeof (strsig_t));
4740*7c478bd9Sstevel@tonic-gate 			} else {
4741*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4742*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4743*7c478bd9Sstevel@tonic-gate 				PID_RELE(pidp);
4744*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4745*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
4746*7c478bd9Sstevel@tonic-gate 			}
4747*7c478bd9Sstevel@tonic-gate 		}
4748*7c478bd9Sstevel@tonic-gate 
4749*7c478bd9Sstevel@tonic-gate 		/*
4750*7c478bd9Sstevel@tonic-gate 		 * Recalculate OR of sig events.
4751*7c478bd9Sstevel@tonic-gate 		 */
4752*7c478bd9Sstevel@tonic-gate 		stp->sd_sigflags = 0;
4753*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
4754*7c478bd9Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
4755*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4756*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
4757*7c478bd9Sstevel@tonic-gate 		PID_RELE(pidp);
4758*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
4759*7c478bd9Sstevel@tonic-gate 		return (0);
4760*7c478bd9Sstevel@tonic-gate 	    }
4761*7c478bd9Sstevel@tonic-gate 
4762*7c478bd9Sstevel@tonic-gate 	case I_EGETSIG:
4763*7c478bd9Sstevel@tonic-gate 		/*
4764*7c478bd9Sstevel@tonic-gate 		 * Return (in arg) the current registration of events
4765*7c478bd9Sstevel@tonic-gate 		 * for which the calling proc is to be signaled.
4766*7c478bd9Sstevel@tonic-gate 		 */
4767*7c478bd9Sstevel@tonic-gate 	    {
4768*7c478bd9Sstevel@tonic-gate 		struct strsig *ssp;
4769*7c478bd9Sstevel@tonic-gate 		struct proc *proc;
4770*7c478bd9Sstevel@tonic-gate 		pid_t pid;
4771*7c478bd9Sstevel@tonic-gate 		struct pid  *pidp;
4772*7c478bd9Sstevel@tonic-gate 		struct strsigset ss;
4773*7c478bd9Sstevel@tonic-gate 
4774*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, &ss, sizeof (ss), copyflag);
4775*7c478bd9Sstevel@tonic-gate 		if (error)
4776*7c478bd9Sstevel@tonic-gate 			return (error);
4777*7c478bd9Sstevel@tonic-gate 
4778*7c478bd9Sstevel@tonic-gate 		pid = ss.ss_pid;
4779*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
4780*7c478bd9Sstevel@tonic-gate 		if (pid == 0)
4781*7c478bd9Sstevel@tonic-gate 			proc = curproc;
4782*7c478bd9Sstevel@tonic-gate 		else if (pid < 0)
4783*7c478bd9Sstevel@tonic-gate 			proc = pgfind(-pid);
4784*7c478bd9Sstevel@tonic-gate 		else
4785*7c478bd9Sstevel@tonic-gate 			proc = prfind(pid);
4786*7c478bd9Sstevel@tonic-gate 		if (proc == NULL) {
4787*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
4788*7c478bd9Sstevel@tonic-gate 			return (ESRCH);
4789*7c478bd9Sstevel@tonic-gate 		}
4790*7c478bd9Sstevel@tonic-gate 		if (pid < 0)
4791*7c478bd9Sstevel@tonic-gate 			pidp = proc->p_pgidp;
4792*7c478bd9Sstevel@tonic-gate 		else
4793*7c478bd9Sstevel@tonic-gate 			pidp = proc->p_pidp;
4794*7c478bd9Sstevel@tonic-gate 
4795*7c478bd9Sstevel@tonic-gate 		/* Prevent the pidp from being reassigned */
4796*7c478bd9Sstevel@tonic-gate 		PID_HOLD(pidp);
4797*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
4798*7c478bd9Sstevel@tonic-gate 
4799*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
4800*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
4801*7c478bd9Sstevel@tonic-gate 			if (ssp->ss_pid == pid) {
4802*7c478bd9Sstevel@tonic-gate 				ss.ss_pid = ssp->ss_pid;
4803*7c478bd9Sstevel@tonic-gate 				ss.ss_events = ssp->ss_events;
4804*7c478bd9Sstevel@tonic-gate 				error = strcopyout(&ss, (void *)arg,
4805*7c478bd9Sstevel@tonic-gate 				    sizeof (struct strsigset), copyflag);
4806*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
4807*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
4808*7c478bd9Sstevel@tonic-gate 				PID_RELE(pidp);
4809*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
4810*7c478bd9Sstevel@tonic-gate 				return (error);
4811*7c478bd9Sstevel@tonic-gate 			}
4812*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
4813*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
4814*7c478bd9Sstevel@tonic-gate 		PID_RELE(pidp);
4815*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
4816*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
4817*7c478bd9Sstevel@tonic-gate 	    }
4818*7c478bd9Sstevel@tonic-gate 
4819*7c478bd9Sstevel@tonic-gate 	case I_PEEK:
4820*7c478bd9Sstevel@tonic-gate 	    {
4821*7c478bd9Sstevel@tonic-gate 		STRUCT_DECL(strpeek, strpeek);
4822*7c478bd9Sstevel@tonic-gate 		size_t n;
4823*7c478bd9Sstevel@tonic-gate 		mblk_t *fmp, *tmp_mp = NULL;
4824*7c478bd9Sstevel@tonic-gate 
4825*7c478bd9Sstevel@tonic-gate 		STRUCT_INIT(strpeek, flag);
4826*7c478bd9Sstevel@tonic-gate 
4827*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strpeek),
4828*7c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek), copyflag);
4829*7c478bd9Sstevel@tonic-gate 		if (error)
4830*7c478bd9Sstevel@tonic-gate 			return (error);
4831*7c478bd9Sstevel@tonic-gate 
4832*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(rdq));
4833*7c478bd9Sstevel@tonic-gate 		/*
4834*7c478bd9Sstevel@tonic-gate 		 * Skip the invalid messages
4835*7c478bd9Sstevel@tonic-gate 		 */
4836*7c478bd9Sstevel@tonic-gate 		for (mp = rdq->q_first; mp != NULL; mp = mp->b_next)
4837*7c478bd9Sstevel@tonic-gate 			if (mp->b_datap->db_type != M_SIG)
4838*7c478bd9Sstevel@tonic-gate 				break;
4839*7c478bd9Sstevel@tonic-gate 
4840*7c478bd9Sstevel@tonic-gate 		/*
4841*7c478bd9Sstevel@tonic-gate 		 * If user has requested to peek at a high priority message
4842*7c478bd9Sstevel@tonic-gate 		 * and first message is not, return 0
4843*7c478bd9Sstevel@tonic-gate 		 */
4844*7c478bd9Sstevel@tonic-gate 		if (mp != NULL) {
4845*7c478bd9Sstevel@tonic-gate 			if ((STRUCT_FGET(strpeek, flags) & RS_HIPRI) &&
4846*7c478bd9Sstevel@tonic-gate 			    queclass(mp) == QNORM) {
4847*7c478bd9Sstevel@tonic-gate 				*rvalp = 0;
4848*7c478bd9Sstevel@tonic-gate 				mutex_exit(QLOCK(rdq));
4849*7c478bd9Sstevel@tonic-gate 				return (0);
4850*7c478bd9Sstevel@tonic-gate 			}
4851*7c478bd9Sstevel@tonic-gate 		} else if (stp->sd_struiordq == NULL ||
4852*7c478bd9Sstevel@tonic-gate 		    (STRUCT_FGET(strpeek, flags) & RS_HIPRI)) {
4853*7c478bd9Sstevel@tonic-gate 			/*
4854*7c478bd9Sstevel@tonic-gate 			 * No mblks to look at at the streamhead and
4855*7c478bd9Sstevel@tonic-gate 			 * 1). This isn't a synch stream or
4856*7c478bd9Sstevel@tonic-gate 			 * 2). This is a synch stream but caller wants high
4857*7c478bd9Sstevel@tonic-gate 			 *	priority messages which is not supported by
4858*7c478bd9Sstevel@tonic-gate 			 *	the synch stream. (it only supports QNORM)
4859*7c478bd9Sstevel@tonic-gate 			 */
4860*7c478bd9Sstevel@tonic-gate 			*rvalp = 0;
4861*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
4862*7c478bd9Sstevel@tonic-gate 			return (0);
4863*7c478bd9Sstevel@tonic-gate 		}
4864*7c478bd9Sstevel@tonic-gate 
4865*7c478bd9Sstevel@tonic-gate 		fmp = mp;
4866*7c478bd9Sstevel@tonic-gate 
4867*7c478bd9Sstevel@tonic-gate 		if (mp && mp->b_datap->db_type == M_PASSFP) {
4868*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
4869*7c478bd9Sstevel@tonic-gate 			return (EBADMSG);
4870*7c478bd9Sstevel@tonic-gate 		}
4871*7c478bd9Sstevel@tonic-gate 
4872*7c478bd9Sstevel@tonic-gate 		ASSERT(mp == NULL || mp->b_datap->db_type == M_PCPROTO ||
4873*7c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type == M_PROTO ||
4874*7c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type == M_DATA);
4875*7c478bd9Sstevel@tonic-gate 
4876*7c478bd9Sstevel@tonic-gate 		if (mp && mp->b_datap->db_type == M_PCPROTO) {
4877*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, flags, RS_HIPRI);
4878*7c478bd9Sstevel@tonic-gate 		} else {
4879*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, flags, 0);
4880*7c478bd9Sstevel@tonic-gate 		}
4881*7c478bd9Sstevel@tonic-gate 
4882*7c478bd9Sstevel@tonic-gate 
4883*7c478bd9Sstevel@tonic-gate 		if (mp && ((tmp_mp = dupmsg(mp)) == NULL)) {
4884*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(rdq));
4885*7c478bd9Sstevel@tonic-gate 			return (ENOSR);
4886*7c478bd9Sstevel@tonic-gate 		}
4887*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(rdq));
4888*7c478bd9Sstevel@tonic-gate 
4889*7c478bd9Sstevel@tonic-gate 		/*
4890*7c478bd9Sstevel@tonic-gate 		 * set mp = tmp_mp, so that I_PEEK processing can continue.
4891*7c478bd9Sstevel@tonic-gate 		 * tmp_mp is used to free the dup'd message.
4892*7c478bd9Sstevel@tonic-gate 		 */
4893*7c478bd9Sstevel@tonic-gate 		mp = tmp_mp;
4894*7c478bd9Sstevel@tonic-gate 
4895*7c478bd9Sstevel@tonic-gate 		uio.uio_fmode = 0;
4896*7c478bd9Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
4897*7c478bd9Sstevel@tonic-gate 		uio.uio_segflg = (copyflag == U_TO_K) ? UIO_USERSPACE :
4898*7c478bd9Sstevel@tonic-gate 		    UIO_SYSSPACE;
4899*7c478bd9Sstevel@tonic-gate 		uio.uio_limit = 0;
4900*7c478bd9Sstevel@tonic-gate 		/*
4901*7c478bd9Sstevel@tonic-gate 		 * First process PROTO blocks, if any.
4902*7c478bd9Sstevel@tonic-gate 		 * If user doesn't want to get ctl info by setting maxlen <= 0,
4903*7c478bd9Sstevel@tonic-gate 		 * then set len to -1/0 and skip control blocks part.
4904*7c478bd9Sstevel@tonic-gate 		 */
4905*7c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, ctlbuf.maxlen) < 0)
4906*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, ctlbuf.len, -1);
4907*7c478bd9Sstevel@tonic-gate 		else if (STRUCT_FGET(strpeek, ctlbuf.maxlen) == 0)
4908*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, ctlbuf.len, 0);
4909*7c478bd9Sstevel@tonic-gate 		else {
4910*7c478bd9Sstevel@tonic-gate 			int	ctl_part = 0;
4911*7c478bd9Sstevel@tonic-gate 
4912*7c478bd9Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, ctlbuf.buf);
4913*7c478bd9Sstevel@tonic-gate 			iov.iov_len = STRUCT_FGET(strpeek, ctlbuf.maxlen);
4914*7c478bd9Sstevel@tonic-gate 			uio.uio_iov = &iov;
4915*7c478bd9Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
4916*7c478bd9Sstevel@tonic-gate 			uio.uio_loffset = 0;
4917*7c478bd9Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
4918*7c478bd9Sstevel@tonic-gate 			while (mp && mp->b_datap->db_type != M_DATA &&
4919*7c478bd9Sstevel@tonic-gate 			    uio.uio_resid >= 0) {
4920*7c478bd9Sstevel@tonic-gate 				ASSERT(STRUCT_FGET(strpeek, flags) == 0 ?
4921*7c478bd9Sstevel@tonic-gate 				    mp->b_datap->db_type == M_PROTO :
4922*7c478bd9Sstevel@tonic-gate 				    mp->b_datap->db_type == M_PCPROTO);
4923*7c478bd9Sstevel@tonic-gate 
4924*7c478bd9Sstevel@tonic-gate 				if ((n = MIN(uio.uio_resid,
4925*7c478bd9Sstevel@tonic-gate 				    mp->b_wptr - mp->b_rptr)) != 0 &&
4926*7c478bd9Sstevel@tonic-gate 				    (error = uiomove((char *)mp->b_rptr, n,
4927*7c478bd9Sstevel@tonic-gate 				    UIO_READ, &uio)) != 0) {
4928*7c478bd9Sstevel@tonic-gate 					freemsg(tmp_mp);
4929*7c478bd9Sstevel@tonic-gate 					return (error);
4930*7c478bd9Sstevel@tonic-gate 				}
4931*7c478bd9Sstevel@tonic-gate 				ctl_part = 1;
4932*7c478bd9Sstevel@tonic-gate 				mp = mp->b_cont;
4933*7c478bd9Sstevel@tonic-gate 			}
4934*7c478bd9Sstevel@tonic-gate 			/* No ctl message */
4935*7c478bd9Sstevel@tonic-gate 			if (ctl_part == 0)
4936*7c478bd9Sstevel@tonic-gate 				STRUCT_FSET(strpeek, ctlbuf.len, -1);
4937*7c478bd9Sstevel@tonic-gate 			else
4938*7c478bd9Sstevel@tonic-gate 				STRUCT_FSET(strpeek, ctlbuf.len,
4939*7c478bd9Sstevel@tonic-gate 				    STRUCT_FGET(strpeek, ctlbuf.maxlen) -
4940*7c478bd9Sstevel@tonic-gate 				    uio.uio_resid);
4941*7c478bd9Sstevel@tonic-gate 		}
4942*7c478bd9Sstevel@tonic-gate 
4943*7c478bd9Sstevel@tonic-gate 		/*
4944*7c478bd9Sstevel@tonic-gate 		 * Now process DATA blocks, if any.
4945*7c478bd9Sstevel@tonic-gate 		 * If user doesn't want to get data info by setting maxlen <= 0,
4946*7c478bd9Sstevel@tonic-gate 		 * then set len to -1/0 and skip data blocks part.
4947*7c478bd9Sstevel@tonic-gate 		 */
4948*7c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, databuf.maxlen) < 0)
4949*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, -1);
4950*7c478bd9Sstevel@tonic-gate 		else if (STRUCT_FGET(strpeek, databuf.maxlen) == 0)
4951*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, 0);
4952*7c478bd9Sstevel@tonic-gate 		else {
4953*7c478bd9Sstevel@tonic-gate 			int	data_part = 0;
4954*7c478bd9Sstevel@tonic-gate 
4955*7c478bd9Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, databuf.buf);
4956*7c478bd9Sstevel@tonic-gate 			iov.iov_len = STRUCT_FGET(strpeek, databuf.maxlen);
4957*7c478bd9Sstevel@tonic-gate 			uio.uio_iov = &iov;
4958*7c478bd9Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
4959*7c478bd9Sstevel@tonic-gate 			uio.uio_loffset = 0;
4960*7c478bd9Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
4961*7c478bd9Sstevel@tonic-gate 			while (mp && uio.uio_resid) {
4962*7c478bd9Sstevel@tonic-gate 				if (mp->b_datap->db_type == M_DATA) {
4963*7c478bd9Sstevel@tonic-gate 					if ((n = MIN(uio.uio_resid,
4964*7c478bd9Sstevel@tonic-gate 					    mp->b_wptr - mp->b_rptr)) != 0 &&
4965*7c478bd9Sstevel@tonic-gate 					    (error = uiomove((char *)mp->b_rptr,
4966*7c478bd9Sstevel@tonic-gate 						n, UIO_READ, &uio)) != 0) {
4967*7c478bd9Sstevel@tonic-gate 						freemsg(tmp_mp);
4968*7c478bd9Sstevel@tonic-gate 						return (error);
4969*7c478bd9Sstevel@tonic-gate 					}
4970*7c478bd9Sstevel@tonic-gate 					data_part = 1;
4971*7c478bd9Sstevel@tonic-gate 				}
4972*7c478bd9Sstevel@tonic-gate 				ASSERT(data_part == 0 ||
4973*7c478bd9Sstevel@tonic-gate 				    mp->b_datap->db_type == M_DATA);
4974*7c478bd9Sstevel@tonic-gate 				mp = mp->b_cont;
4975*7c478bd9Sstevel@tonic-gate 			}
4976*7c478bd9Sstevel@tonic-gate 			/* No data message */
4977*7c478bd9Sstevel@tonic-gate 			if (data_part == 0)
4978*7c478bd9Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len, -1);
4979*7c478bd9Sstevel@tonic-gate 			else
4980*7c478bd9Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len,
4981*7c478bd9Sstevel@tonic-gate 				    STRUCT_FGET(strpeek, databuf.maxlen) -
4982*7c478bd9Sstevel@tonic-gate 				    uio.uio_resid);
4983*7c478bd9Sstevel@tonic-gate 		}
4984*7c478bd9Sstevel@tonic-gate 		freemsg(tmp_mp);
4985*7c478bd9Sstevel@tonic-gate 
4986*7c478bd9Sstevel@tonic-gate 		/*
4987*7c478bd9Sstevel@tonic-gate 		 * It is a synch stream and user wants to get
4988*7c478bd9Sstevel@tonic-gate 		 * data (maxlen > 0).
4989*7c478bd9Sstevel@tonic-gate 		 * uio setup is done by the codes that process DATA
4990*7c478bd9Sstevel@tonic-gate 		 * blocks above.
4991*7c478bd9Sstevel@tonic-gate 		 */
4992*7c478bd9Sstevel@tonic-gate 		if ((fmp == NULL) && STRUCT_FGET(strpeek, databuf.maxlen) > 0) {
4993*7c478bd9Sstevel@tonic-gate 			infod_t infod;
4994*7c478bd9Sstevel@tonic-gate 
4995*7c478bd9Sstevel@tonic-gate 			infod.d_cmd = INFOD_COPYOUT;
4996*7c478bd9Sstevel@tonic-gate 			infod.d_res = 0;
4997*7c478bd9Sstevel@tonic-gate 			infod.d_uiop = &uio;
4998*7c478bd9Sstevel@tonic-gate 			error = infonext(rdq, &infod);
4999*7c478bd9Sstevel@tonic-gate 			if (error == EINVAL || error == EBUSY)
5000*7c478bd9Sstevel@tonic-gate 				error = 0;
5001*7c478bd9Sstevel@tonic-gate 			if (error)
5002*7c478bd9Sstevel@tonic-gate 				return (error);
5003*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strpeek, databuf.len, STRUCT_FGET(strpeek,
5004*7c478bd9Sstevel@tonic-gate 			    databuf.maxlen) - uio.uio_resid);
5005*7c478bd9Sstevel@tonic-gate 			if (STRUCT_FGET(strpeek, databuf.len) == 0) {
5006*7c478bd9Sstevel@tonic-gate 				/*
5007*7c478bd9Sstevel@tonic-gate 				 * No data found by the infonext().
5008*7c478bd9Sstevel@tonic-gate 				 */
5009*7c478bd9Sstevel@tonic-gate 				STRUCT_FSET(strpeek, databuf.len, -1);
5010*7c478bd9Sstevel@tonic-gate 			}
5011*7c478bd9Sstevel@tonic-gate 		}
5012*7c478bd9Sstevel@tonic-gate 		error = strcopyout(STRUCT_BUF(strpeek), (void *)arg,
5013*7c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek), copyflag);
5014*7c478bd9Sstevel@tonic-gate 		if (error) {
5015*7c478bd9Sstevel@tonic-gate 			return (error);
5016*7c478bd9Sstevel@tonic-gate 		}
5017*7c478bd9Sstevel@tonic-gate 		/*
5018*7c478bd9Sstevel@tonic-gate 		 * If there is no message retrieved, set return code to 0
5019*7c478bd9Sstevel@tonic-gate 		 * otherwise, set it to 1.
5020*7c478bd9Sstevel@tonic-gate 		 */
5021*7c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, ctlbuf.len) == -1 &&
5022*7c478bd9Sstevel@tonic-gate 		    STRUCT_FGET(strpeek, databuf.len) == -1)
5023*7c478bd9Sstevel@tonic-gate 			*rvalp = 0;
5024*7c478bd9Sstevel@tonic-gate 		else
5025*7c478bd9Sstevel@tonic-gate 			*rvalp = 1;
5026*7c478bd9Sstevel@tonic-gate 		return (0);
5027*7c478bd9Sstevel@tonic-gate 	    }
5028*7c478bd9Sstevel@tonic-gate 
5029*7c478bd9Sstevel@tonic-gate 	case I_FDINSERT:
5030*7c478bd9Sstevel@tonic-gate 	    {
5031*7c478bd9Sstevel@tonic-gate 		STRUCT_DECL(strfdinsert, strfdinsert);
5032*7c478bd9Sstevel@tonic-gate 		struct file *resftp;
5033*7c478bd9Sstevel@tonic-gate 		struct stdata *resstp;
5034*7c478bd9Sstevel@tonic-gate 		t_uscalar_t	ival;
5035*7c478bd9Sstevel@tonic-gate 		ssize_t msgsize;
5036*7c478bd9Sstevel@tonic-gate 		struct strbuf mctl;
5037*7c478bd9Sstevel@tonic-gate 
5038*7c478bd9Sstevel@tonic-gate 		STRUCT_INIT(strfdinsert, flag);
5039*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRHUP)
5040*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
5041*7c478bd9Sstevel@tonic-gate 		/*
5042*7c478bd9Sstevel@tonic-gate 		 * STRDERR, STWRERR and STPLEX tested above.
5043*7c478bd9Sstevel@tonic-gate 		 */
5044*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, STRUCT_BUF(strfdinsert),
5045*7c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strfdinsert), copyflag);
5046*7c478bd9Sstevel@tonic-gate 		if (error)
5047*7c478bd9Sstevel@tonic-gate 			return (error);
5048*7c478bd9Sstevel@tonic-gate 
5049*7c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, offset) < 0 ||
5050*7c478bd9Sstevel@tonic-gate 		    (STRUCT_FGET(strfdinsert, offset) %
5051*7c478bd9Sstevel@tonic-gate 		    sizeof (t_uscalar_t)) != 0)
5052*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5053*7c478bd9Sstevel@tonic-gate 		if ((resftp = getf(STRUCT_FGET(strfdinsert, fildes))) != NULL) {
5054*7c478bd9Sstevel@tonic-gate 			if ((resstp = resftp->f_vnode->v_stream) == NULL) {
5055*7c478bd9Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
5056*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
5057*7c478bd9Sstevel@tonic-gate 			}
5058*7c478bd9Sstevel@tonic-gate 		} else
5059*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5060*7c478bd9Sstevel@tonic-gate 
5061*7c478bd9Sstevel@tonic-gate 		mutex_enter(&resstp->sd_lock);
5062*7c478bd9Sstevel@tonic-gate 		if (resstp->sd_flag & (STRDERR|STWRERR|STRHUP|STPLEX)) {
5063*7c478bd9Sstevel@tonic-gate 			error = strgeterr(resstp,
5064*7c478bd9Sstevel@tonic-gate 					STRDERR|STWRERR|STRHUP|STPLEX, 0);
5065*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
5066*7c478bd9Sstevel@tonic-gate 				mutex_exit(&resstp->sd_lock);
5067*7c478bd9Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
5068*7c478bd9Sstevel@tonic-gate 				return (error);
5069*7c478bd9Sstevel@tonic-gate 			}
5070*7c478bd9Sstevel@tonic-gate 		}
5071*7c478bd9Sstevel@tonic-gate 		mutex_exit(&resstp->sd_lock);
5072*7c478bd9Sstevel@tonic-gate 
5073*7c478bd9Sstevel@tonic-gate #ifdef	_ILP32
5074*7c478bd9Sstevel@tonic-gate 		{
5075*7c478bd9Sstevel@tonic-gate 			queue_t	*q;
5076*7c478bd9Sstevel@tonic-gate 			queue_t	*mate = NULL;
5077*7c478bd9Sstevel@tonic-gate 
5078*7c478bd9Sstevel@tonic-gate 			/* get read queue of stream terminus */
5079*7c478bd9Sstevel@tonic-gate 			claimstr(resstp->sd_wrq);
5080*7c478bd9Sstevel@tonic-gate 			for (q = resstp->sd_wrq->q_next; q->q_next != NULL;
5081*7c478bd9Sstevel@tonic-gate 			    q = q->q_next)
5082*7c478bd9Sstevel@tonic-gate 				if (!STRMATED(resstp) && STREAM(q) != resstp &&
5083*7c478bd9Sstevel@tonic-gate 				    mate == NULL) {
5084*7c478bd9Sstevel@tonic-gate 					ASSERT(q->q_qinfo->qi_srvp);
5085*7c478bd9Sstevel@tonic-gate 					ASSERT(_OTHERQ(q)->q_qinfo->qi_srvp);
5086*7c478bd9Sstevel@tonic-gate 					claimstr(q);
5087*7c478bd9Sstevel@tonic-gate 					mate = q;
5088*7c478bd9Sstevel@tonic-gate 				}
5089*7c478bd9Sstevel@tonic-gate 			q = _RD(q);
5090*7c478bd9Sstevel@tonic-gate 			if (mate)
5091*7c478bd9Sstevel@tonic-gate 				releasestr(mate);
5092*7c478bd9Sstevel@tonic-gate 			releasestr(resstp->sd_wrq);
5093*7c478bd9Sstevel@tonic-gate 			ival = (t_uscalar_t)q;
5094*7c478bd9Sstevel@tonic-gate 		}
5095*7c478bd9Sstevel@tonic-gate #else
5096*7c478bd9Sstevel@tonic-gate 		ival = (t_uscalar_t)getminor(resftp->f_vnode->v_rdev);
5097*7c478bd9Sstevel@tonic-gate #endif	/* _ILP32 */
5098*7c478bd9Sstevel@tonic-gate 
5099*7c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, ctlbuf.len) <
5100*7c478bd9Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, offset) + sizeof (t_uscalar_t)) {
5101*7c478bd9Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
5102*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5103*7c478bd9Sstevel@tonic-gate 		}
5104*7c478bd9Sstevel@tonic-gate 
5105*7c478bd9Sstevel@tonic-gate 		/*
5106*7c478bd9Sstevel@tonic-gate 		 * Check for legal flag value.
5107*7c478bd9Sstevel@tonic-gate 		 */
5108*7c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strfdinsert, flags) & ~RS_HIPRI) {
5109*7c478bd9Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
5110*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5111*7c478bd9Sstevel@tonic-gate 		}
5112*7c478bd9Sstevel@tonic-gate 
5113*7c478bd9Sstevel@tonic-gate 		/* get these values from those cached in the stream head */
5114*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(stp->sd_wrq));
5115*7c478bd9Sstevel@tonic-gate 		rmin = stp->sd_qn_minpsz;
5116*7c478bd9Sstevel@tonic-gate 		rmax = stp->sd_qn_maxpsz;
5117*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(stp->sd_wrq));
5118*7c478bd9Sstevel@tonic-gate 
5119*7c478bd9Sstevel@tonic-gate 		/*
5120*7c478bd9Sstevel@tonic-gate 		 * Make sure ctl and data sizes together fall within
5121*7c478bd9Sstevel@tonic-gate 		 * the limits of the max and min receive packet sizes
5122*7c478bd9Sstevel@tonic-gate 		 * and do not exceed system limit.  A negative data
5123*7c478bd9Sstevel@tonic-gate 		 * length means that no data part is to be sent.
5124*7c478bd9Sstevel@tonic-gate 		 */
5125*7c478bd9Sstevel@tonic-gate 		ASSERT((rmax >= 0) || (rmax == INFPSZ));
5126*7c478bd9Sstevel@tonic-gate 		if (rmax == 0) {
5127*7c478bd9Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
5128*7c478bd9Sstevel@tonic-gate 			return (ERANGE);
5129*7c478bd9Sstevel@tonic-gate 		}
5130*7c478bd9Sstevel@tonic-gate 		if ((msgsize = STRUCT_FGET(strfdinsert, databuf.len)) < 0)
5131*7c478bd9Sstevel@tonic-gate 			msgsize = 0;
5132*7c478bd9Sstevel@tonic-gate 		if ((msgsize < rmin) ||
5133*7c478bd9Sstevel@tonic-gate 		    ((msgsize > rmax) && (rmax != INFPSZ)) ||
5134*7c478bd9Sstevel@tonic-gate 		    (STRUCT_FGET(strfdinsert, ctlbuf.len) > strctlsz)) {
5135*7c478bd9Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
5136*7c478bd9Sstevel@tonic-gate 			return (ERANGE);
5137*7c478bd9Sstevel@tonic-gate 		}
5138*7c478bd9Sstevel@tonic-gate 
5139*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5140*7c478bd9Sstevel@tonic-gate 		while (!(STRUCT_FGET(strfdinsert, flags) & RS_HIPRI) &&
5141*7c478bd9Sstevel@tonic-gate 		    !canputnext(stp->sd_wrq)) {
5142*7c478bd9Sstevel@tonic-gate 			if ((error = strwaitq(stp, WRITEWAIT, (ssize_t)0,
5143*7c478bd9Sstevel@tonic-gate 			    flag, -1, &done)) != 0 || done) {
5144*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
5145*7c478bd9Sstevel@tonic-gate 				releasef(STRUCT_FGET(strfdinsert, fildes));
5146*7c478bd9Sstevel@tonic-gate 				return (error);
5147*7c478bd9Sstevel@tonic-gate 			}
5148*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
5149*7c478bd9Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
5150*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
5151*7c478bd9Sstevel@tonic-gate 				if (error = straccess(stp, access)) {
5152*7c478bd9Sstevel@tonic-gate 					releasef(
5153*7c478bd9Sstevel@tonic-gate 					    STRUCT_FGET(strfdinsert, fildes));
5154*7c478bd9Sstevel@tonic-gate 					return (error);
5155*7c478bd9Sstevel@tonic-gate 				}
5156*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
5157*7c478bd9Sstevel@tonic-gate 			}
5158*7c478bd9Sstevel@tonic-gate 		}
5159*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5160*7c478bd9Sstevel@tonic-gate 
5161*7c478bd9Sstevel@tonic-gate 		/*
5162*7c478bd9Sstevel@tonic-gate 		 * Copy strfdinsert.ctlbuf into native form of
5163*7c478bd9Sstevel@tonic-gate 		 * ctlbuf to pass down into strmakemsg().
5164*7c478bd9Sstevel@tonic-gate 		 */
5165*7c478bd9Sstevel@tonic-gate 		mctl.maxlen = STRUCT_FGET(strfdinsert, ctlbuf.maxlen);
5166*7c478bd9Sstevel@tonic-gate 		mctl.len = STRUCT_FGET(strfdinsert, ctlbuf.len);
5167*7c478bd9Sstevel@tonic-gate 		mctl.buf = STRUCT_FGETP(strfdinsert, ctlbuf.buf);
5168*7c478bd9Sstevel@tonic-gate 
5169*7c478bd9Sstevel@tonic-gate 		iov.iov_base = STRUCT_FGETP(strfdinsert, databuf.buf);
5170*7c478bd9Sstevel@tonic-gate 		iov.iov_len = STRUCT_FGET(strfdinsert, databuf.len);
5171*7c478bd9Sstevel@tonic-gate 		uio.uio_iov = &iov;
5172*7c478bd9Sstevel@tonic-gate 		uio.uio_iovcnt = 1;
5173*7c478bd9Sstevel@tonic-gate 		uio.uio_loffset = 0;
5174*7c478bd9Sstevel@tonic-gate 		uio.uio_segflg = (copyflag == U_TO_K) ? UIO_USERSPACE :
5175*7c478bd9Sstevel@tonic-gate 		    UIO_SYSSPACE;
5176*7c478bd9Sstevel@tonic-gate 		uio.uio_fmode = 0;
5177*7c478bd9Sstevel@tonic-gate 		uio.uio_extflg = UIO_COPY_CACHED;
5178*7c478bd9Sstevel@tonic-gate 		uio.uio_resid = iov.iov_len;
5179*7c478bd9Sstevel@tonic-gate 		if ((error = strmakemsg(&mctl,
5180*7c478bd9Sstevel@tonic-gate 		    &msgsize, &uio, stp,
5181*7c478bd9Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, flags), &mp)) != 0 || !mp) {
5182*7c478bd9Sstevel@tonic-gate 			STRUCT_FSET(strfdinsert, databuf.len, msgsize);
5183*7c478bd9Sstevel@tonic-gate 			releasef(STRUCT_FGET(strfdinsert, fildes));
5184*7c478bd9Sstevel@tonic-gate 			return (error);
5185*7c478bd9Sstevel@tonic-gate 		}
5186*7c478bd9Sstevel@tonic-gate 
5187*7c478bd9Sstevel@tonic-gate 		STRUCT_FSET(strfdinsert, databuf.len, msgsize);
5188*7c478bd9Sstevel@tonic-gate 
5189*7c478bd9Sstevel@tonic-gate 		/*
5190*7c478bd9Sstevel@tonic-gate 		 * Place the possibly reencoded queue pointer 'offset' bytes
5191*7c478bd9Sstevel@tonic-gate 		 * from the start of the control portion of the message.
5192*7c478bd9Sstevel@tonic-gate 		 */
5193*7c478bd9Sstevel@tonic-gate 		*((t_uscalar_t *)(mp->b_rptr +
5194*7c478bd9Sstevel@tonic-gate 		    STRUCT_FGET(strfdinsert, offset))) = ival;
5195*7c478bd9Sstevel@tonic-gate 
5196*7c478bd9Sstevel@tonic-gate 		/*
5197*7c478bd9Sstevel@tonic-gate 		 * Put message downstream.
5198*7c478bd9Sstevel@tonic-gate 		 */
5199*7c478bd9Sstevel@tonic-gate 		stream_willservice(stp);
5200*7c478bd9Sstevel@tonic-gate 		putnext(stp->sd_wrq, mp);
5201*7c478bd9Sstevel@tonic-gate 		stream_runservice(stp);
5202*7c478bd9Sstevel@tonic-gate 		releasef(STRUCT_FGET(strfdinsert, fildes));
5203*7c478bd9Sstevel@tonic-gate 		return (error);
5204*7c478bd9Sstevel@tonic-gate 	    }
5205*7c478bd9Sstevel@tonic-gate 
5206*7c478bd9Sstevel@tonic-gate 	case I_SENDFD:
5207*7c478bd9Sstevel@tonic-gate 	    {
5208*7c478bd9Sstevel@tonic-gate 		struct file *fp;
5209*7c478bd9Sstevel@tonic-gate 
5210*7c478bd9Sstevel@tonic-gate 		if ((fp = getf((int)arg)) == NULL)
5211*7c478bd9Sstevel@tonic-gate 			return (EBADF);
5212*7c478bd9Sstevel@tonic-gate 		error = do_sendfp(stp, fp, crp);
5213*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
5214*7c478bd9Sstevel@tonic-gate 		if (audit_active) {
5215*7c478bd9Sstevel@tonic-gate 			audit_fdsend((int)arg, fp, error);
5216*7c478bd9Sstevel@tonic-gate 		}
5217*7c478bd9Sstevel@tonic-gate #endif
5218*7c478bd9Sstevel@tonic-gate 		releasef((int)arg);
5219*7c478bd9Sstevel@tonic-gate 		return (error);
5220*7c478bd9Sstevel@tonic-gate 	    }
5221*7c478bd9Sstevel@tonic-gate 
5222*7c478bd9Sstevel@tonic-gate 	case I_RECVFD:
5223*7c478bd9Sstevel@tonic-gate 	case I_E_RECVFD:
5224*7c478bd9Sstevel@tonic-gate 	    {
5225*7c478bd9Sstevel@tonic-gate 		struct k_strrecvfd *srf;
5226*7c478bd9Sstevel@tonic-gate 		int i, fd;
5227*7c478bd9Sstevel@tonic-gate 
5228*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5229*7c478bd9Sstevel@tonic-gate 		while (!(mp = getq(rdq))) {
5230*7c478bd9Sstevel@tonic-gate 			if (stp->sd_flag & (STRHUP|STREOF)) {
5231*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
5232*7c478bd9Sstevel@tonic-gate 				return (ENXIO);
5233*7c478bd9Sstevel@tonic-gate 			}
5234*7c478bd9Sstevel@tonic-gate 			if ((error = strwaitq(stp, GETWAIT, (ssize_t)0,
5235*7c478bd9Sstevel@tonic-gate 			    flag, -1, &done)) != 0 || done) {
5236*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
5237*7c478bd9Sstevel@tonic-gate 				return (error);
5238*7c478bd9Sstevel@tonic-gate 			}
5239*7c478bd9Sstevel@tonic-gate 			if (stp->sd_sidp != NULL &&
5240*7c478bd9Sstevel@tonic-gate 			    stp->sd_vnode->v_type != VFIFO) {
5241*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
5242*7c478bd9Sstevel@tonic-gate 				if (error = straccess(stp, access))
5243*7c478bd9Sstevel@tonic-gate 					return (error);
5244*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
5245*7c478bd9Sstevel@tonic-gate 			}
5246*7c478bd9Sstevel@tonic-gate 		}
5247*7c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type != M_PASSFP) {
5248*7c478bd9Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
5249*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5250*7c478bd9Sstevel@tonic-gate 			return (EBADMSG);
5251*7c478bd9Sstevel@tonic-gate 		}
5252*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5253*7c478bd9Sstevel@tonic-gate 
5254*7c478bd9Sstevel@tonic-gate 		srf = (struct k_strrecvfd *)mp->b_rptr;
5255*7c478bd9Sstevel@tonic-gate 		if ((fd = ufalloc(0)) == -1) {
5256*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
5257*7c478bd9Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
5258*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5259*7c478bd9Sstevel@tonic-gate 			return (EMFILE);
5260*7c478bd9Sstevel@tonic-gate 		}
5261*7c478bd9Sstevel@tonic-gate 		if (cmd == I_RECVFD) {
5262*7c478bd9Sstevel@tonic-gate 			struct o_strrecvfd	ostrfd;
5263*7c478bd9Sstevel@tonic-gate 
5264*7c478bd9Sstevel@tonic-gate 			/* check to see if uid/gid values are too large. */
5265*7c478bd9Sstevel@tonic-gate 
5266*7c478bd9Sstevel@tonic-gate 			if (srf->uid > (o_uid_t)USHRT_MAX ||
5267*7c478bd9Sstevel@tonic-gate 			    srf->gid > (o_gid_t)USHRT_MAX) {
5268*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
5269*7c478bd9Sstevel@tonic-gate 				putback(stp, rdq, mp, mp->b_band);
5270*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
5271*7c478bd9Sstevel@tonic-gate 				setf(fd, NULL);	/* release fd entry */
5272*7c478bd9Sstevel@tonic-gate 				return (EOVERFLOW);
5273*7c478bd9Sstevel@tonic-gate 			}
5274*7c478bd9Sstevel@tonic-gate 
5275*7c478bd9Sstevel@tonic-gate 			ostrfd.fd = fd;
5276*7c478bd9Sstevel@tonic-gate 			ostrfd.uid = (o_uid_t)srf->uid;
5277*7c478bd9Sstevel@tonic-gate 			ostrfd.gid = (o_gid_t)srf->gid;
5278*7c478bd9Sstevel@tonic-gate 
5279*7c478bd9Sstevel@tonic-gate 			/* Null the filler bits */
5280*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < 8; i++)
5281*7c478bd9Sstevel@tonic-gate 				ostrfd.fill[i] = 0;
5282*7c478bd9Sstevel@tonic-gate 
5283*7c478bd9Sstevel@tonic-gate 			error = strcopyout(&ostrfd, (void *)arg,
5284*7c478bd9Sstevel@tonic-gate 			    sizeof (struct o_strrecvfd), copyflag);
5285*7c478bd9Sstevel@tonic-gate 		} else {		/* I_E_RECVFD */
5286*7c478bd9Sstevel@tonic-gate 			struct strrecvfd	strfd;
5287*7c478bd9Sstevel@tonic-gate 
5288*7c478bd9Sstevel@tonic-gate 			strfd.fd = fd;
5289*7c478bd9Sstevel@tonic-gate 			strfd.uid = srf->uid;
5290*7c478bd9Sstevel@tonic-gate 			strfd.gid = srf->gid;
5291*7c478bd9Sstevel@tonic-gate 
5292*7c478bd9Sstevel@tonic-gate 			/* null the filler bits */
5293*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < 8; i++)
5294*7c478bd9Sstevel@tonic-gate 				strfd.fill[i] = 0;
5295*7c478bd9Sstevel@tonic-gate 
5296*7c478bd9Sstevel@tonic-gate 			error = strcopyout(&strfd, (void *)arg,
5297*7c478bd9Sstevel@tonic-gate 			    sizeof (struct strrecvfd), copyflag);
5298*7c478bd9Sstevel@tonic-gate 		}
5299*7c478bd9Sstevel@tonic-gate 
5300*7c478bd9Sstevel@tonic-gate 		if (error) {
5301*7c478bd9Sstevel@tonic-gate 			setf(fd, NULL);	/* release fd entry */
5302*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
5303*7c478bd9Sstevel@tonic-gate 			putback(stp, rdq, mp, mp->b_band);
5304*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5305*7c478bd9Sstevel@tonic-gate 			return (error);
5306*7c478bd9Sstevel@tonic-gate 		}
5307*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
5308*7c478bd9Sstevel@tonic-gate 		if (audit_active) {
5309*7c478bd9Sstevel@tonic-gate 			audit_fdrecv(fd, srf->fp);
5310*7c478bd9Sstevel@tonic-gate 		}
5311*7c478bd9Sstevel@tonic-gate #endif
5312*7c478bd9Sstevel@tonic-gate 
5313*7c478bd9Sstevel@tonic-gate 		/*
5314*7c478bd9Sstevel@tonic-gate 		 * Always increment f_count since the freemsg() below will
5315*7c478bd9Sstevel@tonic-gate 		 * always call free_passfp() which performs a closef().
5316*7c478bd9Sstevel@tonic-gate 		 */
5317*7c478bd9Sstevel@tonic-gate 		mutex_enter(&srf->fp->f_tlock);
5318*7c478bd9Sstevel@tonic-gate 		srf->fp->f_count++;
5319*7c478bd9Sstevel@tonic-gate 		mutex_exit(&srf->fp->f_tlock);
5320*7c478bd9Sstevel@tonic-gate 		setf(fd, srf->fp);
5321*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
5322*7c478bd9Sstevel@tonic-gate 		return (0);
5323*7c478bd9Sstevel@tonic-gate 	    }
5324*7c478bd9Sstevel@tonic-gate 
5325*7c478bd9Sstevel@tonic-gate 	case I_SWROPT:
5326*7c478bd9Sstevel@tonic-gate 		/*
5327*7c478bd9Sstevel@tonic-gate 		 * Set/clear the write options. arg is a bit
5328*7c478bd9Sstevel@tonic-gate 		 * mask with any of the following bits set...
5329*7c478bd9Sstevel@tonic-gate 		 * 	SNDZERO - send zero length message
5330*7c478bd9Sstevel@tonic-gate 		 *	SNDPIPE - send sigpipe to process if
5331*7c478bd9Sstevel@tonic-gate 		 *		sd_werror is set and process is
5332*7c478bd9Sstevel@tonic-gate 		 *		doing a write or putmsg.
5333*7c478bd9Sstevel@tonic-gate 		 * The new stream head write options should reflect
5334*7c478bd9Sstevel@tonic-gate 		 * what is in arg.
5335*7c478bd9Sstevel@tonic-gate 		 */
5336*7c478bd9Sstevel@tonic-gate 		if (arg & ~(SNDZERO|SNDPIPE))
5337*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5338*7c478bd9Sstevel@tonic-gate 
5339*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5340*7c478bd9Sstevel@tonic-gate 		stp->sd_wput_opt &= ~(SW_SIGPIPE|SW_SNDZERO);
5341*7c478bd9Sstevel@tonic-gate 		if (arg & SNDZERO)
5342*7c478bd9Sstevel@tonic-gate 			stp->sd_wput_opt |= SW_SNDZERO;
5343*7c478bd9Sstevel@tonic-gate 		if (arg & SNDPIPE)
5344*7c478bd9Sstevel@tonic-gate 			stp->sd_wput_opt |= SW_SIGPIPE;
5345*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5346*7c478bd9Sstevel@tonic-gate 		return (0);
5347*7c478bd9Sstevel@tonic-gate 
5348*7c478bd9Sstevel@tonic-gate 	case I_GWROPT:
5349*7c478bd9Sstevel@tonic-gate 	    {
5350*7c478bd9Sstevel@tonic-gate 		int wropt = 0;
5351*7c478bd9Sstevel@tonic-gate 
5352*7c478bd9Sstevel@tonic-gate 		if (stp->sd_wput_opt & SW_SNDZERO)
5353*7c478bd9Sstevel@tonic-gate 			wropt |= SNDZERO;
5354*7c478bd9Sstevel@tonic-gate 		if (stp->sd_wput_opt & SW_SIGPIPE)
5355*7c478bd9Sstevel@tonic-gate 			wropt |= SNDPIPE;
5356*7c478bd9Sstevel@tonic-gate 		return (strcopyout(&wropt, (void *)arg, sizeof (wropt),
5357*7c478bd9Sstevel@tonic-gate 		    copyflag));
5358*7c478bd9Sstevel@tonic-gate 	    }
5359*7c478bd9Sstevel@tonic-gate 
5360*7c478bd9Sstevel@tonic-gate 	case I_LIST:
5361*7c478bd9Sstevel@tonic-gate 		/*
5362*7c478bd9Sstevel@tonic-gate 		 * Returns all the modules found on this stream,
5363*7c478bd9Sstevel@tonic-gate 		 * upto the driver. If argument is NULL, return the
5364*7c478bd9Sstevel@tonic-gate 		 * number of modules (including driver). If argument
5365*7c478bd9Sstevel@tonic-gate 		 * is not NULL, copy the names into the structure
5366*7c478bd9Sstevel@tonic-gate 		 * provided.
5367*7c478bd9Sstevel@tonic-gate 		 */
5368*7c478bd9Sstevel@tonic-gate 
5369*7c478bd9Sstevel@tonic-gate 	    {
5370*7c478bd9Sstevel@tonic-gate 		queue_t *q;
5371*7c478bd9Sstevel@tonic-gate 		int num_modules, space_allocated;
5372*7c478bd9Sstevel@tonic-gate 		STRUCT_DECL(str_list, strlist);
5373*7c478bd9Sstevel@tonic-gate 		struct str_mlist *mlist_ptr;
5374*7c478bd9Sstevel@tonic-gate 
5375*7c478bd9Sstevel@tonic-gate 		if (arg == NULL) { /* Return number of modules plus driver */
5376*7c478bd9Sstevel@tonic-gate 			q = stp->sd_wrq;
5377*7c478bd9Sstevel@tonic-gate 			if (stp->sd_vnode->v_type == VFIFO) {
5378*7c478bd9Sstevel@tonic-gate 				*rvalp = stp->sd_pushcnt;
5379*7c478bd9Sstevel@tonic-gate 			} else {
5380*7c478bd9Sstevel@tonic-gate 				*rvalp = stp->sd_pushcnt + 1;
5381*7c478bd9Sstevel@tonic-gate 			}
5382*7c478bd9Sstevel@tonic-gate 		} else {
5383*7c478bd9Sstevel@tonic-gate 			STRUCT_INIT(strlist, flag);
5384*7c478bd9Sstevel@tonic-gate 
5385*7c478bd9Sstevel@tonic-gate 			error = strcopyin((void *)arg, STRUCT_BUF(strlist),
5386*7c478bd9Sstevel@tonic-gate 			    STRUCT_SIZE(strlist), copyflag);
5387*7c478bd9Sstevel@tonic-gate 			if (error)
5388*7c478bd9Sstevel@tonic-gate 				return (error);
5389*7c478bd9Sstevel@tonic-gate 
5390*7c478bd9Sstevel@tonic-gate 			space_allocated = STRUCT_FGET(strlist, sl_nmods);
5391*7c478bd9Sstevel@tonic-gate 			if ((space_allocated) <= 0)
5392*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
5393*7c478bd9Sstevel@tonic-gate 			claimstr(stp->sd_wrq);
5394*7c478bd9Sstevel@tonic-gate 			q = stp->sd_wrq;
5395*7c478bd9Sstevel@tonic-gate 			num_modules = 0;
5396*7c478bd9Sstevel@tonic-gate 			while (_SAMESTR(q) && (space_allocated != 0)) {
5397*7c478bd9Sstevel@tonic-gate 				char *name =
5398*7c478bd9Sstevel@tonic-gate 				    q->q_next->q_qinfo->qi_minfo->mi_idname;
5399*7c478bd9Sstevel@tonic-gate 
5400*7c478bd9Sstevel@tonic-gate 				mlist_ptr = STRUCT_FGETP(strlist, sl_modlist);
5401*7c478bd9Sstevel@tonic-gate 
5402*7c478bd9Sstevel@tonic-gate 				error = strcopyout(name, mlist_ptr,
5403*7c478bd9Sstevel@tonic-gate 				    strlen(name) + 1, copyflag);
5404*7c478bd9Sstevel@tonic-gate 
5405*7c478bd9Sstevel@tonic-gate 				if (error) {
5406*7c478bd9Sstevel@tonic-gate 					releasestr(stp->sd_wrq);
5407*7c478bd9Sstevel@tonic-gate 					return (error);
5408*7c478bd9Sstevel@tonic-gate 				}
5409*7c478bd9Sstevel@tonic-gate 				q = q->q_next;
5410*7c478bd9Sstevel@tonic-gate 				space_allocated--;
5411*7c478bd9Sstevel@tonic-gate 				num_modules++;
5412*7c478bd9Sstevel@tonic-gate 				mlist_ptr =
5413*7c478bd9Sstevel@tonic-gate 				    (struct str_mlist *)((uintptr_t)mlist_ptr +
5414*7c478bd9Sstevel@tonic-gate 				    sizeof (struct str_mlist));
5415*7c478bd9Sstevel@tonic-gate 				STRUCT_FSETP(strlist, sl_modlist, mlist_ptr);
5416*7c478bd9Sstevel@tonic-gate 			}
5417*7c478bd9Sstevel@tonic-gate 			releasestr(stp->sd_wrq);
5418*7c478bd9Sstevel@tonic-gate 			error = strcopyout(&num_modules, (void *)arg,
5419*7c478bd9Sstevel@tonic-gate 			    sizeof (int), copyflag);
5420*7c478bd9Sstevel@tonic-gate 		}
5421*7c478bd9Sstevel@tonic-gate 		return (error);
5422*7c478bd9Sstevel@tonic-gate 	    }
5423*7c478bd9Sstevel@tonic-gate 
5424*7c478bd9Sstevel@tonic-gate 	case I_CKBAND:
5425*7c478bd9Sstevel@tonic-gate 	    {
5426*7c478bd9Sstevel@tonic-gate 		queue_t *q;
5427*7c478bd9Sstevel@tonic-gate 		qband_t *qbp;
5428*7c478bd9Sstevel@tonic-gate 
5429*7c478bd9Sstevel@tonic-gate 		if ((arg < 0) || (arg >= NBAND))
5430*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5431*7c478bd9Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
5432*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
5433*7c478bd9Sstevel@tonic-gate 		if (arg > (int)q->q_nband) {
5434*7c478bd9Sstevel@tonic-gate 			*rvalp = 0;
5435*7c478bd9Sstevel@tonic-gate 		} else {
5436*7c478bd9Sstevel@tonic-gate 			if (arg == 0) {
5437*7c478bd9Sstevel@tonic-gate 				if (q->q_first)
5438*7c478bd9Sstevel@tonic-gate 					*rvalp = 1;
5439*7c478bd9Sstevel@tonic-gate 				else
5440*7c478bd9Sstevel@tonic-gate 					*rvalp = 0;
5441*7c478bd9Sstevel@tonic-gate 			} else {
5442*7c478bd9Sstevel@tonic-gate 				qbp = q->q_bandp;
5443*7c478bd9Sstevel@tonic-gate 				while (--arg > 0)
5444*7c478bd9Sstevel@tonic-gate 					qbp = qbp->qb_next;
5445*7c478bd9Sstevel@tonic-gate 				if (qbp->qb_first)
5446*7c478bd9Sstevel@tonic-gate 					*rvalp = 1;
5447*7c478bd9Sstevel@tonic-gate 				else
5448*7c478bd9Sstevel@tonic-gate 					*rvalp = 0;
5449*7c478bd9Sstevel@tonic-gate 			}
5450*7c478bd9Sstevel@tonic-gate 		}
5451*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
5452*7c478bd9Sstevel@tonic-gate 		return (0);
5453*7c478bd9Sstevel@tonic-gate 	    }
5454*7c478bd9Sstevel@tonic-gate 
5455*7c478bd9Sstevel@tonic-gate 	case I_GETBAND:
5456*7c478bd9Sstevel@tonic-gate 	    {
5457*7c478bd9Sstevel@tonic-gate 		int intpri;
5458*7c478bd9Sstevel@tonic-gate 		queue_t *q;
5459*7c478bd9Sstevel@tonic-gate 
5460*7c478bd9Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
5461*7c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
5462*7c478bd9Sstevel@tonic-gate 		mp = q->q_first;
5463*7c478bd9Sstevel@tonic-gate 		if (!mp) {
5464*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(q));
5465*7c478bd9Sstevel@tonic-gate 			return (ENODATA);
5466*7c478bd9Sstevel@tonic-gate 		}
5467*7c478bd9Sstevel@tonic-gate 		intpri = (int)mp->b_band;
5468*7c478bd9Sstevel@tonic-gate 		error = strcopyout(&intpri, (void *)arg, sizeof (int),
5469*7c478bd9Sstevel@tonic-gate 		    copyflag);
5470*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
5471*7c478bd9Sstevel@tonic-gate 		return (error);
5472*7c478bd9Sstevel@tonic-gate 	    }
5473*7c478bd9Sstevel@tonic-gate 
5474*7c478bd9Sstevel@tonic-gate 	case I_ATMARK:
5475*7c478bd9Sstevel@tonic-gate 	    {
5476*7c478bd9Sstevel@tonic-gate 		queue_t *q;
5477*7c478bd9Sstevel@tonic-gate 
5478*7c478bd9Sstevel@tonic-gate 		if (arg & ~(ANYMARK|LASTMARK))
5479*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5480*7c478bd9Sstevel@tonic-gate 		q = _RD(stp->sd_wrq);
5481*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5482*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & STRATMARK) && (arg == ANYMARK)) {
5483*7c478bd9Sstevel@tonic-gate 			*rvalp = 1;
5484*7c478bd9Sstevel@tonic-gate 		} else {
5485*7c478bd9Sstevel@tonic-gate 			mutex_enter(QLOCK(q));
5486*7c478bd9Sstevel@tonic-gate 			mp = q->q_first;
5487*7c478bd9Sstevel@tonic-gate 
5488*7c478bd9Sstevel@tonic-gate 			if (mp == NULL)
5489*7c478bd9Sstevel@tonic-gate 				*rvalp = 0;
5490*7c478bd9Sstevel@tonic-gate 			else if ((arg == ANYMARK) && (mp->b_flag & MSGMARK))
5491*7c478bd9Sstevel@tonic-gate 				*rvalp = 1;
5492*7c478bd9Sstevel@tonic-gate 			else if ((arg == LASTMARK) && (mp == stp->sd_mark))
5493*7c478bd9Sstevel@tonic-gate 				*rvalp = 1;
5494*7c478bd9Sstevel@tonic-gate 			else
5495*7c478bd9Sstevel@tonic-gate 				*rvalp = 0;
5496*7c478bd9Sstevel@tonic-gate 			mutex_exit(QLOCK(q));
5497*7c478bd9Sstevel@tonic-gate 		}
5498*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5499*7c478bd9Sstevel@tonic-gate 		return (0);
5500*7c478bd9Sstevel@tonic-gate 	    }
5501*7c478bd9Sstevel@tonic-gate 
5502*7c478bd9Sstevel@tonic-gate 	case I_CANPUT:
5503*7c478bd9Sstevel@tonic-gate 	    {
5504*7c478bd9Sstevel@tonic-gate 		char band;
5505*7c478bd9Sstevel@tonic-gate 
5506*7c478bd9Sstevel@tonic-gate 		if ((arg < 0) || (arg >= NBAND))
5507*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5508*7c478bd9Sstevel@tonic-gate 		band = (char)arg;
5509*7c478bd9Sstevel@tonic-gate 		*rvalp = bcanputnext(stp->sd_wrq, band);
5510*7c478bd9Sstevel@tonic-gate 		return (0);
5511*7c478bd9Sstevel@tonic-gate 	    }
5512*7c478bd9Sstevel@tonic-gate 
5513*7c478bd9Sstevel@tonic-gate 	case I_SETCLTIME:
5514*7c478bd9Sstevel@tonic-gate 	    {
5515*7c478bd9Sstevel@tonic-gate 		int closetime;
5516*7c478bd9Sstevel@tonic-gate 
5517*7c478bd9Sstevel@tonic-gate 		error = strcopyin((void *)arg, &closetime, sizeof (int),
5518*7c478bd9Sstevel@tonic-gate 		    copyflag);
5519*7c478bd9Sstevel@tonic-gate 		if (error)
5520*7c478bd9Sstevel@tonic-gate 			return (error);
5521*7c478bd9Sstevel@tonic-gate 		if (closetime < 0)
5522*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5523*7c478bd9Sstevel@tonic-gate 
5524*7c478bd9Sstevel@tonic-gate 		stp->sd_closetime = closetime;
5525*7c478bd9Sstevel@tonic-gate 		return (0);
5526*7c478bd9Sstevel@tonic-gate 	    }
5527*7c478bd9Sstevel@tonic-gate 
5528*7c478bd9Sstevel@tonic-gate 	case I_GETCLTIME:
5529*7c478bd9Sstevel@tonic-gate 	    {
5530*7c478bd9Sstevel@tonic-gate 		int closetime;
5531*7c478bd9Sstevel@tonic-gate 
5532*7c478bd9Sstevel@tonic-gate 		closetime = stp->sd_closetime;
5533*7c478bd9Sstevel@tonic-gate 		return (strcopyout(&closetime, (void *)arg, sizeof (int),
5534*7c478bd9Sstevel@tonic-gate 		    copyflag));
5535*7c478bd9Sstevel@tonic-gate 	    }
5536*7c478bd9Sstevel@tonic-gate 
5537*7c478bd9Sstevel@tonic-gate 	case TIOCGSID:
5538*7c478bd9Sstevel@tonic-gate 	{
5539*7c478bd9Sstevel@tonic-gate 		pid_t sid;
5540*7c478bd9Sstevel@tonic-gate 
5541*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
5542*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp == NULL) {
5543*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
5544*7c478bd9Sstevel@tonic-gate 			return (ENOTTY);
5545*7c478bd9Sstevel@tonic-gate 		}
5546*7c478bd9Sstevel@tonic-gate 		sid = stp->sd_sidp->pid_id;
5547*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
5548*7c478bd9Sstevel@tonic-gate 		return (strcopyout(&sid, (void *)arg, sizeof (pid_t),
5549*7c478bd9Sstevel@tonic-gate 		    copyflag));
5550*7c478bd9Sstevel@tonic-gate 	}
5551*7c478bd9Sstevel@tonic-gate 
5552*7c478bd9Sstevel@tonic-gate 	case TIOCSPGRP:
5553*7c478bd9Sstevel@tonic-gate 	{
5554*7c478bd9Sstevel@tonic-gate 		pid_t pgrp;
5555*7c478bd9Sstevel@tonic-gate 		proc_t *q;
5556*7c478bd9Sstevel@tonic-gate 		pid_t	sid, fg_pgid, bg_pgid;
5557*7c478bd9Sstevel@tonic-gate 
5558*7c478bd9Sstevel@tonic-gate 		if (error = strcopyin((void *)arg, &pgrp, sizeof (pid_t),
5559*7c478bd9Sstevel@tonic-gate 		    copyflag))
5560*7c478bd9Sstevel@tonic-gate 			return (error);
5561*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
5562*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
5563*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp != ttoproc(curthread)->p_sessp->s_sidp) {
5564*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
5565*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5566*7c478bd9Sstevel@tonic-gate 			return (ENOTTY);
5567*7c478bd9Sstevel@tonic-gate 		}
5568*7c478bd9Sstevel@tonic-gate 		if (pgrp == stp->sd_pgidp->pid_id) {
5569*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
5570*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5571*7c478bd9Sstevel@tonic-gate 			return (0);
5572*7c478bd9Sstevel@tonic-gate 		}
5573*7c478bd9Sstevel@tonic-gate 		if (pgrp <= 0 || pgrp >= maxpid) {
5574*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
5575*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5576*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5577*7c478bd9Sstevel@tonic-gate 		}
5578*7c478bd9Sstevel@tonic-gate 		if ((q = pgfind(pgrp)) == NULL ||
5579*7c478bd9Sstevel@tonic-gate 		    q->p_sessp != ttoproc(curthread)->p_sessp) {
5580*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
5581*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5582*7c478bd9Sstevel@tonic-gate 			return (EPERM);
5583*7c478bd9Sstevel@tonic-gate 		}
5584*7c478bd9Sstevel@tonic-gate 		sid = stp->sd_sidp->pid_id;
5585*7c478bd9Sstevel@tonic-gate 		fg_pgid = q->p_pgrp;
5586*7c478bd9Sstevel@tonic-gate 		bg_pgid = stp->sd_pgidp->pid_id;
5587*7c478bd9Sstevel@tonic-gate 		CL_SET_PROCESS_GROUP(curthread, sid, bg_pgid, fg_pgid);
5588*7c478bd9Sstevel@tonic-gate 		PID_RELE(stp->sd_pgidp);
5589*7c478bd9Sstevel@tonic-gate 		stp->sd_pgidp = q->p_pgidp;
5590*7c478bd9Sstevel@tonic-gate 		PID_HOLD(stp->sd_pgidp);
5591*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
5592*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
5593*7c478bd9Sstevel@tonic-gate 		return (0);
5594*7c478bd9Sstevel@tonic-gate 	}
5595*7c478bd9Sstevel@tonic-gate 
5596*7c478bd9Sstevel@tonic-gate 	case TIOCGPGRP:
5597*7c478bd9Sstevel@tonic-gate 	{
5598*7c478bd9Sstevel@tonic-gate 		pid_t pgrp;
5599*7c478bd9Sstevel@tonic-gate 
5600*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
5601*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp == NULL) {
5602*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
5603*7c478bd9Sstevel@tonic-gate 			return (ENOTTY);
5604*7c478bd9Sstevel@tonic-gate 		}
5605*7c478bd9Sstevel@tonic-gate 		pgrp = stp->sd_pgidp->pid_id;
5606*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
5607*7c478bd9Sstevel@tonic-gate 		return (strcopyout(&pgrp, (void *)arg, sizeof (pid_t),
5608*7c478bd9Sstevel@tonic-gate 		    copyflag));
5609*7c478bd9Sstevel@tonic-gate 	}
5610*7c478bd9Sstevel@tonic-gate 
5611*7c478bd9Sstevel@tonic-gate 	case FIONBIO:
5612*7c478bd9Sstevel@tonic-gate 	case FIOASYNC:
5613*7c478bd9Sstevel@tonic-gate 		return (0);	/* handled by the upper layer */
5614*7c478bd9Sstevel@tonic-gate 	}
5615*7c478bd9Sstevel@tonic-gate }
5616*7c478bd9Sstevel@tonic-gate 
5617*7c478bd9Sstevel@tonic-gate /*
5618*7c478bd9Sstevel@tonic-gate  * Custom free routine used for M_PASSFP messages.
5619*7c478bd9Sstevel@tonic-gate  */
5620*7c478bd9Sstevel@tonic-gate static void
5621*7c478bd9Sstevel@tonic-gate free_passfp(struct k_strrecvfd *srf)
5622*7c478bd9Sstevel@tonic-gate {
5623*7c478bd9Sstevel@tonic-gate 	(void) closef(srf->fp);
5624*7c478bd9Sstevel@tonic-gate 	kmem_free(srf, sizeof (struct k_strrecvfd) + sizeof (frtn_t));
5625*7c478bd9Sstevel@tonic-gate }
5626*7c478bd9Sstevel@tonic-gate 
5627*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
5628*7c478bd9Sstevel@tonic-gate int
5629*7c478bd9Sstevel@tonic-gate do_sendfp(struct stdata *stp, struct file *fp, struct cred *cr)
5630*7c478bd9Sstevel@tonic-gate {
5631*7c478bd9Sstevel@tonic-gate 	queue_t *qp, *nextqp;
5632*7c478bd9Sstevel@tonic-gate 	struct k_strrecvfd *srf;
5633*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
5634*7c478bd9Sstevel@tonic-gate 	frtn_t *frtnp;
5635*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
5636*7c478bd9Sstevel@tonic-gate 	queue_t	*mate = NULL;
5637*7c478bd9Sstevel@tonic-gate 	syncq_t	*sq = NULL;
5638*7c478bd9Sstevel@tonic-gate 	int retval = 0;
5639*7c478bd9Sstevel@tonic-gate 
5640*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & STRHUP)
5641*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
5642*7c478bd9Sstevel@tonic-gate 
5643*7c478bd9Sstevel@tonic-gate 	claimstr(stp->sd_wrq);
5644*7c478bd9Sstevel@tonic-gate 
5645*7c478bd9Sstevel@tonic-gate 	/* Fastpath, we have a pipe, and we are already mated, use it. */
5646*7c478bd9Sstevel@tonic-gate 	if (STRMATED(stp)) {
5647*7c478bd9Sstevel@tonic-gate 		qp = _RD(stp->sd_mate->sd_wrq);
5648*7c478bd9Sstevel@tonic-gate 		claimstr(qp);
5649*7c478bd9Sstevel@tonic-gate 		mate = qp;
5650*7c478bd9Sstevel@tonic-gate 	} else { /* Not already mated. */
5651*7c478bd9Sstevel@tonic-gate 
5652*7c478bd9Sstevel@tonic-gate 		/*
5653*7c478bd9Sstevel@tonic-gate 		 * Walk the stream to the end of this one.
5654*7c478bd9Sstevel@tonic-gate 		 * assumes that the claimstr() will prevent
5655*7c478bd9Sstevel@tonic-gate 		 * plumbing between the stream head and the
5656*7c478bd9Sstevel@tonic-gate 		 * driver from changing
5657*7c478bd9Sstevel@tonic-gate 		 */
5658*7c478bd9Sstevel@tonic-gate 		qp = stp->sd_wrq;
5659*7c478bd9Sstevel@tonic-gate 
5660*7c478bd9Sstevel@tonic-gate 		/*
5661*7c478bd9Sstevel@tonic-gate 		 * Loop until we reach the end of this stream.
5662*7c478bd9Sstevel@tonic-gate 		 * On completion, qp points to the write queue
5663*7c478bd9Sstevel@tonic-gate 		 * at the end of the stream, or the read queue
5664*7c478bd9Sstevel@tonic-gate 		 * at the stream head if this is a fifo.
5665*7c478bd9Sstevel@tonic-gate 		 */
5666*7c478bd9Sstevel@tonic-gate 		while (((qp = qp->q_next) != NULL) && _SAMESTR(qp))
5667*7c478bd9Sstevel@tonic-gate 			;
5668*7c478bd9Sstevel@tonic-gate 
5669*7c478bd9Sstevel@tonic-gate 		/*
5670*7c478bd9Sstevel@tonic-gate 		 * Just in case we get a q_next which is NULL, but
5671*7c478bd9Sstevel@tonic-gate 		 * not at the end of the stream.  This is actually
5672*7c478bd9Sstevel@tonic-gate 		 * broken, so we set an assert to catch it in
5673*7c478bd9Sstevel@tonic-gate 		 * debug, and set an error and return if not debug.
5674*7c478bd9Sstevel@tonic-gate 		 */
5675*7c478bd9Sstevel@tonic-gate 		ASSERT(qp);
5676*7c478bd9Sstevel@tonic-gate 		if (qp == NULL) {
5677*7c478bd9Sstevel@tonic-gate 			releasestr(stp->sd_wrq);
5678*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
5679*7c478bd9Sstevel@tonic-gate 		}
5680*7c478bd9Sstevel@tonic-gate 
5681*7c478bd9Sstevel@tonic-gate 		/*
5682*7c478bd9Sstevel@tonic-gate 		 * Enter the syncq for the driver, so (hopefully)
5683*7c478bd9Sstevel@tonic-gate 		 * the queue values will not change on us.
5684*7c478bd9Sstevel@tonic-gate 		 * XXXX - This will only prevent the race IFF only
5685*7c478bd9Sstevel@tonic-gate 		 *   the write side modifies the q_next member, and
5686*7c478bd9Sstevel@tonic-gate 		 *   the put procedure is protected by at least
5687*7c478bd9Sstevel@tonic-gate 		 *   MT_PERQ.
5688*7c478bd9Sstevel@tonic-gate 		 */
5689*7c478bd9Sstevel@tonic-gate 		if ((sq = qp->q_syncq) != NULL)
5690*7c478bd9Sstevel@tonic-gate 			entersq(sq, SQ_PUT);
5691*7c478bd9Sstevel@tonic-gate 
5692*7c478bd9Sstevel@tonic-gate 		/* Now get the q_next value from this qp. */
5693*7c478bd9Sstevel@tonic-gate 		nextqp = qp->q_next;
5694*7c478bd9Sstevel@tonic-gate 
5695*7c478bd9Sstevel@tonic-gate 		/*
5696*7c478bd9Sstevel@tonic-gate 		 * If nextqp exists and the other stream is different
5697*7c478bd9Sstevel@tonic-gate 		 * from this one claim the stream, set the mate, and
5698*7c478bd9Sstevel@tonic-gate 		 * get the read queue at the stream head of the other
5699*7c478bd9Sstevel@tonic-gate 		 * stream.  Assumes that nextqp was at least valid when
5700*7c478bd9Sstevel@tonic-gate 		 * we got it.  Hopefully the entersq of the driver
5701*7c478bd9Sstevel@tonic-gate 		 * will prevent it from changing on us.
5702*7c478bd9Sstevel@tonic-gate 		 */
5703*7c478bd9Sstevel@tonic-gate 		if ((nextqp != NULL) && (STREAM(nextqp) != stp)) {
5704*7c478bd9Sstevel@tonic-gate 			ASSERT(qp->q_qinfo->qi_srvp);
5705*7c478bd9Sstevel@tonic-gate 			ASSERT(_OTHERQ(qp)->q_qinfo->qi_srvp);
5706*7c478bd9Sstevel@tonic-gate 			ASSERT(_OTHERQ(qp->q_next)->q_qinfo->qi_srvp);
5707*7c478bd9Sstevel@tonic-gate 			claimstr(nextqp);
5708*7c478bd9Sstevel@tonic-gate 
5709*7c478bd9Sstevel@tonic-gate 			/* Make sure we still have a q_next */
5710*7c478bd9Sstevel@tonic-gate 			if (nextqp != qp->q_next) {
5711*7c478bd9Sstevel@tonic-gate 				releasestr(stp->sd_wrq);
5712*7c478bd9Sstevel@tonic-gate 				releasestr(nextqp);
5713*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
5714*7c478bd9Sstevel@tonic-gate 			}
5715*7c478bd9Sstevel@tonic-gate 
5716*7c478bd9Sstevel@tonic-gate 			qp = _RD(STREAM(nextqp)->sd_wrq);
5717*7c478bd9Sstevel@tonic-gate 			mate = qp;
5718*7c478bd9Sstevel@tonic-gate 		}
5719*7c478bd9Sstevel@tonic-gate 		/* If we entered the synq above, leave it. */
5720*7c478bd9Sstevel@tonic-gate 		if (sq != NULL)
5721*7c478bd9Sstevel@tonic-gate 			leavesq(sq, SQ_PUT);
5722*7c478bd9Sstevel@tonic-gate 	} /*  STRMATED(STP)  */
5723*7c478bd9Sstevel@tonic-gate 
5724*7c478bd9Sstevel@tonic-gate 	/* XXX prevents substitution of the ops vector */
5725*7c478bd9Sstevel@tonic-gate 	if (qp->q_qinfo != &strdata && qp->q_qinfo != &fifo_strdata) {
5726*7c478bd9Sstevel@tonic-gate 		retval = EINVAL;
5727*7c478bd9Sstevel@tonic-gate 		goto out;
5728*7c478bd9Sstevel@tonic-gate 	}
5729*7c478bd9Sstevel@tonic-gate 
5730*7c478bd9Sstevel@tonic-gate 	if (qp->q_flag & QFULL) {
5731*7c478bd9Sstevel@tonic-gate 		retval = EAGAIN;
5732*7c478bd9Sstevel@tonic-gate 		goto out;
5733*7c478bd9Sstevel@tonic-gate 	}
5734*7c478bd9Sstevel@tonic-gate 
5735*7c478bd9Sstevel@tonic-gate 	/*
5736*7c478bd9Sstevel@tonic-gate 	 * Since M_PASSFP messages include a file descriptor, we use
5737*7c478bd9Sstevel@tonic-gate 	 * esballoc() and specify a custom free routine (free_passfp()) that
5738*7c478bd9Sstevel@tonic-gate 	 * will close the descriptor as part of freeing the message.  For
5739*7c478bd9Sstevel@tonic-gate 	 * convenience, we stash the frtn_t right after the data block.
5740*7c478bd9Sstevel@tonic-gate 	 */
5741*7c478bd9Sstevel@tonic-gate 	bufsize = sizeof (struct k_strrecvfd) + sizeof (frtn_t);
5742*7c478bd9Sstevel@tonic-gate 	srf = kmem_alloc(bufsize, KM_NOSLEEP);
5743*7c478bd9Sstevel@tonic-gate 	if (srf == NULL) {
5744*7c478bd9Sstevel@tonic-gate 		retval = EAGAIN;
5745*7c478bd9Sstevel@tonic-gate 		goto out;
5746*7c478bd9Sstevel@tonic-gate 	}
5747*7c478bd9Sstevel@tonic-gate 
5748*7c478bd9Sstevel@tonic-gate 	frtnp = (frtn_t *)(srf + 1);
5749*7c478bd9Sstevel@tonic-gate 	frtnp->free_arg = (caddr_t)srf;
5750*7c478bd9Sstevel@tonic-gate 	frtnp->free_func = free_passfp;
5751*7c478bd9Sstevel@tonic-gate 
5752*7c478bd9Sstevel@tonic-gate 	mp = esballoc((uchar_t *)srf, bufsize, BPRI_MED, frtnp);
5753*7c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
5754*7c478bd9Sstevel@tonic-gate 		kmem_free(srf, bufsize);
5755*7c478bd9Sstevel@tonic-gate 		retval = EAGAIN;
5756*7c478bd9Sstevel@tonic-gate 		goto out;
5757*7c478bd9Sstevel@tonic-gate 	}
5758*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (struct k_strrecvfd);
5759*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_PASSFP;
5760*7c478bd9Sstevel@tonic-gate 
5761*7c478bd9Sstevel@tonic-gate 	srf->fp = fp;
5762*7c478bd9Sstevel@tonic-gate 	srf->uid = crgetuid(curthread->t_cred);
5763*7c478bd9Sstevel@tonic-gate 	srf->gid = crgetgid(curthread->t_cred);
5764*7c478bd9Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
5765*7c478bd9Sstevel@tonic-gate 	fp->f_count++;
5766*7c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
5767*7c478bd9Sstevel@tonic-gate 
5768*7c478bd9Sstevel@tonic-gate 	put(qp, mp);
5769*7c478bd9Sstevel@tonic-gate out:
5770*7c478bd9Sstevel@tonic-gate 	releasestr(stp->sd_wrq);
5771*7c478bd9Sstevel@tonic-gate 	if (mate)
5772*7c478bd9Sstevel@tonic-gate 		releasestr(mate);
5773*7c478bd9Sstevel@tonic-gate 	return (retval);
5774*7c478bd9Sstevel@tonic-gate }
5775*7c478bd9Sstevel@tonic-gate 
5776*7c478bd9Sstevel@tonic-gate /*
5777*7c478bd9Sstevel@tonic-gate  * Send an ioctl message downstream and wait for acknowledgement.
5778*7c478bd9Sstevel@tonic-gate  * flags may be set to either U_TO_K or K_TO_K and a combination
5779*7c478bd9Sstevel@tonic-gate  * of STR_NOERROR or STR_NOSIG
5780*7c478bd9Sstevel@tonic-gate  * STR_NOSIG: Signals are essentially ignored or held and have
5781*7c478bd9Sstevel@tonic-gate  *	no effect for the duration of the call.
5782*7c478bd9Sstevel@tonic-gate  * STR_NOERROR: Ignores stream head read, write and hup errors.
5783*7c478bd9Sstevel@tonic-gate  *	Additionally, if an existing ioctl times out, it is assumed
5784*7c478bd9Sstevel@tonic-gate  *	lost and and this ioctl will continue as if the previous ioctl had
5785*7c478bd9Sstevel@tonic-gate  *	finished.  ETIME may be returned if this ioctl times out (i.e.
5786*7c478bd9Sstevel@tonic-gate  *	ic_timout is not INFTIM).  Non-stream head errors may be returned if
5787*7c478bd9Sstevel@tonic-gate  *	the ioc_error indicates that the driver/module had problems,
5788*7c478bd9Sstevel@tonic-gate  *	an EFAULT was found when accessing user data, a lack of
5789*7c478bd9Sstevel@tonic-gate  * 	resources, etc.
5790*7c478bd9Sstevel@tonic-gate  */
5791*7c478bd9Sstevel@tonic-gate int
5792*7c478bd9Sstevel@tonic-gate strdoioctl(
5793*7c478bd9Sstevel@tonic-gate 	struct stdata *stp,
5794*7c478bd9Sstevel@tonic-gate 	struct strioctl *strioc,
5795*7c478bd9Sstevel@tonic-gate 	int fflags,		/* file flags with model info */
5796*7c478bd9Sstevel@tonic-gate 	int flag,
5797*7c478bd9Sstevel@tonic-gate 	cred_t *crp,
5798*7c478bd9Sstevel@tonic-gate 	int *rvalp)
5799*7c478bd9Sstevel@tonic-gate {
5800*7c478bd9Sstevel@tonic-gate 	mblk_t *bp;
5801*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocbp;
5802*7c478bd9Sstevel@tonic-gate 	struct copyreq *reqp;
5803*7c478bd9Sstevel@tonic-gate 	struct copyresp *resp;
5804*7c478bd9Sstevel@tonic-gate 	int id;
5805*7c478bd9Sstevel@tonic-gate 	int transparent = 0;
5806*7c478bd9Sstevel@tonic-gate 	int error = 0;
5807*7c478bd9Sstevel@tonic-gate 	int len = 0;
5808*7c478bd9Sstevel@tonic-gate 	caddr_t taddr;
5809*7c478bd9Sstevel@tonic-gate 	int copyflag = (flag & (U_TO_K | K_TO_K));
5810*7c478bd9Sstevel@tonic-gate 	int sigflag = (flag & STR_NOSIG);
5811*7c478bd9Sstevel@tonic-gate 	int errs;
5812*7c478bd9Sstevel@tonic-gate 	uint_t waitflags;
5813*7c478bd9Sstevel@tonic-gate 
5814*7c478bd9Sstevel@tonic-gate 	ASSERT(copyflag == U_TO_K || copyflag == K_TO_K);
5815*7c478bd9Sstevel@tonic-gate 	ASSERT((fflags & FMODELS) != 0);
5816*7c478bd9Sstevel@tonic-gate 
5817*7c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR,
5818*7c478bd9Sstevel@tonic-gate 		TR_STRDOIOCTL,
5819*7c478bd9Sstevel@tonic-gate 		"strdoioctl:stp %p strioc %p", stp, strioc);
5820*7c478bd9Sstevel@tonic-gate 	if (strioc->ic_len == TRANSPARENT) {	/* send arg in M_DATA block */
5821*7c478bd9Sstevel@tonic-gate 		transparent = 1;
5822*7c478bd9Sstevel@tonic-gate 		strioc->ic_len = sizeof (intptr_t);
5823*7c478bd9Sstevel@tonic-gate 	}
5824*7c478bd9Sstevel@tonic-gate 
5825*7c478bd9Sstevel@tonic-gate 	if (strioc->ic_len < 0 || (strmsgsz > 0 && strioc->ic_len > strmsgsz))
5826*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
5827*7c478bd9Sstevel@tonic-gate 
5828*7c478bd9Sstevel@tonic-gate 	if ((bp = allocb_cred_wait(sizeof (union ioctypes), sigflag, &error,
5829*7c478bd9Sstevel@tonic-gate 	    crp)) == NULL)
5830*7c478bd9Sstevel@tonic-gate 			return (error);
5831*7c478bd9Sstevel@tonic-gate 
5832*7c478bd9Sstevel@tonic-gate 	bzero(bp->b_wptr, sizeof (union ioctypes));
5833*7c478bd9Sstevel@tonic-gate 
5834*7c478bd9Sstevel@tonic-gate 	iocbp = (struct iocblk *)bp->b_wptr;
5835*7c478bd9Sstevel@tonic-gate 	iocbp->ioc_count = strioc->ic_len;
5836*7c478bd9Sstevel@tonic-gate 	iocbp->ioc_cmd = strioc->ic_cmd;
5837*7c478bd9Sstevel@tonic-gate 	iocbp->ioc_flag = (fflags & FMODELS);
5838*7c478bd9Sstevel@tonic-gate 
5839*7c478bd9Sstevel@tonic-gate 	crhold(crp);
5840*7c478bd9Sstevel@tonic-gate 	iocbp->ioc_cr = crp;
5841*7c478bd9Sstevel@tonic-gate 	DB_TYPE(bp) = M_IOCTL;
5842*7c478bd9Sstevel@tonic-gate 	DB_CPID(bp) = curproc->p_pid;
5843*7c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct iocblk);
5844*7c478bd9Sstevel@tonic-gate 
5845*7c478bd9Sstevel@tonic-gate 	if (flag & STR_NOERROR)
5846*7c478bd9Sstevel@tonic-gate 		errs = STPLEX;
5847*7c478bd9Sstevel@tonic-gate 	else
5848*7c478bd9Sstevel@tonic-gate 		errs = STRHUP|STRDERR|STWRERR|STPLEX;
5849*7c478bd9Sstevel@tonic-gate 
5850*7c478bd9Sstevel@tonic-gate 	/*
5851*7c478bd9Sstevel@tonic-gate 	 * If there is data to copy into ioctl block, do so.
5852*7c478bd9Sstevel@tonic-gate 	 */
5853*7c478bd9Sstevel@tonic-gate 	if (iocbp->ioc_count > 0) {
5854*7c478bd9Sstevel@tonic-gate 		if (transparent)
5855*7c478bd9Sstevel@tonic-gate 			/*
5856*7c478bd9Sstevel@tonic-gate 			 * Note: STR_NOERROR does not have an effect
5857*7c478bd9Sstevel@tonic-gate 			 * in putiocd()
5858*7c478bd9Sstevel@tonic-gate 			 */
5859*7c478bd9Sstevel@tonic-gate 			id = K_TO_K | sigflag;
5860*7c478bd9Sstevel@tonic-gate 		else
5861*7c478bd9Sstevel@tonic-gate 			id = flag;
5862*7c478bd9Sstevel@tonic-gate 		if ((error = putiocd(bp, strioc->ic_dp, id, crp)) != 0) {
5863*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
5864*7c478bd9Sstevel@tonic-gate 			crfree(crp);
5865*7c478bd9Sstevel@tonic-gate 			return (error);
5866*7c478bd9Sstevel@tonic-gate 		}
5867*7c478bd9Sstevel@tonic-gate 
5868*7c478bd9Sstevel@tonic-gate 		/*
5869*7c478bd9Sstevel@tonic-gate 		 * We could have slept copying in user pages.
5870*7c478bd9Sstevel@tonic-gate 		 * Recheck the stream head state (the other end
5871*7c478bd9Sstevel@tonic-gate 		 * of a pipe could have gone away).
5872*7c478bd9Sstevel@tonic-gate 		 */
5873*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & errs) {
5874*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
5875*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
5876*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5877*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
5878*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
5879*7c478bd9Sstevel@tonic-gate 				crfree(crp);
5880*7c478bd9Sstevel@tonic-gate 				return (error);
5881*7c478bd9Sstevel@tonic-gate 			}
5882*7c478bd9Sstevel@tonic-gate 		}
5883*7c478bd9Sstevel@tonic-gate 	}
5884*7c478bd9Sstevel@tonic-gate 	if (transparent)
5885*7c478bd9Sstevel@tonic-gate 		iocbp->ioc_count = TRANSPARENT;
5886*7c478bd9Sstevel@tonic-gate 
5887*7c478bd9Sstevel@tonic-gate 	/*
5888*7c478bd9Sstevel@tonic-gate 	 * Block for up to STRTIMOUT milliseconds if there is an outstanding
5889*7c478bd9Sstevel@tonic-gate 	 * ioctl for this stream already running.  All processes
5890*7c478bd9Sstevel@tonic-gate 	 * sleeping here will be awakened as a result of an ACK
5891*7c478bd9Sstevel@tonic-gate 	 * or NAK being received for the outstanding ioctl, or
5892*7c478bd9Sstevel@tonic-gate 	 * as a result of the timer expiring on the outstanding
5893*7c478bd9Sstevel@tonic-gate 	 * ioctl (a failure), or as a result of any waiting
5894*7c478bd9Sstevel@tonic-gate 	 * process's timer expiring (also a failure).
5895*7c478bd9Sstevel@tonic-gate 	 */
5896*7c478bd9Sstevel@tonic-gate 
5897*7c478bd9Sstevel@tonic-gate 	error = 0;
5898*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
5899*7c478bd9Sstevel@tonic-gate 	while (stp->sd_flag & (IOCWAIT | IOCWAITNE)) {
5900*7c478bd9Sstevel@tonic-gate 		clock_t cv_rval;
5901*7c478bd9Sstevel@tonic-gate 
5902*7c478bd9Sstevel@tonic-gate 		TRACE_0(TR_FAC_STREAMS_FR,
5903*7c478bd9Sstevel@tonic-gate 			TR_STRDOIOCTL_WAIT,
5904*7c478bd9Sstevel@tonic-gate 			"strdoioctl sleeps - IOCWAIT");
5905*7c478bd9Sstevel@tonic-gate 		cv_rval = str_cv_wait(&stp->sd_iocmonitor, &stp->sd_lock,
5906*7c478bd9Sstevel@tonic-gate 		    STRTIMOUT, sigflag);
5907*7c478bd9Sstevel@tonic-gate 		if (cv_rval <= 0) {
5908*7c478bd9Sstevel@tonic-gate 			if (cv_rval == 0) {
5909*7c478bd9Sstevel@tonic-gate 				error = EINTR;
5910*7c478bd9Sstevel@tonic-gate 			} else {
5911*7c478bd9Sstevel@tonic-gate 				if (flag & STR_NOERROR) {
5912*7c478bd9Sstevel@tonic-gate 					/*
5913*7c478bd9Sstevel@tonic-gate 					 * Terminating current ioctl in
5914*7c478bd9Sstevel@tonic-gate 					 * progress -- assume it got lost and
5915*7c478bd9Sstevel@tonic-gate 					 * wake up the other thread so that the
5916*7c478bd9Sstevel@tonic-gate 					 * operation completes.
5917*7c478bd9Sstevel@tonic-gate 					 */
5918*7c478bd9Sstevel@tonic-gate 					if (!(stp->sd_flag & IOCWAITNE)) {
5919*7c478bd9Sstevel@tonic-gate 						stp->sd_flag |= IOCWAITNE;
5920*7c478bd9Sstevel@tonic-gate 						cv_broadcast(&stp->sd_monitor);
5921*7c478bd9Sstevel@tonic-gate 					}
5922*7c478bd9Sstevel@tonic-gate 					/*
5923*7c478bd9Sstevel@tonic-gate 					 * Otherwise, there's a running
5924*7c478bd9Sstevel@tonic-gate 					 * STR_NOERROR -- we have no choice
5925*7c478bd9Sstevel@tonic-gate 					 * here but to wait forever (or until
5926*7c478bd9Sstevel@tonic-gate 					 * interrupted).
5927*7c478bd9Sstevel@tonic-gate 					 */
5928*7c478bd9Sstevel@tonic-gate 				} else {
5929*7c478bd9Sstevel@tonic-gate 					/*
5930*7c478bd9Sstevel@tonic-gate 					 * pending ioctl has caused
5931*7c478bd9Sstevel@tonic-gate 					 * us to time out
5932*7c478bd9Sstevel@tonic-gate 					 */
5933*7c478bd9Sstevel@tonic-gate 					error = ETIME;
5934*7c478bd9Sstevel@tonic-gate 				}
5935*7c478bd9Sstevel@tonic-gate 			}
5936*7c478bd9Sstevel@tonic-gate 		} else if ((stp->sd_flag & errs)) {
5937*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
5938*7c478bd9Sstevel@tonic-gate 		}
5939*7c478bd9Sstevel@tonic-gate 		if (error) {
5940*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
5941*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
5942*7c478bd9Sstevel@tonic-gate 			crfree(crp);
5943*7c478bd9Sstevel@tonic-gate 			return (error);
5944*7c478bd9Sstevel@tonic-gate 		}
5945*7c478bd9Sstevel@tonic-gate 	}
5946*7c478bd9Sstevel@tonic-gate 
5947*7c478bd9Sstevel@tonic-gate 	/*
5948*7c478bd9Sstevel@tonic-gate 	 * Have control of ioctl mechanism.
5949*7c478bd9Sstevel@tonic-gate 	 * Send down ioctl packet and wait for response.
5950*7c478bd9Sstevel@tonic-gate 	 */
5951*7c478bd9Sstevel@tonic-gate 	if (stp->sd_iocblk != (mblk_t *)-1) {
5952*7c478bd9Sstevel@tonic-gate 		freemsg(stp->sd_iocblk);
5953*7c478bd9Sstevel@tonic-gate 	}
5954*7c478bd9Sstevel@tonic-gate 	stp->sd_iocblk = NULL;
5955*7c478bd9Sstevel@tonic-gate 
5956*7c478bd9Sstevel@tonic-gate 	/*
5957*7c478bd9Sstevel@tonic-gate 	 * If this is marked with 'noerror' (internal; mostly
5958*7c478bd9Sstevel@tonic-gate 	 * I_{P,}{UN,}LINK), then make sure nobody else is able to get
5959*7c478bd9Sstevel@tonic-gate 	 * in here by setting IOCWAITNE.
5960*7c478bd9Sstevel@tonic-gate 	 */
5961*7c478bd9Sstevel@tonic-gate 	waitflags = IOCWAIT;
5962*7c478bd9Sstevel@tonic-gate 	if (flag & STR_NOERROR)
5963*7c478bd9Sstevel@tonic-gate 		waitflags |= IOCWAITNE;
5964*7c478bd9Sstevel@tonic-gate 
5965*7c478bd9Sstevel@tonic-gate 	stp->sd_flag |= waitflags;
5966*7c478bd9Sstevel@tonic-gate 
5967*7c478bd9Sstevel@tonic-gate 	/*
5968*7c478bd9Sstevel@tonic-gate 	 * Assign sequence number.
5969*7c478bd9Sstevel@tonic-gate 	 */
5970*7c478bd9Sstevel@tonic-gate 	iocbp->ioc_id = stp->sd_iocid = getiocseqno();
5971*7c478bd9Sstevel@tonic-gate 
5972*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
5973*7c478bd9Sstevel@tonic-gate 
5974*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
5975*7c478bd9Sstevel@tonic-gate 		TR_STRDOIOCTL_PUT, "strdoioctl put: stp %p", stp);
5976*7c478bd9Sstevel@tonic-gate 	stream_willservice(stp);
5977*7c478bd9Sstevel@tonic-gate 	putnext(stp->sd_wrq, bp);
5978*7c478bd9Sstevel@tonic-gate 	stream_runservice(stp);
5979*7c478bd9Sstevel@tonic-gate 
5980*7c478bd9Sstevel@tonic-gate 	/*
5981*7c478bd9Sstevel@tonic-gate 	 * Timed wait for acknowledgment.  The wait time is limited by the
5982*7c478bd9Sstevel@tonic-gate 	 * timeout value, which must be a positive integer (number of
5983*7c478bd9Sstevel@tonic-gate 	 * milliseconds to wait, or 0 (use default value of STRTIMOUT
5984*7c478bd9Sstevel@tonic-gate 	 * milliseconds), or -1 (wait forever).  This will be awakened
5985*7c478bd9Sstevel@tonic-gate 	 * either by an ACK/NAK message arriving, the timer expiring, or
5986*7c478bd9Sstevel@tonic-gate 	 * the timer expiring on another ioctl waiting for control of the
5987*7c478bd9Sstevel@tonic-gate 	 * mechanism.
5988*7c478bd9Sstevel@tonic-gate 	 */
5989*7c478bd9Sstevel@tonic-gate waitioc:
5990*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
5991*7c478bd9Sstevel@tonic-gate 
5992*7c478bd9Sstevel@tonic-gate 
5993*7c478bd9Sstevel@tonic-gate 	/*
5994*7c478bd9Sstevel@tonic-gate 	 * If the reply has already arrived, don't sleep.  If awakened from
5995*7c478bd9Sstevel@tonic-gate 	 * the sleep, fail only if the reply has not arrived by then.
5996*7c478bd9Sstevel@tonic-gate 	 * Otherwise, process the reply.
5997*7c478bd9Sstevel@tonic-gate 	 */
5998*7c478bd9Sstevel@tonic-gate 	while (!stp->sd_iocblk) {
5999*7c478bd9Sstevel@tonic-gate 		clock_t cv_rval;
6000*7c478bd9Sstevel@tonic-gate 
6001*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & errs) {
6002*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, errs, 0);
6003*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
6004*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~waitflags;
6005*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&stp->sd_iocmonitor);
6006*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
6007*7c478bd9Sstevel@tonic-gate 				crfree(crp);
6008*7c478bd9Sstevel@tonic-gate 				return (error);
6009*7c478bd9Sstevel@tonic-gate 			}
6010*7c478bd9Sstevel@tonic-gate 		}
6011*7c478bd9Sstevel@tonic-gate 
6012*7c478bd9Sstevel@tonic-gate 		TRACE_0(TR_FAC_STREAMS_FR,
6013*7c478bd9Sstevel@tonic-gate 			TR_STRDOIOCTL_WAIT2,
6014*7c478bd9Sstevel@tonic-gate 			"strdoioctl sleeps awaiting reply");
6015*7c478bd9Sstevel@tonic-gate 		ASSERT(error == 0);
6016*7c478bd9Sstevel@tonic-gate 
6017*7c478bd9Sstevel@tonic-gate 		cv_rval = str_cv_wait(&stp->sd_monitor, &stp->sd_lock,
6018*7c478bd9Sstevel@tonic-gate 		    (strioc->ic_timout ?
6019*7c478bd9Sstevel@tonic-gate 		    strioc->ic_timout * 1000 : STRTIMOUT), sigflag);
6020*7c478bd9Sstevel@tonic-gate 
6021*7c478bd9Sstevel@tonic-gate 		/*
6022*7c478bd9Sstevel@tonic-gate 		 * There are four possible cases here: interrupt, timeout,
6023*7c478bd9Sstevel@tonic-gate 		 * wakeup by IOCWAITNE (above), or wakeup by strrput_nondata (a
6024*7c478bd9Sstevel@tonic-gate 		 * valid M_IOCTL reply).
6025*7c478bd9Sstevel@tonic-gate 		 *
6026*7c478bd9Sstevel@tonic-gate 		 * If we've been awakened by a STR_NOERROR ioctl on some other
6027*7c478bd9Sstevel@tonic-gate 		 * thread, then sd_iocblk will still be NULL, and IOCWAITNE
6028*7c478bd9Sstevel@tonic-gate 		 * will be set.  Pretend as if we just timed out.  Note that
6029*7c478bd9Sstevel@tonic-gate 		 * this other thread waited at least STRTIMOUT before trying to
6030*7c478bd9Sstevel@tonic-gate 		 * awaken our thread, so this is indistinguishable (even for
6031*7c478bd9Sstevel@tonic-gate 		 * INFTIM) from the case where we failed with ETIME waiting on
6032*7c478bd9Sstevel@tonic-gate 		 * IOCWAIT in the prior loop.
6033*7c478bd9Sstevel@tonic-gate 		 */
6034*7c478bd9Sstevel@tonic-gate 		if (cv_rval > 0 && !(flag & STR_NOERROR) &&
6035*7c478bd9Sstevel@tonic-gate 		    stp->sd_iocblk == NULL && (stp->sd_flag & IOCWAITNE)) {
6036*7c478bd9Sstevel@tonic-gate 			cv_rval = -1;
6037*7c478bd9Sstevel@tonic-gate 		}
6038*7c478bd9Sstevel@tonic-gate 
6039*7c478bd9Sstevel@tonic-gate 		/*
6040*7c478bd9Sstevel@tonic-gate 		 * note: STR_NOERROR does not protect
6041*7c478bd9Sstevel@tonic-gate 		 * us here.. use ic_timout < 0
6042*7c478bd9Sstevel@tonic-gate 		 */
6043*7c478bd9Sstevel@tonic-gate 		if (cv_rval <= 0) {
6044*7c478bd9Sstevel@tonic-gate 			if (cv_rval == 0) {
6045*7c478bd9Sstevel@tonic-gate 				error = EINTR;
6046*7c478bd9Sstevel@tonic-gate 			} else {
6047*7c478bd9Sstevel@tonic-gate 				error =  ETIME;
6048*7c478bd9Sstevel@tonic-gate 			}
6049*7c478bd9Sstevel@tonic-gate 			/*
6050*7c478bd9Sstevel@tonic-gate 			 * A message could have come in after we were scheduled
6051*7c478bd9Sstevel@tonic-gate 			 * but before we were actually run.
6052*7c478bd9Sstevel@tonic-gate 			 */
6053*7c478bd9Sstevel@tonic-gate 			bp = stp->sd_iocblk;
6054*7c478bd9Sstevel@tonic-gate 			stp->sd_iocblk = NULL;
6055*7c478bd9Sstevel@tonic-gate 			if (bp != NULL) {
6056*7c478bd9Sstevel@tonic-gate 				if ((bp->b_datap->db_type == M_COPYIN) ||
6057*7c478bd9Sstevel@tonic-gate 				    (bp->b_datap->db_type == M_COPYOUT)) {
6058*7c478bd9Sstevel@tonic-gate 					mutex_exit(&stp->sd_lock);
6059*7c478bd9Sstevel@tonic-gate 					if (bp->b_cont) {
6060*7c478bd9Sstevel@tonic-gate 						freemsg(bp->b_cont);
6061*7c478bd9Sstevel@tonic-gate 						bp->b_cont = NULL;
6062*7c478bd9Sstevel@tonic-gate 					}
6063*7c478bd9Sstevel@tonic-gate 					bp->b_datap->db_type = M_IOCDATA;
6064*7c478bd9Sstevel@tonic-gate 					bp->b_wptr = bp->b_rptr +
6065*7c478bd9Sstevel@tonic-gate 						sizeof (struct copyresp);
6066*7c478bd9Sstevel@tonic-gate 					resp = (struct copyresp *)bp->b_rptr;
6067*7c478bd9Sstevel@tonic-gate 					resp->cp_rval =
6068*7c478bd9Sstevel@tonic-gate 					    (caddr_t)1; /* failure */
6069*7c478bd9Sstevel@tonic-gate 					stream_willservice(stp);
6070*7c478bd9Sstevel@tonic-gate 					putnext(stp->sd_wrq, bp);
6071*7c478bd9Sstevel@tonic-gate 					stream_runservice(stp);
6072*7c478bd9Sstevel@tonic-gate 					mutex_enter(&stp->sd_lock);
6073*7c478bd9Sstevel@tonic-gate 				} else {
6074*7c478bd9Sstevel@tonic-gate 					freemsg(bp);
6075*7c478bd9Sstevel@tonic-gate 				}
6076*7c478bd9Sstevel@tonic-gate 			}
6077*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
6078*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
6079*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6080*7c478bd9Sstevel@tonic-gate 			crfree(crp);
6081*7c478bd9Sstevel@tonic-gate 			return (error);
6082*7c478bd9Sstevel@tonic-gate 		}
6083*7c478bd9Sstevel@tonic-gate 	}
6084*7c478bd9Sstevel@tonic-gate 	bp = stp->sd_iocblk;
6085*7c478bd9Sstevel@tonic-gate 	/*
6086*7c478bd9Sstevel@tonic-gate 	 * Note: it is strictly impossible to get here with sd_iocblk set to
6087*7c478bd9Sstevel@tonic-gate 	 * -1.  This is because the initial loop above doesn't allow any new
6088*7c478bd9Sstevel@tonic-gate 	 * ioctls into the fray until all others have passed this point.
6089*7c478bd9Sstevel@tonic-gate 	 */
6090*7c478bd9Sstevel@tonic-gate 	ASSERT(bp != NULL && bp != (mblk_t *)-1);
6091*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR,
6092*7c478bd9Sstevel@tonic-gate 		TR_STRDOIOCTL_ACK, "strdoioctl got reply: bp %p", bp);
6093*7c478bd9Sstevel@tonic-gate 	if ((bp->b_datap->db_type == M_IOCACK) ||
6094*7c478bd9Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_IOCNAK)) {
6095*7c478bd9Sstevel@tonic-gate 		/* for detection of duplicate ioctl replies */
6096*7c478bd9Sstevel@tonic-gate 		stp->sd_iocblk = (mblk_t *)-1;
6097*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~waitflags;
6098*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_iocmonitor);
6099*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6100*7c478bd9Sstevel@tonic-gate 	} else {
6101*7c478bd9Sstevel@tonic-gate 		/*
6102*7c478bd9Sstevel@tonic-gate 		 * flags not cleared here because we're still doing
6103*7c478bd9Sstevel@tonic-gate 		 * copy in/out for ioctl.
6104*7c478bd9Sstevel@tonic-gate 		 */
6105*7c478bd9Sstevel@tonic-gate 		stp->sd_iocblk = NULL;
6106*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6107*7c478bd9Sstevel@tonic-gate 	}
6108*7c478bd9Sstevel@tonic-gate 
6109*7c478bd9Sstevel@tonic-gate 
6110*7c478bd9Sstevel@tonic-gate 	/*
6111*7c478bd9Sstevel@tonic-gate 	 * Have received acknowledgment.
6112*7c478bd9Sstevel@tonic-gate 	 */
6113*7c478bd9Sstevel@tonic-gate 
6114*7c478bd9Sstevel@tonic-gate 	switch (bp->b_datap->db_type) {
6115*7c478bd9Sstevel@tonic-gate 	case M_IOCACK:
6116*7c478bd9Sstevel@tonic-gate 		/*
6117*7c478bd9Sstevel@tonic-gate 		 * Positive ack.
6118*7c478bd9Sstevel@tonic-gate 		 */
6119*7c478bd9Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
6120*7c478bd9Sstevel@tonic-gate 
6121*7c478bd9Sstevel@tonic-gate 		/*
6122*7c478bd9Sstevel@tonic-gate 		 * Set error if indicated.
6123*7c478bd9Sstevel@tonic-gate 		 */
6124*7c478bd9Sstevel@tonic-gate 		if (iocbp->ioc_error) {
6125*7c478bd9Sstevel@tonic-gate 			error = iocbp->ioc_error;
6126*7c478bd9Sstevel@tonic-gate 			break;
6127*7c478bd9Sstevel@tonic-gate 		}
6128*7c478bd9Sstevel@tonic-gate 
6129*7c478bd9Sstevel@tonic-gate 		/*
6130*7c478bd9Sstevel@tonic-gate 		 * Set return value.
6131*7c478bd9Sstevel@tonic-gate 		 */
6132*7c478bd9Sstevel@tonic-gate 		*rvalp = iocbp->ioc_rval;
6133*7c478bd9Sstevel@tonic-gate 
6134*7c478bd9Sstevel@tonic-gate 		/*
6135*7c478bd9Sstevel@tonic-gate 		 * Data may have been returned in ACK message (ioc_count > 0).
6136*7c478bd9Sstevel@tonic-gate 		 * If so, copy it out to the user's buffer.
6137*7c478bd9Sstevel@tonic-gate 		 */
6138*7c478bd9Sstevel@tonic-gate 		if (iocbp->ioc_count && !transparent) {
6139*7c478bd9Sstevel@tonic-gate 			if (error = getiocd(bp, strioc->ic_dp, copyflag))
6140*7c478bd9Sstevel@tonic-gate 				break;
6141*7c478bd9Sstevel@tonic-gate 		}
6142*7c478bd9Sstevel@tonic-gate 		if (!transparent) {
6143*7c478bd9Sstevel@tonic-gate 			if (len)	/* an M_COPYOUT was used with I_STR */
6144*7c478bd9Sstevel@tonic-gate 				strioc->ic_len = len;
6145*7c478bd9Sstevel@tonic-gate 			else
6146*7c478bd9Sstevel@tonic-gate 				strioc->ic_len = (int)iocbp->ioc_count;
6147*7c478bd9Sstevel@tonic-gate 		}
6148*7c478bd9Sstevel@tonic-gate 		break;
6149*7c478bd9Sstevel@tonic-gate 
6150*7c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
6151*7c478bd9Sstevel@tonic-gate 		/*
6152*7c478bd9Sstevel@tonic-gate 		 * Negative ack.
6153*7c478bd9Sstevel@tonic-gate 		 *
6154*7c478bd9Sstevel@tonic-gate 		 * The only thing to do is set error as specified
6155*7c478bd9Sstevel@tonic-gate 		 * in neg ack packet.
6156*7c478bd9Sstevel@tonic-gate 		 */
6157*7c478bd9Sstevel@tonic-gate 		iocbp = (struct iocblk *)bp->b_rptr;
6158*7c478bd9Sstevel@tonic-gate 
6159*7c478bd9Sstevel@tonic-gate 		error = (iocbp->ioc_error ? iocbp->ioc_error : EINVAL);
6160*7c478bd9Sstevel@tonic-gate 		break;
6161*7c478bd9Sstevel@tonic-gate 
6162*7c478bd9Sstevel@tonic-gate 	case M_COPYIN:
6163*7c478bd9Sstevel@tonic-gate 		/*
6164*7c478bd9Sstevel@tonic-gate 		 * Driver or module has requested user ioctl data.
6165*7c478bd9Sstevel@tonic-gate 		 */
6166*7c478bd9Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
6167*7c478bd9Sstevel@tonic-gate 
6168*7c478bd9Sstevel@tonic-gate 		/*
6169*7c478bd9Sstevel@tonic-gate 		 * M_COPYIN should *never* have a message attached, though
6170*7c478bd9Sstevel@tonic-gate 		 * it's harmless if it does -- thus, panic on a DEBUG
6171*7c478bd9Sstevel@tonic-gate 		 * kernel and just free it on a non-DEBUG build.
6172*7c478bd9Sstevel@tonic-gate 		 */
6173*7c478bd9Sstevel@tonic-gate 		ASSERT(bp->b_cont == NULL);
6174*7c478bd9Sstevel@tonic-gate 		if (bp->b_cont != NULL) {
6175*7c478bd9Sstevel@tonic-gate 			freemsg(bp->b_cont);
6176*7c478bd9Sstevel@tonic-gate 			bp->b_cont = NULL;
6177*7c478bd9Sstevel@tonic-gate 		}
6178*7c478bd9Sstevel@tonic-gate 
6179*7c478bd9Sstevel@tonic-gate 		error = putiocd(bp, reqp->cq_addr, flag, crp);
6180*7c478bd9Sstevel@tonic-gate 		if (error && bp->b_cont) {
6181*7c478bd9Sstevel@tonic-gate 			freemsg(bp->b_cont);
6182*7c478bd9Sstevel@tonic-gate 			bp->b_cont = NULL;
6183*7c478bd9Sstevel@tonic-gate 		}
6184*7c478bd9Sstevel@tonic-gate 
6185*7c478bd9Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
6186*7c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
6187*7c478bd9Sstevel@tonic-gate 
6188*7c478bd9Sstevel@tonic-gate 		mblk_setcred(bp, crp);
6189*7c478bd9Sstevel@tonic-gate 		DB_CPID(bp) = curproc->p_pid;
6190*7c478bd9Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
6191*7c478bd9Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)(uintptr_t)error;
6192*7c478bd9Sstevel@tonic-gate 		resp->cp_flag = (fflags & FMODELS);
6193*7c478bd9Sstevel@tonic-gate 
6194*7c478bd9Sstevel@tonic-gate 		stream_willservice(stp);
6195*7c478bd9Sstevel@tonic-gate 		putnext(stp->sd_wrq, bp);
6196*7c478bd9Sstevel@tonic-gate 		stream_runservice(stp);
6197*7c478bd9Sstevel@tonic-gate 
6198*7c478bd9Sstevel@tonic-gate 		if (error) {
6199*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
6200*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
6201*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
6202*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6203*7c478bd9Sstevel@tonic-gate 			crfree(crp);
6204*7c478bd9Sstevel@tonic-gate 			return (error);
6205*7c478bd9Sstevel@tonic-gate 		}
6206*7c478bd9Sstevel@tonic-gate 
6207*7c478bd9Sstevel@tonic-gate 		goto waitioc;
6208*7c478bd9Sstevel@tonic-gate 
6209*7c478bd9Sstevel@tonic-gate 	case M_COPYOUT:
6210*7c478bd9Sstevel@tonic-gate 		/*
6211*7c478bd9Sstevel@tonic-gate 		 * Driver or module has ioctl data for a user.
6212*7c478bd9Sstevel@tonic-gate 		 */
6213*7c478bd9Sstevel@tonic-gate 		reqp = (struct copyreq *)bp->b_rptr;
6214*7c478bd9Sstevel@tonic-gate 		ASSERT(bp->b_cont != NULL);
6215*7c478bd9Sstevel@tonic-gate 
6216*7c478bd9Sstevel@tonic-gate 		/*
6217*7c478bd9Sstevel@tonic-gate 		 * Always (transparent or non-transparent )
6218*7c478bd9Sstevel@tonic-gate 		 * use the address specified in the request
6219*7c478bd9Sstevel@tonic-gate 		 */
6220*7c478bd9Sstevel@tonic-gate 		taddr = reqp->cq_addr;
6221*7c478bd9Sstevel@tonic-gate 		if (!transparent)
6222*7c478bd9Sstevel@tonic-gate 			len = (int)reqp->cq_size;
6223*7c478bd9Sstevel@tonic-gate 
6224*7c478bd9Sstevel@tonic-gate 		/* copyout data to the provided address */
6225*7c478bd9Sstevel@tonic-gate 		error = getiocd(bp, taddr, copyflag);
6226*7c478bd9Sstevel@tonic-gate 
6227*7c478bd9Sstevel@tonic-gate 		freemsg(bp->b_cont);
6228*7c478bd9Sstevel@tonic-gate 		bp->b_cont = NULL;
6229*7c478bd9Sstevel@tonic-gate 
6230*7c478bd9Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + sizeof (struct copyresp);
6231*7c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_IOCDATA;
6232*7c478bd9Sstevel@tonic-gate 
6233*7c478bd9Sstevel@tonic-gate 		mblk_setcred(bp, crp);
6234*7c478bd9Sstevel@tonic-gate 		DB_CPID(bp) = curproc->p_pid;
6235*7c478bd9Sstevel@tonic-gate 		resp = (struct copyresp *)bp->b_rptr;
6236*7c478bd9Sstevel@tonic-gate 		resp->cp_rval = (caddr_t)(uintptr_t)error;
6237*7c478bd9Sstevel@tonic-gate 		resp->cp_flag = (fflags & FMODELS);
6238*7c478bd9Sstevel@tonic-gate 
6239*7c478bd9Sstevel@tonic-gate 		stream_willservice(stp);
6240*7c478bd9Sstevel@tonic-gate 		putnext(stp->sd_wrq, bp);
6241*7c478bd9Sstevel@tonic-gate 		stream_runservice(stp);
6242*7c478bd9Sstevel@tonic-gate 
6243*7c478bd9Sstevel@tonic-gate 		if (error) {
6244*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
6245*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~waitflags;
6246*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&stp->sd_iocmonitor);
6247*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6248*7c478bd9Sstevel@tonic-gate 			crfree(crp);
6249*7c478bd9Sstevel@tonic-gate 			return (error);
6250*7c478bd9Sstevel@tonic-gate 		}
6251*7c478bd9Sstevel@tonic-gate 		goto waitioc;
6252*7c478bd9Sstevel@tonic-gate 
6253*7c478bd9Sstevel@tonic-gate 	default:
6254*7c478bd9Sstevel@tonic-gate 		ASSERT(0);
6255*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
6256*7c478bd9Sstevel@tonic-gate 		stp->sd_flag &= ~waitflags;
6257*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&stp->sd_iocmonitor);
6258*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6259*7c478bd9Sstevel@tonic-gate 		break;
6260*7c478bd9Sstevel@tonic-gate 	}
6261*7c478bd9Sstevel@tonic-gate 
6262*7c478bd9Sstevel@tonic-gate 	freemsg(bp);
6263*7c478bd9Sstevel@tonic-gate 	crfree(crp);
6264*7c478bd9Sstevel@tonic-gate 	return (error);
6265*7c478bd9Sstevel@tonic-gate }
6266*7c478bd9Sstevel@tonic-gate 
6267*7c478bd9Sstevel@tonic-gate /*
6268*7c478bd9Sstevel@tonic-gate  * For the SunOS keyboard driver.
6269*7c478bd9Sstevel@tonic-gate  * Return the next available "ioctl" sequence number.
6270*7c478bd9Sstevel@tonic-gate  * Exported, so that streams modules can send "ioctl" messages
6271*7c478bd9Sstevel@tonic-gate  * downstream from their open routine.
6272*7c478bd9Sstevel@tonic-gate  */
6273*7c478bd9Sstevel@tonic-gate int
6274*7c478bd9Sstevel@tonic-gate getiocseqno(void)
6275*7c478bd9Sstevel@tonic-gate {
6276*7c478bd9Sstevel@tonic-gate 	int	i;
6277*7c478bd9Sstevel@tonic-gate 
6278*7c478bd9Sstevel@tonic-gate 	mutex_enter(&strresources);
6279*7c478bd9Sstevel@tonic-gate 	i = ++ioc_id;
6280*7c478bd9Sstevel@tonic-gate 	mutex_exit(&strresources);
6281*7c478bd9Sstevel@tonic-gate 	return (i);
6282*7c478bd9Sstevel@tonic-gate }
6283*7c478bd9Sstevel@tonic-gate 
6284*7c478bd9Sstevel@tonic-gate /*
6285*7c478bd9Sstevel@tonic-gate  * Get the next message from the read queue.  If the message is
6286*7c478bd9Sstevel@tonic-gate  * priority, STRPRI will have been set by strrput().  This flag
6287*7c478bd9Sstevel@tonic-gate  * should be reset only when the entire message at the front of the
6288*7c478bd9Sstevel@tonic-gate  * queue as been consumed.
6289*7c478bd9Sstevel@tonic-gate  *
6290*7c478bd9Sstevel@tonic-gate  * NOTE: strgetmsg and kstrgetmsg have much of the logic in common.
6291*7c478bd9Sstevel@tonic-gate  */
6292*7c478bd9Sstevel@tonic-gate int
6293*7c478bd9Sstevel@tonic-gate strgetmsg(
6294*7c478bd9Sstevel@tonic-gate 	struct vnode *vp,
6295*7c478bd9Sstevel@tonic-gate 	struct strbuf *mctl,
6296*7c478bd9Sstevel@tonic-gate 	struct strbuf *mdata,
6297*7c478bd9Sstevel@tonic-gate 	unsigned char *prip,
6298*7c478bd9Sstevel@tonic-gate 	int *flagsp,
6299*7c478bd9Sstevel@tonic-gate 	int fmode,
6300*7c478bd9Sstevel@tonic-gate 	rval_t *rvp)
6301*7c478bd9Sstevel@tonic-gate {
6302*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
6303*7c478bd9Sstevel@tonic-gate 	mblk_t *bp, *nbp;
6304*7c478bd9Sstevel@tonic-gate 	mblk_t *savemp = NULL;
6305*7c478bd9Sstevel@tonic-gate 	mblk_t *savemptail = NULL;
6306*7c478bd9Sstevel@tonic-gate 	uint_t old_sd_flag;
6307*7c478bd9Sstevel@tonic-gate 	int flg;
6308*7c478bd9Sstevel@tonic-gate 	int more = 0;
6309*7c478bd9Sstevel@tonic-gate 	int error = 0;
6310*7c478bd9Sstevel@tonic-gate 	char first = 1;
6311*7c478bd9Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
6312*7c478bd9Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
6313*7c478bd9Sstevel@tonic-gate 	unsigned char pri = 0;
6314*7c478bd9Sstevel@tonic-gate 	queue_t *q;
6315*7c478bd9Sstevel@tonic-gate 	int	pr = 0;			/* Partial read successful */
6316*7c478bd9Sstevel@tonic-gate 	struct uio uios;
6317*7c478bd9Sstevel@tonic-gate 	struct uio *uiop = &uios;
6318*7c478bd9Sstevel@tonic-gate 	struct iovec iovs;
6319*7c478bd9Sstevel@tonic-gate 	unsigned char type;
6320*7c478bd9Sstevel@tonic-gate 
6321*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRGETMSG_ENTER,
6322*7c478bd9Sstevel@tonic-gate 		"strgetmsg:%p", vp);
6323*7c478bd9Sstevel@tonic-gate 
6324*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
6325*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
6326*7c478bd9Sstevel@tonic-gate 	rvp->r_val1 = 0;
6327*7c478bd9Sstevel@tonic-gate 
6328*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
6329*7c478bd9Sstevel@tonic-gate 		if (error = straccess(stp, JCREAD))
6330*7c478bd9Sstevel@tonic-gate 			return (error);
6331*7c478bd9Sstevel@tonic-gate 
6332*7c478bd9Sstevel@tonic-gate 	/* Fast check of flags before acquiring the lock */
6333*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
6334*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
6335*7c478bd9Sstevel@tonic-gate 		error = strgeterr(stp, STRDERR|STPLEX, 0);
6336*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6337*7c478bd9Sstevel@tonic-gate 		if (error != 0)
6338*7c478bd9Sstevel@tonic-gate 			return (error);
6339*7c478bd9Sstevel@tonic-gate 	}
6340*7c478bd9Sstevel@tonic-gate 
6341*7c478bd9Sstevel@tonic-gate 	switch (*flagsp) {
6342*7c478bd9Sstevel@tonic-gate 	case MSG_HIPRI:
6343*7c478bd9Sstevel@tonic-gate 		if (*prip != 0)
6344*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
6345*7c478bd9Sstevel@tonic-gate 		break;
6346*7c478bd9Sstevel@tonic-gate 
6347*7c478bd9Sstevel@tonic-gate 	case MSG_ANY:
6348*7c478bd9Sstevel@tonic-gate 	case MSG_BAND:
6349*7c478bd9Sstevel@tonic-gate 		break;
6350*7c478bd9Sstevel@tonic-gate 
6351*7c478bd9Sstevel@tonic-gate 	default:
6352*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
6353*7c478bd9Sstevel@tonic-gate 	}
6354*7c478bd9Sstevel@tonic-gate 	/*
6355*7c478bd9Sstevel@tonic-gate 	 * Setup uio and iov for data part
6356*7c478bd9Sstevel@tonic-gate 	 */
6357*7c478bd9Sstevel@tonic-gate 	iovs.iov_base = mdata->buf;
6358*7c478bd9Sstevel@tonic-gate 	iovs.iov_len = mdata->maxlen;
6359*7c478bd9Sstevel@tonic-gate 	uios.uio_iov = &iovs;
6360*7c478bd9Sstevel@tonic-gate 	uios.uio_iovcnt = 1;
6361*7c478bd9Sstevel@tonic-gate 	uios.uio_loffset = 0;
6362*7c478bd9Sstevel@tonic-gate 	uios.uio_segflg = UIO_USERSPACE;
6363*7c478bd9Sstevel@tonic-gate 	uios.uio_fmode = 0;
6364*7c478bd9Sstevel@tonic-gate 	uios.uio_extflg = UIO_COPY_CACHED;
6365*7c478bd9Sstevel@tonic-gate 	uios.uio_resid = mdata->maxlen;
6366*7c478bd9Sstevel@tonic-gate 	uios.uio_offset = 0;
6367*7c478bd9Sstevel@tonic-gate 
6368*7c478bd9Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
6369*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
6370*7c478bd9Sstevel@tonic-gate 	old_sd_flag = stp->sd_flag;
6371*7c478bd9Sstevel@tonic-gate 	mark = 0;
6372*7c478bd9Sstevel@tonic-gate 	for (;;) {
6373*7c478bd9Sstevel@tonic-gate 		int done = 0;
6374*7c478bd9Sstevel@tonic-gate 		mblk_t *q_first = q->q_first;
6375*7c478bd9Sstevel@tonic-gate 
6376*7c478bd9Sstevel@tonic-gate 		/*
6377*7c478bd9Sstevel@tonic-gate 		 * Get the next message of appropriate priority
6378*7c478bd9Sstevel@tonic-gate 		 * from the stream head.  If the caller is interested
6379*7c478bd9Sstevel@tonic-gate 		 * in band or hipri messages, then they should already
6380*7c478bd9Sstevel@tonic-gate 		 * be enqueued at the stream head.  On the other hand
6381*7c478bd9Sstevel@tonic-gate 		 * if the caller wants normal (band 0) messages, they
6382*7c478bd9Sstevel@tonic-gate 		 * might be deferred in a synchronous stream and they
6383*7c478bd9Sstevel@tonic-gate 		 * will need to be pulled up.
6384*7c478bd9Sstevel@tonic-gate 		 *
6385*7c478bd9Sstevel@tonic-gate 		 * After we have dequeued a message, we might find that
6386*7c478bd9Sstevel@tonic-gate 		 * it was a deferred M_SIG that was enqueued at the
6387*7c478bd9Sstevel@tonic-gate 		 * stream head.  It must now be posted as part of the
6388*7c478bd9Sstevel@tonic-gate 		 * read by calling strsignal_nolock().
6389*7c478bd9Sstevel@tonic-gate 		 *
6390*7c478bd9Sstevel@tonic-gate 		 * Also note that strrput does not enqueue an M_PCSIG,
6391*7c478bd9Sstevel@tonic-gate 		 * and there cannot be more than one hipri message,
6392*7c478bd9Sstevel@tonic-gate 		 * so there was no need to have the M_PCSIG case.
6393*7c478bd9Sstevel@tonic-gate 		 *
6394*7c478bd9Sstevel@tonic-gate 		 * At some time it might be nice to try and wrap the
6395*7c478bd9Sstevel@tonic-gate 		 * functionality of kstrgetmsg() and strgetmsg() into
6396*7c478bd9Sstevel@tonic-gate 		 * a common routine so to reduce the amount of replicated
6397*7c478bd9Sstevel@tonic-gate 		 * code (since they are extremely similar).
6398*7c478bd9Sstevel@tonic-gate 		 */
6399*7c478bd9Sstevel@tonic-gate 		if (!(*flagsp & (MSG_HIPRI|MSG_BAND))) {
6400*7c478bd9Sstevel@tonic-gate 			/* Asking for normal, band0 data */
6401*7c478bd9Sstevel@tonic-gate 			bp = strget(stp, q, uiop, first, &error);
6402*7c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
6403*7c478bd9Sstevel@tonic-gate 			if (bp != NULL) {
6404*7c478bd9Sstevel@tonic-gate 				if (bp->b_datap->db_type == M_SIG) {
6405*7c478bd9Sstevel@tonic-gate 					strsignal_nolock(stp, *bp->b_rptr,
6406*7c478bd9Sstevel@tonic-gate 					    (int32_t)bp->b_band);
6407*7c478bd9Sstevel@tonic-gate 					continue;
6408*7c478bd9Sstevel@tonic-gate 				} else {
6409*7c478bd9Sstevel@tonic-gate 					break;
6410*7c478bd9Sstevel@tonic-gate 				}
6411*7c478bd9Sstevel@tonic-gate 			}
6412*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
6413*7c478bd9Sstevel@tonic-gate 				goto getmout;
6414*7c478bd9Sstevel@tonic-gate 			}
6415*7c478bd9Sstevel@tonic-gate 
6416*7c478bd9Sstevel@tonic-gate 		/*
6417*7c478bd9Sstevel@tonic-gate 		 * We can't depend on the value of STRPRI here because
6418*7c478bd9Sstevel@tonic-gate 		 * the stream head may be in transit. Therefore, we
6419*7c478bd9Sstevel@tonic-gate 		 * must look at the type of the first message to
6420*7c478bd9Sstevel@tonic-gate 		 * determine if a high priority messages is waiting
6421*7c478bd9Sstevel@tonic-gate 		 */
6422*7c478bd9Sstevel@tonic-gate 		} else if ((*flagsp & MSG_HIPRI) && q_first != NULL &&
6423*7c478bd9Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL &&
6424*7c478bd9Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
6425*7c478bd9Sstevel@tonic-gate 			/* Asked for HIPRI and got one */
6426*7c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_datap->db_type >= QPCTL);
6427*7c478bd9Sstevel@tonic-gate 			break;
6428*7c478bd9Sstevel@tonic-gate 		} else if ((*flagsp & MSG_BAND) && q_first != NULL &&
6429*7c478bd9Sstevel@tonic-gate 			    ((q_first->b_band >= *prip) ||
6430*7c478bd9Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL) &&
6431*7c478bd9Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
6432*7c478bd9Sstevel@tonic-gate 			/*
6433*7c478bd9Sstevel@tonic-gate 			 * Asked for at least band "prip" and got either at
6434*7c478bd9Sstevel@tonic-gate 			 * least that band or a hipri message.
6435*7c478bd9Sstevel@tonic-gate 			 */
6436*7c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_band >= *prip ||
6437*7c478bd9Sstevel@tonic-gate 				bp->b_datap->db_type >= QPCTL);
6438*7c478bd9Sstevel@tonic-gate 			if (bp->b_datap->db_type == M_SIG) {
6439*7c478bd9Sstevel@tonic-gate 				strsignal_nolock(stp, *bp->b_rptr,
6440*7c478bd9Sstevel@tonic-gate 				    (int32_t)bp->b_band);
6441*7c478bd9Sstevel@tonic-gate 				continue;
6442*7c478bd9Sstevel@tonic-gate 			} else {
6443*7c478bd9Sstevel@tonic-gate 				break;
6444*7c478bd9Sstevel@tonic-gate 			}
6445*7c478bd9Sstevel@tonic-gate 		}
6446*7c478bd9Sstevel@tonic-gate 
6447*7c478bd9Sstevel@tonic-gate 		/* No data. Time to sleep? */
6448*7c478bd9Sstevel@tonic-gate 		qbackenable(q, 0);
6449*7c478bd9Sstevel@tonic-gate 
6450*7c478bd9Sstevel@tonic-gate 		/*
6451*7c478bd9Sstevel@tonic-gate 		 * If STRHUP or STREOF, return 0 length control and data.
6452*7c478bd9Sstevel@tonic-gate 		 * If resid is 0, then a read(fd,buf,0) was done. Do not
6453*7c478bd9Sstevel@tonic-gate 		 * sleep to satisfy this request because by default we have
6454*7c478bd9Sstevel@tonic-gate 		 * zero bytes to return.
6455*7c478bd9Sstevel@tonic-gate 		 */
6456*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & (STRHUP|STREOF)) || (mctl->maxlen == 0 &&
6457*7c478bd9Sstevel@tonic-gate 		    mdata->maxlen == 0)) {
6458*7c478bd9Sstevel@tonic-gate 			mctl->len = mdata->len = 0;
6459*7c478bd9Sstevel@tonic-gate 			*flagsp = 0;
6460*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6461*7c478bd9Sstevel@tonic-gate 			return (0);
6462*7c478bd9Sstevel@tonic-gate 		}
6463*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_WAIT,
6464*7c478bd9Sstevel@tonic-gate 			"strgetmsg calls strwaitq:%p, %p",
6465*7c478bd9Sstevel@tonic-gate 			vp, uiop);
6466*7c478bd9Sstevel@tonic-gate 		if (((error = strwaitq(stp, GETWAIT, (ssize_t)0, fmode, -1,
6467*7c478bd9Sstevel@tonic-gate 		    &done)) != 0) || done) {
6468*7c478bd9Sstevel@tonic-gate 			TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_DONE,
6469*7c478bd9Sstevel@tonic-gate 				"strgetmsg error or done:%p, %p",
6470*7c478bd9Sstevel@tonic-gate 				vp, uiop);
6471*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6472*7c478bd9Sstevel@tonic-gate 			return (error);
6473*7c478bd9Sstevel@tonic-gate 		}
6474*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRGETMSG_AWAKE,
6475*7c478bd9Sstevel@tonic-gate 			"strgetmsg awakes:%p, %p", vp, uiop);
6476*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
6477*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6478*7c478bd9Sstevel@tonic-gate 			if (error = straccess(stp, JCREAD))
6479*7c478bd9Sstevel@tonic-gate 				return (error);
6480*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
6481*7c478bd9Sstevel@tonic-gate 		}
6482*7c478bd9Sstevel@tonic-gate 		first = 0;
6483*7c478bd9Sstevel@tonic-gate 	}
6484*7c478bd9Sstevel@tonic-gate 	ASSERT(bp != NULL);
6485*7c478bd9Sstevel@tonic-gate 	/*
6486*7c478bd9Sstevel@tonic-gate 	 * Extract any mark information. If the message is not completely
6487*7c478bd9Sstevel@tonic-gate 	 * consumed this information will be put in the mblk
6488*7c478bd9Sstevel@tonic-gate 	 * that is putback.
6489*7c478bd9Sstevel@tonic-gate 	 * If MSGMARKNEXT is set and the message is completely consumed
6490*7c478bd9Sstevel@tonic-gate 	 * the STRATMARK flag will be set below. Likewise, if
6491*7c478bd9Sstevel@tonic-gate 	 * MSGNOTMARKNEXT is set and the message is
6492*7c478bd9Sstevel@tonic-gate 	 * completely consumed STRNOTATMARK will be set.
6493*7c478bd9Sstevel@tonic-gate 	 */
6494*7c478bd9Sstevel@tonic-gate 	mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
6495*7c478bd9Sstevel@tonic-gate 	ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
6496*7c478bd9Sstevel@tonic-gate 		(MSGMARKNEXT|MSGNOTMARKNEXT));
6497*7c478bd9Sstevel@tonic-gate 	if (mark != 0 && bp == stp->sd_mark) {
6498*7c478bd9Sstevel@tonic-gate 		mark |= _LASTMARK;
6499*7c478bd9Sstevel@tonic-gate 		stp->sd_mark = NULL;
6500*7c478bd9Sstevel@tonic-gate 	}
6501*7c478bd9Sstevel@tonic-gate 	/*
6502*7c478bd9Sstevel@tonic-gate 	 * keep track of the original message type and priority
6503*7c478bd9Sstevel@tonic-gate 	 */
6504*7c478bd9Sstevel@tonic-gate 	pri = bp->b_band;
6505*7c478bd9Sstevel@tonic-gate 	type = bp->b_datap->db_type;
6506*7c478bd9Sstevel@tonic-gate 	if (type == M_PASSFP) {
6507*7c478bd9Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
6508*7c478bd9Sstevel@tonic-gate 			stp->sd_mark = bp;
6509*7c478bd9Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
6510*7c478bd9Sstevel@tonic-gate 		putback(stp, q, bp, pri);
6511*7c478bd9Sstevel@tonic-gate 		qbackenable(q, pri);
6512*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6513*7c478bd9Sstevel@tonic-gate 		return (EBADMSG);
6514*7c478bd9Sstevel@tonic-gate 	}
6515*7c478bd9Sstevel@tonic-gate 	ASSERT(type != M_SIG);
6516*7c478bd9Sstevel@tonic-gate 
6517*7c478bd9Sstevel@tonic-gate 	/*
6518*7c478bd9Sstevel@tonic-gate 	 * Set this flag so strrput will not generate signals. Need to
6519*7c478bd9Sstevel@tonic-gate 	 * make sure this flag is cleared before leaving this routine
6520*7c478bd9Sstevel@tonic-gate 	 * else signals will stop being sent.
6521*7c478bd9Sstevel@tonic-gate 	 */
6522*7c478bd9Sstevel@tonic-gate 	stp->sd_flag |= STRGETINPROG;
6523*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
6524*7c478bd9Sstevel@tonic-gate 
6525*7c478bd9Sstevel@tonic-gate 	if (STREAM_NEEDSERVICE(stp))
6526*7c478bd9Sstevel@tonic-gate 		stream_runservice(stp);
6527*7c478bd9Sstevel@tonic-gate 
6528*7c478bd9Sstevel@tonic-gate 	/*
6529*7c478bd9Sstevel@tonic-gate 	 * Set HIPRI flag if message is priority.
6530*7c478bd9Sstevel@tonic-gate 	 */
6531*7c478bd9Sstevel@tonic-gate 	if (type >= QPCTL)
6532*7c478bd9Sstevel@tonic-gate 		flg = MSG_HIPRI;
6533*7c478bd9Sstevel@tonic-gate 	else
6534*7c478bd9Sstevel@tonic-gate 		flg = MSG_BAND;
6535*7c478bd9Sstevel@tonic-gate 
6536*7c478bd9Sstevel@tonic-gate 	/*
6537*7c478bd9Sstevel@tonic-gate 	 * First process PROTO or PCPROTO blocks, if any.
6538*7c478bd9Sstevel@tonic-gate 	 */
6539*7c478bd9Sstevel@tonic-gate 	if (mctl->maxlen >= 0 && type != M_DATA) {
6540*7c478bd9Sstevel@tonic-gate 		size_t	n, bcnt;
6541*7c478bd9Sstevel@tonic-gate 		char	*ubuf;
6542*7c478bd9Sstevel@tonic-gate 
6543*7c478bd9Sstevel@tonic-gate 		bcnt = mctl->maxlen;
6544*7c478bd9Sstevel@tonic-gate 		ubuf = mctl->buf;
6545*7c478bd9Sstevel@tonic-gate 		while (bp != NULL && bp->b_datap->db_type != M_DATA) {
6546*7c478bd9Sstevel@tonic-gate 			if ((n = MIN(bcnt, bp->b_wptr - bp->b_rptr)) != 0 &&
6547*7c478bd9Sstevel@tonic-gate 			    copyout(bp->b_rptr, ubuf, n)) {
6548*7c478bd9Sstevel@tonic-gate 				error = EFAULT;
6549*7c478bd9Sstevel@tonic-gate 				mutex_enter(&stp->sd_lock);
6550*7c478bd9Sstevel@tonic-gate 				/*
6551*7c478bd9Sstevel@tonic-gate 				 * clear stream head pri flag based on
6552*7c478bd9Sstevel@tonic-gate 				 * first message type
6553*7c478bd9Sstevel@tonic-gate 				 */
6554*7c478bd9Sstevel@tonic-gate 				if (type >= QPCTL) {
6555*7c478bd9Sstevel@tonic-gate 					ASSERT(type == M_PCPROTO);
6556*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
6557*7c478bd9Sstevel@tonic-gate 				}
6558*7c478bd9Sstevel@tonic-gate 				more = 0;
6559*7c478bd9Sstevel@tonic-gate 				freemsg(bp);
6560*7c478bd9Sstevel@tonic-gate 				goto getmout;
6561*7c478bd9Sstevel@tonic-gate 			}
6562*7c478bd9Sstevel@tonic-gate 			ubuf += n;
6563*7c478bd9Sstevel@tonic-gate 			bp->b_rptr += n;
6564*7c478bd9Sstevel@tonic-gate 			if (bp->b_rptr >= bp->b_wptr) {
6565*7c478bd9Sstevel@tonic-gate 				nbp = bp;
6566*7c478bd9Sstevel@tonic-gate 				bp = bp->b_cont;
6567*7c478bd9Sstevel@tonic-gate 				freeb(nbp);
6568*7c478bd9Sstevel@tonic-gate 			}
6569*7c478bd9Sstevel@tonic-gate 			ASSERT(n <= bcnt);
6570*7c478bd9Sstevel@tonic-gate 			bcnt -= n;
6571*7c478bd9Sstevel@tonic-gate 			if (bcnt == 0)
6572*7c478bd9Sstevel@tonic-gate 				break;
6573*7c478bd9Sstevel@tonic-gate 		}
6574*7c478bd9Sstevel@tonic-gate 		mctl->len = mctl->maxlen - bcnt;
6575*7c478bd9Sstevel@tonic-gate 	} else
6576*7c478bd9Sstevel@tonic-gate 		mctl->len = -1;
6577*7c478bd9Sstevel@tonic-gate 
6578*7c478bd9Sstevel@tonic-gate 	if (bp && bp->b_datap->db_type != M_DATA) {
6579*7c478bd9Sstevel@tonic-gate 		/*
6580*7c478bd9Sstevel@tonic-gate 		 * More PROTO blocks in msg.
6581*7c478bd9Sstevel@tonic-gate 		 */
6582*7c478bd9Sstevel@tonic-gate 		more |= MORECTL;
6583*7c478bd9Sstevel@tonic-gate 		savemp = bp;
6584*7c478bd9Sstevel@tonic-gate 		while (bp && bp->b_datap->db_type != M_DATA) {
6585*7c478bd9Sstevel@tonic-gate 			savemptail = bp;
6586*7c478bd9Sstevel@tonic-gate 			bp = bp->b_cont;
6587*7c478bd9Sstevel@tonic-gate 		}
6588*7c478bd9Sstevel@tonic-gate 		savemptail->b_cont = NULL;
6589*7c478bd9Sstevel@tonic-gate 	}
6590*7c478bd9Sstevel@tonic-gate 
6591*7c478bd9Sstevel@tonic-gate 	/*
6592*7c478bd9Sstevel@tonic-gate 	 * Now process DATA blocks, if any.
6593*7c478bd9Sstevel@tonic-gate 	 */
6594*7c478bd9Sstevel@tonic-gate 	if (mdata->maxlen >= 0 && bp) {
6595*7c478bd9Sstevel@tonic-gate 		/*
6596*7c478bd9Sstevel@tonic-gate 		 * struiocopyout will consume a potential zero-length
6597*7c478bd9Sstevel@tonic-gate 		 * M_DATA even if uio_resid is zero.
6598*7c478bd9Sstevel@tonic-gate 		 */
6599*7c478bd9Sstevel@tonic-gate 		size_t oldresid = uiop->uio_resid;
6600*7c478bd9Sstevel@tonic-gate 
6601*7c478bd9Sstevel@tonic-gate 		bp = struiocopyout(bp, uiop, &error);
6602*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
6603*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
6604*7c478bd9Sstevel@tonic-gate 			/*
6605*7c478bd9Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
6606*7c478bd9Sstevel@tonic-gate 			 * first message
6607*7c478bd9Sstevel@tonic-gate 			 */
6608*7c478bd9Sstevel@tonic-gate 			if (type >= QPCTL) {
6609*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
6610*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
6611*7c478bd9Sstevel@tonic-gate 			}
6612*7c478bd9Sstevel@tonic-gate 			more = 0;
6613*7c478bd9Sstevel@tonic-gate 			freemsg(savemp);
6614*7c478bd9Sstevel@tonic-gate 			goto getmout;
6615*7c478bd9Sstevel@tonic-gate 		}
6616*7c478bd9Sstevel@tonic-gate 		/*
6617*7c478bd9Sstevel@tonic-gate 		 * (pr == 1) indicates a partial read.
6618*7c478bd9Sstevel@tonic-gate 		 */
6619*7c478bd9Sstevel@tonic-gate 		if (oldresid > uiop->uio_resid)
6620*7c478bd9Sstevel@tonic-gate 			pr = 1;
6621*7c478bd9Sstevel@tonic-gate 		mdata->len = mdata->maxlen - uiop->uio_resid;
6622*7c478bd9Sstevel@tonic-gate 	} else
6623*7c478bd9Sstevel@tonic-gate 		mdata->len = -1;
6624*7c478bd9Sstevel@tonic-gate 
6625*7c478bd9Sstevel@tonic-gate 	if (bp) {			/* more data blocks in msg */
6626*7c478bd9Sstevel@tonic-gate 		more |= MOREDATA;
6627*7c478bd9Sstevel@tonic-gate 		if (savemp)
6628*7c478bd9Sstevel@tonic-gate 			savemptail->b_cont = bp;
6629*7c478bd9Sstevel@tonic-gate 		else
6630*7c478bd9Sstevel@tonic-gate 			savemp = bp;
6631*7c478bd9Sstevel@tonic-gate 	}
6632*7c478bd9Sstevel@tonic-gate 
6633*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
6634*7c478bd9Sstevel@tonic-gate 	if (savemp) {
6635*7c478bd9Sstevel@tonic-gate 		if (pr && (savemp->b_datap->db_type == M_DATA) &&
6636*7c478bd9Sstevel@tonic-gate 		    msgnodata(savemp)) {
6637*7c478bd9Sstevel@tonic-gate 			/*
6638*7c478bd9Sstevel@tonic-gate 			 * Avoid queuing a zero-length tail part of
6639*7c478bd9Sstevel@tonic-gate 			 * a message. pr=1 indicates that we read some of
6640*7c478bd9Sstevel@tonic-gate 			 * the message.
6641*7c478bd9Sstevel@tonic-gate 			 */
6642*7c478bd9Sstevel@tonic-gate 			freemsg(savemp);
6643*7c478bd9Sstevel@tonic-gate 			more &= ~MOREDATA;
6644*7c478bd9Sstevel@tonic-gate 			/*
6645*7c478bd9Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
6646*7c478bd9Sstevel@tonic-gate 			 * first message
6647*7c478bd9Sstevel@tonic-gate 			 */
6648*7c478bd9Sstevel@tonic-gate 			if (type >= QPCTL) {
6649*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
6650*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
6651*7c478bd9Sstevel@tonic-gate 			}
6652*7c478bd9Sstevel@tonic-gate 		} else {
6653*7c478bd9Sstevel@tonic-gate 			savemp->b_band = pri;
6654*7c478bd9Sstevel@tonic-gate 			/*
6655*7c478bd9Sstevel@tonic-gate 			 * If the first message was HIPRI and the one we're
6656*7c478bd9Sstevel@tonic-gate 			 * putting back isn't, then clear STRPRI, otherwise
6657*7c478bd9Sstevel@tonic-gate 			 * set STRPRI again.  Note that we must set STRPRI
6658*7c478bd9Sstevel@tonic-gate 			 * again since the flush logic in strrput_nondata()
6659*7c478bd9Sstevel@tonic-gate 			 * may have cleared it while we had sd_lock dropped.
6660*7c478bd9Sstevel@tonic-gate 			 */
6661*7c478bd9Sstevel@tonic-gate 			if (type >= QPCTL) {
6662*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
6663*7c478bd9Sstevel@tonic-gate 				if (queclass(savemp) < QPCTL)
6664*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
6665*7c478bd9Sstevel@tonic-gate 				else
6666*7c478bd9Sstevel@tonic-gate 					stp->sd_flag |= STRPRI;
6667*7c478bd9Sstevel@tonic-gate 			} else if (queclass(savemp) >= QPCTL) {
6668*7c478bd9Sstevel@tonic-gate 				/*
6669*7c478bd9Sstevel@tonic-gate 				 * The first message was not a HIPRI message,
6670*7c478bd9Sstevel@tonic-gate 				 * but the one we are about to putback is.
6671*7c478bd9Sstevel@tonic-gate 				 * For simplicitly, we do not allow for HIPRI
6672*7c478bd9Sstevel@tonic-gate 				 * messages to be embedded in the message
6673*7c478bd9Sstevel@tonic-gate 				 * body, so just force it to same type as
6674*7c478bd9Sstevel@tonic-gate 				 * first message.
6675*7c478bd9Sstevel@tonic-gate 				 */
6676*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_DATA || type == M_PROTO);
6677*7c478bd9Sstevel@tonic-gate 				ASSERT(savemp->b_datap->db_type == M_PCPROTO);
6678*7c478bd9Sstevel@tonic-gate 				savemp->b_datap->db_type = type;
6679*7c478bd9Sstevel@tonic-gate 			}
6680*7c478bd9Sstevel@tonic-gate 			if (mark != 0) {
6681*7c478bd9Sstevel@tonic-gate 				savemp->b_flag |= mark & ~_LASTMARK;
6682*7c478bd9Sstevel@tonic-gate 				if ((mark & _LASTMARK) &&
6683*7c478bd9Sstevel@tonic-gate 				    (stp->sd_mark == NULL)) {
6684*7c478bd9Sstevel@tonic-gate 					/*
6685*7c478bd9Sstevel@tonic-gate 					 * If another marked message arrived
6686*7c478bd9Sstevel@tonic-gate 					 * while sd_lock was not held sd_mark
6687*7c478bd9Sstevel@tonic-gate 					 * would be non-NULL.
6688*7c478bd9Sstevel@tonic-gate 					 */
6689*7c478bd9Sstevel@tonic-gate 					stp->sd_mark = savemp;
6690*7c478bd9Sstevel@tonic-gate 				}
6691*7c478bd9Sstevel@tonic-gate 			}
6692*7c478bd9Sstevel@tonic-gate 			putback(stp, q, savemp, pri);
6693*7c478bd9Sstevel@tonic-gate 		}
6694*7c478bd9Sstevel@tonic-gate 	} else {
6695*7c478bd9Sstevel@tonic-gate 		/*
6696*7c478bd9Sstevel@tonic-gate 		 * The complete message was consumed.
6697*7c478bd9Sstevel@tonic-gate 		 *
6698*7c478bd9Sstevel@tonic-gate 		 * If another M_PCPROTO arrived while sd_lock was not held
6699*7c478bd9Sstevel@tonic-gate 		 * it would have been discarded since STRPRI was still set.
6700*7c478bd9Sstevel@tonic-gate 		 *
6701*7c478bd9Sstevel@tonic-gate 		 * Move the MSG*MARKNEXT information
6702*7c478bd9Sstevel@tonic-gate 		 * to the stream head just in case
6703*7c478bd9Sstevel@tonic-gate 		 * the read queue becomes empty.
6704*7c478bd9Sstevel@tonic-gate 		 * clear stream head hi pri flag based on
6705*7c478bd9Sstevel@tonic-gate 		 * first message
6706*7c478bd9Sstevel@tonic-gate 		 *
6707*7c478bd9Sstevel@tonic-gate 		 * If the stream head was at the mark
6708*7c478bd9Sstevel@tonic-gate 		 * (STRATMARK) before we dropped sd_lock above
6709*7c478bd9Sstevel@tonic-gate 		 * and some data was consumed then we have
6710*7c478bd9Sstevel@tonic-gate 		 * moved past the mark thus STRATMARK is
6711*7c478bd9Sstevel@tonic-gate 		 * cleared. However, if a message arrived in
6712*7c478bd9Sstevel@tonic-gate 		 * strrput during the copyout above causing
6713*7c478bd9Sstevel@tonic-gate 		 * STRATMARK to be set we can not clear that
6714*7c478bd9Sstevel@tonic-gate 		 * flag.
6715*7c478bd9Sstevel@tonic-gate 		 */
6716*7c478bd9Sstevel@tonic-gate 		if (type >= QPCTL) {
6717*7c478bd9Sstevel@tonic-gate 			ASSERT(type == M_PCPROTO);
6718*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRPRI;
6719*7c478bd9Sstevel@tonic-gate 		}
6720*7c478bd9Sstevel@tonic-gate 		if (mark & (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
6721*7c478bd9Sstevel@tonic-gate 			if (mark & MSGMARKNEXT) {
6722*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRNOTATMARK;
6723*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= STRATMARK;
6724*7c478bd9Sstevel@tonic-gate 			} else if (mark & MSGNOTMARKNEXT) {
6725*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRATMARK;
6726*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= STRNOTATMARK;
6727*7c478bd9Sstevel@tonic-gate 			} else {
6728*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~(STRATMARK|STRNOTATMARK);
6729*7c478bd9Sstevel@tonic-gate 			}
6730*7c478bd9Sstevel@tonic-gate 		} else if (pr && (old_sd_flag & STRATMARK)) {
6731*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
6732*7c478bd9Sstevel@tonic-gate 		}
6733*7c478bd9Sstevel@tonic-gate 	}
6734*7c478bd9Sstevel@tonic-gate 
6735*7c478bd9Sstevel@tonic-gate 	*flagsp = flg;
6736*7c478bd9Sstevel@tonic-gate 	*prip = pri;
6737*7c478bd9Sstevel@tonic-gate 
6738*7c478bd9Sstevel@tonic-gate 	/*
6739*7c478bd9Sstevel@tonic-gate 	 * Getmsg cleanup processing - if the state of the queue has changed
6740*7c478bd9Sstevel@tonic-gate 	 * some signals may need to be sent and/or poll awakened.
6741*7c478bd9Sstevel@tonic-gate 	 */
6742*7c478bd9Sstevel@tonic-gate getmout:
6743*7c478bd9Sstevel@tonic-gate 	qbackenable(q, pri);
6744*7c478bd9Sstevel@tonic-gate 
6745*7c478bd9Sstevel@tonic-gate 	/*
6746*7c478bd9Sstevel@tonic-gate 	 * We dropped the stream head lock above. Send all M_SIG messages
6747*7c478bd9Sstevel@tonic-gate 	 * before processing stream head for SIGPOLL messages.
6748*7c478bd9Sstevel@tonic-gate 	 */
6749*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
6750*7c478bd9Sstevel@tonic-gate 	while ((bp = q->q_first) != NULL &&
6751*7c478bd9Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_SIG)) {
6752*7c478bd9Sstevel@tonic-gate 		/*
6753*7c478bd9Sstevel@tonic-gate 		 * sd_lock is held so the content of the read queue can not
6754*7c478bd9Sstevel@tonic-gate 		 * change.
6755*7c478bd9Sstevel@tonic-gate 		 */
6756*7c478bd9Sstevel@tonic-gate 		bp = getq(q);
6757*7c478bd9Sstevel@tonic-gate 		ASSERT(bp != NULL && bp->b_datap->db_type == M_SIG);
6758*7c478bd9Sstevel@tonic-gate 
6759*7c478bd9Sstevel@tonic-gate 		strsignal_nolock(stp, *bp->b_rptr, (int32_t)bp->b_band);
6760*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
6761*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
6762*7c478bd9Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
6763*7c478bd9Sstevel@tonic-gate 			stream_runservice(stp);
6764*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
6765*7c478bd9Sstevel@tonic-gate 	}
6766*7c478bd9Sstevel@tonic-gate 
6767*7c478bd9Sstevel@tonic-gate 	/*
6768*7c478bd9Sstevel@tonic-gate 	 * stream head cannot change while we make the determination
6769*7c478bd9Sstevel@tonic-gate 	 * whether or not to send a signal. Drop the flag to allow strrput
6770*7c478bd9Sstevel@tonic-gate 	 * to send firstmsgsigs again.
6771*7c478bd9Sstevel@tonic-gate 	 */
6772*7c478bd9Sstevel@tonic-gate 	stp->sd_flag &= ~STRGETINPROG;
6773*7c478bd9Sstevel@tonic-gate 
6774*7c478bd9Sstevel@tonic-gate 	/*
6775*7c478bd9Sstevel@tonic-gate 	 * If the type of message at the front of the queue changed
6776*7c478bd9Sstevel@tonic-gate 	 * due to the receive the appropriate signals and pollwakeup events
6777*7c478bd9Sstevel@tonic-gate 	 * are generated. The type of changes are:
6778*7c478bd9Sstevel@tonic-gate 	 *	Processed a hipri message, q_first is not hipri.
6779*7c478bd9Sstevel@tonic-gate 	 *	Processed a band X message, and q_first is band Y.
6780*7c478bd9Sstevel@tonic-gate 	 * The generated signals and pollwakeups are identical to what
6781*7c478bd9Sstevel@tonic-gate 	 * strrput() generates should the message that is now on q_first
6782*7c478bd9Sstevel@tonic-gate 	 * arrive to an empty read queue.
6783*7c478bd9Sstevel@tonic-gate 	 *
6784*7c478bd9Sstevel@tonic-gate 	 * Note: only strrput will send a signal for a hipri message.
6785*7c478bd9Sstevel@tonic-gate 	 */
6786*7c478bd9Sstevel@tonic-gate 	if ((bp = q->q_first) != NULL && !(stp->sd_flag & STRPRI)) {
6787*7c478bd9Sstevel@tonic-gate 		strsigset_t signals = 0;
6788*7c478bd9Sstevel@tonic-gate 		strpollset_t pollwakeups = 0;
6789*7c478bd9Sstevel@tonic-gate 
6790*7c478bd9Sstevel@tonic-gate 		if (flg & MSG_HIPRI) {
6791*7c478bd9Sstevel@tonic-gate 			/*
6792*7c478bd9Sstevel@tonic-gate 			 * Removed a hipri message. Regular data at
6793*7c478bd9Sstevel@tonic-gate 			 * the front of  the queue.
6794*7c478bd9Sstevel@tonic-gate 			 */
6795*7c478bd9Sstevel@tonic-gate 			if (bp->b_band == 0) {
6796*7c478bd9Sstevel@tonic-gate 				signals = S_INPUT | S_RDNORM;
6797*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
6798*7c478bd9Sstevel@tonic-gate 			} else {
6799*7c478bd9Sstevel@tonic-gate 				signals = S_INPUT | S_RDBAND;
6800*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
6801*7c478bd9Sstevel@tonic-gate 			}
6802*7c478bd9Sstevel@tonic-gate 		} else if (pri != bp->b_band) {
6803*7c478bd9Sstevel@tonic-gate 			/*
6804*7c478bd9Sstevel@tonic-gate 			 * The band is different for the new q_first.
6805*7c478bd9Sstevel@tonic-gate 			 */
6806*7c478bd9Sstevel@tonic-gate 			if (bp->b_band == 0) {
6807*7c478bd9Sstevel@tonic-gate 				signals = S_RDNORM;
6808*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
6809*7c478bd9Sstevel@tonic-gate 			} else {
6810*7c478bd9Sstevel@tonic-gate 				signals = S_RDBAND;
6811*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
6812*7c478bd9Sstevel@tonic-gate 			}
6813*7c478bd9Sstevel@tonic-gate 		}
6814*7c478bd9Sstevel@tonic-gate 
6815*7c478bd9Sstevel@tonic-gate 		if (pollwakeups != 0) {
6816*7c478bd9Sstevel@tonic-gate 			if (pollwakeups == (POLLIN | POLLRDNORM)) {
6817*7c478bd9Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
6818*7c478bd9Sstevel@tonic-gate 					goto no_pollwake;
6819*7c478bd9Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
6820*7c478bd9Sstevel@tonic-gate 			}
6821*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6822*7c478bd9Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, pollwakeups);
6823*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
6824*7c478bd9Sstevel@tonic-gate 		}
6825*7c478bd9Sstevel@tonic-gate no_pollwake:
6826*7c478bd9Sstevel@tonic-gate 
6827*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sigflags & signals)
6828*7c478bd9Sstevel@tonic-gate 			strsendsig(stp->sd_siglist, signals, bp->b_band, 0);
6829*7c478bd9Sstevel@tonic-gate 	}
6830*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
6831*7c478bd9Sstevel@tonic-gate 
6832*7c478bd9Sstevel@tonic-gate 	rvp->r_val1 = more;
6833*7c478bd9Sstevel@tonic-gate 	return (error);
6834*7c478bd9Sstevel@tonic-gate #undef	_LASTMARK
6835*7c478bd9Sstevel@tonic-gate }
6836*7c478bd9Sstevel@tonic-gate 
6837*7c478bd9Sstevel@tonic-gate /*
6838*7c478bd9Sstevel@tonic-gate  * Get the next message from the read queue.  If the message is
6839*7c478bd9Sstevel@tonic-gate  * priority, STRPRI will have been set by strrput().  This flag
6840*7c478bd9Sstevel@tonic-gate  * should be reset only when the entire message at the front of the
6841*7c478bd9Sstevel@tonic-gate  * queue as been consumed.
6842*7c478bd9Sstevel@tonic-gate  *
6843*7c478bd9Sstevel@tonic-gate  * If uiop is NULL all data is returned in mctlp.
6844*7c478bd9Sstevel@tonic-gate  * Note that a NULL uiop implies that FNDELAY and FNONBLOCK are assumed
6845*7c478bd9Sstevel@tonic-gate  * not enabled.
6846*7c478bd9Sstevel@tonic-gate  * The timeout parameter is in milliseconds; -1 for infinity.
6847*7c478bd9Sstevel@tonic-gate  * This routine handles the consolidation private flags:
6848*7c478bd9Sstevel@tonic-gate  *	MSG_IGNERROR	Ignore any stream head error except STPLEX.
6849*7c478bd9Sstevel@tonic-gate  *	MSG_DELAYERROR	Defer the error check until the queue is empty.
6850*7c478bd9Sstevel@tonic-gate  *	MSG_HOLDSIG	Hold signals while waiting for data.
6851*7c478bd9Sstevel@tonic-gate  *	MSG_IPEEK	Only peek at messages.
6852*7c478bd9Sstevel@tonic-gate  *	MSG_DISCARDTAIL	Discard the tail M_DATA part of the message
6853*7c478bd9Sstevel@tonic-gate  *			that doesn't fit.
6854*7c478bd9Sstevel@tonic-gate  *	MSG_NOMARK	If the message is marked leave it on the queue.
6855*7c478bd9Sstevel@tonic-gate  *
6856*7c478bd9Sstevel@tonic-gate  * NOTE: strgetmsg and kstrgetmsg have much of the logic in common.
6857*7c478bd9Sstevel@tonic-gate  */
6858*7c478bd9Sstevel@tonic-gate int
6859*7c478bd9Sstevel@tonic-gate kstrgetmsg(
6860*7c478bd9Sstevel@tonic-gate 	struct vnode *vp,
6861*7c478bd9Sstevel@tonic-gate 	mblk_t **mctlp,
6862*7c478bd9Sstevel@tonic-gate 	struct uio *uiop,
6863*7c478bd9Sstevel@tonic-gate 	unsigned char *prip,
6864*7c478bd9Sstevel@tonic-gate 	int *flagsp,
6865*7c478bd9Sstevel@tonic-gate 	clock_t timout,
6866*7c478bd9Sstevel@tonic-gate 	rval_t *rvp)
6867*7c478bd9Sstevel@tonic-gate {
6868*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
6869*7c478bd9Sstevel@tonic-gate 	mblk_t *bp, *nbp;
6870*7c478bd9Sstevel@tonic-gate 	mblk_t *savemp = NULL;
6871*7c478bd9Sstevel@tonic-gate 	mblk_t *savemptail = NULL;
6872*7c478bd9Sstevel@tonic-gate 	int flags;
6873*7c478bd9Sstevel@tonic-gate 	uint_t old_sd_flag;
6874*7c478bd9Sstevel@tonic-gate 	int flg;
6875*7c478bd9Sstevel@tonic-gate 	int more = 0;
6876*7c478bd9Sstevel@tonic-gate 	int error = 0;
6877*7c478bd9Sstevel@tonic-gate 	char first = 1;
6878*7c478bd9Sstevel@tonic-gate 	uint_t mark;		/* Contains MSG*MARK and _LASTMARK */
6879*7c478bd9Sstevel@tonic-gate #define	_LASTMARK	0x8000	/* Distinct from MSG*MARK */
6880*7c478bd9Sstevel@tonic-gate 	unsigned char pri = 0;
6881*7c478bd9Sstevel@tonic-gate 	queue_t *q;
6882*7c478bd9Sstevel@tonic-gate 	int	pr = 0;			/* Partial read successful */
6883*7c478bd9Sstevel@tonic-gate 	unsigned char type;
6884*7c478bd9Sstevel@tonic-gate 
6885*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_ENTER,
6886*7c478bd9Sstevel@tonic-gate 		"kstrgetmsg:%p", vp);
6887*7c478bd9Sstevel@tonic-gate 
6888*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
6889*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
6890*7c478bd9Sstevel@tonic-gate 	rvp->r_val1 = 0;
6891*7c478bd9Sstevel@tonic-gate 
6892*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
6893*7c478bd9Sstevel@tonic-gate 		if (error = straccess(stp, JCREAD))
6894*7c478bd9Sstevel@tonic-gate 			return (error);
6895*7c478bd9Sstevel@tonic-gate 
6896*7c478bd9Sstevel@tonic-gate 	flags = *flagsp;
6897*7c478bd9Sstevel@tonic-gate 	/* Fast check of flags before acquiring the lock */
6898*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STRDERR|STPLEX)) {
6899*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & STPLEX) ||
6900*7c478bd9Sstevel@tonic-gate 		    (flags & (MSG_IGNERROR|MSG_DELAYERROR)) == 0) {
6901*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
6902*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX,
6903*7c478bd9Sstevel@tonic-gate 					(flags & MSG_IPEEK));
6904*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
6905*7c478bd9Sstevel@tonic-gate 			if (error != 0)
6906*7c478bd9Sstevel@tonic-gate 				return (error);
6907*7c478bd9Sstevel@tonic-gate 		}
6908*7c478bd9Sstevel@tonic-gate 	}
6909*7c478bd9Sstevel@tonic-gate 
6910*7c478bd9Sstevel@tonic-gate 	switch (flags & (MSG_HIPRI|MSG_ANY|MSG_BAND)) {
6911*7c478bd9Sstevel@tonic-gate 	case MSG_HIPRI:
6912*7c478bd9Sstevel@tonic-gate 		if (*prip != 0)
6913*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
6914*7c478bd9Sstevel@tonic-gate 		break;
6915*7c478bd9Sstevel@tonic-gate 
6916*7c478bd9Sstevel@tonic-gate 	case MSG_ANY:
6917*7c478bd9Sstevel@tonic-gate 	case MSG_BAND:
6918*7c478bd9Sstevel@tonic-gate 		break;
6919*7c478bd9Sstevel@tonic-gate 
6920*7c478bd9Sstevel@tonic-gate 	default:
6921*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
6922*7c478bd9Sstevel@tonic-gate 	}
6923*7c478bd9Sstevel@tonic-gate 
6924*7c478bd9Sstevel@tonic-gate retry:
6925*7c478bd9Sstevel@tonic-gate 	q = _RD(stp->sd_wrq);
6926*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
6927*7c478bd9Sstevel@tonic-gate 	old_sd_flag = stp->sd_flag;
6928*7c478bd9Sstevel@tonic-gate 	mark = 0;
6929*7c478bd9Sstevel@tonic-gate 	for (;;) {
6930*7c478bd9Sstevel@tonic-gate 		int done = 0;
6931*7c478bd9Sstevel@tonic-gate 		int waitflag;
6932*7c478bd9Sstevel@tonic-gate 		int fmode;
6933*7c478bd9Sstevel@tonic-gate 		mblk_t *q_first = q->q_first;
6934*7c478bd9Sstevel@tonic-gate 
6935*7c478bd9Sstevel@tonic-gate 		/*
6936*7c478bd9Sstevel@tonic-gate 		 * This section of the code operates just like the code
6937*7c478bd9Sstevel@tonic-gate 		 * in strgetmsg().  There is a comment there about what
6938*7c478bd9Sstevel@tonic-gate 		 * is going on here.
6939*7c478bd9Sstevel@tonic-gate 		 */
6940*7c478bd9Sstevel@tonic-gate 		if (!(flags & (MSG_HIPRI|MSG_BAND))) {
6941*7c478bd9Sstevel@tonic-gate 			/* Asking for normal, band0 data */
6942*7c478bd9Sstevel@tonic-gate 			bp = strget(stp, q, uiop, first, &error);
6943*7c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(&stp->sd_lock));
6944*7c478bd9Sstevel@tonic-gate 			if (bp != NULL) {
6945*7c478bd9Sstevel@tonic-gate 				if (bp->b_datap->db_type == M_SIG) {
6946*7c478bd9Sstevel@tonic-gate 					strsignal_nolock(stp, *bp->b_rptr,
6947*7c478bd9Sstevel@tonic-gate 					    (int32_t)bp->b_band);
6948*7c478bd9Sstevel@tonic-gate 					continue;
6949*7c478bd9Sstevel@tonic-gate 				} else {
6950*7c478bd9Sstevel@tonic-gate 					break;
6951*7c478bd9Sstevel@tonic-gate 				}
6952*7c478bd9Sstevel@tonic-gate 			}
6953*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
6954*7c478bd9Sstevel@tonic-gate 				goto getmout;
6955*7c478bd9Sstevel@tonic-gate 			}
6956*7c478bd9Sstevel@tonic-gate 		/*
6957*7c478bd9Sstevel@tonic-gate 		 * We can't depend on the value of STRPRI here because
6958*7c478bd9Sstevel@tonic-gate 		 * the stream head may be in transit. Therefore, we
6959*7c478bd9Sstevel@tonic-gate 		 * must look at the type of the first message to
6960*7c478bd9Sstevel@tonic-gate 		 * determine if a high priority messages is waiting
6961*7c478bd9Sstevel@tonic-gate 		 */
6962*7c478bd9Sstevel@tonic-gate 		} else if ((flags & MSG_HIPRI) && q_first != NULL &&
6963*7c478bd9Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL &&
6964*7c478bd9Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
6965*7c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_datap->db_type >= QPCTL);
6966*7c478bd9Sstevel@tonic-gate 			break;
6967*7c478bd9Sstevel@tonic-gate 		} else if ((flags & MSG_BAND) && q_first != NULL &&
6968*7c478bd9Sstevel@tonic-gate 			    ((q_first->b_band >= *prip) ||
6969*7c478bd9Sstevel@tonic-gate 			    q_first->b_datap->db_type >= QPCTL) &&
6970*7c478bd9Sstevel@tonic-gate 			    (bp = getq_noenab(q)) != NULL) {
6971*7c478bd9Sstevel@tonic-gate 			/*
6972*7c478bd9Sstevel@tonic-gate 			 * Asked for at least band "prip" and got either at
6973*7c478bd9Sstevel@tonic-gate 			 * least that band or a hipri message.
6974*7c478bd9Sstevel@tonic-gate 			 */
6975*7c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_band >= *prip ||
6976*7c478bd9Sstevel@tonic-gate 				bp->b_datap->db_type >= QPCTL);
6977*7c478bd9Sstevel@tonic-gate 			if (bp->b_datap->db_type == M_SIG) {
6978*7c478bd9Sstevel@tonic-gate 				strsignal_nolock(stp, *bp->b_rptr,
6979*7c478bd9Sstevel@tonic-gate 				    (int32_t)bp->b_band);
6980*7c478bd9Sstevel@tonic-gate 				continue;
6981*7c478bd9Sstevel@tonic-gate 			} else {
6982*7c478bd9Sstevel@tonic-gate 				break;
6983*7c478bd9Sstevel@tonic-gate 			}
6984*7c478bd9Sstevel@tonic-gate 		}
6985*7c478bd9Sstevel@tonic-gate 
6986*7c478bd9Sstevel@tonic-gate 		/* No data. Time to sleep? */
6987*7c478bd9Sstevel@tonic-gate 		qbackenable(q, 0);
6988*7c478bd9Sstevel@tonic-gate 
6989*7c478bd9Sstevel@tonic-gate 		/*
6990*7c478bd9Sstevel@tonic-gate 		 * Delayed error notification?
6991*7c478bd9Sstevel@tonic-gate 		 */
6992*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & (STRDERR|STPLEX)) &&
6993*7c478bd9Sstevel@tonic-gate 		    (flags & (MSG_IGNERROR|MSG_DELAYERROR)) == MSG_DELAYERROR) {
6994*7c478bd9Sstevel@tonic-gate 			error = strgeterr(stp, STRDERR|STPLEX,
6995*7c478bd9Sstevel@tonic-gate 					(flags & MSG_IPEEK));
6996*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
6997*7c478bd9Sstevel@tonic-gate 				mutex_exit(&stp->sd_lock);
6998*7c478bd9Sstevel@tonic-gate 				return (error);
6999*7c478bd9Sstevel@tonic-gate 			}
7000*7c478bd9Sstevel@tonic-gate 		}
7001*7c478bd9Sstevel@tonic-gate 
7002*7c478bd9Sstevel@tonic-gate 		/*
7003*7c478bd9Sstevel@tonic-gate 		 * If STRHUP or STREOF, return 0 length control and data.
7004*7c478bd9Sstevel@tonic-gate 		 * If a read(fd,buf,0) has been done, do not sleep, just
7005*7c478bd9Sstevel@tonic-gate 		 * return.
7006*7c478bd9Sstevel@tonic-gate 		 *
7007*7c478bd9Sstevel@tonic-gate 		 * If mctlp == NULL and uiop == NULL, then the code will
7008*7c478bd9Sstevel@tonic-gate 		 * do the strwaitq. This is an understood way of saying
7009*7c478bd9Sstevel@tonic-gate 		 * sleep "polling" until a message is received.
7010*7c478bd9Sstevel@tonic-gate 		 */
7011*7c478bd9Sstevel@tonic-gate 		if ((stp->sd_flag & (STRHUP|STREOF)) ||
7012*7c478bd9Sstevel@tonic-gate 		    (uiop != NULL && uiop->uio_resid == 0)) {
7013*7c478bd9Sstevel@tonic-gate 			if (mctlp != NULL)
7014*7c478bd9Sstevel@tonic-gate 				*mctlp = NULL;
7015*7c478bd9Sstevel@tonic-gate 			*flagsp = 0;
7016*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7017*7c478bd9Sstevel@tonic-gate 			return (0);
7018*7c478bd9Sstevel@tonic-gate 		}
7019*7c478bd9Sstevel@tonic-gate 
7020*7c478bd9Sstevel@tonic-gate 		waitflag = GETWAIT;
7021*7c478bd9Sstevel@tonic-gate 		if (flags &
7022*7c478bd9Sstevel@tonic-gate 		    (MSG_HOLDSIG|MSG_IGNERROR|MSG_IPEEK|MSG_DELAYERROR)) {
7023*7c478bd9Sstevel@tonic-gate 			if (flags & MSG_HOLDSIG)
7024*7c478bd9Sstevel@tonic-gate 				waitflag |= STR_NOSIG;
7025*7c478bd9Sstevel@tonic-gate 			if (flags & MSG_IGNERROR)
7026*7c478bd9Sstevel@tonic-gate 				waitflag |= STR_NOERROR;
7027*7c478bd9Sstevel@tonic-gate 			if (flags & MSG_IPEEK)
7028*7c478bd9Sstevel@tonic-gate 				waitflag |= STR_PEEK;
7029*7c478bd9Sstevel@tonic-gate 			if (flags & MSG_DELAYERROR)
7030*7c478bd9Sstevel@tonic-gate 				waitflag |= STR_DELAYERR;
7031*7c478bd9Sstevel@tonic-gate 		}
7032*7c478bd9Sstevel@tonic-gate 		if (uiop != NULL)
7033*7c478bd9Sstevel@tonic-gate 			fmode = uiop->uio_fmode;
7034*7c478bd9Sstevel@tonic-gate 		else
7035*7c478bd9Sstevel@tonic-gate 			fmode = 0;
7036*7c478bd9Sstevel@tonic-gate 
7037*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_WAIT,
7038*7c478bd9Sstevel@tonic-gate 			"kstrgetmsg calls strwaitq:%p, %p",
7039*7c478bd9Sstevel@tonic-gate 			vp, uiop);
7040*7c478bd9Sstevel@tonic-gate 		if (((error = strwaitq(stp, waitflag, (ssize_t)0,
7041*7c478bd9Sstevel@tonic-gate 		    fmode, timout, &done)) != 0) || done) {
7042*7c478bd9Sstevel@tonic-gate 			TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_DONE,
7043*7c478bd9Sstevel@tonic-gate 				"kstrgetmsg error or done:%p, %p",
7044*7c478bd9Sstevel@tonic-gate 				vp, uiop);
7045*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7046*7c478bd9Sstevel@tonic-gate 			return (error);
7047*7c478bd9Sstevel@tonic-gate 		}
7048*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRGETMSG_AWAKE,
7049*7c478bd9Sstevel@tonic-gate 			"kstrgetmsg awakes:%p, %p", vp, uiop);
7050*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
7051*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7052*7c478bd9Sstevel@tonic-gate 			if (error = straccess(stp, JCREAD))
7053*7c478bd9Sstevel@tonic-gate 				return (error);
7054*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
7055*7c478bd9Sstevel@tonic-gate 		}
7056*7c478bd9Sstevel@tonic-gate 		first = 0;
7057*7c478bd9Sstevel@tonic-gate 	}
7058*7c478bd9Sstevel@tonic-gate 	ASSERT(bp != NULL);
7059*7c478bd9Sstevel@tonic-gate 	/*
7060*7c478bd9Sstevel@tonic-gate 	 * Extract any mark information. If the message is not completely
7061*7c478bd9Sstevel@tonic-gate 	 * consumed this information will be put in the mblk
7062*7c478bd9Sstevel@tonic-gate 	 * that is putback.
7063*7c478bd9Sstevel@tonic-gate 	 * If MSGMARKNEXT is set and the message is completely consumed
7064*7c478bd9Sstevel@tonic-gate 	 * the STRATMARK flag will be set below. Likewise, if
7065*7c478bd9Sstevel@tonic-gate 	 * MSGNOTMARKNEXT is set and the message is
7066*7c478bd9Sstevel@tonic-gate 	 * completely consumed STRNOTATMARK will be set.
7067*7c478bd9Sstevel@tonic-gate 	 */
7068*7c478bd9Sstevel@tonic-gate 	mark = bp->b_flag & (MSGMARK | MSGMARKNEXT | MSGNOTMARKNEXT);
7069*7c478bd9Sstevel@tonic-gate 	ASSERT((mark & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
7070*7c478bd9Sstevel@tonic-gate 		(MSGMARKNEXT|MSGNOTMARKNEXT));
7071*7c478bd9Sstevel@tonic-gate 	pri = bp->b_band;
7072*7c478bd9Sstevel@tonic-gate 	if (mark != 0) {
7073*7c478bd9Sstevel@tonic-gate 		/*
7074*7c478bd9Sstevel@tonic-gate 		 * If the caller doesn't want the mark return.
7075*7c478bd9Sstevel@tonic-gate 		 * Used to implement MSG_WAITALL in sockets.
7076*7c478bd9Sstevel@tonic-gate 		 */
7077*7c478bd9Sstevel@tonic-gate 		if (flags & MSG_NOMARK) {
7078*7c478bd9Sstevel@tonic-gate 			putback(stp, q, bp, pri);
7079*7c478bd9Sstevel@tonic-gate 			qbackenable(q, pri);
7080*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7081*7c478bd9Sstevel@tonic-gate 			return (EWOULDBLOCK);
7082*7c478bd9Sstevel@tonic-gate 		}
7083*7c478bd9Sstevel@tonic-gate 		if (bp == stp->sd_mark) {
7084*7c478bd9Sstevel@tonic-gate 			mark |= _LASTMARK;
7085*7c478bd9Sstevel@tonic-gate 			stp->sd_mark = NULL;
7086*7c478bd9Sstevel@tonic-gate 		}
7087*7c478bd9Sstevel@tonic-gate 	}
7088*7c478bd9Sstevel@tonic-gate 
7089*7c478bd9Sstevel@tonic-gate 	/*
7090*7c478bd9Sstevel@tonic-gate 	 * keep track of the first message type
7091*7c478bd9Sstevel@tonic-gate 	 */
7092*7c478bd9Sstevel@tonic-gate 	type = bp->b_datap->db_type;
7093*7c478bd9Sstevel@tonic-gate 
7094*7c478bd9Sstevel@tonic-gate 	if (bp->b_datap->db_type == M_PASSFP) {
7095*7c478bd9Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
7096*7c478bd9Sstevel@tonic-gate 			stp->sd_mark = bp;
7097*7c478bd9Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
7098*7c478bd9Sstevel@tonic-gate 		putback(stp, q, bp, pri);
7099*7c478bd9Sstevel@tonic-gate 		qbackenable(q, pri);
7100*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
7101*7c478bd9Sstevel@tonic-gate 		return (EBADMSG);
7102*7c478bd9Sstevel@tonic-gate 	}
7103*7c478bd9Sstevel@tonic-gate 	ASSERT(type != M_SIG);
7104*7c478bd9Sstevel@tonic-gate 
7105*7c478bd9Sstevel@tonic-gate 	if (flags & MSG_IPEEK) {
7106*7c478bd9Sstevel@tonic-gate 		/*
7107*7c478bd9Sstevel@tonic-gate 		 * Clear any struioflag - we do the uiomove over again
7108*7c478bd9Sstevel@tonic-gate 		 * when peeking since it simplifies the code.
7109*7c478bd9Sstevel@tonic-gate 		 *
7110*7c478bd9Sstevel@tonic-gate 		 * Dup the message and put the original back on the queue.
7111*7c478bd9Sstevel@tonic-gate 		 * If dupmsg() fails, try again with copymsg() to see if
7112*7c478bd9Sstevel@tonic-gate 		 * there is indeed a shortage of memory.  dupmsg() may fail
7113*7c478bd9Sstevel@tonic-gate 		 * if db_ref in any of the messages reaches its limit.
7114*7c478bd9Sstevel@tonic-gate 		 */
7115*7c478bd9Sstevel@tonic-gate 		if ((nbp = dupmsg(bp)) == NULL && (nbp = copymsg(bp)) == NULL) {
7116*7c478bd9Sstevel@tonic-gate 			/*
7117*7c478bd9Sstevel@tonic-gate 			 * Restore the state of the stream head since we
7118*7c478bd9Sstevel@tonic-gate 			 * need to drop sd_lock (strwaitbuf is sleeping).
7119*7c478bd9Sstevel@tonic-gate 			 */
7120*7c478bd9Sstevel@tonic-gate 			size_t size = msgdsize(bp);
7121*7c478bd9Sstevel@tonic-gate 
7122*7c478bd9Sstevel@tonic-gate 			if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
7123*7c478bd9Sstevel@tonic-gate 				stp->sd_mark = bp;
7124*7c478bd9Sstevel@tonic-gate 			bp->b_flag |= mark & ~_LASTMARK;
7125*7c478bd9Sstevel@tonic-gate 			putback(stp, q, bp, pri);
7126*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7127*7c478bd9Sstevel@tonic-gate 			error = strwaitbuf(size, BPRI_HI);
7128*7c478bd9Sstevel@tonic-gate 			if (error) {
7129*7c478bd9Sstevel@tonic-gate 				/*
7130*7c478bd9Sstevel@tonic-gate 				 * There is no net change to the queue thus
7131*7c478bd9Sstevel@tonic-gate 				 * no need to qbackenable.
7132*7c478bd9Sstevel@tonic-gate 				 */
7133*7c478bd9Sstevel@tonic-gate 				return (error);
7134*7c478bd9Sstevel@tonic-gate 			}
7135*7c478bd9Sstevel@tonic-gate 			goto retry;
7136*7c478bd9Sstevel@tonic-gate 		}
7137*7c478bd9Sstevel@tonic-gate 
7138*7c478bd9Sstevel@tonic-gate 		if ((mark & _LASTMARK) && (stp->sd_mark == NULL))
7139*7c478bd9Sstevel@tonic-gate 			stp->sd_mark = bp;
7140*7c478bd9Sstevel@tonic-gate 		bp->b_flag |= mark & ~_LASTMARK;
7141*7c478bd9Sstevel@tonic-gate 		putback(stp, q, bp, pri);
7142*7c478bd9Sstevel@tonic-gate 		bp = nbp;
7143*7c478bd9Sstevel@tonic-gate 	}
7144*7c478bd9Sstevel@tonic-gate 
7145*7c478bd9Sstevel@tonic-gate 	/*
7146*7c478bd9Sstevel@tonic-gate 	 * Set this flag so strrput will not generate signals. Need to
7147*7c478bd9Sstevel@tonic-gate 	 * make sure this flag is cleared before leaving this routine
7148*7c478bd9Sstevel@tonic-gate 	 * else signals will stop being sent.
7149*7c478bd9Sstevel@tonic-gate 	 */
7150*7c478bd9Sstevel@tonic-gate 	stp->sd_flag |= STRGETINPROG;
7151*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
7152*7c478bd9Sstevel@tonic-gate 
7153*7c478bd9Sstevel@tonic-gate 	if (STREAM_NEEDSERVICE(stp))
7154*7c478bd9Sstevel@tonic-gate 		stream_runservice(stp);
7155*7c478bd9Sstevel@tonic-gate 
7156*7c478bd9Sstevel@tonic-gate 	/*
7157*7c478bd9Sstevel@tonic-gate 	 * Set HIPRI flag if message is priority.
7158*7c478bd9Sstevel@tonic-gate 	 */
7159*7c478bd9Sstevel@tonic-gate 	if (type >= QPCTL)
7160*7c478bd9Sstevel@tonic-gate 		flg = MSG_HIPRI;
7161*7c478bd9Sstevel@tonic-gate 	else
7162*7c478bd9Sstevel@tonic-gate 		flg = MSG_BAND;
7163*7c478bd9Sstevel@tonic-gate 
7164*7c478bd9Sstevel@tonic-gate 	/*
7165*7c478bd9Sstevel@tonic-gate 	 * First process PROTO or PCPROTO blocks, if any.
7166*7c478bd9Sstevel@tonic-gate 	 */
7167*7c478bd9Sstevel@tonic-gate 	if (mctlp != NULL && type != M_DATA) {
7168*7c478bd9Sstevel@tonic-gate 		mblk_t *nbp;
7169*7c478bd9Sstevel@tonic-gate 
7170*7c478bd9Sstevel@tonic-gate 		*mctlp = bp;
7171*7c478bd9Sstevel@tonic-gate 		while (bp->b_cont && bp->b_cont->b_datap->db_type != M_DATA)
7172*7c478bd9Sstevel@tonic-gate 			bp = bp->b_cont;
7173*7c478bd9Sstevel@tonic-gate 		nbp = bp->b_cont;
7174*7c478bd9Sstevel@tonic-gate 		bp->b_cont = NULL;
7175*7c478bd9Sstevel@tonic-gate 		bp = nbp;
7176*7c478bd9Sstevel@tonic-gate 	}
7177*7c478bd9Sstevel@tonic-gate 
7178*7c478bd9Sstevel@tonic-gate 	if (bp && bp->b_datap->db_type != M_DATA) {
7179*7c478bd9Sstevel@tonic-gate 		/*
7180*7c478bd9Sstevel@tonic-gate 		 * More PROTO blocks in msg. Will only happen if mctlp is NULL.
7181*7c478bd9Sstevel@tonic-gate 		 */
7182*7c478bd9Sstevel@tonic-gate 		more |= MORECTL;
7183*7c478bd9Sstevel@tonic-gate 		savemp = bp;
7184*7c478bd9Sstevel@tonic-gate 		while (bp && bp->b_datap->db_type != M_DATA) {
7185*7c478bd9Sstevel@tonic-gate 			savemptail = bp;
7186*7c478bd9Sstevel@tonic-gate 			bp = bp->b_cont;
7187*7c478bd9Sstevel@tonic-gate 		}
7188*7c478bd9Sstevel@tonic-gate 		savemptail->b_cont = NULL;
7189*7c478bd9Sstevel@tonic-gate 	}
7190*7c478bd9Sstevel@tonic-gate 
7191*7c478bd9Sstevel@tonic-gate 	/*
7192*7c478bd9Sstevel@tonic-gate 	 * Now process DATA blocks, if any.
7193*7c478bd9Sstevel@tonic-gate 	 */
7194*7c478bd9Sstevel@tonic-gate 	if (uiop == NULL) {
7195*7c478bd9Sstevel@tonic-gate 		/* Append data to tail of mctlp */
7196*7c478bd9Sstevel@tonic-gate 		if (mctlp != NULL) {
7197*7c478bd9Sstevel@tonic-gate 			mblk_t **mpp = mctlp;
7198*7c478bd9Sstevel@tonic-gate 
7199*7c478bd9Sstevel@tonic-gate 			while (*mpp != NULL)
7200*7c478bd9Sstevel@tonic-gate 				mpp = &((*mpp)->b_cont);
7201*7c478bd9Sstevel@tonic-gate 			*mpp = bp;
7202*7c478bd9Sstevel@tonic-gate 			bp = NULL;
7203*7c478bd9Sstevel@tonic-gate 		}
7204*7c478bd9Sstevel@tonic-gate 	} else if (uiop->uio_resid >= 0 && bp) {
7205*7c478bd9Sstevel@tonic-gate 		size_t oldresid = uiop->uio_resid;
7206*7c478bd9Sstevel@tonic-gate 
7207*7c478bd9Sstevel@tonic-gate 		/*
7208*7c478bd9Sstevel@tonic-gate 		 * If a streams message is likely to consist
7209*7c478bd9Sstevel@tonic-gate 		 * of many small mblks, it is pulled up into
7210*7c478bd9Sstevel@tonic-gate 		 * one continuous chunk of memory.
7211*7c478bd9Sstevel@tonic-gate 		 * see longer comment at top of page
7212*7c478bd9Sstevel@tonic-gate 		 * by mblk_pull_len declaration.
7213*7c478bd9Sstevel@tonic-gate 		 */
7214*7c478bd9Sstevel@tonic-gate 
7215*7c478bd9Sstevel@tonic-gate 		if (MBLKL(bp) < mblk_pull_len) {
7216*7c478bd9Sstevel@tonic-gate 			(void) pullupmsg(bp, -1);
7217*7c478bd9Sstevel@tonic-gate 		}
7218*7c478bd9Sstevel@tonic-gate 
7219*7c478bd9Sstevel@tonic-gate 		bp = struiocopyout(bp, uiop, &error);
7220*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
7221*7c478bd9Sstevel@tonic-gate 			if (mctlp != NULL) {
7222*7c478bd9Sstevel@tonic-gate 				freemsg(*mctlp);
7223*7c478bd9Sstevel@tonic-gate 				*mctlp = NULL;
7224*7c478bd9Sstevel@tonic-gate 			} else
7225*7c478bd9Sstevel@tonic-gate 				freemsg(savemp);
7226*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
7227*7c478bd9Sstevel@tonic-gate 			/*
7228*7c478bd9Sstevel@tonic-gate 			 * clear stream head hi pri flag based on
7229*7c478bd9Sstevel@tonic-gate 			 * first message
7230*7c478bd9Sstevel@tonic-gate 			 */
7231*7c478bd9Sstevel@tonic-gate 			if (!(flags & MSG_IPEEK) && (type >= QPCTL)) {
7232*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
7233*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
7234*7c478bd9Sstevel@tonic-gate 			}
7235*7c478bd9Sstevel@tonic-gate 			more = 0;
7236*7c478bd9Sstevel@tonic-gate 			goto getmout;
7237*7c478bd9Sstevel@tonic-gate 		}
7238*7c478bd9Sstevel@tonic-gate 		/*
7239*7c478bd9Sstevel@tonic-gate 		 * (pr == 1) indicates a partial read.
7240*7c478bd9Sstevel@tonic-gate 		 */
7241*7c478bd9Sstevel@tonic-gate 		if (oldresid > uiop->uio_resid)
7242*7c478bd9Sstevel@tonic-gate 			pr = 1;
7243*7c478bd9Sstevel@tonic-gate 	}
7244*7c478bd9Sstevel@tonic-gate 
7245*7c478bd9Sstevel@tonic-gate 	if (bp) {			/* more data blocks in msg */
7246*7c478bd9Sstevel@tonic-gate 		more |= MOREDATA;
7247*7c478bd9Sstevel@tonic-gate 		if (savemp)
7248*7c478bd9Sstevel@tonic-gate 			savemptail->b_cont = bp;
7249*7c478bd9Sstevel@tonic-gate 		else
7250*7c478bd9Sstevel@tonic-gate 			savemp = bp;
7251*7c478bd9Sstevel@tonic-gate 	}
7252*7c478bd9Sstevel@tonic-gate 
7253*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
7254*7c478bd9Sstevel@tonic-gate 	if (savemp) {
7255*7c478bd9Sstevel@tonic-gate 		if (flags & (MSG_IPEEK|MSG_DISCARDTAIL)) {
7256*7c478bd9Sstevel@tonic-gate 			/*
7257*7c478bd9Sstevel@tonic-gate 			 * When MSG_DISCARDTAIL is set or
7258*7c478bd9Sstevel@tonic-gate 			 * when peeking discard any tail. When peeking this
7259*7c478bd9Sstevel@tonic-gate 			 * is the tail of the dup that was copied out - the
7260*7c478bd9Sstevel@tonic-gate 			 * message has already been putback on the queue.
7261*7c478bd9Sstevel@tonic-gate 			 * Return MOREDATA to the caller even though the data
7262*7c478bd9Sstevel@tonic-gate 			 * is discarded. This is used by sockets (to
7263*7c478bd9Sstevel@tonic-gate 			 * set MSG_TRUNC).
7264*7c478bd9Sstevel@tonic-gate 			 */
7265*7c478bd9Sstevel@tonic-gate 			freemsg(savemp);
7266*7c478bd9Sstevel@tonic-gate 			if (!(flags & MSG_IPEEK) && (type >= QPCTL)) {
7267*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
7268*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
7269*7c478bd9Sstevel@tonic-gate 			}
7270*7c478bd9Sstevel@tonic-gate 		} else if (pr && (savemp->b_datap->db_type == M_DATA) &&
7271*7c478bd9Sstevel@tonic-gate 			    msgnodata(savemp)) {
7272*7c478bd9Sstevel@tonic-gate 			/*
7273*7c478bd9Sstevel@tonic-gate 			 * Avoid queuing a zero-length tail part of
7274*7c478bd9Sstevel@tonic-gate 			 * a message. pr=1 indicates that we read some of
7275*7c478bd9Sstevel@tonic-gate 			 * the message.
7276*7c478bd9Sstevel@tonic-gate 			 */
7277*7c478bd9Sstevel@tonic-gate 			freemsg(savemp);
7278*7c478bd9Sstevel@tonic-gate 			more &= ~MOREDATA;
7279*7c478bd9Sstevel@tonic-gate 			if (type >= QPCTL) {
7280*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
7281*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRPRI;
7282*7c478bd9Sstevel@tonic-gate 			}
7283*7c478bd9Sstevel@tonic-gate 		} else {
7284*7c478bd9Sstevel@tonic-gate 			savemp->b_band = pri;
7285*7c478bd9Sstevel@tonic-gate 			/*
7286*7c478bd9Sstevel@tonic-gate 			 * If the first message was HIPRI and the one we're
7287*7c478bd9Sstevel@tonic-gate 			 * putting back isn't, then clear STRPRI, otherwise
7288*7c478bd9Sstevel@tonic-gate 			 * set STRPRI again.  Note that we must set STRPRI
7289*7c478bd9Sstevel@tonic-gate 			 * again since the flush logic in strrput_nondata()
7290*7c478bd9Sstevel@tonic-gate 			 * may have cleared it while we had sd_lock dropped.
7291*7c478bd9Sstevel@tonic-gate 			 */
7292*7c478bd9Sstevel@tonic-gate 			if (type >= QPCTL) {
7293*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_PCPROTO);
7294*7c478bd9Sstevel@tonic-gate 				if (queclass(savemp) < QPCTL)
7295*7c478bd9Sstevel@tonic-gate 					stp->sd_flag &= ~STRPRI;
7296*7c478bd9Sstevel@tonic-gate 				else
7297*7c478bd9Sstevel@tonic-gate 					stp->sd_flag |= STRPRI;
7298*7c478bd9Sstevel@tonic-gate 			} else if (queclass(savemp) >= QPCTL) {
7299*7c478bd9Sstevel@tonic-gate 				/*
7300*7c478bd9Sstevel@tonic-gate 				 * The first message was not a HIPRI message,
7301*7c478bd9Sstevel@tonic-gate 				 * but the one we are about to putback is.
7302*7c478bd9Sstevel@tonic-gate 				 * For simplicitly, we do not allow for HIPRI
7303*7c478bd9Sstevel@tonic-gate 				 * messages to be embedded in the message
7304*7c478bd9Sstevel@tonic-gate 				 * body, so just force it to same type as
7305*7c478bd9Sstevel@tonic-gate 				 * first message.
7306*7c478bd9Sstevel@tonic-gate 				 */
7307*7c478bd9Sstevel@tonic-gate 				ASSERT(type == M_DATA || type == M_PROTO);
7308*7c478bd9Sstevel@tonic-gate 				ASSERT(savemp->b_datap->db_type == M_PCPROTO);
7309*7c478bd9Sstevel@tonic-gate 				savemp->b_datap->db_type = type;
7310*7c478bd9Sstevel@tonic-gate 			}
7311*7c478bd9Sstevel@tonic-gate 			if (mark != 0) {
7312*7c478bd9Sstevel@tonic-gate 				if ((mark & _LASTMARK) &&
7313*7c478bd9Sstevel@tonic-gate 				    (stp->sd_mark == NULL)) {
7314*7c478bd9Sstevel@tonic-gate 					/*
7315*7c478bd9Sstevel@tonic-gate 					 * If another marked message arrived
7316*7c478bd9Sstevel@tonic-gate 					 * while sd_lock was not held sd_mark
7317*7c478bd9Sstevel@tonic-gate 					 * would be non-NULL.
7318*7c478bd9Sstevel@tonic-gate 					 */
7319*7c478bd9Sstevel@tonic-gate 					stp->sd_mark = savemp;
7320*7c478bd9Sstevel@tonic-gate 				}
7321*7c478bd9Sstevel@tonic-gate 				savemp->b_flag |= mark & ~_LASTMARK;
7322*7c478bd9Sstevel@tonic-gate 			}
7323*7c478bd9Sstevel@tonic-gate 			putback(stp, q, savemp, pri);
7324*7c478bd9Sstevel@tonic-gate 		}
7325*7c478bd9Sstevel@tonic-gate 	} else if (!(flags & MSG_IPEEK)) {
7326*7c478bd9Sstevel@tonic-gate 		/*
7327*7c478bd9Sstevel@tonic-gate 		 * The complete message was consumed.
7328*7c478bd9Sstevel@tonic-gate 		 *
7329*7c478bd9Sstevel@tonic-gate 		 * If another M_PCPROTO arrived while sd_lock was not held
7330*7c478bd9Sstevel@tonic-gate 		 * it would have been discarded since STRPRI was still set.
7331*7c478bd9Sstevel@tonic-gate 		 *
7332*7c478bd9Sstevel@tonic-gate 		 * Move the MSG*MARKNEXT information
7333*7c478bd9Sstevel@tonic-gate 		 * to the stream head just in case
7334*7c478bd9Sstevel@tonic-gate 		 * the read queue becomes empty.
7335*7c478bd9Sstevel@tonic-gate 		 * clear stream head hi pri flag based on
7336*7c478bd9Sstevel@tonic-gate 		 * first message
7337*7c478bd9Sstevel@tonic-gate 		 *
7338*7c478bd9Sstevel@tonic-gate 		 * If the stream head was at the mark
7339*7c478bd9Sstevel@tonic-gate 		 * (STRATMARK) before we dropped sd_lock above
7340*7c478bd9Sstevel@tonic-gate 		 * and some data was consumed then we have
7341*7c478bd9Sstevel@tonic-gate 		 * moved past the mark thus STRATMARK is
7342*7c478bd9Sstevel@tonic-gate 		 * cleared. However, if a message arrived in
7343*7c478bd9Sstevel@tonic-gate 		 * strrput during the copyout above causing
7344*7c478bd9Sstevel@tonic-gate 		 * STRATMARK to be set we can not clear that
7345*7c478bd9Sstevel@tonic-gate 		 * flag.
7346*7c478bd9Sstevel@tonic-gate 		 * XXX A "perimeter" would help by single-threading strrput,
7347*7c478bd9Sstevel@tonic-gate 		 * strread, strgetmsg and kstrgetmsg.
7348*7c478bd9Sstevel@tonic-gate 		 */
7349*7c478bd9Sstevel@tonic-gate 		if (type >= QPCTL) {
7350*7c478bd9Sstevel@tonic-gate 			ASSERT(type == M_PCPROTO);
7351*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRPRI;
7352*7c478bd9Sstevel@tonic-gate 		}
7353*7c478bd9Sstevel@tonic-gate 		if (mark & (MSGMARKNEXT|MSGNOTMARKNEXT|MSGMARK)) {
7354*7c478bd9Sstevel@tonic-gate 			if (mark & MSGMARKNEXT) {
7355*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRNOTATMARK;
7356*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= STRATMARK;
7357*7c478bd9Sstevel@tonic-gate 			} else if (mark & MSGNOTMARKNEXT) {
7358*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~STRATMARK;
7359*7c478bd9Sstevel@tonic-gate 				stp->sd_flag |= STRNOTATMARK;
7360*7c478bd9Sstevel@tonic-gate 			} else {
7361*7c478bd9Sstevel@tonic-gate 				stp->sd_flag &= ~(STRATMARK|STRNOTATMARK);
7362*7c478bd9Sstevel@tonic-gate 			}
7363*7c478bd9Sstevel@tonic-gate 		} else if (pr && (old_sd_flag & STRATMARK)) {
7364*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
7365*7c478bd9Sstevel@tonic-gate 		}
7366*7c478bd9Sstevel@tonic-gate 	}
7367*7c478bd9Sstevel@tonic-gate 
7368*7c478bd9Sstevel@tonic-gate 	*flagsp = flg;
7369*7c478bd9Sstevel@tonic-gate 	*prip = pri;
7370*7c478bd9Sstevel@tonic-gate 
7371*7c478bd9Sstevel@tonic-gate 	/*
7372*7c478bd9Sstevel@tonic-gate 	 * Getmsg cleanup processing - if the state of the queue has changed
7373*7c478bd9Sstevel@tonic-gate 	 * some signals may need to be sent and/or poll awakened.
7374*7c478bd9Sstevel@tonic-gate 	 */
7375*7c478bd9Sstevel@tonic-gate getmout:
7376*7c478bd9Sstevel@tonic-gate 	qbackenable(q, pri);
7377*7c478bd9Sstevel@tonic-gate 
7378*7c478bd9Sstevel@tonic-gate 	/*
7379*7c478bd9Sstevel@tonic-gate 	 * We dropped the stream head lock above. Send all M_SIG messages
7380*7c478bd9Sstevel@tonic-gate 	 * before processing stream head for SIGPOLL messages.
7381*7c478bd9Sstevel@tonic-gate 	 */
7382*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
7383*7c478bd9Sstevel@tonic-gate 	while ((bp = q->q_first) != NULL &&
7384*7c478bd9Sstevel@tonic-gate 	    (bp->b_datap->db_type == M_SIG)) {
7385*7c478bd9Sstevel@tonic-gate 		/*
7386*7c478bd9Sstevel@tonic-gate 		 * sd_lock is held so the content of the read queue can not
7387*7c478bd9Sstevel@tonic-gate 		 * change.
7388*7c478bd9Sstevel@tonic-gate 		 */
7389*7c478bd9Sstevel@tonic-gate 		bp = getq(q);
7390*7c478bd9Sstevel@tonic-gate 		ASSERT(bp != NULL && bp->b_datap->db_type == M_SIG);
7391*7c478bd9Sstevel@tonic-gate 
7392*7c478bd9Sstevel@tonic-gate 		strsignal_nolock(stp, *bp->b_rptr, (int32_t)bp->b_band);
7393*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
7394*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
7395*7c478bd9Sstevel@tonic-gate 		if (STREAM_NEEDSERVICE(stp))
7396*7c478bd9Sstevel@tonic-gate 			stream_runservice(stp);
7397*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
7398*7c478bd9Sstevel@tonic-gate 	}
7399*7c478bd9Sstevel@tonic-gate 
7400*7c478bd9Sstevel@tonic-gate 	/*
7401*7c478bd9Sstevel@tonic-gate 	 * stream head cannot change while we make the determination
7402*7c478bd9Sstevel@tonic-gate 	 * whether or not to send a signal. Drop the flag to allow strrput
7403*7c478bd9Sstevel@tonic-gate 	 * to send firstmsgsigs again.
7404*7c478bd9Sstevel@tonic-gate 	 */
7405*7c478bd9Sstevel@tonic-gate 	stp->sd_flag &= ~STRGETINPROG;
7406*7c478bd9Sstevel@tonic-gate 
7407*7c478bd9Sstevel@tonic-gate 	/*
7408*7c478bd9Sstevel@tonic-gate 	 * If the type of message at the front of the queue changed
7409*7c478bd9Sstevel@tonic-gate 	 * due to the receive the appropriate signals and pollwakeup events
7410*7c478bd9Sstevel@tonic-gate 	 * are generated. The type of changes are:
7411*7c478bd9Sstevel@tonic-gate 	 *	Processed a hipri message, q_first is not hipri.
7412*7c478bd9Sstevel@tonic-gate 	 *	Processed a band X message, and q_first is band Y.
7413*7c478bd9Sstevel@tonic-gate 	 * The generated signals and pollwakeups are identical to what
7414*7c478bd9Sstevel@tonic-gate 	 * strrput() generates should the message that is now on q_first
7415*7c478bd9Sstevel@tonic-gate 	 * arrive to an empty read queue.
7416*7c478bd9Sstevel@tonic-gate 	 *
7417*7c478bd9Sstevel@tonic-gate 	 * Note: only strrput will send a signal for a hipri message.
7418*7c478bd9Sstevel@tonic-gate 	 */
7419*7c478bd9Sstevel@tonic-gate 	if ((bp = q->q_first) != NULL && !(stp->sd_flag & STRPRI)) {
7420*7c478bd9Sstevel@tonic-gate 		strsigset_t signals = 0;
7421*7c478bd9Sstevel@tonic-gate 		strpollset_t pollwakeups = 0;
7422*7c478bd9Sstevel@tonic-gate 
7423*7c478bd9Sstevel@tonic-gate 		if (flg & MSG_HIPRI) {
7424*7c478bd9Sstevel@tonic-gate 			/*
7425*7c478bd9Sstevel@tonic-gate 			 * Removed a hipri message. Regular data at
7426*7c478bd9Sstevel@tonic-gate 			 * the front of  the queue.
7427*7c478bd9Sstevel@tonic-gate 			 */
7428*7c478bd9Sstevel@tonic-gate 			if (bp->b_band == 0) {
7429*7c478bd9Sstevel@tonic-gate 				signals = S_INPUT | S_RDNORM;
7430*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
7431*7c478bd9Sstevel@tonic-gate 			} else {
7432*7c478bd9Sstevel@tonic-gate 				signals = S_INPUT | S_RDBAND;
7433*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
7434*7c478bd9Sstevel@tonic-gate 			}
7435*7c478bd9Sstevel@tonic-gate 		} else if (pri != bp->b_band) {
7436*7c478bd9Sstevel@tonic-gate 			/*
7437*7c478bd9Sstevel@tonic-gate 			 * The band is different for the new q_first.
7438*7c478bd9Sstevel@tonic-gate 			 */
7439*7c478bd9Sstevel@tonic-gate 			if (bp->b_band == 0) {
7440*7c478bd9Sstevel@tonic-gate 				signals = S_RDNORM;
7441*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDNORM;
7442*7c478bd9Sstevel@tonic-gate 			} else {
7443*7c478bd9Sstevel@tonic-gate 				signals = S_RDBAND;
7444*7c478bd9Sstevel@tonic-gate 				pollwakeups = POLLIN | POLLRDBAND;
7445*7c478bd9Sstevel@tonic-gate 			}
7446*7c478bd9Sstevel@tonic-gate 		}
7447*7c478bd9Sstevel@tonic-gate 
7448*7c478bd9Sstevel@tonic-gate 		if (pollwakeups != 0) {
7449*7c478bd9Sstevel@tonic-gate 			if (pollwakeups == (POLLIN | POLLRDNORM)) {
7450*7c478bd9Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
7451*7c478bd9Sstevel@tonic-gate 					goto no_pollwake;
7452*7c478bd9Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
7453*7c478bd9Sstevel@tonic-gate 			}
7454*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7455*7c478bd9Sstevel@tonic-gate 			pollwakeup(&stp->sd_pollist, pollwakeups);
7456*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
7457*7c478bd9Sstevel@tonic-gate 		}
7458*7c478bd9Sstevel@tonic-gate no_pollwake:
7459*7c478bd9Sstevel@tonic-gate 
7460*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sigflags & signals)
7461*7c478bd9Sstevel@tonic-gate 			strsendsig(stp->sd_siglist, signals, bp->b_band, 0);
7462*7c478bd9Sstevel@tonic-gate 	}
7463*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
7464*7c478bd9Sstevel@tonic-gate 
7465*7c478bd9Sstevel@tonic-gate 	rvp->r_val1 = more;
7466*7c478bd9Sstevel@tonic-gate 	return (error);
7467*7c478bd9Sstevel@tonic-gate #undef	_LASTMARK
7468*7c478bd9Sstevel@tonic-gate }
7469*7c478bd9Sstevel@tonic-gate 
7470*7c478bd9Sstevel@tonic-gate /*
7471*7c478bd9Sstevel@tonic-gate  * Put a message downstream.
7472*7c478bd9Sstevel@tonic-gate  *
7473*7c478bd9Sstevel@tonic-gate  * NOTE: strputmsg and kstrputmsg have much of the logic in common.
7474*7c478bd9Sstevel@tonic-gate  */
7475*7c478bd9Sstevel@tonic-gate int
7476*7c478bd9Sstevel@tonic-gate strputmsg(
7477*7c478bd9Sstevel@tonic-gate 	struct vnode *vp,
7478*7c478bd9Sstevel@tonic-gate 	struct strbuf *mctl,
7479*7c478bd9Sstevel@tonic-gate 	struct strbuf *mdata,
7480*7c478bd9Sstevel@tonic-gate 	unsigned char pri,
7481*7c478bd9Sstevel@tonic-gate 	int flag,
7482*7c478bd9Sstevel@tonic-gate 	int fmode)
7483*7c478bd9Sstevel@tonic-gate {
7484*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
7485*7c478bd9Sstevel@tonic-gate 	queue_t *wqp;
7486*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
7487*7c478bd9Sstevel@tonic-gate 	ssize_t msgsize;
7488*7c478bd9Sstevel@tonic-gate 	ssize_t rmin, rmax;
7489*7c478bd9Sstevel@tonic-gate 	int error;
7490*7c478bd9Sstevel@tonic-gate 	struct uio uios;
7491*7c478bd9Sstevel@tonic-gate 	struct uio *uiop = &uios;
7492*7c478bd9Sstevel@tonic-gate 	struct iovec iovs;
7493*7c478bd9Sstevel@tonic-gate 	int xpg4 = 0;
7494*7c478bd9Sstevel@tonic-gate 
7495*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
7496*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
7497*7c478bd9Sstevel@tonic-gate 	wqp = stp->sd_wrq;
7498*7c478bd9Sstevel@tonic-gate 
7499*7c478bd9Sstevel@tonic-gate 	/*
7500*7c478bd9Sstevel@tonic-gate 	 * If it is an XPG4 application, we need to send
7501*7c478bd9Sstevel@tonic-gate 	 * SIGPIPE below
7502*7c478bd9Sstevel@tonic-gate 	 */
7503*7c478bd9Sstevel@tonic-gate 
7504*7c478bd9Sstevel@tonic-gate 	xpg4 = (flag & MSG_XPG4) ? 1 : 0;
7505*7c478bd9Sstevel@tonic-gate 	flag &= ~MSG_XPG4;
7506*7c478bd9Sstevel@tonic-gate 
7507*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
7508*7c478bd9Sstevel@tonic-gate 	if (audit_active)
7509*7c478bd9Sstevel@tonic-gate 		audit_strputmsg(vp, mctl, mdata, pri, flag, fmode);
7510*7c478bd9Sstevel@tonic-gate #endif
7511*7c478bd9Sstevel@tonic-gate 
7512*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
7513*7c478bd9Sstevel@tonic-gate 		if (error = straccess(stp, JCWRITE))
7514*7c478bd9Sstevel@tonic-gate 			return (error);
7515*7c478bd9Sstevel@tonic-gate 
7516*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
7517*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
7518*7c478bd9Sstevel@tonic-gate 		error = strwriteable(stp, B_FALSE, xpg4);
7519*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
7520*7c478bd9Sstevel@tonic-gate 		if (error != 0)
7521*7c478bd9Sstevel@tonic-gate 			return (error);
7522*7c478bd9Sstevel@tonic-gate 	}
7523*7c478bd9Sstevel@tonic-gate 
7524*7c478bd9Sstevel@tonic-gate 	/*
7525*7c478bd9Sstevel@tonic-gate 	 * Check for legal flag value.
7526*7c478bd9Sstevel@tonic-gate 	 */
7527*7c478bd9Sstevel@tonic-gate 	switch (flag) {
7528*7c478bd9Sstevel@tonic-gate 	case MSG_HIPRI:
7529*7c478bd9Sstevel@tonic-gate 		if ((mctl->len < 0) || (pri != 0))
7530*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
7531*7c478bd9Sstevel@tonic-gate 		break;
7532*7c478bd9Sstevel@tonic-gate 	case MSG_BAND:
7533*7c478bd9Sstevel@tonic-gate 		break;
7534*7c478bd9Sstevel@tonic-gate 
7535*7c478bd9Sstevel@tonic-gate 	default:
7536*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7537*7c478bd9Sstevel@tonic-gate 	}
7538*7c478bd9Sstevel@tonic-gate 
7539*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_STRPUTMSG_IN,
7540*7c478bd9Sstevel@tonic-gate 		"strputmsg in:stp %p", stp);
7541*7c478bd9Sstevel@tonic-gate 
7542*7c478bd9Sstevel@tonic-gate 	/* get these values from those cached in the stream head */
7543*7c478bd9Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
7544*7c478bd9Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
7545*7c478bd9Sstevel@tonic-gate 
7546*7c478bd9Sstevel@tonic-gate 	/*
7547*7c478bd9Sstevel@tonic-gate 	 * Make sure ctl and data sizes together fall within the
7548*7c478bd9Sstevel@tonic-gate 	 * limits of the max and min receive packet sizes and do
7549*7c478bd9Sstevel@tonic-gate 	 * not exceed system limit.
7550*7c478bd9Sstevel@tonic-gate 	 */
7551*7c478bd9Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
7552*7c478bd9Sstevel@tonic-gate 	if (rmax == 0) {
7553*7c478bd9Sstevel@tonic-gate 		return (ERANGE);
7554*7c478bd9Sstevel@tonic-gate 	}
7555*7c478bd9Sstevel@tonic-gate 	/*
7556*7c478bd9Sstevel@tonic-gate 	 * Use the MAXIMUM of sd_maxblk and q_maxpsz.
7557*7c478bd9Sstevel@tonic-gate 	 * Needed to prevent partial failures in the strmakedata loop.
7558*7c478bd9Sstevel@tonic-gate 	 */
7559*7c478bd9Sstevel@tonic-gate 	if (stp->sd_maxblk != INFPSZ && rmax != INFPSZ && rmax < stp->sd_maxblk)
7560*7c478bd9Sstevel@tonic-gate 		rmax = stp->sd_maxblk;
7561*7c478bd9Sstevel@tonic-gate 
7562*7c478bd9Sstevel@tonic-gate 	if ((msgsize = mdata->len) < 0) {
7563*7c478bd9Sstevel@tonic-gate 		msgsize = 0;
7564*7c478bd9Sstevel@tonic-gate 		rmin = 0;	/* no range check for NULL data part */
7565*7c478bd9Sstevel@tonic-gate 	}
7566*7c478bd9Sstevel@tonic-gate 	if ((msgsize < rmin) ||
7567*7c478bd9Sstevel@tonic-gate 	    ((msgsize > rmax) && (rmax != INFPSZ)) ||
7568*7c478bd9Sstevel@tonic-gate 	    (mctl->len > strctlsz)) {
7569*7c478bd9Sstevel@tonic-gate 		return (ERANGE);
7570*7c478bd9Sstevel@tonic-gate 	}
7571*7c478bd9Sstevel@tonic-gate 
7572*7c478bd9Sstevel@tonic-gate 	/*
7573*7c478bd9Sstevel@tonic-gate 	 * Setup uio and iov for data part
7574*7c478bd9Sstevel@tonic-gate 	 */
7575*7c478bd9Sstevel@tonic-gate 	iovs.iov_base = mdata->buf;
7576*7c478bd9Sstevel@tonic-gate 	iovs.iov_len = msgsize;
7577*7c478bd9Sstevel@tonic-gate 	uios.uio_iov = &iovs;
7578*7c478bd9Sstevel@tonic-gate 	uios.uio_iovcnt = 1;
7579*7c478bd9Sstevel@tonic-gate 	uios.uio_loffset = 0;
7580*7c478bd9Sstevel@tonic-gate 	uios.uio_segflg = UIO_USERSPACE;
7581*7c478bd9Sstevel@tonic-gate 	uios.uio_fmode = fmode;
7582*7c478bd9Sstevel@tonic-gate 	uios.uio_extflg = UIO_COPY_DEFAULT;
7583*7c478bd9Sstevel@tonic-gate 	uios.uio_resid = msgsize;
7584*7c478bd9Sstevel@tonic-gate 	uios.uio_offset = 0;
7585*7c478bd9Sstevel@tonic-gate 
7586*7c478bd9Sstevel@tonic-gate 	/* Ignore flow control in strput for HIPRI */
7587*7c478bd9Sstevel@tonic-gate 	if (flag & MSG_HIPRI)
7588*7c478bd9Sstevel@tonic-gate 		flag |= MSG_IGNFLOW;
7589*7c478bd9Sstevel@tonic-gate 
7590*7c478bd9Sstevel@tonic-gate 	for (;;) {
7591*7c478bd9Sstevel@tonic-gate 		int done = 0;
7592*7c478bd9Sstevel@tonic-gate 
7593*7c478bd9Sstevel@tonic-gate 		/*
7594*7c478bd9Sstevel@tonic-gate 		 * strput will always free the ctl mblk - even when strput
7595*7c478bd9Sstevel@tonic-gate 		 * fails.
7596*7c478bd9Sstevel@tonic-gate 		 */
7597*7c478bd9Sstevel@tonic-gate 		if ((error = strmakectl(mctl, flag, fmode, &mp)) != 0) {
7598*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
7599*7c478bd9Sstevel@tonic-gate 				"strputmsg out:stp %p out %d error %d",
7600*7c478bd9Sstevel@tonic-gate 				stp, 1, error);
7601*7c478bd9Sstevel@tonic-gate 			return (error);
7602*7c478bd9Sstevel@tonic-gate 		}
7603*7c478bd9Sstevel@tonic-gate 		/*
7604*7c478bd9Sstevel@tonic-gate 		 * Verify that the whole message can be transferred by
7605*7c478bd9Sstevel@tonic-gate 		 * strput.
7606*7c478bd9Sstevel@tonic-gate 		 */
7607*7c478bd9Sstevel@tonic-gate 		ASSERT(stp->sd_maxblk == INFPSZ ||
7608*7c478bd9Sstevel@tonic-gate 			stp->sd_maxblk >= mdata->len);
7609*7c478bd9Sstevel@tonic-gate 
7610*7c478bd9Sstevel@tonic-gate 		msgsize = mdata->len;
7611*7c478bd9Sstevel@tonic-gate 		error = strput(stp, mp, uiop, &msgsize, 0, pri, flag);
7612*7c478bd9Sstevel@tonic-gate 		mdata->len = msgsize;
7613*7c478bd9Sstevel@tonic-gate 
7614*7c478bd9Sstevel@tonic-gate 		if (error == 0)
7615*7c478bd9Sstevel@tonic-gate 			break;
7616*7c478bd9Sstevel@tonic-gate 
7617*7c478bd9Sstevel@tonic-gate 		if (error != EWOULDBLOCK)
7618*7c478bd9Sstevel@tonic-gate 			goto out;
7619*7c478bd9Sstevel@tonic-gate 
7620*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
7621*7c478bd9Sstevel@tonic-gate 		/*
7622*7c478bd9Sstevel@tonic-gate 		 * Check for a missed wakeup.
7623*7c478bd9Sstevel@tonic-gate 		 * Needed since strput did not hold sd_lock across
7624*7c478bd9Sstevel@tonic-gate 		 * the canputnext.
7625*7c478bd9Sstevel@tonic-gate 		 */
7626*7c478bd9Sstevel@tonic-gate 		if (bcanputnext(wqp, pri)) {
7627*7c478bd9Sstevel@tonic-gate 			/* Try again */
7628*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7629*7c478bd9Sstevel@tonic-gate 			continue;
7630*7c478bd9Sstevel@tonic-gate 		}
7631*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_STRPUTMSG_WAIT,
7632*7c478bd9Sstevel@tonic-gate 			"strputmsg wait:stp %p waits pri %d", stp, pri);
7633*7c478bd9Sstevel@tonic-gate 		if (((error = strwaitq(stp, WRITEWAIT, (ssize_t)0, fmode, -1,
7634*7c478bd9Sstevel@tonic-gate 		    &done)) != 0) || done) {
7635*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7636*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
7637*7c478bd9Sstevel@tonic-gate 				"strputmsg out:q %p out %d error %d",
7638*7c478bd9Sstevel@tonic-gate 				stp, 0, error);
7639*7c478bd9Sstevel@tonic-gate 			return (error);
7640*7c478bd9Sstevel@tonic-gate 		}
7641*7c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR, TR_STRPUTMSG_WAKE,
7642*7c478bd9Sstevel@tonic-gate 			"strputmsg wake:stp %p wakes", stp);
7643*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
7644*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO)
7645*7c478bd9Sstevel@tonic-gate 			if (error = straccess(stp, JCWRITE))
7646*7c478bd9Sstevel@tonic-gate 				return (error);
7647*7c478bd9Sstevel@tonic-gate 	}
7648*7c478bd9Sstevel@tonic-gate out:
7649*7c478bd9Sstevel@tonic-gate 	/*
7650*7c478bd9Sstevel@tonic-gate 	 * For historic reasons, applications expect EAGAIN
7651*7c478bd9Sstevel@tonic-gate 	 * when data mblk could not be allocated. so change
7652*7c478bd9Sstevel@tonic-gate 	 * ENOMEM back to EAGAIN
7653*7c478bd9Sstevel@tonic-gate 	 */
7654*7c478bd9Sstevel@tonic-gate 	if (error == ENOMEM)
7655*7c478bd9Sstevel@tonic-gate 		error = EAGAIN;
7656*7c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_STRPUTMSG_OUT,
7657*7c478bd9Sstevel@tonic-gate 		"strputmsg out:stp %p out %d error %d", stp, 2, error);
7658*7c478bd9Sstevel@tonic-gate 	return (error);
7659*7c478bd9Sstevel@tonic-gate }
7660*7c478bd9Sstevel@tonic-gate 
7661*7c478bd9Sstevel@tonic-gate /*
7662*7c478bd9Sstevel@tonic-gate  * Put a message downstream.
7663*7c478bd9Sstevel@tonic-gate  * Can send only an M_PROTO/M_PCPROTO by passing in a NULL uiop.
7664*7c478bd9Sstevel@tonic-gate  * The fmode flag (NDELAY, NONBLOCK) is the or of the flags in the uio
7665*7c478bd9Sstevel@tonic-gate  * and the fmode parameter.
7666*7c478bd9Sstevel@tonic-gate  *
7667*7c478bd9Sstevel@tonic-gate  * This routine handles the consolidation private flags:
7668*7c478bd9Sstevel@tonic-gate  *	MSG_IGNERROR	Ignore any stream head error except STPLEX.
7669*7c478bd9Sstevel@tonic-gate  *	MSG_HOLDSIG	Hold signals while waiting for data.
7670*7c478bd9Sstevel@tonic-gate  *	MSG_IGNFLOW	Don't check streams flow control.
7671*7c478bd9Sstevel@tonic-gate  *
7672*7c478bd9Sstevel@tonic-gate  * NOTE: strputmsg and kstrputmsg have much of the logic in common.
7673*7c478bd9Sstevel@tonic-gate  */
7674*7c478bd9Sstevel@tonic-gate int
7675*7c478bd9Sstevel@tonic-gate kstrputmsg(
7676*7c478bd9Sstevel@tonic-gate 	struct vnode *vp,
7677*7c478bd9Sstevel@tonic-gate 	mblk_t *mctl,
7678*7c478bd9Sstevel@tonic-gate 	struct uio *uiop,
7679*7c478bd9Sstevel@tonic-gate 	ssize_t msgsize,
7680*7c478bd9Sstevel@tonic-gate 	unsigned char pri,
7681*7c478bd9Sstevel@tonic-gate 	int flag,
7682*7c478bd9Sstevel@tonic-gate 	int fmode)
7683*7c478bd9Sstevel@tonic-gate {
7684*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
7685*7c478bd9Sstevel@tonic-gate 	queue_t *wqp;
7686*7c478bd9Sstevel@tonic-gate 	ssize_t rmin, rmax;
7687*7c478bd9Sstevel@tonic-gate 	int error;
7688*7c478bd9Sstevel@tonic-gate 
7689*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
7690*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
7691*7c478bd9Sstevel@tonic-gate 	wqp = stp->sd_wrq;
7692*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
7693*7c478bd9Sstevel@tonic-gate 	if (audit_active)
7694*7c478bd9Sstevel@tonic-gate 		audit_strputmsg(vp, NULL, NULL, pri, flag, fmode);
7695*7c478bd9Sstevel@tonic-gate #endif
7696*7c478bd9Sstevel@tonic-gate 
7697*7c478bd9Sstevel@tonic-gate 	if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
7698*7c478bd9Sstevel@tonic-gate 		if (error = straccess(stp, JCWRITE)) {
7699*7c478bd9Sstevel@tonic-gate 			freemsg(mctl);
7700*7c478bd9Sstevel@tonic-gate 			return (error);
7701*7c478bd9Sstevel@tonic-gate 		}
7702*7c478bd9Sstevel@tonic-gate 	}
7703*7c478bd9Sstevel@tonic-gate 
7704*7c478bd9Sstevel@tonic-gate 	if ((stp->sd_flag & STPLEX) || !(flag & MSG_IGNERROR)) {
7705*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) {
7706*7c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
7707*7c478bd9Sstevel@tonic-gate 			error = strwriteable(stp, B_FALSE, B_TRUE);
7708*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7709*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
7710*7c478bd9Sstevel@tonic-gate 				freemsg(mctl);
7711*7c478bd9Sstevel@tonic-gate 				return (error);
7712*7c478bd9Sstevel@tonic-gate 			}
7713*7c478bd9Sstevel@tonic-gate 		}
7714*7c478bd9Sstevel@tonic-gate 	}
7715*7c478bd9Sstevel@tonic-gate 
7716*7c478bd9Sstevel@tonic-gate 	/*
7717*7c478bd9Sstevel@tonic-gate 	 * Check for legal flag value.
7718*7c478bd9Sstevel@tonic-gate 	 */
7719*7c478bd9Sstevel@tonic-gate 	switch (flag & (MSG_HIPRI|MSG_BAND|MSG_ANY)) {
7720*7c478bd9Sstevel@tonic-gate 	case MSG_HIPRI:
7721*7c478bd9Sstevel@tonic-gate 		if ((mctl == NULL) || (pri != 0)) {
7722*7c478bd9Sstevel@tonic-gate 			freemsg(mctl);
7723*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
7724*7c478bd9Sstevel@tonic-gate 		}
7725*7c478bd9Sstevel@tonic-gate 		break;
7726*7c478bd9Sstevel@tonic-gate 	case MSG_BAND:
7727*7c478bd9Sstevel@tonic-gate 		break;
7728*7c478bd9Sstevel@tonic-gate 
7729*7c478bd9Sstevel@tonic-gate 	default:
7730*7c478bd9Sstevel@tonic-gate 		freemsg(mctl);
7731*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7732*7c478bd9Sstevel@tonic-gate 	}
7733*7c478bd9Sstevel@tonic-gate 
7734*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_IN,
7735*7c478bd9Sstevel@tonic-gate 		"kstrputmsg in:stp %p", stp);
7736*7c478bd9Sstevel@tonic-gate 
7737*7c478bd9Sstevel@tonic-gate 	/* get these values from those cached in the stream head */
7738*7c478bd9Sstevel@tonic-gate 	rmin = stp->sd_qn_minpsz;
7739*7c478bd9Sstevel@tonic-gate 	rmax = stp->sd_qn_maxpsz;
7740*7c478bd9Sstevel@tonic-gate 
7741*7c478bd9Sstevel@tonic-gate 	/*
7742*7c478bd9Sstevel@tonic-gate 	 * Make sure ctl and data sizes together fall within the
7743*7c478bd9Sstevel@tonic-gate 	 * limits of the max and min receive packet sizes and do
7744*7c478bd9Sstevel@tonic-gate 	 * not exceed system limit.
7745*7c478bd9Sstevel@tonic-gate 	 */
7746*7c478bd9Sstevel@tonic-gate 	ASSERT((rmax >= 0) || (rmax == INFPSZ));
7747*7c478bd9Sstevel@tonic-gate 	if (rmax == 0) {
7748*7c478bd9Sstevel@tonic-gate 		freemsg(mctl);
7749*7c478bd9Sstevel@tonic-gate 		return (ERANGE);
7750*7c478bd9Sstevel@tonic-gate 	}
7751*7c478bd9Sstevel@tonic-gate 	/*
7752*7c478bd9Sstevel@tonic-gate 	 * Use the MAXIMUM of sd_maxblk and q_maxpsz.
7753*7c478bd9Sstevel@tonic-gate 	 * Needed to prevent partial failures in the strmakedata loop.
7754*7c478bd9Sstevel@tonic-gate 	 */
7755*7c478bd9Sstevel@tonic-gate 	if (stp->sd_maxblk != INFPSZ && rmax != INFPSZ && rmax < stp->sd_maxblk)
7756*7c478bd9Sstevel@tonic-gate 		rmax = stp->sd_maxblk;
7757*7c478bd9Sstevel@tonic-gate 
7758*7c478bd9Sstevel@tonic-gate 	if (uiop == NULL) {
7759*7c478bd9Sstevel@tonic-gate 		msgsize = -1;
7760*7c478bd9Sstevel@tonic-gate 		rmin = -1;	/* no range check for NULL data part */
7761*7c478bd9Sstevel@tonic-gate 	} else {
7762*7c478bd9Sstevel@tonic-gate 		/* Use uio flags as well as the fmode parameter flags */
7763*7c478bd9Sstevel@tonic-gate 		fmode |= uiop->uio_fmode;
7764*7c478bd9Sstevel@tonic-gate 
7765*7c478bd9Sstevel@tonic-gate 		if ((msgsize < rmin) ||
7766*7c478bd9Sstevel@tonic-gate 		    ((msgsize > rmax) && (rmax != INFPSZ))) {
7767*7c478bd9Sstevel@tonic-gate 			freemsg(mctl);
7768*7c478bd9Sstevel@tonic-gate 			return (ERANGE);
7769*7c478bd9Sstevel@tonic-gate 		}
7770*7c478bd9Sstevel@tonic-gate 	}
7771*7c478bd9Sstevel@tonic-gate 
7772*7c478bd9Sstevel@tonic-gate 	/* Ignore flow control in strput for HIPRI */
7773*7c478bd9Sstevel@tonic-gate 	if (flag & MSG_HIPRI)
7774*7c478bd9Sstevel@tonic-gate 		flag |= MSG_IGNFLOW;
7775*7c478bd9Sstevel@tonic-gate 
7776*7c478bd9Sstevel@tonic-gate 	for (;;) {
7777*7c478bd9Sstevel@tonic-gate 		int done = 0;
7778*7c478bd9Sstevel@tonic-gate 		int waitflag;
7779*7c478bd9Sstevel@tonic-gate 		mblk_t *mp;
7780*7c478bd9Sstevel@tonic-gate 
7781*7c478bd9Sstevel@tonic-gate 		/*
7782*7c478bd9Sstevel@tonic-gate 		 * strput will always free the ctl mblk - even when strput
7783*7c478bd9Sstevel@tonic-gate 		 * fails. If MSG_IGNFLOW is set then any error returned
7784*7c478bd9Sstevel@tonic-gate 		 * will cause us to break the loop, so we don't need a copy
7785*7c478bd9Sstevel@tonic-gate 		 * of the message. If MSG_IGNFLOW is not set, then we can
7786*7c478bd9Sstevel@tonic-gate 		 * get hit by flow control and be forced to try again. In
7787*7c478bd9Sstevel@tonic-gate 		 * this case we need to have a copy of the message. We
7788*7c478bd9Sstevel@tonic-gate 		 * do this using copymsg since the message may get modified
7789*7c478bd9Sstevel@tonic-gate 		 * by something below us.
7790*7c478bd9Sstevel@tonic-gate 		 *
7791*7c478bd9Sstevel@tonic-gate 		 * We've observed that many TPI providers do not check db_ref
7792*7c478bd9Sstevel@tonic-gate 		 * on the control messages but blindly reuse them for the
7793*7c478bd9Sstevel@tonic-gate 		 * T_OK_ACK/T_ERROR_ACK. Thus using copymsg is more
7794*7c478bd9Sstevel@tonic-gate 		 * friendly to such providers than using dupmsg. Also, note
7795*7c478bd9Sstevel@tonic-gate 		 * that sockfs uses MSG_IGNFLOW for all TPI control messages.
7796*7c478bd9Sstevel@tonic-gate 		 * Only data messages are subject to flow control, hence
7797*7c478bd9Sstevel@tonic-gate 		 * subject to this copymsg.
7798*7c478bd9Sstevel@tonic-gate 		 */
7799*7c478bd9Sstevel@tonic-gate 		if (flag & MSG_IGNFLOW) {
7800*7c478bd9Sstevel@tonic-gate 			mp = mctl;
7801*7c478bd9Sstevel@tonic-gate 			mctl = NULL;
7802*7c478bd9Sstevel@tonic-gate 		} else {
7803*7c478bd9Sstevel@tonic-gate 			do {
7804*7c478bd9Sstevel@tonic-gate 				/*
7805*7c478bd9Sstevel@tonic-gate 				 * If a message has a free pointer, the message
7806*7c478bd9Sstevel@tonic-gate 				 * must be dupmsg to maintain this pointer.
7807*7c478bd9Sstevel@tonic-gate 				 * Code using this facility must be sure
7808*7c478bd9Sstevel@tonic-gate 				 * that modules below will not change the
7809*7c478bd9Sstevel@tonic-gate 				 * contents of the dblk without checking db_ref
7810*7c478bd9Sstevel@tonic-gate 				 * first. If db_ref is > 1, then the module
7811*7c478bd9Sstevel@tonic-gate 				 * needs to do a copymsg first. Otherwise,
7812*7c478bd9Sstevel@tonic-gate 				 * the contents of the dblk may become
7813*7c478bd9Sstevel@tonic-gate 				 * inconsistent because the freesmg/freeb below
7814*7c478bd9Sstevel@tonic-gate 				 * may end up calling atomic_add_32_nv.
7815*7c478bd9Sstevel@tonic-gate 				 * The atomic_add_32_nv in freeb (accessing
7816*7c478bd9Sstevel@tonic-gate 				 * all of db_ref, db_type, db_flags, and
7817*7c478bd9Sstevel@tonic-gate 				 * db_struioflag) does not prevent other threads
7818*7c478bd9Sstevel@tonic-gate 				 * from concurrently trying to modify e.g.
7819*7c478bd9Sstevel@tonic-gate 				 * db_type.
7820*7c478bd9Sstevel@tonic-gate 				 */
7821*7c478bd9Sstevel@tonic-gate 				if (mctl->b_datap->db_frtnp != NULL)
7822*7c478bd9Sstevel@tonic-gate 					mp = dupmsg(mctl);
7823*7c478bd9Sstevel@tonic-gate 				else
7824*7c478bd9Sstevel@tonic-gate 					mp = copymsg(mctl);
7825*7c478bd9Sstevel@tonic-gate 
7826*7c478bd9Sstevel@tonic-gate 				if (mp != NULL || mctl == NULL)
7827*7c478bd9Sstevel@tonic-gate 					break;
7828*7c478bd9Sstevel@tonic-gate 
7829*7c478bd9Sstevel@tonic-gate 				error = strwaitbuf(msgdsize(mctl), BPRI_MED);
7830*7c478bd9Sstevel@tonic-gate 				if (error) {
7831*7c478bd9Sstevel@tonic-gate 					freemsg(mctl);
7832*7c478bd9Sstevel@tonic-gate 					return (error);
7833*7c478bd9Sstevel@tonic-gate 				}
7834*7c478bd9Sstevel@tonic-gate 			} while (mp == NULL);
7835*7c478bd9Sstevel@tonic-gate 		}
7836*7c478bd9Sstevel@tonic-gate 		/*
7837*7c478bd9Sstevel@tonic-gate 		 * Verify that all of msgsize can be transferred by
7838*7c478bd9Sstevel@tonic-gate 		 * strput.
7839*7c478bd9Sstevel@tonic-gate 		 */
7840*7c478bd9Sstevel@tonic-gate 		ASSERT(stp->sd_maxblk == INFPSZ ||
7841*7c478bd9Sstevel@tonic-gate 			stp->sd_maxblk >= msgsize);
7842*7c478bd9Sstevel@tonic-gate 		error = strput(stp, mp, uiop, &msgsize, 0, pri, flag);
7843*7c478bd9Sstevel@tonic-gate 		if (error == 0)
7844*7c478bd9Sstevel@tonic-gate 			break;
7845*7c478bd9Sstevel@tonic-gate 
7846*7c478bd9Sstevel@tonic-gate 		if (error != EWOULDBLOCK)
7847*7c478bd9Sstevel@tonic-gate 			goto out;
7848*7c478bd9Sstevel@tonic-gate 
7849*7c478bd9Sstevel@tonic-gate 		/*
7850*7c478bd9Sstevel@tonic-gate 		 * IF MSG_IGNFLOW is set we should have broken out of loop
7851*7c478bd9Sstevel@tonic-gate 		 * above.
7852*7c478bd9Sstevel@tonic-gate 		 */
7853*7c478bd9Sstevel@tonic-gate 		ASSERT(!(flag & MSG_IGNFLOW));
7854*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
7855*7c478bd9Sstevel@tonic-gate 		/*
7856*7c478bd9Sstevel@tonic-gate 		 * Check for a missed wakeup.
7857*7c478bd9Sstevel@tonic-gate 		 * Needed since strput did not hold sd_lock across
7858*7c478bd9Sstevel@tonic-gate 		 * the canputnext.
7859*7c478bd9Sstevel@tonic-gate 		 */
7860*7c478bd9Sstevel@tonic-gate 		if (bcanputnext(wqp, pri)) {
7861*7c478bd9Sstevel@tonic-gate 			/* Try again */
7862*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7863*7c478bd9Sstevel@tonic-gate 			continue;
7864*7c478bd9Sstevel@tonic-gate 		}
7865*7c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_WAIT,
7866*7c478bd9Sstevel@tonic-gate 			"kstrputmsg wait:stp %p waits pri %d", stp, pri);
7867*7c478bd9Sstevel@tonic-gate 
7868*7c478bd9Sstevel@tonic-gate 		waitflag = WRITEWAIT;
7869*7c478bd9Sstevel@tonic-gate 		if (flag & (MSG_HOLDSIG|MSG_IGNERROR)) {
7870*7c478bd9Sstevel@tonic-gate 			if (flag & MSG_HOLDSIG)
7871*7c478bd9Sstevel@tonic-gate 				waitflag |= STR_NOSIG;
7872*7c478bd9Sstevel@tonic-gate 			if (flag & MSG_IGNERROR)
7873*7c478bd9Sstevel@tonic-gate 				waitflag |= STR_NOERROR;
7874*7c478bd9Sstevel@tonic-gate 		}
7875*7c478bd9Sstevel@tonic-gate 		if (((error = strwaitq(stp, waitflag,
7876*7c478bd9Sstevel@tonic-gate 		    (ssize_t)0, fmode, -1, &done)) != 0) || done) {
7877*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
7878*7c478bd9Sstevel@tonic-gate 			TRACE_3(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_OUT,
7879*7c478bd9Sstevel@tonic-gate 				"kstrputmsg out:stp %p out %d error %d",
7880*7c478bd9Sstevel@tonic-gate 				stp, 0, error);
7881*7c478bd9Sstevel@tonic-gate 			freemsg(mctl);
7882*7c478bd9Sstevel@tonic-gate 			return (error);
7883*7c478bd9Sstevel@tonic-gate 		}
7884*7c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_WAKE,
7885*7c478bd9Sstevel@tonic-gate 			"kstrputmsg wake:stp %p wakes", stp);
7886*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
7887*7c478bd9Sstevel@tonic-gate 		if (stp->sd_sidp != NULL && stp->sd_vnode->v_type != VFIFO) {
7888*7c478bd9Sstevel@tonic-gate 			if (error = straccess(stp, JCWRITE)) {
7889*7c478bd9Sstevel@tonic-gate 				freemsg(mctl);
7890*7c478bd9Sstevel@tonic-gate 				return (error);
7891*7c478bd9Sstevel@tonic-gate 			}
7892*7c478bd9Sstevel@tonic-gate 		}
7893*7c478bd9Sstevel@tonic-gate 	}
7894*7c478bd9Sstevel@tonic-gate out:
7895*7c478bd9Sstevel@tonic-gate 	freemsg(mctl);
7896*7c478bd9Sstevel@tonic-gate 	/*
7897*7c478bd9Sstevel@tonic-gate 	 * For historic reasons, applications expect EAGAIN
7898*7c478bd9Sstevel@tonic-gate 	 * when data mblk could not be allocated. so change
7899*7c478bd9Sstevel@tonic-gate 	 * ENOMEM back to EAGAIN
7900*7c478bd9Sstevel@tonic-gate 	 */
7901*7c478bd9Sstevel@tonic-gate 	if (error == ENOMEM)
7902*7c478bd9Sstevel@tonic-gate 		error = EAGAIN;
7903*7c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_STREAMS_FR, TR_KSTRPUTMSG_OUT,
7904*7c478bd9Sstevel@tonic-gate 		"kstrputmsg out:stp %p out %d error %d", stp, 2, error);
7905*7c478bd9Sstevel@tonic-gate 	return (error);
7906*7c478bd9Sstevel@tonic-gate }
7907*7c478bd9Sstevel@tonic-gate 
7908*7c478bd9Sstevel@tonic-gate /*
7909*7c478bd9Sstevel@tonic-gate  * Determines whether the necessary conditions are set on a stream
7910*7c478bd9Sstevel@tonic-gate  * for it to be readable, writeable, or have exceptions.
7911*7c478bd9Sstevel@tonic-gate  *
7912*7c478bd9Sstevel@tonic-gate  * strpoll handles the consolidation private events:
7913*7c478bd9Sstevel@tonic-gate  *	POLLNOERR	Do not return POLLERR even if there are stream
7914*7c478bd9Sstevel@tonic-gate  *			head errors.
7915*7c478bd9Sstevel@tonic-gate  *			Used by sockfs.
7916*7c478bd9Sstevel@tonic-gate  *	POLLRDDATA	Do not return POLLIN unless at least one message on
7917*7c478bd9Sstevel@tonic-gate  *			the queue contains one or more M_DATA mblks. Thus
7918*7c478bd9Sstevel@tonic-gate  *			when this flag is set a queue with only
7919*7c478bd9Sstevel@tonic-gate  *			M_PROTO/M_PCPROTO mblks does not return POLLIN.
7920*7c478bd9Sstevel@tonic-gate  *			Used by sockfs to ignore T_EXDATA_IND messages.
7921*7c478bd9Sstevel@tonic-gate  *
7922*7c478bd9Sstevel@tonic-gate  * Note: POLLRDDATA assumes that synch streams only return messages with
7923*7c478bd9Sstevel@tonic-gate  * an M_DATA attached (i.e. not messages consisting of only
7924*7c478bd9Sstevel@tonic-gate  * an M_PROTO/M_PCPROTO part).
7925*7c478bd9Sstevel@tonic-gate  */
7926*7c478bd9Sstevel@tonic-gate int
7927*7c478bd9Sstevel@tonic-gate strpoll(
7928*7c478bd9Sstevel@tonic-gate 	struct stdata *stp,
7929*7c478bd9Sstevel@tonic-gate 	short events_arg,
7930*7c478bd9Sstevel@tonic-gate 	int anyyet,
7931*7c478bd9Sstevel@tonic-gate 	short *reventsp,
7932*7c478bd9Sstevel@tonic-gate 	struct pollhead **phpp)
7933*7c478bd9Sstevel@tonic-gate {
7934*7c478bd9Sstevel@tonic-gate 	int events = (ushort_t)events_arg;
7935*7c478bd9Sstevel@tonic-gate 	int retevents = 0;
7936*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
7937*7c478bd9Sstevel@tonic-gate 	qband_t *qbp;
7938*7c478bd9Sstevel@tonic-gate 	long sd_flags = stp->sd_flag;
7939*7c478bd9Sstevel@tonic-gate 	int headlocked = 0;
7940*7c478bd9Sstevel@tonic-gate 
7941*7c478bd9Sstevel@tonic-gate 	/*
7942*7c478bd9Sstevel@tonic-gate 	 * For performance, a single 'if' tests for most possible edge
7943*7c478bd9Sstevel@tonic-gate 	 * conditions in one shot
7944*7c478bd9Sstevel@tonic-gate 	 */
7945*7c478bd9Sstevel@tonic-gate 	if (sd_flags & (STPLEX | STRDERR | STWRERR)) {
7946*7c478bd9Sstevel@tonic-gate 		if (sd_flags & STPLEX) {
7947*7c478bd9Sstevel@tonic-gate 			*reventsp = POLLNVAL;
7948*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
7949*7c478bd9Sstevel@tonic-gate 		}
7950*7c478bd9Sstevel@tonic-gate 		if (((events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) &&
7951*7c478bd9Sstevel@tonic-gate 		    (sd_flags & STRDERR)) ||
7952*7c478bd9Sstevel@tonic-gate 		    ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) &&
7953*7c478bd9Sstevel@tonic-gate 		    (sd_flags & STWRERR))) {
7954*7c478bd9Sstevel@tonic-gate 			if (!(events & POLLNOERR)) {
7955*7c478bd9Sstevel@tonic-gate 				*reventsp = POLLERR;
7956*7c478bd9Sstevel@tonic-gate 				return (0);
7957*7c478bd9Sstevel@tonic-gate 			}
7958*7c478bd9Sstevel@tonic-gate 		}
7959*7c478bd9Sstevel@tonic-gate 	}
7960*7c478bd9Sstevel@tonic-gate 	if (sd_flags & STRHUP) {
7961*7c478bd9Sstevel@tonic-gate 		retevents |= POLLHUP;
7962*7c478bd9Sstevel@tonic-gate 	} else if (events & (POLLWRNORM | POLLWRBAND)) {
7963*7c478bd9Sstevel@tonic-gate 		queue_t *tq;
7964*7c478bd9Sstevel@tonic-gate 		queue_t	*qp = stp->sd_wrq;
7965*7c478bd9Sstevel@tonic-gate 
7966*7c478bd9Sstevel@tonic-gate 		claimstr(qp);
7967*7c478bd9Sstevel@tonic-gate 		/* Find next module forward that has a service procedure */
7968*7c478bd9Sstevel@tonic-gate 		tq = qp->q_next->q_nfsrv;
7969*7c478bd9Sstevel@tonic-gate 		ASSERT(tq != NULL);
7970*7c478bd9Sstevel@tonic-gate 
7971*7c478bd9Sstevel@tonic-gate 		polllock(&stp->sd_pollist, QLOCK(tq));
7972*7c478bd9Sstevel@tonic-gate 		if (events & POLLWRNORM) {
7973*7c478bd9Sstevel@tonic-gate 			queue_t *sqp;
7974*7c478bd9Sstevel@tonic-gate 
7975*7c478bd9Sstevel@tonic-gate 			if (tq->q_flag & QFULL)
7976*7c478bd9Sstevel@tonic-gate 				/* ensure backq svc procedure runs */
7977*7c478bd9Sstevel@tonic-gate 				tq->q_flag |= QWANTW;
7978*7c478bd9Sstevel@tonic-gate 			else if ((sqp = stp->sd_struiowrq) != NULL) {
7979*7c478bd9Sstevel@tonic-gate 				/* Check sync stream barrier write q */
7980*7c478bd9Sstevel@tonic-gate 				mutex_exit(QLOCK(tq));
7981*7c478bd9Sstevel@tonic-gate 				polllock(&stp->sd_pollist, QLOCK(sqp));
7982*7c478bd9Sstevel@tonic-gate 				if (sqp->q_flag & QFULL)
7983*7c478bd9Sstevel@tonic-gate 					/* ensure pollwakeup() is done */
7984*7c478bd9Sstevel@tonic-gate 					sqp->q_flag |= QWANTWSYNC;
7985*7c478bd9Sstevel@tonic-gate 				else
7986*7c478bd9Sstevel@tonic-gate 					retevents |= POLLOUT;
7987*7c478bd9Sstevel@tonic-gate 				/* More write events to process ??? */
7988*7c478bd9Sstevel@tonic-gate 				if (! (events & POLLWRBAND)) {
7989*7c478bd9Sstevel@tonic-gate 					mutex_exit(QLOCK(sqp));
7990*7c478bd9Sstevel@tonic-gate 					releasestr(qp);
7991*7c478bd9Sstevel@tonic-gate 					goto chkrd;
7992*7c478bd9Sstevel@tonic-gate 				}
7993*7c478bd9Sstevel@tonic-gate 				mutex_exit(QLOCK(sqp));
7994*7c478bd9Sstevel@tonic-gate 				polllock(&stp->sd_pollist, QLOCK(tq));
7995*7c478bd9Sstevel@tonic-gate 			} else
7996*7c478bd9Sstevel@tonic-gate 				retevents |= POLLOUT;
7997*7c478bd9Sstevel@tonic-gate 		}
7998*7c478bd9Sstevel@tonic-gate 		if (events & POLLWRBAND) {
7999*7c478bd9Sstevel@tonic-gate 			qbp = tq->q_bandp;
8000*7c478bd9Sstevel@tonic-gate 			if (qbp) {
8001*7c478bd9Sstevel@tonic-gate 				while (qbp) {
8002*7c478bd9Sstevel@tonic-gate 					if (qbp->qb_flag & QB_FULL)
8003*7c478bd9Sstevel@tonic-gate 						qbp->qb_flag |= QB_WANTW;
8004*7c478bd9Sstevel@tonic-gate 					else
8005*7c478bd9Sstevel@tonic-gate 						retevents |= POLLWRBAND;
8006*7c478bd9Sstevel@tonic-gate 					qbp = qbp->qb_next;
8007*7c478bd9Sstevel@tonic-gate 				}
8008*7c478bd9Sstevel@tonic-gate 			} else {
8009*7c478bd9Sstevel@tonic-gate 				retevents |= POLLWRBAND;
8010*7c478bd9Sstevel@tonic-gate 			}
8011*7c478bd9Sstevel@tonic-gate 		}
8012*7c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(tq));
8013*7c478bd9Sstevel@tonic-gate 		releasestr(qp);
8014*7c478bd9Sstevel@tonic-gate 	}
8015*7c478bd9Sstevel@tonic-gate chkrd:
8016*7c478bd9Sstevel@tonic-gate 	if (sd_flags & STRPRI) {
8017*7c478bd9Sstevel@tonic-gate 		retevents |= (events & POLLPRI);
8018*7c478bd9Sstevel@tonic-gate 	} else if (events & (POLLRDNORM | POLLRDBAND | POLLIN)) {
8019*7c478bd9Sstevel@tonic-gate 		queue_t	*qp = _RD(stp->sd_wrq);
8020*7c478bd9Sstevel@tonic-gate 		int normevents = (events & (POLLIN | POLLRDNORM));
8021*7c478bd9Sstevel@tonic-gate 
8022*7c478bd9Sstevel@tonic-gate 		/*
8023*7c478bd9Sstevel@tonic-gate 		 * Note: Need to do polllock() here since ps_lock may be
8024*7c478bd9Sstevel@tonic-gate 		 * held. See bug 4191544.
8025*7c478bd9Sstevel@tonic-gate 		 */
8026*7c478bd9Sstevel@tonic-gate 		polllock(&stp->sd_pollist, &stp->sd_lock);
8027*7c478bd9Sstevel@tonic-gate 		headlocked = 1;
8028*7c478bd9Sstevel@tonic-gate 		mp = qp->q_first;
8029*7c478bd9Sstevel@tonic-gate 		while (mp) {
8030*7c478bd9Sstevel@tonic-gate 			/*
8031*7c478bd9Sstevel@tonic-gate 			 * For POLLRDDATA we scan b_cont and b_next until we
8032*7c478bd9Sstevel@tonic-gate 			 * find an M_DATA.
8033*7c478bd9Sstevel@tonic-gate 			 */
8034*7c478bd9Sstevel@tonic-gate 			if ((events & POLLRDDATA) &&
8035*7c478bd9Sstevel@tonic-gate 			    mp->b_datap->db_type != M_DATA) {
8036*7c478bd9Sstevel@tonic-gate 				mblk_t *nmp = mp->b_cont;
8037*7c478bd9Sstevel@tonic-gate 
8038*7c478bd9Sstevel@tonic-gate 				while (nmp != NULL &&
8039*7c478bd9Sstevel@tonic-gate 				    nmp->b_datap->db_type != M_DATA)
8040*7c478bd9Sstevel@tonic-gate 					nmp = nmp->b_cont;
8041*7c478bd9Sstevel@tonic-gate 				if (nmp == NULL) {
8042*7c478bd9Sstevel@tonic-gate 					mp = mp->b_next;
8043*7c478bd9Sstevel@tonic-gate 					continue;
8044*7c478bd9Sstevel@tonic-gate 				}
8045*7c478bd9Sstevel@tonic-gate 			}
8046*7c478bd9Sstevel@tonic-gate 			if (mp->b_band == 0)
8047*7c478bd9Sstevel@tonic-gate 				retevents |= normevents;
8048*7c478bd9Sstevel@tonic-gate 			else
8049*7c478bd9Sstevel@tonic-gate 				retevents |= (events & (POLLIN | POLLRDBAND));
8050*7c478bd9Sstevel@tonic-gate 			break;
8051*7c478bd9Sstevel@tonic-gate 		}
8052*7c478bd9Sstevel@tonic-gate 		if (! (retevents & normevents) &&
8053*7c478bd9Sstevel@tonic-gate 		    (stp->sd_wakeq & RSLEEP)) {
8054*7c478bd9Sstevel@tonic-gate 			/*
8055*7c478bd9Sstevel@tonic-gate 			 * Sync stream barrier read queue has data.
8056*7c478bd9Sstevel@tonic-gate 			 */
8057*7c478bd9Sstevel@tonic-gate 			retevents |= normevents;
8058*7c478bd9Sstevel@tonic-gate 		}
8059*7c478bd9Sstevel@tonic-gate 		/* Treat eof as normal data */
8060*7c478bd9Sstevel@tonic-gate 		if (sd_flags & STREOF)
8061*7c478bd9Sstevel@tonic-gate 			retevents |= normevents;
8062*7c478bd9Sstevel@tonic-gate 	}
8063*7c478bd9Sstevel@tonic-gate 
8064*7c478bd9Sstevel@tonic-gate 	*reventsp = (short)retevents;
8065*7c478bd9Sstevel@tonic-gate 	if (retevents) {
8066*7c478bd9Sstevel@tonic-gate 		if (headlocked)
8067*7c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
8068*7c478bd9Sstevel@tonic-gate 		return (0);
8069*7c478bd9Sstevel@tonic-gate 	}
8070*7c478bd9Sstevel@tonic-gate 
8071*7c478bd9Sstevel@tonic-gate 	/*
8072*7c478bd9Sstevel@tonic-gate 	 * If poll() has not found any events yet, set up event cell
8073*7c478bd9Sstevel@tonic-gate 	 * to wake up the poll if a requested event occurs on this
8074*7c478bd9Sstevel@tonic-gate 	 * stream.  Check for collisions with outstanding poll requests.
8075*7c478bd9Sstevel@tonic-gate 	 */
8076*7c478bd9Sstevel@tonic-gate 	if (!anyyet) {
8077*7c478bd9Sstevel@tonic-gate 		*phpp = &stp->sd_pollist;
8078*7c478bd9Sstevel@tonic-gate 		if (headlocked == 0) {
8079*7c478bd9Sstevel@tonic-gate 			polllock(&stp->sd_pollist, &stp->sd_lock);
8080*7c478bd9Sstevel@tonic-gate 			headlocked = 1;
8081*7c478bd9Sstevel@tonic-gate 		}
8082*7c478bd9Sstevel@tonic-gate 		stp->sd_rput_opt |= SR_POLLIN;
8083*7c478bd9Sstevel@tonic-gate 	}
8084*7c478bd9Sstevel@tonic-gate 	if (headlocked)
8085*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
8086*7c478bd9Sstevel@tonic-gate 	return (0);
8087*7c478bd9Sstevel@tonic-gate }
8088*7c478bd9Sstevel@tonic-gate 
8089*7c478bd9Sstevel@tonic-gate /*
8090*7c478bd9Sstevel@tonic-gate  * The purpose of putback() is to assure sleeping polls/reads
8091*7c478bd9Sstevel@tonic-gate  * are awakened when there are no new messages arriving at the,
8092*7c478bd9Sstevel@tonic-gate  * stream head, and a message is placed back on the read queue.
8093*7c478bd9Sstevel@tonic-gate  *
8094*7c478bd9Sstevel@tonic-gate  * sd_lock must be held when messages are placed back on stream
8095*7c478bd9Sstevel@tonic-gate  * head.  (getq() holds sd_lock when it removes messages from
8096*7c478bd9Sstevel@tonic-gate  * the queue)
8097*7c478bd9Sstevel@tonic-gate  */
8098*7c478bd9Sstevel@tonic-gate 
8099*7c478bd9Sstevel@tonic-gate static void
8100*7c478bd9Sstevel@tonic-gate putback(struct stdata *stp, queue_t *q, mblk_t *bp, int band)
8101*7c478bd9Sstevel@tonic-gate {
8102*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&stp->sd_lock));
8103*7c478bd9Sstevel@tonic-gate 	(void) putbq(q, bp);
8104*7c478bd9Sstevel@tonic-gate 	/*
8105*7c478bd9Sstevel@tonic-gate 	 * A message may have come in when the sd_lock was dropped in the
8106*7c478bd9Sstevel@tonic-gate 	 * calling routine. If this is the case and STR*ATMARK info was
8107*7c478bd9Sstevel@tonic-gate 	 * received, need to move that from the stream head to the q_last
8108*7c478bd9Sstevel@tonic-gate 	 * so that SIOCATMARK can return the proper value.
8109*7c478bd9Sstevel@tonic-gate 	 */
8110*7c478bd9Sstevel@tonic-gate 	if (stp->sd_flag & (STRATMARK | STRNOTATMARK)) {
8111*7c478bd9Sstevel@tonic-gate 		unsigned short *flagp = &q->q_last->b_flag;
8112*7c478bd9Sstevel@tonic-gate 		uint_t b_flag = (uint_t)*flagp;
8113*7c478bd9Sstevel@tonic-gate 
8114*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRATMARK) {
8115*7c478bd9Sstevel@tonic-gate 			b_flag &= ~MSGNOTMARKNEXT;
8116*7c478bd9Sstevel@tonic-gate 			b_flag |= MSGMARKNEXT;
8117*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRATMARK;
8118*7c478bd9Sstevel@tonic-gate 		} else {
8119*7c478bd9Sstevel@tonic-gate 			b_flag &= ~MSGMARKNEXT;
8120*7c478bd9Sstevel@tonic-gate 			b_flag |= MSGNOTMARKNEXT;
8121*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STRNOTATMARK;
8122*7c478bd9Sstevel@tonic-gate 		}
8123*7c478bd9Sstevel@tonic-gate 		*flagp = (unsigned short) b_flag;
8124*7c478bd9Sstevel@tonic-gate 	}
8125*7c478bd9Sstevel@tonic-gate 
8126*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
8127*7c478bd9Sstevel@tonic-gate 	/*
8128*7c478bd9Sstevel@tonic-gate 	 * Make sure that the flags are not messed up.
8129*7c478bd9Sstevel@tonic-gate 	 */
8130*7c478bd9Sstevel@tonic-gate 	{
8131*7c478bd9Sstevel@tonic-gate 		mblk_t *mp;
8132*7c478bd9Sstevel@tonic-gate 		mp = q->q_last;
8133*7c478bd9Sstevel@tonic-gate 		while (mp != NULL) {
8134*7c478bd9Sstevel@tonic-gate 			ASSERT((mp->b_flag & (MSGMARKNEXT|MSGNOTMARKNEXT)) !=
8135*7c478bd9Sstevel@tonic-gate 			    (MSGMARKNEXT|MSGNOTMARKNEXT));
8136*7c478bd9Sstevel@tonic-gate 			mp = mp->b_cont;
8137*7c478bd9Sstevel@tonic-gate 		}
8138*7c478bd9Sstevel@tonic-gate 	}
8139*7c478bd9Sstevel@tonic-gate #endif
8140*7c478bd9Sstevel@tonic-gate 	if (q->q_first == bp) {
8141*7c478bd9Sstevel@tonic-gate 		short pollevents;
8142*7c478bd9Sstevel@tonic-gate 
8143*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & RSLEEP) {
8144*7c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~RSLEEP;
8145*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&q->q_wait);
8146*7c478bd9Sstevel@tonic-gate 		}
8147*7c478bd9Sstevel@tonic-gate 		if (stp->sd_flag & STRPRI) {
8148*7c478bd9Sstevel@tonic-gate 			pollevents = POLLPRI;
8149*7c478bd9Sstevel@tonic-gate 		} else {
8150*7c478bd9Sstevel@tonic-gate 			if (band == 0) {
8151*7c478bd9Sstevel@tonic-gate 				if (!(stp->sd_rput_opt & SR_POLLIN))
8152*7c478bd9Sstevel@tonic-gate 					return;
8153*7c478bd9Sstevel@tonic-gate 				stp->sd_rput_opt &= ~SR_POLLIN;
8154*7c478bd9Sstevel@tonic-gate 				pollevents = POLLIN | POLLRDNORM;
8155*7c478bd9Sstevel@tonic-gate 			} else {
8156*7c478bd9Sstevel@tonic-gate 				pollevents = POLLIN | POLLRDBAND;
8157*7c478bd9Sstevel@tonic-gate 			}
8158*7c478bd9Sstevel@tonic-gate 		}
8159*7c478bd9Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
8160*7c478bd9Sstevel@tonic-gate 		pollwakeup(&stp->sd_pollist, pollevents);
8161*7c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
8162*7c478bd9Sstevel@tonic-gate 	}
8163*7c478bd9Sstevel@tonic-gate }
8164*7c478bd9Sstevel@tonic-gate 
8165*7c478bd9Sstevel@tonic-gate /*
8166*7c478bd9Sstevel@tonic-gate  * Return the held vnode attached to the stream head of a
8167*7c478bd9Sstevel@tonic-gate  * given queue
8168*7c478bd9Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
8169*7c478bd9Sstevel@tonic-gate  * that the queue does not go away (e.g. pop).
8170*7c478bd9Sstevel@tonic-gate  */
8171*7c478bd9Sstevel@tonic-gate vnode_t *
8172*7c478bd9Sstevel@tonic-gate strq2vp(queue_t *qp)
8173*7c478bd9Sstevel@tonic-gate {
8174*7c478bd9Sstevel@tonic-gate 	vnode_t *vp;
8175*7c478bd9Sstevel@tonic-gate 	vp = STREAM(qp)->sd_vnode;
8176*7c478bd9Sstevel@tonic-gate 	ASSERT(vp != NULL);
8177*7c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
8178*7c478bd9Sstevel@tonic-gate 	return (vp);
8179*7c478bd9Sstevel@tonic-gate }
8180*7c478bd9Sstevel@tonic-gate 
8181*7c478bd9Sstevel@tonic-gate /*
8182*7c478bd9Sstevel@tonic-gate  * return the stream head write queue for the given vp
8183*7c478bd9Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
8184*7c478bd9Sstevel@tonic-gate  * that the stream or vnode do not close.
8185*7c478bd9Sstevel@tonic-gate  */
8186*7c478bd9Sstevel@tonic-gate queue_t *
8187*7c478bd9Sstevel@tonic-gate strvp2wq(vnode_t *vp)
8188*7c478bd9Sstevel@tonic-gate {
8189*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream != NULL);
8190*7c478bd9Sstevel@tonic-gate 	return (vp->v_stream->sd_wrq);
8191*7c478bd9Sstevel@tonic-gate }
8192*7c478bd9Sstevel@tonic-gate 
8193*7c478bd9Sstevel@tonic-gate /*
8194*7c478bd9Sstevel@tonic-gate  * pollwakeup stream head
8195*7c478bd9Sstevel@tonic-gate  * It is the responsibility of the calling routine to ensure
8196*7c478bd9Sstevel@tonic-gate  * that the stream or vnode do not close.
8197*7c478bd9Sstevel@tonic-gate  */
8198*7c478bd9Sstevel@tonic-gate void
8199*7c478bd9Sstevel@tonic-gate strpollwakeup(vnode_t *vp, short event)
8200*7c478bd9Sstevel@tonic-gate {
8201*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
8202*7c478bd9Sstevel@tonic-gate 	pollwakeup(&vp->v_stream->sd_pollist, event);
8203*7c478bd9Sstevel@tonic-gate }
8204*7c478bd9Sstevel@tonic-gate 
8205*7c478bd9Sstevel@tonic-gate /*
8206*7c478bd9Sstevel@tonic-gate  * Mate the stream heads of two vnodes together. If the two vnodes are the
8207*7c478bd9Sstevel@tonic-gate  * same, we just make the write-side point at the read-side -- otherwise,
8208*7c478bd9Sstevel@tonic-gate  * we do a full mate.  Only works on vnodes associated with streams that are
8209*7c478bd9Sstevel@tonic-gate  * still being built and thus have only a stream head.
8210*7c478bd9Sstevel@tonic-gate  */
8211*7c478bd9Sstevel@tonic-gate void
8212*7c478bd9Sstevel@tonic-gate strmate(vnode_t *vp1, vnode_t *vp2)
8213*7c478bd9Sstevel@tonic-gate {
8214*7c478bd9Sstevel@tonic-gate 	queue_t *wrq1 = strvp2wq(vp1);
8215*7c478bd9Sstevel@tonic-gate 	queue_t *wrq2 = strvp2wq(vp2);
8216*7c478bd9Sstevel@tonic-gate 
8217*7c478bd9Sstevel@tonic-gate 	/*
8218*7c478bd9Sstevel@tonic-gate 	 * Verify that there are no modules on the stream yet.  We also
8219*7c478bd9Sstevel@tonic-gate 	 * rely on the stream head always having a service procedure to
8220*7c478bd9Sstevel@tonic-gate 	 * avoid tweaking q_nfsrv.
8221*7c478bd9Sstevel@tonic-gate 	 */
8222*7c478bd9Sstevel@tonic-gate 	ASSERT(wrq1->q_next == NULL && wrq2->q_next == NULL);
8223*7c478bd9Sstevel@tonic-gate 	ASSERT(wrq1->q_qinfo->qi_srvp != NULL);
8224*7c478bd9Sstevel@tonic-gate 	ASSERT(wrq2->q_qinfo->qi_srvp != NULL);
8225*7c478bd9Sstevel@tonic-gate 
8226*7c478bd9Sstevel@tonic-gate 	/*
8227*7c478bd9Sstevel@tonic-gate 	 * If the queues are the same, just twist; otherwise do a full mate.
8228*7c478bd9Sstevel@tonic-gate 	 */
8229*7c478bd9Sstevel@tonic-gate 	if (wrq1 == wrq2) {
8230*7c478bd9Sstevel@tonic-gate 		wrq1->q_next = _RD(wrq1);
8231*7c478bd9Sstevel@tonic-gate 	} else {
8232*7c478bd9Sstevel@tonic-gate 		wrq1->q_next = _RD(wrq2);
8233*7c478bd9Sstevel@tonic-gate 		wrq2->q_next = _RD(wrq1);
8234*7c478bd9Sstevel@tonic-gate 		STREAM(wrq1)->sd_mate = STREAM(wrq2);
8235*7c478bd9Sstevel@tonic-gate 		STREAM(wrq1)->sd_flag |= STRMATE;
8236*7c478bd9Sstevel@tonic-gate 		STREAM(wrq2)->sd_mate = STREAM(wrq1);
8237*7c478bd9Sstevel@tonic-gate 		STREAM(wrq2)->sd_flag |= STRMATE;
8238*7c478bd9Sstevel@tonic-gate 	}
8239*7c478bd9Sstevel@tonic-gate }
8240*7c478bd9Sstevel@tonic-gate 
8241*7c478bd9Sstevel@tonic-gate /*
8242*7c478bd9Sstevel@tonic-gate  * XXX will go away when console is correctly fixed.
8243*7c478bd9Sstevel@tonic-gate  * Clean up the console PIDS, from previous I_SETSIG,
8244*7c478bd9Sstevel@tonic-gate  * called only for cnopen which never calls strclean().
8245*7c478bd9Sstevel@tonic-gate  */
8246*7c478bd9Sstevel@tonic-gate void
8247*7c478bd9Sstevel@tonic-gate str_cn_clean(struct vnode *vp)
8248*7c478bd9Sstevel@tonic-gate {
8249*7c478bd9Sstevel@tonic-gate 	strsig_t *ssp, *pssp, *tssp;
8250*7c478bd9Sstevel@tonic-gate 	struct stdata *stp;
8251*7c478bd9Sstevel@tonic-gate 	struct pid  *pidp;
8252*7c478bd9Sstevel@tonic-gate 	int update = 0;
8253*7c478bd9Sstevel@tonic-gate 
8254*7c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
8255*7c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
8256*7c478bd9Sstevel@tonic-gate 	pssp = NULL;
8257*7c478bd9Sstevel@tonic-gate 	mutex_enter(&stp->sd_lock);
8258*7c478bd9Sstevel@tonic-gate 	ssp = stp->sd_siglist;
8259*7c478bd9Sstevel@tonic-gate 	while (ssp) {
8260*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
8261*7c478bd9Sstevel@tonic-gate 		pidp = ssp->ss_pidp;
8262*7c478bd9Sstevel@tonic-gate 		/*
8263*7c478bd9Sstevel@tonic-gate 		 * Get rid of PID if the proc is gone.
8264*7c478bd9Sstevel@tonic-gate 		 */
8265*7c478bd9Sstevel@tonic-gate 		if (pidp->pid_prinactive) {
8266*7c478bd9Sstevel@tonic-gate 			tssp = ssp->ss_next;
8267*7c478bd9Sstevel@tonic-gate 			if (pssp)
8268*7c478bd9Sstevel@tonic-gate 				pssp->ss_next = tssp;
8269*7c478bd9Sstevel@tonic-gate 			else
8270*7c478bd9Sstevel@tonic-gate 				stp->sd_siglist = tssp;
8271*7c478bd9Sstevel@tonic-gate 			ASSERT(pidp->pid_ref <= 1);
8272*7c478bd9Sstevel@tonic-gate 			PID_RELE(ssp->ss_pidp);
8273*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
8274*7c478bd9Sstevel@tonic-gate 			kmem_free(ssp, sizeof (strsig_t));
8275*7c478bd9Sstevel@tonic-gate 			update = 1;
8276*7c478bd9Sstevel@tonic-gate 			ssp = tssp;
8277*7c478bd9Sstevel@tonic-gate 			continue;
8278*7c478bd9Sstevel@tonic-gate 		} else
8279*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
8280*7c478bd9Sstevel@tonic-gate 		pssp = ssp;
8281*7c478bd9Sstevel@tonic-gate 		ssp = ssp->ss_next;
8282*7c478bd9Sstevel@tonic-gate 	}
8283*7c478bd9Sstevel@tonic-gate 	if (update) {
8284*7c478bd9Sstevel@tonic-gate 		stp->sd_sigflags = 0;
8285*7c478bd9Sstevel@tonic-gate 		for (ssp = stp->sd_siglist; ssp; ssp = ssp->ss_next)
8286*7c478bd9Sstevel@tonic-gate 			stp->sd_sigflags |= ssp->ss_events;
8287*7c478bd9Sstevel@tonic-gate 	}
8288*7c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_lock);
8289*7c478bd9Sstevel@tonic-gate }
8290*7c478bd9Sstevel@tonic-gate 
8291*7c478bd9Sstevel@tonic-gate /*
8292*7c478bd9Sstevel@tonic-gate  * Return B_TRUE if there is data in the message, B_FALSE otherwise.
8293*7c478bd9Sstevel@tonic-gate  */
8294*7c478bd9Sstevel@tonic-gate static boolean_t
8295*7c478bd9Sstevel@tonic-gate msghasdata(mblk_t *bp)
8296*7c478bd9Sstevel@tonic-gate {
8297*7c478bd9Sstevel@tonic-gate 	for (; bp; bp = bp->b_cont)
8298*7c478bd9Sstevel@tonic-gate 		if (bp->b_datap->db_type == M_DATA) {
8299*7c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_wptr >= bp->b_rptr);
8300*7c478bd9Sstevel@tonic-gate 			if (bp->b_wptr > bp->b_rptr)
8301*7c478bd9Sstevel@tonic-gate 				return (B_TRUE);
8302*7c478bd9Sstevel@tonic-gate 		}
8303*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
8304*7c478bd9Sstevel@tonic-gate }
8305